在print()中的end ='...'键不是线程安全的吗?

Sem*_*ark 5 python python-3.x jupyter jupyter-notebook

使用下面的代码,我尝试使用a在jupyter-notebook上并行打印一堆东西ThreadPoolExecutor.请注意,使用该功能show(),输出不是您通常所期望的.

from concurrent.futures import ThreadPoolExecutor
import sys

items = ['A','B','C','D','E','F',
         'G','H','I','J','K','L',
         'M','N','O','P','Q','R',
         'S','T','U','V','W','X','Y','Z']

def show(name):
    print(name, end=' ')

with ThreadPoolExecutor(10) as executor:
    executor.map(show, items)

# This outputs
# AB  C D E F G H I J KLMNOP      QR STU VW    XY Z 
Run Code Online (Sandbox Code Playgroud)

但是当我尝试时sys.stdout.write(),我没有得到这种行为.

def show2(name):
    sys.stdout.write(name + ' ')

with ThreadPoolExecutor(10) as executor:
    executor.map(show2, items)

# This gives
# A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 
Run Code Online (Sandbox Code Playgroud)

奇怪的是,我在jupyter笔记本上尝试了这个,并编写了一个.py文件并运行它.但是后者我似乎没有遇到这个问题.我试过搜索,但我得到的是print()python-3.x 中的线程安全.如果它确实是线程安全的,那么有人可以解释为什么会发生这种情况吗?

Jos*_*osh 3

end实际上不需要指定来公开这一点;即使只是这样做print(name)有时也会导致字母彼此相邻:

\n\n
A\nB\nC\nD\nEF\nG\n\nH\nI\n
Run Code Online (Sandbox Code Playgroud)\n\n

甚至flush=True没有解决它。

\n\n

print 函数在这里用 CPython 实现,并用 C 编写。有趣的是:

\n\n
A\nB\nC\nD\nEF\nG\n\nH\nI\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以看到它PyFile_WriteObject为每个参数(以及 for sep,如果指定)调用一次,然后为该end参数再次调用一次(PyFile_WriteString基本上只是一个PyFile_WriteObject需要 aconst char*而不是 a 的包装器PyObject) \xe2\x80\x93 我认为最终会出现是在这些调用之间进行上下文切换的机会。

\n\n

每次调用PyFile_WriteString本质上与调用(在Python中)相同sys.stdout.write,这可以解释为什么你在执行 ; 时没有看到这个sys.stdout.write(name + \' \')。如果你这样做:

\n\n
sys.stdout.write(name)\nsys.stdout.write(" ")\n
Run Code Online (Sandbox Code Playgroud)\n\n

这更像是 print 函数本身正在做的事情,这也解释了为什么 doprint(name + " ", end="")也有效。

\n