【问题标题】:Why does writing concurrently to a file using different processes produce weird result?为什么使用不同进程同时写入文件会产生奇怪的结果?
【发布时间】:2020-08-17 23:44:07
【问题描述】:

我正在尝试使用 Ruby 来理解流程。我正在从我的父进程创建 4 个子进程。主进程首先写入文件,然后创建子进程,每个子进程都写入同一个文件:

require 'csv'
a = [1, 2, 3, 4]
CSV.open("temp_and_cases_batch_parallel.csv", "ab") do |target_file|
  target_file << ["hello from parent process #{Process.pid}"]
  a.each do |num|
    pid = Process.fork do
      target_file << ["hello from child Process #{Process.pid}"]
    end
    puts "parent, pid #{Process.pid}, waiting on child pid #{pid}"
  end
end
Process.wait
puts "parent exiting"

我期望的文件输出

hello from parent process 3336
hello from child Process 3350
hello from child Process 3351
hello from child Process 3349
hello from child Process 3352

我实际得到的文件输出:

hello from parent process 3336
hello from parent process 3336
hello from child Process 3350
hello from parent process 3336
hello from child Process 3351
hello from parent process 3336
hello from child Process 3349
hello from parent process 3336
hello from child Process 3352

似乎来自父进程的插入重新运行了 5 次。这怎么可能?这是怎么回事?

【问题讨论】:

  • 什么版本的 ruby​​ 以及你的 csv 的内容是什么?
  • 脚本开始时 csv 为空,我使用的是 ruby​​ 2.6.3

标签: ruby csv parallel-processing process


【解决方案1】:

让多个进程写入同一个文件通常不是一个好主意。在大多数情况下,除非您完全知道自己在做什么,否则结果将是不可预测的,正如您刚刚在示例中演示的那样。

你得到奇怪结果的原因是Ruby IO对象has its own internal buffer。此缓冲区保存在内存中,不保证在调用&lt;&lt; 时会写入磁盘。

这里发生的是字符串hello from parent 只被写入内部缓冲区,而不是磁盘。然后当你调用fork 时,你将把这个缓冲区复制到子进程中。然后子进程会将hello from child 附加到缓冲区,只有 THEN 才会将缓冲区刷新到磁盘。

结果是除了写hello from child之外,所有子进程都会写hello from parent,因为这是在Ruby决定将缓冲区写入磁盘时内部内存缓冲区将包含的内容。

要解决这个问题,您可以在分叉之前调用IO.flush,以确保内存缓冲区为空并在分叉之前刷新到磁盘。这样可以确保子缓冲区中的缓冲区为空,您现在将获得预期的输出:

CSV.open(...) do |target_file|
  target_file << ...
  target_file.flush  # <-- Make sure the internal buffer is flushed to disk before forking

  a.each do |num|
    ... Process.fork ...
  end
end
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 2021-11-10
    • 2015-06-30
    相关资源
    最近更新 更多