使用下面的代码,我尝试使用ThreadPoolExecutor
在jupyter-notebook上并行打印一堆内容。请注意,使用函数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
但是当我尝试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
奇怪的是,我在jupyter笔记本上编写了这个,并编写了一个.py文件并运行它。但是后者我似乎没有遇到这个问题。我试过搜索,但我得到的是print()
在python-3.x 中线程安全。如果它确实是线程安全的,那么有人可以解释为什么会发生这种情况吗?
答案 0 :(得分:3)
指定end
实际上并不需要公开此内容;即使只是做print(name)
,有时会导致字母彼此相邻:
A
B
C
D
EF
G
H
I
即使flush=True
也无法解决问题。
print函数在CPython here中实现,用C语言编写。有趣的是:
for (i = 0; i < nargs; i++) {
if (i > 0) {
if (sep == NULL)
err = PyFile_WriteString(" ", file);
else
err = PyFile_WriteObject(sep, file,
Py_PRINT_RAW);
if (err)
return NULL;
}
err = PyFile_WriteObject(args[i], file, Py_PRINT_RAW);
if (err)
return NULL;
}
if (end == NULL)
err = PyFile_WriteString("\n", file);
else
err = PyFile_WriteObject(end, file, Py_PRINT_RAW);
您可以看到它为每个参数调用PyFile_WriteObject
一次(对于sep
,如果已指定),然后再次为end
参数调用PyFile_WriteString
基本上只是一个PyFile_WriteObject
的包装器,它接受const char*
而不是PyObject
- 我认为最终有机会在这些调用之间的某个地方进行上下文切换。
对PyFile_WriteString
的每次调用与调用(在Python中)sys.stdout.write
基本相同,这可以解释为什么在执行sys.stdout.write(name + ' ')
时你没有看到这一点;如果你这样做了:
sys.stdout.write(name)
sys.stdout.write(" ")
这更类似于打印功能本身正在做的事情,这也解释了为什么做print(name + " ", end="")
也有效。