我必须在10个大文件中搜索一个字符串(zip格式为70 MB),并且必须将搜索字符串的行打印到相应的10个输出文件(即文件1的输出应该在output_file1 ... file2中---> output_file2)。同一个程序需要15分钟才能完成一个文件。但是如果使用10个线程读取10个文件并写入10个不同的文件,它应该在15分钟内完成,但需要40分钟。Java中的MultiThreading是否需要很多时间才能完成任务?
我该如何解决这个问题。或者多线程只需要这么多时间?
我必须在10个大文件中搜索一个字符串(zip格式为70 MB),并且必须将搜索字符串的行打印到相应的10个输出文件(即文件1的输出应该在output_file1 ... file2中---> output_file2)。同一个程序需要15分钟才能完成一个文件。但是如果使用10个线程读取10个文件并写入10个不同的文件,它应该在15分钟内完成,但需要40分钟。Java中的MultiThreading是否需要很多时间才能完成任务?
我该如何解决这个问题。或者多线程只需要这么多时间?
我想你没有使用10-core-cpu-machine - 所以你的线程并不是真正的并行运行。因此需要比数学应用更长的时间。接下来的事情是你必须意识到线程管理也需要一些时间(这是不相关的)。 也许你可以加快你的文件搜索机制,以获得一定的速度。为此,您需要发布源代码。 但一些建议:
但是请注意这种措施可能会导致一个非常复杂的代码读取另一个人或你自己在...让我们说六个月+,因为你不会记得你所做的一切,为什么你这样做(评论;))
如果您正在搜索文字,indexOf(startIdx,pattern)比正则表达式快得多。 – ddimitrov 2010-06-10 00:20:46
你可能存在硬盘争用,这对多线程无济于事。在你的情况下,你可能只需要足够的线程来使磁盘驱动器保持100%的使用率。
我假设硬盘是你的瓶颈,而不是CPU。如果每个线程不必争夺相同的硬件,多线程只能“更快”地完成任务。因此,使用多核(CPU)和多个硬盘驱动器,您将看到多线程的更好性能。
我很惊讶它需要15分钟的单个文件。
下面是我将如何设计这个。 70 MB并不大。您可以将每个70 MB的未压缩文件加载到内存中,每个线程一个。然后,在搜索压缩流时实时解压缩数据,在内存中保留一定数量的未压缩数据。 (一旦你搜索了它,扔掉它)。这将避免硬盘颠簸,并使您的CPU达到100%的使用率。
如果内存有问题,则从磁盘一次加载几MB。
对于70 MB以上的10个文件,15分钟不是不太可能出现磁盘问题(除非它真的是*碎片)。 – 2010-05-17 14:23:33
并发访问文件通常在2-3个线程之后变慢,因为硬盘结束了试图从所有文件同时读取的颠簸,类似于读取经碎片整理的文件。
为了避免这种情况,请将工作分为文件读取器和文件解析器。文件阅读器从文件中提取数据(也解压缩),文件解析器解析数据。您可以使用PipedInputStream
/PipedOutputStream
将文件读取器中的数据转发到文件解析器。
因为你的文件是压缩的,所以读取涉及I/O和cpu,它们可以很好地跨2-4个线程交错读取所有文件。为了解析这些文件,从PipedInputStream中只读取一个线程是最容易的,因此每个文件都有一个解析器线程。每个文件使用多个线程需要分割流并在块边界处理seaching,这会使进程复杂化,在此不一定需要,因为您可能具有足够的10个解析器线程和2-4个读取器线程的并行度。
更多的线程很可能会让它运行得更慢,因为你的瓶颈将是磁盘IO。如果你可以先把所有的数据加载到内存中,那么你会看到来自多线程的速度有所提高,但是仅仅到#core + 1的位置,更多的只是上下文切换开销。
当你运行这个,你的CPU已经是100%了吗?如果不是,则是两件事之一;
我打算猜测这是一个GC问题。我猜你正在将文件一次读入String
。也许你甚至为每一行重新编译一个正则表达式。无论如何,大量的内存分配,但短暂的对象。多个线程可能会提示足够多的内容以便将其复制到“幸存者”空间中(在典型的Sun GC实现中)。我猜想使用visualvm或一个模糊的命令行参数来监视GC工作的难度。
也可能是锁争用问题,但这看起来很尴尬并行。
您可能想看看Tim Bray创建的the "Wide Finder"项目。这听起来很像你正在做的事情,而且我认为,如果不是所有的问题都会被检查。 hth
你有10个处理器吗? – 2010-05-17 13:52:21
您是否仍然期望在百万个文件中使用一百万个线程需要15分钟? – 2010-05-17 14:06:43
为什么一个文件需要15分钟?那段时间它在做什么?性能瓶颈是什么? – 2010-05-18 13:15:28