背景:我最初回答了this fine gentleman's question关于使用threading
解决方案在中间程序中打开非阻塞交互式解释器的问题。他指出它有效,但它对他表现不佳(可以理解,因为threading
)。在惶恐不安的情况下,面对高CPU利用率,我转向multiprocessing
以获得更高性能的解决方案。
将multiprocessing
用于此类事情的基本问题是子进程不共享主进程'STDIN - 我可以解决这个问题,但是......
问题:虽然我确实找到了解决方案(请参阅主题),但我的解决方案存在一个持久性问题:通过调用code.interact()
退出exit()
会话(即提升SystemExit
)给出了这个追溯:
Traceback (most recent call last):
File "/usr/lib/python3.2/multiprocessing/process.py", line 267, in _bootstrap
self.run()
File "/usr/lib/python3.2/multiprocessing/process.py", line 116, in run
self._target(*self._args, **self._kwargs)
File "./test2.py", line 6, in interp
code.interact(local=locs)
File "/usr/lib/python3.2/code.py", line 287, in interact
console.interact(banner)
File "/usr/lib/python3.2/code.py", line 223, in interact
more = self.push(line)
File "/usr/lib/python3.2/code.py", line 245, in push
more = self.runsource(source, self.filename)
File "/usr/lib/python3.2/code.py", line 74, in runsource
self.runcode(code)
File "/usr/lib/python3.2/code.py", line 90, in runcode
exec(code, self.locals)
File "<console>", line 1, in <module>
File "/usr/lib/python3.2/site.py", line 382, in __call__
raise SystemExit(code)
SystemExit: None
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.2/multiprocessing/process.py", line 278, in _bootstrap
sys.stderr.write(e.args[0] + '\n')
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./test2.py", line 12, in <module>
p.start()
File "/usr/lib/python3.2/multiprocessing/process.py", line 132, in start
self._popen = Popen(self)
File "/usr/lib/python3.2/multiprocessing/forking.py", line 126, in __init__
code = process_obj._bootstrap()
File "/usr/lib/python3.2/multiprocessing/process.py", line 286, in _bootstrap
util.info('process exiting with exitcode %d' % exitcode)
UnboundLocalError: local variable 'exitcode' referenced before assignment
转载:这里是重现的代码:
#!/usr/bin/python3
def interp(locs,handle):
import code, os, sys
sys.stdin = os.fdopen(handle)
code.interact(local=locs)
if __name__ == '__main__':
from multiprocessing import Process
import sys
p=Process(target=interp,args=(locals(),sys.stdin.fileno()))
p.start()
import time
time.sleep(20)
在互动口译员处,您必须输入exit()
。正确执行ctrl-D退出。这是踢球者:做raise SystemExit
也优雅地退出。 什么?!的
进一步调查:此处是process.py
中存在问题的块:
except SystemExit as e:
if not e.args:
exitcode = 1
elif type(e.args[0]) is int:
exitcode = e.args[0]
else:
sys.stderr.write(e.args[0] + '\n') #exception here
exitcode = 1
在该行之前直接插入调试语句表明e.args
是长度为1的元组(None,)
。我猜是有道理的。
问题:发生了什么事?! SystemExit
生成的exit()
版本如何获得(None,)
的{{1}}元组?这显然不会发生 - 只有e.args
表示raise SystemExit
我也愿意接受改进我的代码的方法(或者我对链接线程的回答),但主要是我想知道我是否正在做一些我明确不应该做的事情。在子进程中重定向e.args == ()
似乎是无害的,但是......
决议:感谢Peters先生,结果发现这是python 3.2中的一个错误。在3.3中,违规行转为:sys.stdin
。 sys.stderr.write(str(e.args[0]) + '\n')
不再导致爆炸。凉。
答案 0 :(得分:3)
我在这里无法洞察你的真实问题,但可以清除exit()
之谜。它是记录在案的行为,来自site
模块文档:
quit(code=None)
exit(code=None)
Objects that when printed, print a message like “Use quit() or
Ctrl-D (i.e. EOF) to exit”, and when called, raise SystemExit with
the specified exit code
因此exit()
与exit(None)
相同,而None
来自quit
。但还有别的东西! exit
和Quitter
是Lib/_sitebuiltins.py
中定义的__call__
类的实例,并采用此def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)
方法:
sys.stdin
我很惊讶他们关闭{{1}}。有关?不知道。评论意味着它是一个技巧,以便像IDLE这样的程序知道用户真的想要退出。
BTW,我正在查看当前(3.4.0a4 +)开发分支的源代码,因此与您正在使用的Python可能存在细微差别。