Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/google-chrome/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python多线程程序正在提供意外的输出_Python_Multithreading_Python Multithreading - Fatal编程技术网

Python多线程程序正在提供意外的输出

Python多线程程序正在提供意外的输出,python,multithreading,python-multithreading,Python,Multithreading,Python Multithreading,我知道对于线程的执行顺序没有保证。但我的疑问是当我运行下面的代码时 import threading def doSomething(): print("Hello ") d = threading.Thread(target=doSomething, args=()) d.start() print("done") 即将到来的输出是 Hello done 还是这个 Hello done 可能是如果我尝试太多,那么它可能会给我以下以及

我知道对于线程的执行顺序没有保证。但我的疑问是当我运行下面的代码时

import threading

def doSomething():
    print("Hello ")

d = threading.Thread(target=doSomething, args=())
d.start()
print("done")
即将到来的输出是

Hello done
还是这个

Hello 
done
可能是如果我尝试太多,那么它可能会给我以下以及

done
Hello

但我不相信第一个输出。因为顺序可以不同,但是为什么两个输出都可以在同一行中使用呢。这是否意味着一个线程正在与其他正在工作的线程发生冲突?

这是一个典型的争用条件。我个人无法复制它,它可能会因解释器实现和应用于
stdout
的精确配置而异。在没有GIL的Python解释器上,基本上没有针对种族的保护,这种行为在一定程度上是可以预期的。与C/C++不同,Python解释器确实倾向于保护您免受线程导致的异常数据损坏,但即使它们确保写入的每个字节最终都被实际打印出来,它们通常也不会试图明确保证不会交错<当您不努力同步对
stdout
的访问时,code>hdelnoe将是一种可能的输出(如果考虑到可能的实现,这种可能性很小)

在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以响应第一次
写入
,它们将在执行实际写入之前释放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")

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

在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以响应第一次
写入
,它们将在执行实际写入之前释放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")

真奇怪。我已经在我的机器上运行了1000次你的代码,我得到的唯一输出是Hello在单独的行中完成。老实说,我不会读太多。听起来你的解释器比你的代码更像是个问题?@H4KKR:是的,这对解释器、操作系统、输出是发送到终端还是文件等方面的细微差异非常敏感。为了有机会复制,我们至少需要知道正在使用的操作系统、终端/外壳,以及Python解释器和版本。但这最终不是一个有趣的问题<代码>打印不是原子的,所以交错是合法的。可以只从单个线程写入,也可以跨线程同步。感谢您的宝贵意见。我还认为可能是因为非原子操作。但每当我运行这个时,它是50%,给我的输出只是同一行-(不确定它是否可复制。以防需要。@ShadowRanger机器是Mac.OS是BigSur.Python版本:Python 3.8.5(默认,2009年9月4日)