web-dev-qa-db-ja.com

Python例外を処理するスレッドプール

私は単純なpythonスレッドプールパターンの良い実装を探していましたが、本当に私のニーズに合ったものを見つけることができません。私はpython = 2.7および私が見つけたすべてのモジュールが機能しないか、ワーカーの例外を適切に処理しません。誰かが私が探しているタイプの機能を提供できるライブラリを知っているかどうか疑問に思いました。大いに助けてください。感謝。

マルチプロセッシング

私の最初の試みは組み込みのmultiprocessingモジュールを使用しましたが、これはスレッドではなくサブプロセスを使用するため、オブジェクトをpickle化できないという問題が発生します。ここには行かない。

from multiprocessing import Pool

class Sample(object):
    def compute_fib(self, n):
        phi = (1 + 5**0.5) / 2
        self.fib = int(round((phi**n - (1-phi)**n) / 5**0.5))

samples = [Sample() for i in range(8)]
pool = Pool(processes=8)
for s in samples: pool.apply_async(s.compute_fib, [20])
pool.join()
for s in samples: print s.fib

# PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed

先物

だから私はpython 3.2 here のクールな同時機能のいくつかのバックポートがあるのを見る。これは完璧で使いやすいようだ。問題はあなたがワーカーの1つで例外を取得すると、「ZeroDivisionError」などの例外のタイプのみが取得され、トレースバックが取得されないため、どの行が例外を引き起こしたかが示されません。コードのデバッグが不可能になります。

from concurrent import futures

class Sample(object):
    def compute_fib(self, n):
        phi = (1 + 5**0.5) / 2
        1/0
        self.fib = int(round((phi**n - (1-phi)**n) / 5**0.5))

samples = [Sample() for i in range(8)]
pool = futures.ThreadPoolExecutor(max_workers=8)
threads = [pool.submit(s.compute_fib, 20) for s in samples]
futures.wait(threads, return_when=futures.FIRST_EXCEPTION)
for t in threads: t.result()
for s in samples: print s.fib


#    futures-2.1.3-py2.7.Egg/concurrent/futures/_base.pyc in __get_result(self)
#    354     def __get_result(self):
#    355         if self._exception:
#--> 356             raise self._exception
#    357         else:
#    358             return self._result
#
# ZeroDivisionError: integer division or modulo by zero

ワーカープール

このパターンの他の実装を見つけました ここ 。今回は例外が発生すると出力されますが、ipythonインタラクティブインタープリターはハング状態のままであり、他のシェルから強制終了する必要があります。立ち入り禁止。

import workerpool

class Sample(object):
    def compute_fib(self, n):
        phi = (1 + 5**0.5) / 2
        1/0
        self.fib = int(round((phi**n - (1-phi)**n) / 5**0.5))

samples = [Sample() for i in range(8)]
pool = workerpool.WorkerPool(size=8)
for s in samples: pool.map(s.compute_fib, [20])
pool.wait()
for s in samples: print s.fib

# ZeroDivisionError: integer division or modulo by zero
# ^C^C^C^C^C^C^C^C^D^D
# $ kill 1783

スレッドプール

さらに他の実装 ここ 。今回は例外が発生すると、それはstderrに出力されますが、スクリプトは中断されず、代わりに実行を継続します。これは例外の目的に反し、物事を危険にさらす可能性があります。まだ使えません。

import threadpool

class Sample(object):
    def compute_fib(self, n):
        phi = (1 + 5**0.5) / 2
        1/0
        self.fib = int(round((phi**n - (1-phi)**n) / 5**0.5))

samples = [Sample() for i in range(8)]
pool = threadpool.ThreadPool(8)
requests = [threadpool.makeRequests(s.compute_fib, [20]) for s in samples]
requests = [y for x in requests for y in x]
for r in requests: pool.putRequest(r)
pool.wait()
for s in samples: print s.fib

# ZeroDivisionError: integer division or modulo by zero
# ZeroDivisionError: integer division or modulo by zero
# ZeroDivisionError: integer division or modulo by zero
# ZeroDivisionError: integer division or modulo by zero
# ZeroDivisionError: integer division or modulo by zero
# ZeroDivisionError: integer division or modulo by zero
# ZeroDivisionError: integer division or modulo by zero
# ZeroDivisionError: integer division or modulo by zero
#---> 17 for s in samples: print s.fib
#
#AttributeError: 'Sample' object has no attribute 'fib'

-更新-

futuresライブラリに関して、python 3の動作はpython 2と同じではないようです。

futures_exceptions.py

from concurrent.futures import ThreadPoolExecutor, as_completed

def div_zero(x):
    return x / 0

with ThreadPoolExecutor(max_workers=4) as executor:
    futures = executor.map(div_zero, range(4))
    for future in as_completed(futures): print(future)

Python 2.7.6出力:

Traceback (most recent call last):
  File "...futures_exceptions.py", line 12, in <module>
    for future in as_completed(futures):
  File "...python2.7/site-packages/concurrent/futures/_base.py", line 198, in as_completed
    with _AcquireFutures(fs):
  File "...python2.7/site-packages/concurrent/futures/_base.py", line 147, in __init__
    self.futures = sorted(futures, key=id)
  File "...python2.7/site-packages/concurrent/futures/_base.py", line 549, in map
    yield future.result()
  File "...python2.7/site-packages/concurrent/futures/_base.py", line 397, in result
    return self.__get_result()
  File "...python2.7/site-packages/concurrent/futures/_base.py", line 356, in __get_result
    raise self._exception
ZeroDivisionError: integer division or modulo by zero

Python 3.3.2出力:

Traceback (most recent call last):
  File "...futures_exceptions.py", line 11, in <module>
    for future in as_completed(futures):
  File "...python3.3/concurrent/futures/_base.py", line 193, in as_completed
    with _AcquireFutures(fs):
  File "...python3.3/concurrent/futures/_base.py", line 142, in __init__
    self.futures = sorted(futures, key=id)
  File "...python3.3/concurrent/futures/_base.py", line 546, in result_iterator
    yield future.result()
  File "...python3.3/concurrent/futures/_base.py", line 392, in result
    return self.__get_result()
  File "...python3.3/concurrent/futures/_base.py", line 351, in __get_result
    raise self._exception
  File "...python3.3/concurrent/futures/thread.py", line 54, in run
    result = self.fn(*self.args, **self.kwargs)
  File "...futures_exceptions.py", line 7, in div_zero
    return x / 0
ZeroDivisionError: division by zero
17
xApple

インターフェースがとてもシンプルなので、私は個人的にFuturesを使用しています。トレースバックの問題については、それを保持するための回避策を見つけました。この他の質問に対する私の答えをチェックしてください:

concurrent.futuresで例外の元の行番号を取得する

3
se7entyse7en

簡単な解決策:自分に最も適した代替手段を使用し、ワーカーに独自のtry-exceptブロックを実装します。必要に応じて、ルート呼び出しを囲みます。

これらのライブラリが例外を「誤って」処理するとは言いません。デフォルトの動作ですが、プリミティブです。デフォルトが適切でない場合は、これを自分で処理する必要があります。

0
slezica