Py学习  »  Python

多线程python访问似乎是同步的

Pace • 5 年前 • 1498 次点击  

我有一个任务,10个线程每个线程“同时”向一个文件写入100行。我原以为这些字会交错排列相反,写操作似乎是同步的我知道GIL,但我不认为它适用于文件I/O,因为底层OS调用不在GIL之外。

import threading
import tempfile

with tempfile.NamedTemporaryFile(delete=False) as named_temp:

    temp_filename = named_temp.name
    print(temp_filename)

    with open(temp_filename, mode='a') as writer:

        def thread_task(writer, thread_index):
            for iter_index in range(0, 100):
                writer.write(f'{(iter_index + thread_index * 100):06}')
                writer.write('\n')

        def make_thread(writer, thread_index):
            return threading.Thread(target=lambda: thread_task(writer, thread_index))

        threads = []
        for thread_index in range(0, 10):
            threads.append(make_thread(writer, thread_index))

        for thread in threads:
            thread.start()
        for thread in threads:
            thread.join()

    with open(temp_filename, mode='r+') as reader:
        for line in reader.readlines():
            print(line, end='')

这是意料之中的,还是我设置的不正确?我担心上面的代码交错输出(我不介意行的顺序,但不希望像 000007000008\n\n 是的。所以我计划引入锁,但在我这么做之前,我想创建一个失败的测试,我很难这样做。

这是在Python3.6.8上,如果相关的话。

另外,我的意思是我的输出是 000001\n000002\n...000999\n 井然有序至少我会预料到编号有问题。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/48345
 
1498 次点击  
文章 [ 1 ]  |  最新文章 5 年前
ShadowRanger
Reply   •   1 楼
ShadowRanger    5 年前

问题是写操作是被缓冲的,所以gil实际上并没有被释放(它只在缓冲区实际被写出来时才被释放,通常只有在缓冲区已满或文件显式地 flush ED或 close d)由于每个线程所做的工作非常少,它们永远不会运行足够长的时间来释放gil,因为超时,并且永远不会真正写入磁盘,它们永远不会因为开始阻塞系统调用而释放gil。

如果你成功了 脸红 对于每一行(或者使缓冲区足够小,以至于在完成所有的 write s),您将看到预期的交错。一种方法是改变:

with open(temp_filename, mode='a') as writer:

致:

with open(temp_filename, mode='a', buffering=1) as writer:

在哪里? buffering=1 表示缓存线。