【问题标题】:Muti-threaded access to the same text file多线程访问同一个文本文件
【发布时间】:2012-02-26 12:45:55
【问题描述】:

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

我想出了两个选择:

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

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

须知:

  • 我对这项任务的速度表现非常感兴趣
  • 每一行都是独立的
  • 我在 C++ 中工作,但我想这里的问题有点与语言无关

你会选择哪个选项,为什么?

【问题讨论】:

  • 您将使用多少处理器以及文件有多大?
  • 文件大约 20GB,在未来的实现中会更大。目前我在 4 核上运行
  • @Alexandros:我知道我回答得太晚了:)。但是为每个线程分配一行行会容易得多吗?您可以使用单个文件指针预先计算每个线程的块大小,然后每个线程打开文件并查找该预先计算的位置。我认为这将是更容易和更快的方法
  • 这听起来是个很聪明的人,谢谢!唯一的问题是多个线程读取同一文件中的远程部分可能会产生一些磁盘读取开销,但我认为这不会太多。

标签: java c++ c multithreading producer-consumer


【解决方案1】:

我建议第二个选项,因为它比第一个选项更清晰,设计更简洁。第一个选项的可扩展性较低,并且需要线程之间的额外通信才能同步它们在文件行上的进度。而在第二种选择中,您有一个调度程序来处理 IO 并启动工作线程以开始计算,并且每个计算线程彼此完全独立,因此允许您进行扩展。此外,在第二个选项中,您可以更清晰地分离您的逻辑。

【讨论】:

  • +1 用于 P-C 队列。我建议为线程间通信提供一个类,它可以缓冲一些有用的行数,以便每个处理线程将大部分时间用于实际处理。我会通过在启动时创建一个包含这些行缓冲区对象的池来控制这个系统(即另一个加载了它们的 P-C 队列)。
【解决方案2】:

如果我们谈论的是需要用大型集群处理的超大文件 - MapReduce 可能是最好的解决方案。

该框架为您提供了出色的可扩展性,并且已经为您处理了管理工作人员和容忍故障的所有繁琐工作。
该框架专门设计用于接收从文件系统中读取的文件 [最初用于 GFS] 作为输入。

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

【讨论】:

  • 没有必要存在正确的情况来使用 MapReduce。如果在他的案例中没有实际的减少概念怎么办?
  • @ArtemBarger:map-reduce 经常与 identity 函数一起用作 reduce 步骤。一个很好的例子是基于 map-reduce 的排序。
  • 我知道,但问题是,如果 Alexandros 用例不符合这个概念怎么办。
【解决方案3】:

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

然后您的所有线程都可以并行处理。例如,如果您有 200 行和 4 个线程,则每个线程可以执行 50 行的计算。此外,由于这种方法的并行性令人尴尬,因此您可以轻松地使用 OpenMP。

【讨论】:

  • 不幸的是文件太大而无法放入内存
  • 那么我认为你的第二个选择很好,主线程读取大块数据并将其提供给工作线程。
【解决方案4】:

我建议第二个选项,因为它在设计方面肯定更好,并且可以让您更好地控制工作线程正在执行的工作。

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

【讨论】:

  • 从什么时候复制过去的答案算作正确答案?
  • @ArtemBarger 在我发布我的答案之前我没有看到你的答案,只是在处理其他事情时输入了我的意见,因此真的很慢。 OP 很好地接受了您的答案,因为它更完整、更快且通常更好,但没有理由仅仅因为这个原因就指责人们复制粘贴或投反对票
  • 我很抱歉,但第一句话几乎完全符合我的要求,而且您的发布时间与我的相差 10 分钟。只要我知道 SO 在您发布之前发布的新答案之前会警告您,因此乍一看它看起来很奇怪。
  • @ArtemBarger 没关系,我应该按下更新按钮,看看其他人已经发布了比我更好的答案,但我没有。这在很大程度上是我的错,但我只是想向您说明我没有复制粘贴并且没有理由这样做,因此我认为我不应该投反对票。
  • 好的,我明白了,再次抱歉。
【解决方案5】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多