【问题标题】:interleaved output on shared file write共享文件写入时交错输出
【发布时间】:2017-04-20 14:43:19
【问题描述】:

我有一个长时间运行的 python 程序在共享文件上“追加”写入(多进程):

out = open("shared_file", "a")
while has_input:
     do_processing()
     out.write("%s, %s, %s\n" % field1, field2, field3)

上面的伪代码运行 8 个进程,比如说。这将导致一小部分交错输出。这似乎与基于谷歌搜索的缓冲区相关。共享文件追加的正确方法是什么?

【问题讨论】:

  • 尝试实现文件锁定系统。有一些软件包,例如 FileLock 和 unix util flock
  • 不需要外部包——Python标准库支持flock()
  • 也就是说,您可能只是考虑为您的文件禁用缓冲。内核级语义通常会阻止任何单个 O_APPEND 成为非原子,只要写入时间不长以至于需要将它们分成两个或多个调用。 out = open("shared_file", "a", 0)
  • 备份,重新:“交错输出”——您关心的是单行包含来自两个不同进程的内容的情况,还是您的输出在多个进程之间交替的情况?

标签: python


【解决方案1】:

问题:共享文件追加的正确方法是什么?

  1. 使用 one writer Process,仅用于将数据写入/追加到文件中。

  2. 与其他进程共享工作负载。

  3. 使用Queue 将数据从工作负载进程追加到写入进程。

阅读此 SO 答案:python-multiprocessing-write-to-same-excel-file

【讨论】:

  • 使用更复杂的文件格式(如 XLS)绝对是正确的选择,但对于仅附加的内容来说不是必需的。
  • 如果您的 "文件格式" 允许并发读/写,请同时使用 one 阅读器 process
  • 为什么?您可以让多个单独的进程同时读取一个文件,而不会相互影响。如果您的目标是避免让任何读取器尝试使用部分或不完整写入的文件,那么答案不是避免并发读取器,而是取出 shared 读取锁(多个读取器可以持有一次,但这会阻止任何独占写入锁定,直到所有此类读取器都退出)。
  • @CharlesDuffy:这只是一个概念性的建议,请随时与locking 联系。考虑到,带锁定的文件 IO 会导致性能下降。整体性能取决于内存工作负载和文件 IO 工作负载之间的平衡。
  • (旁白:将processlocking 放在反引号中意味着它们是代码——即有一个Python 模块、关键字、函数等,以该名称命名,而不是只是人类语言的技术术语)。
【解决方案2】:

fcntl module 有与此处相关的助手。如果您想将整个写入块 (while has_input:) 保存在一起,您可以使用以下方法:

with out = open("shared_file", "a"):
    fcntl.flock(out, fcntl.LOCK_EX)
    try:
        while has_input:
            out.write("%s, %s, %s\n" % (field1, field2, field3))
    finally:
        fcntl.flock(out, fcntl.LOCK_UN)

相比之下,如果您只关心将各个行保持在一起,并且不介意一点额外的开销,则可以使用更细粒度的锁定:

with out = open("shared_file", "a"):
    while has_input:
        try:
            fcntl.flock(out, fcntl.LOCK_EX)
            out.write("%s, %s, %s\n" % (field1, field2, field3))
        finally:
            fcntl.flock(out, fcntl.LOCK_UN)

也就是说,如果您的目标只是防止单行包含来自两个不同进程的内容,并且使用 O_APPEND 打开文件,那么操作系统级语义通常在保持单个写入原子性方面相当有效。可以破坏原子性的一种方法是缓冲,但您可以通过在没有缓冲的情况下打开文件来避免这种影响,以便立即刷新所有写入:

out = open("shared_file", "a", 0)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多