java 多线程 文件下载_Java多线程文件下载性能

最近,我完成了一个项目,该项目比以前需要更多的IO交互,我觉得我想超越常规库(尤其是Common IO),并解决一些更深入的IO问题。

作为一项学术测试,我决定实现一个基本的多线程HTTP下载程序。这个想法很简单:提供要下载的URL,然后代码将下载文件。为了提高下载速度,将文件分块,并同时下载每个块(使用HTTP

Range: bytes=x-x标头)以使用尽可能多的带宽。

我有一个可以正常工作的原型,但是正如您可能已经猜到的那样,它并不理想。目前,我手动启动了3个“下载程序”线程,每个线程下载文件的1/3。这些线程使用通用的同步“文件编写器”实例将文件实际写入磁盘。完成所有线程后,“文件编写器”完成,所有打开的流都关闭。一些代码片段可以帮助您:

线程启动:

ExecutorService downloadExecutor = Executors.newFixedThreadPool(3);

...

downloadExecutor.execute(new Downloader(fileWriter, download, start1, end1));

downloadExecutor.execute(new Downloader(fileWriter, download, start2, end2));

downloadExecutor.execute(new Downloader(fileWriter, download, start3, end3));

每个“下载器”线程都下载一块(缓冲的)块,并使用“文件编写器”将其写入磁盘:

int bytesRead = 0;

byte[] buffer = new byte[1024*1024];

InputStream inStream = entity.getContent();

long seekOffset = chunkStart;

while ((bytesRead = inStream.read(buffer)) != -1)

{

fileWriter.write(buffer, bytesRead, seekOffset);

seekOffset += bytesRead;

}

“文件编写器”使用RandomAccessFileto seek()和write()将大块写入磁盘:

public synchronized void write(byte[] bytes, int len, long start) throws IOException

{

output.seek(start);

output.write(bytes, 0, len);

}

考虑所有事情,这种方法似乎行得通。但是,它不能很好地工作。对于以下几点,我将不胜感激。非常感激。

此代码的 CPU使用率 是通过屋顶计算的。它使用了我一半的CPU(2个内核中的每个内核的50%)来执行此操作,这比类似的下载工具成倍增加,后者几乎没有给CPU带来压力。我对这种CPU使用量的来源有些怀疑,因为我没想到这一点。

通常,似乎3个线程中有1个明显 滞后 。其他2个线程将完成,此后,第三个线程(似乎主要是带有第一个块的第一个线程)需要30秒钟或更长时间才能完成。我从任务管理器中可以看到javaw进程仍在进行较小的IO写入,但是我真的不知道为什么会发生这种情况(我正在猜测竞争条件?)。

尽管我选择了一个很大的缓冲区(1MB),但我仍然感到InputStream几乎从来没有真正填充过缓冲区,这会导致IO写操作比我想要的更多。我的印象是,在这种情况下,最好将IO访问保持在最低水平,但是我不确定这是否是最好的方法。

我意识到Java可能不是执行此类操作的理想语言,但是我坚信要拥有比当前实现更多的性能。在这种情况下,NIO是否值得探索?

注意: 我使用Apache HTTPClient进行HTTP交互,这就是它的来历entity.getContent()(以防万一有人想知道)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值