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

使用ThreadPoolExecutor多线程写文件出现输出不完整问题

问题原因分析

核心问题出在Windows系统与Unix-like系统(如Mac)对文件追加写入的原子性实现差异:

  • 在Windows下,Python以'a'模式打开文件时,"获取文件末尾位置+执行写入"是两个分离的操作,并非原子性的。当多个线程并发执行时,线程A刚获取到文件末尾位置,线程B就完成了写入并改变了文件长度,此时线程A再写入会直接覆盖线程B的内容,导致字符丢失。
  • 而Mac等Unix-like系统中,追加模式的写入是原子操作,系统会自动保证每个写入请求都追加到文件末尾,不会出现覆盖。

max_workers=3时问题更频繁,是因为线程数增加后,并发写入的冲突概率直线上升。

可行解决方案

1. 线程锁保证写入原子性

这是最直接的修复方式,通过threading.Lock确保同一时间只有一个线程操作文件,彻底避免并发冲突。
修改后的代码:

from concurrent import futures
import threading

write_lock = threading.Lock()

def print_one(character):
    with write_lock:
        with open('test.txt', 'a') as output:
            output.write(character + ' ')

def print_many():
    with futures.ThreadPoolExecutor(3) as executor:
        executor.map(print_one, ['1','2','3','4','5','6','7','8','9','10'])

if __name__=='__main__':
    with open('test.txt', 'w') as init:
        pass
    print_many()

优缺点:代码改动极小,完全解决问题;高并发场景下有轻微性能损耗,但对你的场景几乎可忽略。

2. 单线程统一处理写入

用队列解耦任务执行与文件写入:多线程只负责生成要写入的内容,将内容放入线程安全队列;单独一个线程从队列取内容写入文件。既保留多线程并行能力,又避免写入冲突。
修改后的代码:

from concurrent import futures
import queue
import threading

def print_one(character, q):
    q.put(character + ' ')

def writer(q):
    with open('test.txt', 'a') as output:
        while True:
            content = q.get()
            if content is None:
                break
            output.write(content)
            q.task_done()

def print_many():
    q = queue.Queue()
    threading.Thread(target=writer, args=(q,), daemon=True).start()
    
    with futures.ThreadPoolExecutor(3) as executor:
        executor.map(print_one, ['1','2','3','4','5','6','7','8','9','10'], [q]*10)
    
    q.join()
    q.put(None)

if __name__=='__main__':
    with open('test.txt', 'w') as init:
        pass
    print_many()

优缺点:性能优异,适合后续任务逻辑复杂的场景;代码稍复杂,但解耦清晰,扩展性强。

3. 全局打开文件+锁(优化IO开销)

如果不想频繁打开关闭文件,可以全局打开文件,但必须配合锁保证写入的线程安全(Python文件对象的write方法本身并非线程安全)。
修改后的代码:

from concurrent import futures
import threading

write_lock = threading.Lock()

def print_one(character, output_file):
    with write_lock:
        output_file.write(character + ' ')
        output_file.flush()

def print_many():
    with open('test.txt', 'a') as output:
        with futures.ThreadPoolExecutor(3) as executor:
            executor.map(print_one, ['1','2','3','4','5','6','7','8','9','10'], [output]*10)

if __name__=='__main__':
    with open('test.txt', 'w') as init:
        pass
    print_many()

优缺点:减少文件IO开销,性能较好;加锁后既不会丢失字符,也能保留多线程的随机写入顺序,解决你之前遇到的“顺序接近1到10”的问题。

内容的提问来源于stack exchange,提问作者hzh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 01:06:20