3

tl;dr

Python でパイプを読み取るときに、EINTR の「system call interrupted」エラーを処理する必要がありますか? その場合、そのようなコードをテストするにはどうすればよいですか?

説明

以下のトレースバックでself._dataqは、multiprocessing.Queue(技術的にはbilliardライブラリを使用していますが、基本的に同じコードだと思います)です。Python サブプロセスは、キューの反対側に書き込みを行うことがあります。何が起こったのかは、システム コールがキューにフィードするパイプを読み取っていて、シグナルが到着したことだと思います。おそらく、2 番目の Ctrl+C イベントからの SIGINT です (最初の SIGINT は、ユーザー^Cがロギング出力、およびシグナル ハンドラーがその SIGINT をキャッチしたことは、ログの WARNING メッセージで確認できます)。

[INFO     2014-03-05 14:16:06,000] Doing some work, la-dee-da
^C[WARNING 2014-03-05 14:16:07,344] Commencing shutdown. (Signal SIGINT, process 2469.). Press Ctrl+C again to exit immediately.
[DEBUG    2014-03-05 14:16:07,347] Terminating subprocess
Traceback (most recent call last):
[... a bunch of stuff omitted]
  File "mycode.py", line 97, in __next__
    result = self._dataq.get(timeout=0.1)
  File "/usr/local/lib/python2.7/site-packages/billiard/queues.py", line 103, in get
    if timeout < 0 or not self._poll(timeout):
IOError: [Errno 4] Interrupted system call

上記のトレースバックのステートメントresult = self._dataq.get(timeout=0.1)は、次のようなループの途中にあります。ループの主な目的は、戻り始めるself._dataqときにからの読み取りをあきらめることができるようにすることです。self.timedout()True

import queue
while True:
    try:
        result = self._dataq.get(timeout=0.1)
    except queue.Empty:
        if self.timedout():
            self.close()
            raise MyTimedoutError()
    else:
        break

質問

発生した理由についての私の理論IOErrorが正しい場合、上記のtry...ブロックは、システムコールの中断によって発生した sexceptをキャッチして無視する必要があります。IOErrorEINTR エラーの原因がシグナルである場合、Python に戻ってexcept IOError:ステートメントを実行するだけで、Python レベルのシグナル ハンドラーを実行できます。

あれは正しいですか?もしそうなら、私のコードでこの変更をテストすることは可能ですか? 深刻な競合状態を含まない単体テストをどのように作成するかは、私には明らかではありません。

4

2 に答える 2

1

EINTRPython 3.5 では、処理の責任をアプリケーション コードではなく Python ランタイムに置くことで、この問題を解決しています。PEP 475Python 3.5 Changelogを参照してください。

于 2016-07-08T04:07:59.423 に答える
0

これを Python のバグと呼ぶことにします。multiprocessing.Queue発生が許可されているドキュメントを見つけることができません(ただし、他の I/O 問題で発生IOErrorEINTRせることは理にかなっています。そのため、発生した例外を無視する前に、その errno 属性を確認する必要がありますerrno。参照) 。 t は、そのような動作を提供する任意の低レベル C 関数に直接マップされます。すべての s を C レベルで処理するという議論がありましたがEINTR、それは 3.4 にはなりませんでした (そして、2.x にはまったくならないのではないかと思います)。

于 2014-12-25T16:45:12.190 に答える