多线程方法在文件中查找文本模式

时间:2011-12-16 13:20:24

标签: java multithreading performance search

考虑简单的Java应用程序,该应用程序应遍历光盘中的文件树,以在文件正文中查找特定模式。

想知道是否有可能使用多线程获得更好的性能,例如当我们找到新文件夹时,我们在固定的ThreadPool中提交新的Runnable。 Runnable任务应遍历文件夹以查找新文件夹等。在我看来,此操作应该是IO绑定,而不是CPU绑定,因此生成新线程不会提高性能。

是否取决于硬盘类型? (hdd,...等) 它取决于操作系统类型吗?

恕我直言,唯一可以并行的是 - 生成新的Thread来解析文件内容以找出文件体中的模式。

解决这个问题的常见模式是什么呢?它应该是多线程还是单线程?

4 个答案:

答案 0 :(得分:2)

我在测试项目下进行了一些研究,你可以在github上查看项目:http://github.com/4ndrew/filesearcher。当然主要的问题是磁盘I / O速度,但如果您使用最佳线程数来并行执行读取/搜索,您可以获得更好的共同结果。

UPD:另请参阅本文http://drdobbs.com/parallel/220300055

答案 1 :(得分:2)

我前段时间就这个问题做了一些实验。最后,我得出结论,通过改变访问文件的方式,我可以获得更好的改进。

这是我最终使用的文件助手:

// 4k buffer size ... near-optimal for Windows.
static final int SIZE = 4 * 1024;

// Fastest because a FileInputStream has an associated channel.
private static void ScanDataFile(Hunter h, FileInputStream f) throws FileNotFoundException, IOException {
  // Use a mapped and buffered stream for best speed.
  // See: http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly
  FileChannel ch = f.getChannel();
  // How much I've read.
  long red = 0L;
  do {
    // How much to read this time around. 
    long read = Math.min(Integer.MAX_VALUE, ch.size() - red);
    // Map a byte buffer to the file.
    MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, red, read);
    // How much to get.
    int nGet;
    // Walk the buffer to the end or until the hunter has finished.
    while (mb.hasRemaining() && h.ok()) {
      // Get a max of 4k.
      nGet = Math.min(mb.remaining(), SIZE);
      // Get that much.
      mb.get(buffer, 0, nGet);
      // Offer each byte to the hunter.
      for (int i = 0; i < nGet && h.ok(); i++) {
        h.check(buffer[i]);
      }
    }
    // Keep track of how far we've got.
    red += read;
    // Stop at the end of the file.
  } while (red < ch.size() && h.ok());
  // Finish off.
  h.close();
  ch.close();
  f.close();
}

答案 2 :(得分:1)

您说得对,您需要确定您的任务是CPU还是IO绑定,然后决定是否可以从多线程中受益。通常磁盘操作非常慢,因此除非需要解析和解析复杂性的数据量,否则您可能无法从多线程中受益。我只想写一个简单的测试 - 只是为了读取没有在单个线程中解析的文件,测量它然后添加解析并查看它是否慢得多然后决定。

也许好的设计是使用两个线程 - 一个读取文件并将数据放入(有界)队列的读取器线程,然后另一个线程(或更好地使用ExecutorService)解析数据 - 它会让你很好地分离关注点你总是可以调整解析的线程数。我不确定使用多个线程读取磁盘是否有意义(除非您需要从多个物理磁盘读取等)。

答案 3 :(得分:1)

您可以做的是:实现单生产者多消费者模式,其中一个线程搜索磁盘,检索文件,然后消费者线程处理它们。

你是对的,在这种情况下,使用多个线程来扫描磁盘是没有好处的,事实上它可能会降低性能,因为磁盘每次都需要寻找下一个读取位置,所以你最终弹出磁盘线程之间。