Java多线程文件下载性能

tmb*_*gmn 18 java io performance multithreading http

最近我在一个需要比以前更多的IO交互的项目上工作,我觉得我想要查看常规库(特别是Commons 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));
Run Code Online (Sandbox Code Playgroud)

每个"下载程序"线程下载一个块(缓冲)并使用"文件编写器"写入磁盘:

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;
}
Run Code Online (Sandbox Code Playgroud)

"文件写入器"使用RandomAccessFileto seek()write()磁盘块写入磁盘:

public synchronized void write(byte[] bytes, int len, long start) throws IOException
{
      output.seek(start);
      output.write(bytes, 0, len);
}
Run Code Online (Sandbox Code Playgroud)

考虑到所有事情,这种方法似乎有效.但是,它不能很好地工作.我对以下几点有一些建议/帮助/意见表示感谢.非常感激.

  1. 此代码的CPU使用率是通过屋顶.它使用了我的一半CPU(两个内核中每个内核的50%)来实现这一点,这比可比的下载工具要多得多,这些工具根本不会给CPU带来压力.关于这个CPU使用率来自哪里,我有点神秘,因为我没想到这一点.
  2. 通常,3个线程中有1个显着落后.其他2个线程将完成,之后它需要第三个线程(看起来主要是第一个具有第一个块的线程)30秒或更长时间才能完成.我可以从任务管理器看到javaw进程仍在进行小的IO写操作,但我真的不知道为什么会发生这种情况(我猜竞争条件?).
  3. 尽管事实上我已经选择了相当大的缓冲区(1MB),但我感觉InputStream几乎从未实际填充缓冲区,这导致了比我想要的更多的IO写入.我的印象是,在这种情况下,最好将IO访问保持在最低限度,但我不确定这是否是最佳方法.
  4. 我意识到Java可能不是做这样的事情的理想语言,但我确信有比我目前的实现更多的性能.在这种情况下,NIO值得探索吗?

注意:我使用Apache HTTPClient进行HTTP交互,这是entity.getContent()来自的地方(如果有人想知道的话).

tmb*_*gmn 6

回答我自己的问题:

  1. 增加的CPU使用率是由于while() {}等待线程完成的循环.事实证明,awaitTermination等待Executor完成是一个更好的选择:)
  2. (和3和4)这似乎是野兽的本性; 最后我取得了我想要的东西,通过使用不同的线程,每个下载数据块(当然,特别是这些块的写回磁盘)的仔细同步做.