【问题标题】:Is it safe to pipe the output of several parallel processes to one file using >>?使用>>将多个并行进程的输出通过管道传输到一个文件是否安全?
【发布时间】:2011-01-27 11:28:36
【问题描述】:

我正在从网络上抓取数据,并且我的抓取器的多个进程并行运行。

我希望每个进程的输出都在同一个文件中。只要文本行保持完整并且不相互混淆,行的顺序就无关紧要。在 UNIX 中,我可以使用 >> 运算符将每个进程的输出通过管道传输到同一个文件吗?

【问题讨论】:

  • InRe:关闭投票。 我看到它的方式“操作 Foo 在语言栏中并发使用是否安全?”每次都是一道编程题。在这种情况下,Foo 是管道输入到 std[in,err] 而 Bar 是一些 unix shell。不得不说我认为它应该留下来。

标签: unix concurrency parallel-processing pipe


【解决方案1】:

没有。不能保证线路将保持完整。它们可以混合在一起。

根据 liori 的回答搜索,我找到了this

{PIPE_BUF} 字节或更少字节的写入请求不应与其他进程在同一管道上进行写入的数据交错。无论文件状态标志的 O_NONBLOCK 标志是否设置,大于 {PIPE_BUF} 字节的写入可能会在任意边界上与其他进程的写入交错数据。

因此,不能保证超过 {PIPE_BUF} 字节的行保持​​完整。

【讨论】:

  • 只是为了说清楚——这种情况仅适用于管道,包括命名管道(又名 FIFO 文件)。它不适用于其他类型的文件,在这种情况下,可能不太保证不会有混合写入。
  • 这是否适用于> 的正常重定向?我猜在低级别,shell 会以不同的方式打开文件(打开追加而不打开写入)所以结果可能不同
【解决方案2】:

简而言之,不。 >> 不尊重多个进程。

【讨论】:

    【解决方案3】:

    您需要确保在单次写入操作中写入整行(因此,如果您使用某种形式的 stdio,则需要将其设置为行缓冲至少最长的长度您可以输出的行。)由于 shell 使用 O_APPEND 进行 >> 重定向,因此您的所有写入将自动附加到文件中,您无需采取进一步行动。

    【讨论】:

      【解决方案4】:

      使用临时文件并将它们连接在一起。这是做你想做的事情的唯一安全方法,并且(可能)这样的性能损失可以忽略不计。如果性能确实是个问题,请尝试确保您的 /tmp 目录是基于 RAM 的文件系统,并将您的临时文件放在那里。通过这种方式,临时文件存储在 RAM 中而不是硬盘上,因此读取/写入它们几乎是即时的。

      【讨论】:

        【解决方案5】:

        一般不会。

        在 Linux 上这可能是可能的,只要满足两个条件:每一行都写在一个操作中,并且该行不超过 PIPE_SIZE(通常与 PAGE_SIZE 相同,通常为 4096)。但是......我不会指望那个;这种行为可能会改变。

        最好使用某种真正的日志记录机制,例如 syslog。

        【讨论】:

          【解决方案6】:

          除了使用临时文件的想法之外,您还可以使用某种聚合过程,尽管您仍然需要确保您的写入是原子的。

          考虑使用管道日志记录的 Apache2(如果您有野心,可以在管道的另一端使用类似的东西)。这就是它采用的方法,多个线程/进程共享一个日志记录进程。

          【讨论】:

            【解决方案7】:

            绝对不,我有一个日志管理脚本,我认为它有效,并且确实有效,直到我将它移至负载不足的生产服务器。不是一个美好的一天......但基本上你最终有时会完全混淆线条。

            如果我试图从多个来源捕获,使用多文件“纸质记录”会更简单(也更容易调试),如果我需要一个完整的日志文件,请根据时间戳连接(您正在使用时间戳,对吗?)或者如 liori 所说,syslog。

            【讨论】:

              【解决方案8】:

              您可以做的一件有趣的事情是使用 gnu 并行:http://www.gnu.org/s/parallel/ 例如,如果您正在爬取网站:

              stackoverflow.com, stackexchange.com, fogcreek.com 
              

              你可以这样做

              (echo stackoverflow.com; echo stackexchange.com; echo fogcreek.com) | parallel -k your_spider_script
              

              并且输出被并行缓冲,因为 -k 选项按照上面站点列表的顺序返回给您。一个真实的例子(基本上是从第二个并行截屏中复制的):

               ~ $ (echo stackoverflow.com; echo stackexchange.com; echo fogcreek.com) | parallel -k ping -c 1 {}
              
              
              PING stackoverflow.com (64.34.119.12): 56 data bytes
              
              --- stackoverflow.com ping statistics ---
              1 packets transmitted, 0 packets received, 100.0% packet loss
              PING stackexchange.com (64.34.119.12): 56 data bytes
              
              --- stackexchange.com ping statistics ---
              1 packets transmitted, 0 packets received, 100.0% packet loss
              PING fogcreek.com (64.34.80.170): 56 data bytes
              64 bytes from 64.34.80.170: icmp_seq=0 ttl=250 time=23.961 ms
              
              --- fogcreek.com ping statistics ---
              1 packets transmitted, 1 packets received, 0.0% packet loss
              round-trip min/avg/max/stddev = 23.961/23.961/23.961/0.000 ms
              

              无论如何,ymmv

              【讨论】:

                【解决方案9】:

                正如上面提到的,这是一个相当的 hack,但效果很好 =)

                ( ping stackoverflow.com & ping stackexchange.com & ping fogcreek.com ) | cat
                

                与 '>>' 相同:

                ( ping stackoverflow.com & ping stackexchange.com & ping fogcreek.com ) >> log
                

                在最后一个使用 exec 可以保存一个进程:

                ( ping stackoverflow.com & ping stackexchange.com & exec ping fogcreek.com ) | cat
                

                【讨论】:

                • 在原始问题中,我指定输出中的文本行必须保持完整(即它们不应相互混淆)。如果两个 ping 请求同时返回,您的示例中的行不会“交错”(相互混合)吗?其他一些答案表明他们会......
                • @conradlee 我怀疑这大多数的工作是因为每个 ping 的输出都进入管道,只要每次写入都在 PIPE_BUF 下,Linux 就保证不会交错大小(通常为 4 KB)。但是,这通常并不安全,因为不能保证 ping 的每次写入都小于 PIPE_BUF。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-02-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-08-09
                • 2018-12-03
                • 1970-01-01
                相关资源
                最近更新 更多