2

背景:私はもともと、ソリューションを使用してプログラムの途中でノンブロッキングの対話型インタープリターを開くことについて、この素晴らしい紳士の質問に答えました。threading彼はそれがうまくいったことを指摘しましたが、彼にとってはうまくいきませんでした(理由は理解できthreadingます). 恐れを抱いて、私multiprocessingは高い CPU 使用率に直面して、よりパフォーマンスの高いソリューションを実現することに目を向けました。

このタイプのものを使用する際の基本的な問題multiprocessingは、子プロセスがメインプロセスの STDIN を共有しないことです-これは回避できますが...

問題:解決策にたどり着きましたが (スレッドを参照)、私の解決策には 1 つの永続的な問題がありました: を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が 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 に答える