问题不在于 IDLE。问题是尝试在没有 sys.stdout 的进程中打印到 sys.stdout。这就是为什么 Spyder 有同样的问题。 Windows 上的任何 GUI 程序都可能有同样的问题。
至少在 Windows 上,GUI 程序通常在没有标准输入、标准输出或标准错误流的进程中运行。 Windows 期望 GUI 程序通过在屏幕上绘制像素(图形中的 G)的小部件与用户交互,并从 Windows 事件系统接收键和鼠标事件。这就是 IDLE GUI 所做的,使用 tcl tk GUI 框架的 tkinter 包装器。
当 IDLE 在子进程中运行用户代码时,idlelib.run 首先运行,它用通过套接字与 IDLE 自身交互的对象替换标准流的 None。然后它执行()的用户代码。当用户代码运行 multiprocessing 时,multiprocessing 会启动更多没有 std 流但永远不会得到它们的进程。
解决方案是在控制台中启动 IDLE:python -m idlelib.idle(在 3.x 上不需要 .idle)。在控制台中启动的进程将 std 流连接到控制台。进一步的子流程也是如此。所有进程的真正标准输出(相对于 sys.stdout)是控制台。如果运行文档中的第三个示例,
from multiprocessing import Process
import os
def info(title):
print(title)
print('module name:', __name__)
print('parent process:', os.getppid())
print('process id:', os.getpid())
def f(name):
info('function f')
print('hello', name)
if __name__ == '__main__':
info('main line')
p = Process(target=f, args=('bob',))
p.start()
p.join()
然后“主线”块进入 IDLE shell,“函数 f”块进入控制台。
这个结果表明,Justin Barber 声称 IDLE 运行的用户文件不能导入到 multiprocessing 启动的进程中是不正确的。
编辑:Python 将进程的原始标准输出保存在 sys.__stdout__ 中。这是在 Windows 上以纯 GUI 进程正常启动 IDLE 时 IDLE 的 shell 中的结果。
>>> sys.__stdout__
>>>
这是从 CommandPrompt 启动 IDLE 时的结果。
>>> import sys
>>> sys.__stdout__
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
>>> sys.__stdout__.fileno()
1
stdin、stdout 和 stderr 的标准文件编号是 0、1、2。使用以下命令运行文件
from multiprocessing import Process
import sys
def f(name):
print('hello', name)
print(sys.__stdout__)
print(sys.__stdout__.fileno())
if __name__ == '__main__':
p = Process(target=f, args=('bob',))
p.start()
p.join()
在IDLE中在控制台启动和输出是一样的。