【问题标题】:Should threads act on separate memory?线程应该作用于单独的内存吗?
【发布时间】:2018-07-06 09:00:51
【问题描述】:

我有一个 C++ 程序,其任务是分析二进制数据流(通常是磁盘上的文件)并提取一些信息。这个任务是“无记忆”的,这意味着每一步的结果都独立于前一步。因此,我想通过将数据提供给单独的线程来加快速度,以提高性能。

目前,数据一次读取 1GB 块并保存在数组中,以避免 I/O 瓶颈。我应该将n 块/数组中的数据分开(其中n 是线程数)还是多个线程访问的单个数组不是问题?

我有一个 C++ 程序,其任务是分析二进制数据流(通常是磁盘上的文件)并提取一些信息。这个任务是“无记忆”的,这意味着每一步的结果都独立于前一步。因此,我想通过将数据提供给单独的线程来加快速度,以提高性能。

目前,数据一次读取 1GB 块并保存在数组中,以避免 I/O 瓶颈。我应该将n 块/数组中的数据分开(其中n 是线程数)还是多个线程访问的单个数组不是问题?

编辑 1:数据和分析规范 我意识到问题的措辞可能过于宽泛,正如其中一位 cmets 所指出的那样。我会尝试更详细一点。

正在分析的数据是由所谓的“时间到数字”转换器 (TDC) 生成的一系列无符号 64 位整数,其中存储有关它们注册的某些事件的时间戳信息。我的 TDC 有多个通道,因此每个时间戳都有关于触发哪个通道(前 3 位)、是上升沿还是下降沿触发(第 4 位)以及实际时间(以 TDC 通电后的时钟滴答为单位的信息,最后60 位)。

当然,时间戳是按时间顺序保存在文件中的。任务是在用户设置的特定时间窗口内查找通道之间的重合事件。因此,您继续阅读时间戳,当您在感兴趣的通道中发现两个时间距离小于设置的通道时,您会增加巧合事件的数量。

这些文件可能非常大(几十 GB)并且时间戳数量巨大(一个时钟滴答是 80 微微秒)。

现在我只浏览整个文件一次,我的想法是将它“切割”成更小的部分,然后由不同的线程进行分析。两次剪辑之间可能丢失的事件对我来说是可以接受的,因为最多会是几十万分之二。

当然,他们会只读取文件/内存中的数据。如果这有助于避免同步问题,我可以将重合计数写入三个单独的变量中,然后在所有线程完成时将它们相加。

我希望现在事情更清楚了。

【问题讨论】:

  • C++中有四种storage durations。线程本地是其中之一。原样的主题对于 SO 格式来说太宽泛了。可能也不清楚。
  • 也许您的意思是无状态而不是无内存?
  • 你可以从任意数量的线程中读取一块内存,只要它们没有改变它(意味着可以被其他线程访问的部分)
  • 1GB??认真的吗?
  • 如果他们不打算修改数据,那么他们所有人都可以在没有任何同步的情况下访问单个数组。

标签: c++ multithreading shared-memory


【解决方案1】:

是的,同一个数组可以被多个线程访问:如果线程只读取数组(这里似乎就是这种情况),就不会有虚假的共享效果。

为了优化缓存使用,您可以让每个线程读取数组的连续元素(即在线程之间交错读取)。

作为旁注,您可能需要重新考虑 1GB 块:太多了!您是否测量过它比 1MB 或 10KB 更好?

您可能还希望并行化“文件读取”(一次一小块)和“处理读取的内容”(使用许多线程),使用(至少)2 个数组(已处理,另一个将接收下一次读取)

【讨论】:

  • 我相信让每个块缓存对齐也会有所帮助,不是吗?
  • @Tudor 是的,但如果我们说的是 1GB 块,它不会有很大的不同 :)
  • 旁注:如果每个线程只写入它读取的“自己的”部分,那么即使写入数组也不是问题......
  • @Aconcagua 同意,如果你的节是指 L1 缓存对齐的节,以避免错误共享。我不想在这里详细介绍,因为问题只是关于阅读。
  • 对我来说,你的措辞听起来像是两个连续的元素应该被赋予两个连续的线程。但我怀疑这应该意味着应该给每个线程一个连续的块
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多