我遇到过一些类似的情况,我可以将单核绑定任务分成多个部分,并在 bash 中将每个部分作为单独的作业运行以对其进行并行化,但我很难将返回的数据整理回单个数据溪流。到目前为止,我的天真的方法必须创建一个临时文件夹,跟踪 PID,让每个线程将其 pid 写入一个文件,然后一旦所有作业完成,读取所有 pid 并将它们按照 PID 生成的顺序合并到一个文件中。有没有更好的方法使用 bash/shell 工具来处理这种多进一出的情况?
答案1
到目前为止,我的天真的方法必须创建一个临时文件夹,跟踪 PID,让每个线程将其 pid 写入一个文件,然后一旦所有作业完成,读取所有 pid 并将它们按照 PID 生成的顺序合并到一个文件中。
这几乎正是 GNU Parallel 所做的事情。
parallel do_stuff ::: job1 job2 job3 ... jobn > output
还有一些额外的好处:
- 临时文件会自动删除,因此无需清理 - 即使您终止了 GNU Parallel。
- 您只需要为当前正在运行的作业提供临时空间:已完成作业的临时空间将在作业完成后释放。
- 如果您希望输出的顺序与输入的顺序相同,请使用
--keep-order
. - 如果您希望不同作业的逐行混合输出,请使用
--line-buffer
.
GNU Parallel 有很多功能可以将任务分割成更小的作业。也许您甚至可以使用其中之一来创造较小的就业机会?
答案2
您的建议似乎非常明智,因为它避免了在完成之前考虑如何合并数据。所以,老实说,这不是一个坏方法!
另一个常见的解决方案是拥有一个中央程序来收集数据、理解数据“片段”语义/边界并随时合并内容。
如何实现在很大程度上取决于您生成的数据类型!这可以像一个真正最小的程序一样简单,例如从 UNIX 或 UDP 或 TCP 套接字读取消息(但您可能需要考虑使用一种序列化格式,可以知道某个数据点在哪一点完成),每个工人一个插座。或者只运行一个小型关系数据库服务器(PostgreSQL?)。或者您使用 ZeroMQ 套接字来拥有多个发布者,并将中央合并作为这些发布者的订阅者,还有一个额外的好处,即这也可以立即通过网络运行。或者您使用数据库来存储时间序列数据。或者您的数据看起来更像是日志消息,因此您实现了通过 syslog 或 记录结果的工作程序sd_journal_print
,并使用 Journald 的日志命名空间将所有这些日志消息放入单个文件中。或者...
最后,您的选择实际上是:
- 写入许多文件,事后合并(这里您使用的是文件系统允许不同工作人员对不同文件进行并发写入访问,没有问题)。
- 使用某种管道/套接字/进程间通信方法将消息发送到中央进程(在这里您使用的事实是您知道数据的结构并且可以实时进行合并)。
实际上如何做到这一点 100% 取决于您的数据结构、数量以及您想要合并的方式。