2

背景:我最初回答了这位绅士关于使用解决方案打开非阻塞交互式解释器中间程序的threading问题。他指出它有效,但对他来说表现不佳(可以理解,因为threading)。面对高 CPU 利用率,我怀着忐忑的心情转而寻求multiprocessing一种性能更高的解决方案。

使用multiprocessing这种类型的基本问题是子进程不共享主进程的 STDIN - 我可以解决这个问题,但是......

问题:虽然我确实找到了解决方案(请参阅线程),但我的解决方案存在一个持续存在的问题:code.interact()通过调用exit()(即 raise 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是 length-1 tuple (None,)。有道理,我猜。

问题:这是怎么回事?!通过获取元组SystemExit生成的版本如何?这显然不会正常发生 - 裸露的意思是exit()(None,)e.argsraise SystemExite.args == ()

我也愿意接受改进我的代码(或我对链接线程的回答)的方法,但主要是我想知道我是否正在做一些我明确不应该做的事情。sys.stdin在子进程中重定向似乎无害,但是......

解决方案:感谢 Peters 先生,原来这是 python 3.2 中的一个错误。在 3.3 中,违规行变成了:sys.stderr.write(str(e.args[0]) + '\n'). str(None) + '\n'不再引起爆炸。凉爽的。

4

1 回答 1

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

Soexit()与 相同exit(None),这None就是 的来源。但还有别的! quit和是 中定义的类exit的实例,并具有以下方法:QuitterLib/_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。相关的?不知道。该评论暗示这是一个技巧,以便像 IDLE 这样的程序知道用户真的想退出。

顺便说一句,我正在查看当前(3.4.0a4+)开发分支负责人的源代码,因此与您使用的 Python 可能存在细微差别。

于 2013-11-04T05:16:21.787 回答