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

Python multithreading program is giving unexpected output

我知道没有关于线程执行顺序的gua运行tee。但我的疑问是当我运行下面的代码时,

import threading

def doSomething():
    print("Hello ")

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

即将到来的输出是

Hello done

或这个

Hello 
done

可能是如果我尝试太多,它可能也会给我下面的结果

done
Hello

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

这是一个典型的竞争条件。我无法亲自重现它,它可能会因解释器实现和应用于 stdout 的精确配置而异。在 Python 没有 GIL 的解释器上,基本上没有对种族的保护,这种行为在一定程度上是意料之中的。 Python 与 C/C++ 不同,解释器确实倾向于保护您免受由于线程引起的严重数据损坏,但即使他们确保写入的每个字节最终都实际打印出来,他们通常也不会尝试明确保证不交错; Hdelolnoe 当您不做任何努力来同步对 stdout.

的访问时,可能(如果给定可能的实现不太可能)输出

在 CPython 上,GIL 对您的保护更多,将单个字符串写入 stdout 更有可能是原子的,但您并不是在写入单个字符串。本质上,print 的实现是将对象一个一个地写入输出文件对象,它不会批处理到单个字符串然后只调用一次 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")