当前位置: 首页 > 面试题库 >

Java多线程文件下载性能

呼延俊风
2023-03-14
问题内容

最近,我完成了一个项目,该项目比以前需要更多的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);
}

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

  1. 此代码的 CPU使用率 是通过屋顶计算的。它使用了我一半的CPU(2个内核中的每个内核的50%)来执行此操作,这比类似的下载工具成倍增加,后者几乎没有给CPU带来压力。我对这种CPU使用量的来源有些怀疑,因为我没想到这一点。
  2. 通常,似乎3个线程中有1个明显 滞后 。其他2个线程将完成,此后,第三个线程(似乎主要是带有第一个块的第一个线程)需要30秒钟或更长时间才能完成。我从任务管理器中可以看到javaw进程仍在进行较小的IO写入,但是我真的不知道为什么会发生这种情况(我正在猜测竞争条件?)。
  3. 尽管我选择了一个很大的缓冲区(1MB),但我仍然感到InputStream几乎从来没有真正填充过缓冲区,这会导致IO写操作比我想要的更多。我的印象是,在这种情况下,最好将IO访问保持在最低水平,但是我不确定这是否是最好的方法。
  4. 我意识到Java可能不是执行此类操作的理想语言,但是我坚信要拥有比当前实现更多的性能。在这种情况下,NIO是否值得探索?

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


问题答案:

要回答我自己的问题:

  1. CPU使用率增加是由于while() {}循环正在等待线程完成。事实证明,awaitTermination等待Executor完成是更好的选择:)
  2. (以及3和4)这似乎是野兽的本质。最后,我通过仔细同步每个下载一块数据的不同线程(好了,特别是将这些块写回到磁盘上)来实现了我想做的事情。


 类似资料:
  • 本文向大家介绍java多线程实现文件下载,包括了java多线程实现文件下载的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了java多线程实现文件下载的具体代码,供大家参考,具体内容如下 1、DownloadManager类  2、DownloadThread类 3、TestDownload测试类 代码已经测试可以运行! 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多

  • 本文向大家介绍java多线程实现文件下载功能,包括了java多线程实现文件下载功能的使用技巧和注意事项,需要的朋友参考一下 多线程下载文件的思路: 1.首先获取到文件的总大小 获取文件大小的方式是通过网络读取,getContentLength()即可获取到文件的大小,使用RandomAccessFile()支持随机访问 2.根据所准备的线程数据,计算每一个线程需要下载的文件的大小 上图显示下载40

  • 问题内容: 我正在尝试使用线程下载多个与模式匹配的文件。该模式可以匹配1或5或10个差异大小的文件。 为了简单起见,可以说下载文件的实际代码在downloadFile()方法中,而fileNames是与模式匹配的文件名列表。我该如何使用线程。每个线程将仅下载一个文件。建议在for循环内创建一个新线程。 问题答案: 您确实想使用ExecutorService而不是单个线程,它更干净,性能可能更高,并

  • 本文向大家介绍java多线程下载文件原理解析,包括了java多线程下载文件原理解析的使用技巧和注意事项,需要的朋友参考一下 原理解析:利用RandomAccessFile在本地创建一个随机访问文件,文件大小和服务器要下载的文件大小相同。根据线程的数量(假设有三个线程),服务器的文件三等分,并把我们在本地创建的文件同样三等分,每个线程下载自己负责的部分,到相应的位置即可。 示例图: 示例demo 以

  • 本文向大家介绍Java多线程下载文件实例详解,包括了Java多线程下载文件实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Java多线程下载文件的具体代码,供大家参考,具体内容如下 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 问题内容: 首先,每个人都需要知道我对Java编码还比较陌生。更准确地说,我是面向对象编程的新手。 问题。 我试图创建一个下载类来更新进度条,以显示其进度。可能还有其他决定,我决定在以后进行更新。 目前的问题是,在我看来,这不起作用。我可以在“主要”方法上做任何我想做的事情,而且GUI仍然响应迅速。根据我过去的编程经验,除非我对GUI进行线程化,否则这是不可能的。为什么是这样? 既然可以了,这样可