You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多进程并发写入文件未触发预期竞态条件的原因咨询

多进程并发写入文件未触发预期竞态条件的原因咨询

我原本以为操作系统会抛出某种错误,或者至少文本文件里会出现不可读的乱码数据!有人能告诉我这是怎么回事吗?

我尝试让不同进程写入同一个文件,预期会收到OS错误提示或者文件里出现乱码,但实际输出却看起来相对有序(部分输出如下):

0 = 2024-06-10 15:30:19
2 = 2024-06-10 15:30:19
4 = 2024-06-10 15:30:19
8 = 2024-06-10 15:30:19
6 = 2024-06-10 15:30:19
12 = 2024-06-10 15:30:19
10 = 2024-06-10 15:30:19
14 = 2024-06-10 15:30:19
1 = 202...

我的测试代码如下:

from multiprocessing import Pool
import time

def open_file(metadata):
    with open("text.txt","a") as f:
        s = f"""{metadata} = {time.strftime("%Y-%m-%d %H:%M:%S")}\n"""
        for ch in s:
            f.write(ch)
        print(f"writing {s[:-2]}, now sleeping for 10 seconds before closing the file.")
        time.sleep(10)

if __name__ == "__main__":
    with Pool() as p:
        p.map(open_file, range(50))

为什么没出现你预期的错误或乱码?

这几个关键点可以解释你看到的现象:

  • 追加模式的原子性保障:大多数操作系统(比如Linux、Windows)对以追加模式("a")打开的文件,会保证单个write()系统调用的原子性——也就是说,每次调用write()时,OS会自动把数据写到文件当前的末尾,不会和其他进程的write()操作穿插。不过你的代码里是逐个字符调用f.write(ch),理论上每个字符都是一次独立的写入,应该会出现字符混乱,但这里还有另一个因素在起作用。

  • Python文件对象的用户态缓存:Python的open()返回的文件对象默认会开启缓存机制。你逐个调用f.write(ch)时,这些字符并不会立刻触发系统级的write()调用,而是先被存在用户态的缓存里。直到文件被关闭(也就是with块结束的时候),缓存里的所有数据才会一次性被刷入磁盘。你的代码里每个进程在写完所有字符后会sleep10秒,然后才关闭文件——这意味着每个进程的整行内容会被作为一个整体写入文件,自然不会出现字符穿插的情况。

  • 进程调度与Pool的默认行为:multiprocessing.Pool默认会根据你的CPU核心数创建进程池,比如4核CPU就同时运行4个进程。每个进程写完字符后会进入10秒的sleep状态,这时候进程会被操作系统挂起,其他进程才会开始执行。这进一步降低了不同进程写入操作的重叠概率,让每个进程的完整行更大概率被连续写入。

怎么才能触发预期的竞态条件?

如果你想看到数据混乱的效果,可以做这两个修改:

  • 在每次f.write(ch)后立刻调用f.flush(),强制把缓存里的字符刷入磁盘,这样每个字符都会触发独立的系统级写入。
  • 去掉time.sleep(10),让进程写完立刻关闭文件,增加不同进程写入操作的重叠机会。

这样修改后,你应该就能看到不同进程的字符相互穿插,出现乱码的情况了。


备注:内容来源于stack exchange,提问作者Farhad Mohammadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.16 11:13:14