我正在Python中制作一个小程序,使用tkinter来移动多个对象。
首先,我尝试线程化来创建两个对象,并使它们同时移动。因此,我复制/粘贴创建和移动1个对象的函数,然后在2个线程中执行这两个函数。
现在我想尝试选择移动对象的数量,所以我得到了1个函数,我想同时执行它多次。线程不再是可能的。
所以我尝试了多处理,但我遇到了一个问题:它什么都不做。。。我用一个简单的代码重新创建了这个问题:
import multiprocessing
def pr(number):
print(number)
p = multiprocessing.Process(target=pr,args=(40,))
p.start()
它返回一个绝对的"无",不打印任何内容。我认为多处理不是做我想做的事情的合适工具,但我不理解这段代码的问题。
PS:我在Windows 上使用IDLE Python 3.7.2
这篇文章本质上是可以从IDLE运行多处理进程类的副本。我在SO中搜索";[python idle]多处理";。我在这里给出了我之前答案的修订和扩展版本。
-
正如@Booboo所说,至少在Windows和macOS上需要
if __name __ == '__main__':
块。在这种情况下,multiprocessing
本身在Windows上从IDLE启动时运行良好。 -
失败在于打印。当
multiprocessing
启动一个新的python进程时,它会将当前进程sys.__stdout__
复制到新进程中的sys.__stdout__
和sys.stdout
。默认情况下,print
将请求的文本写入sys.stdout
。
当GUI程序从图标或以某种方式而非终端启动时,sys.__stdout__
和sys.stdout
会初始化为None
,至少在Windows上是这样。IDLE将sys.stdout
替换为一个对象,该对象的write
方法将文本发送到IDLE的Shell。复制IDLE特定的sys.stdout是没有用的,因为它不起作用。
如果在Windows上使用py -m idlelib
从命令行启动IDLE,则sys属性将初始化为一个普通的python-io对象,该对象将文本发送到控制台/终端。IDLE只替换sys.stdout,因此多处理可以将工作的sys.__stdout__
io
对象复制到新进程的两个sys属性中。默认情况下,"print"将打印到控制台,如本例所示。
import multiprocessing, sys
def pr():
print(sys.stdout)
if __name__ == '__main__':
p = multiprocessing.Process(target=pr)
p.start()
p.join()
# Writes the following to the
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
打印到CommandPrompt显然不太好,但这是使用非IDLE代码所能做的最好的操作。在您的特定情况下,想要对tkinter对象设置动画(可能是在tkinter画布上(,您应该在循环后使用tk/tkinter,而不是多处理。IDLE是为开发tkinter程序而设计的。在SO中搜索[tkinter] animate
可以得到几百次点击。
IDLE的问题与在Jupyter Notebook等环境中尝试进行多处理时遇到的问题相同。也就是说,除了您的辅助函数pr
必须在导入的单独模块中之外,还可以执行此操作。如果你不这样做,那么你会得到以下异常:
AttributeError: Can't get attribute 'pr' on <module '__main__' (built-in)>
不幸的是,通过从Windows开始菜单启动IDLE,从未看到该异常消息。如果IDLE是从命令提示符启动的,而不是用。。。
python -m idlelib
则CCD_ 19异常将显示在命令提示符控制台上。
因此:
- 将
pr
函数放在某个目录中的文件中,例如pr.py - 打开命令提示符,将当前目录更改为包含pr.py的目录
- 使用python-m idlelib启动IDLE
然后您的程序变成:
import multiprocessing
from pr import pr
if __name__ == '__main__': # required for Windows
p = multiprocessing.Process(target=pr,args=(40,))
p.start()
p.join() # Wait for the completion explicitly