最近在一个需要更多IO交互的项目上工作比我习惯的要多,我觉得我想看看常规库(特别是Commons IO),并且更多地处理深入的IO问题。Java多线程文件下载性能
作为一项学术测试,我决定实施一个基本的多线程HTTP下载程序。这个想法很简单:提供一个URL下载,代码将下载该文件。为了提高下载速度,文件被分块并且每个块同时下载(使用HTTP头)以尽可能多地使用带宽。
我有一个工作原型,但正如您可能已经猜到的那样,它并不完全理想。目前我手动启动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));
每一个“下载”线程下载一个块(缓冲),并使用“文件写入”写入磁盘:
public synchronized void write(byte[] bytes, int len, long start) throws IOException
{
output.seek(start);
output.write(bytes, 0, len);
}
:
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;
}
“文件作家” 使用RandomAccessFile
到seek()
和write()
的块磁盘写入磁盘
所有考虑事项,这种方法似乎工作。但是,它不能很好地工作。我希望对以下几点提供一些建议/帮助/意见。非常感激。
- 该代码的CPU使用率是是通过屋顶。它使用了我的CPU的一半(两个内核中的每一个的50%)来完成这个任务,这比可比较的下载工具指数级地高出许多CPU。我对这个CPU使用来自哪里感到有些迷惑,因为我并不期待这一点。
- 通常情况下,显然落后于。其他2个线程将完成,之后它将占用第三个线程(这似乎主要是第一个线程的第一个线程)需要30秒或更长时间才能完成。我可以从任务管理器中看到,javaw进程仍在执行小IO写入,但我不知道为什么会发生这种情况(我猜测竞争条件?)。
- 尽管我选择了一个相当大的缓冲区(1MB),但我感觉
InputStream
几乎从未实际填充缓冲区,这会导致比我想要的更多的IO写入。我的印象是,在这种情况下,最好将IO访问保持在最低限度,但我不确定这是否是最好的方法。 - 我意识到Java可能不是完成这样的事情的理想语言,但我相信在我目前的实现中,要获得比我更高的性能。在这种情况下,NIO值得探索吗?
注:我使用Apache了HTTPClient做HTTP交互,这哪里是entity.getContent()
来自(如果你想知道)。
找到了很好的相关主题在这里:http://stackoverflow.com/questions/921262/how-to-download-and-save-a-file-from-internet-using-java 可能会给该当我回家时试试今晚:) – tmbrggmn 2010-08-05 07:31:04
更新:CPU使用率高是由于ExecutorService isTerminated()方法调用的while()循环造成的。卫生署! – tmbrggmn 2010-08-09 07:42:32
我认为很多还取决于网络配置以及网络接口卡(物理)。即使你有多个线程正在下载相同的文件,但是负责串行化字节的NIC也可能成为瓶颈! – TriCore 2016-05-11 04:02:25