Java 对同一文本文件的多线程访问

Java 对同一文本文件的多线程访问,java,c++,c,multithreading,producer-consumer,Java,C++,C,Multithreading,Producer Consumer,我有一个巨大的行分隔文本文件,我想对每一行进行一些计算。我需要制作一个多线程程序来处理它,因为完成每一行的处理比读取每一行花费的时间要多。(瓶颈在于CPU处理,而不是IO) 我有两个选择: 1) 从主线程打开文件,在文件句柄上创建锁,并将文件句柄传递给工作线程,然后让每个工作线程直接读取访问文件 2) 创建生产者/消费者设置,其中只有主线程可以直接读取文件,并使用共享队列将行馈送给每个工作线程 需要知道的事情: 我对这项任务的速度性能非常感兴趣 每条线都是独立的 我在C++中工作,但是我猜这里

我有一个巨大的行分隔文本文件,我想对每一行进行一些计算。我需要制作一个多线程程序来处理它,因为完成每一行的处理比读取每一行花费的时间要多。(瓶颈在于CPU处理,而不是IO)

我有两个选择:

1) 从主线程打开文件,在文件句柄上创建锁,并将文件句柄传递给工作线程,然后让每个工作线程直接读取访问文件

2) 创建生产者/消费者设置,其中只有主线程可以直接读取文件,并使用共享队列将行馈送给每个工作线程

需要知道的事情:

  • 我对这项任务的速度性能非常感兴趣
  • 每条线都是独立的
  • 我在C++中工作,但是我猜这里的问题是有点语言无关的

您会选择哪个选项?为什么?

如果每一行都是独立的,并且处理速度比读取文件慢得多,那么您可以一次读取所有数据并将其存储在一个数组中,这样每一行都代表一个数组的元素


然后,所有线程都可以并行处理。例如,如果有200行和4个线程,则每个线程可以在50行上执行计算。此外,由于这种方法的并行性令人尴尬,您可以很容易地使用OpenMP来实现这一点。

我建议使用第二种方法,因为它在设计方面比第一种方法更清晰,也不太复杂。第一个选项的可伸缩性较差,需要在线程之间进行额外的通信,以便同步它们在文件行上的进度。而在第二个选项中,您有一个处理IO和启动工作线程以启动计算的调度程序,并且每个计算线程彼此完全独立,因此允许进行扩展。此外,在第二个选项中,您可以更清晰地分离逻辑。

如果我们讨论的是需要使用大型集群处理的大型文件,那么这可能是最好的解决方案

该框架允许您具有很好的可伸缩性,并且已经为您处理了管理工作人员和容忍失败的所有脏活。
该框架专门设计用于接收从文件系统[最初用于]读取的文件作为输入


请注意,map reduce有一个开源实现:

我建议使用第二个选项,因为它绝对是更好的设计方式,可以让您更好地控制辅助线程正在执行的工作


此外,这将提高性能,因为在这种情况下,线程间通信是您描述的两个选项中的最小选项

另一个选项是内存映射文件并维护共享结构,以正确处理线程的互斥

您将使用多少处理器以及该文件有多大?该文件大约为20GB,在未来的实现中将更大。目前我正在运行4cores@Alexandros:我知道我来不及回答:)。但是给每个线程分配一个行块不是更容易吗?您可以使用单个文件指针预先计算每个线程的块大小,然后每个线程打开文件并搜索到预先计算的位置。我认为这将是一种更简单、更快的方法。这听起来是一个非常聪明的主意,谢谢!唯一的问题是,多个线程读取同一文件中的远程部分可能会产生一些磁盘读取开销,但我认为这不会太多。不幸的是,文件太大,无法放入内存。我认为第二个选项很好,主线程读取大块数据并将其提供给工作线程。使用MapReduce不一定存在正确的情况。如果在他的例子中没有实际的reduce概念怎么办?@artemberger:map reduce通常与identity函数一起用作reduce步骤。一个很好的例子是基于map reduce的排序。我知道这一点,但问题是,如果Alexandros用例不符合这一概念怎么办。既然以前答案的副本什么时候被算作正确答案?@ArtemBarger我在发布我的答案之前没有看到你的答案,只是在处理其他问题时输入了我的意见,因此速度非常慢。OP很好地接受了你的答案,认为你的答案更完整、更快、总体上更好,但没有理由仅仅因为这个原因就指责人们粘贴或否决我真的很抱歉,但第一句话几乎完全符合我的要求,而且你的发帖时间与我的相差10分钟。只要我知道,SO会在你发帖之前警告你关于之前出现的新答案,因此,乍一看,这看起来很奇怪。@Artemberger没关系,我应该按下更新按钮,看看其他人发布的答案已经比我的好,但我没有。这很大程度上是我的错,但我只是想向你表明,我没有复制粘贴,也没有理由复制粘贴,因此我认为我不值得投反对票。好的,我理解,我再次道歉。P-C队列+1。我建议为线程间通信创建一个类,该类缓冲一些有用的行数,以便每个处理线程将大部分时间用于实际处理。我将通过在启动时创建这些行缓冲区对象的池(即另一个加载了它们的P-C队列)来控制这个系统。