繁体   English   中英

Python 多线程程序给出了意外的 output

[英]Python multithreading program is giving unexpected output

我知道不能保证线程的执行顺序。 但我的疑问是当我运行以下代码时,

import threading

def doSomething():
    print("Hello ")

d = threading.Thread(target=doSomething, args=())
d.start()
print("done")

即将到来的 Output 要么

Hello done

或这个

Hello 
done

可能是如果我尝试太多,那么它也可能给我下面

done
Hello

但我不相信第一个 output。 由于顺序可能不同,但是为什么两个输出都在同一行中可用。 这是否意味着一个线程正在与其他线程一起工作?

这是一个经典的比赛条件。 我无法亲自复制它,它可能会因解释器实现和应用于stdout的精确配置而异。 在没有 GIL 的 Python 解释器上,基本上没有针对种族的保护,这种行为在一定程度上是可以预料的。 与 C/C++ 不同,Python 解释器确实倾向于保护您免受由于线程导致的严重数据损坏,但即使它们确保写入的每个字节最终都实际打印出来,它们通常也不会尝试明确保证不会发生交错; 当您不努力同步对stdout的访问时, Hdelolnoe将是可能的(如果考虑到可能的实现,则不太可能) output 。

在 CPython 上,GIL 为您提供更多保护,将单个字符串写入stdout更有可能是原子的,但您不是在编写单个字符串。 本质上, print的实现是将对象一个一个地写入 output 文件 object ,它不会批量处理单个字符串,然后只调用一次write 这意味着:

print("Hello ")  # Implicitly outputs default end argument of '\n' after printing provided args

大致相当于:

sys.stdout.write("Hello ")
sys.stdout.write("\n")

如果实现sys.stdout的底层文件对象堆栈决定参与真正的 I/O 以响应第一次write ,它们将在执行实际写入之前释放 GIL,从而允许主线程赶上并可能抢占GIL 在工作线程有机会写入换行符之前。 然后主线程输出done ,然后每个print的换行符根据进一步的潜在比赛以某种未指定(和不相关)的顺序出现。

假设您使用的是 CPython,您可能可以通过使用单个write调用将代码更改为等效代码来解决此问题:

import threading
import sys

def doSomething():
    sys.stdout.write("Hello \n")

d = threading.Thread(target=doSomething)  # If it takes no arguments, no need to pass args
d.start()
sys.stdout.write("done\n")

并且您将回到仅交换顺序而没有交错的竞争条件(语言规范不能保证任何事情,但对于这种情况,最合理的实现将是原子的)。 如果您希望它在不依赖实现的怪癖的情况下使用任何保证,则必须同步:

import threading

lck = threading.Lock()

def doSomething():
    with lck:
        print("Hello ")

d = threading.Thread(target=doSomething)
d.start()
with lck:
    print("done")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM