私は現在、次のように複数のプロセスを生成するコードを持っています。
_pool = Pool(processes=None)
results = [pool.apply(f, args=(arg1, arg2, arg3)) for arg3 in arg_list]
_
私の考えは、これにより、_processes=None
_以降に使用可能なすべてのコアを使用して、作業がコア間で分割されるというものでした。ただし、 multiprocessing module docs のPool.apply()
メソッドのドキュメントには次のように書かれています。
Apply()組み込み関数と同等です。結果の準備ができるまでブロックされるため、apply_async()は作業を並行して実行するのに適しています。さらに、funcは、プールのワーカーの1つでのみ実行されます。
最初の質問:私はこれをはっきりと理解していません。 apply
はどのように作業をワーカー間で分散し、_apply_async
_が行うこととどのように異なりますか?タスクがワーカー間で分散される場合、func
がワーカーの1つでのみ実行される可能性はありますか?
私の推測:私の推測では、現在の実装では、apply
が特定の引数のセットを使用してワーカーにタスクを与え、待機していると思いますそのワーカーを実行し、次の一連の引数を別のワーカーに渡します。このようにして、作業をさまざまなプロセスに送信していますが、並列処理は行われていません。 apply
は実際には次のようになっているため、これが当てはまるようです。
_def apply(self, func, args=(), kwds={}):
'''
Equivalent of `func(*args, **kwds)`.
Pool must be running.
'''
return self.apply_async(func, args, kwds).get()
_
2番目の質問:docs 、セクション16.6.1.5の紹介で、理由をよりよく理解したいと思います。 (「ワーカーのプールを使用する」)、[pool.apply_async(os.getpid, ()) for i in range(4)]
mayなどの_apply_async
_を使用した構造でも、より多くのプロセスを使用すると言われていますが、それは確かではありません。そうなる。 複数のプロセスを使用するかどうかを決定するものは何ですか?
あなたはPython2.7のドキュメントを指摘しているので、Python2.7マルチプロセッシングの実装に基づいて答えます。 Python3.Xでは異なる場合がありますが、それほど異なるものではありません。
apply
とapply_async
の違いこれら2つの違いは、それらが実際にどのように実装されているかを見ると、本当に自己記述的です。ここでは、ボット関数のmultiprocessing/pool.py
からコードをコピーして貼り付けます。
def apply(self, func, args=(), kwds={}):
'''
Equivalent of `apply()` builtin
'''
assert self._state == RUN
return self.apply_async(func, args, kwds).get()
ご覧のとおり、apply
は実際にはapply_async
を呼び出していますが、結果を返す直前にget
が呼び出されています。これにより、基本的に、結果が返されるまでapply_async
ブロックが作成されます。
def apply_async(self, func, args=(), kwds={}, callback=None):
'''
Asynchronous equivalent of `apply()` builtin
'''
assert self._state == RUN
result = ApplyResult(self._cache, callback)
self._taskqueue.put(([(result._job, None, func, args, kwds)], None))
return result
apply_async
は、タスクをタスクキューにエンキューし、送信されたタスクのhandle
を返します。そのhandle
を使用して、get
またはwait
を呼び出して、それぞれ結果を取得するか、タスクが終了するのを待つことができます。タスクが終了すると、タスクが返すものが引数としてcallback
関数に渡されます。
from multiprocessing import Pool
from time import sleep
def callback(a):
print a
def worker(i, n):
print 'Entering worker ', i
sleep(n)
print 'Exiting worker'
return 'worker_response'
if __name__ == '__main__':
pool = Pool(4)
a = [pool.apply_async(worker, (i, 4), callback=callback) for i in range(8)]
for i in a:
i.wait()
Entering worker 0
Entering worker 1
Entering worker 2
Entering worker 3
Exiting worker
Exiting worker
Exiting worker
Exiting worker
Entering worker 4
Entering worker 5
worker_response
Entering worker 6
worker_response
Entering worker 7
worker_response
worker_response
Exiting worker
Exiting worker
Exiting worker
Exiting worker
worker_response
worker_response
worker_response
worker_response
apply_async
を使用する場合は、結果を待つか、タスクが完了するのを待つ必要があることに注意してください。私の例の最後の2行にコメントを付けない場合、スクリプトは実行後すぐに終了します。
apply_async
がより多くのプロセスを使用する理由apply
がどのように記述され、機能しているかに関して、私はこれを理解しています。 apply
はタスクごとにタスクを実行してPool
の使用可能なプロセスに送信するため、apply_async
はタスクをキューに追加し、タスクキュースレッドはそれらをPool
の使用可能なプロセスに送信します。これが、apply_async
を使用するときに複数のプロセスが実行される可能性がある理由です。
著者が伝えようとした考えをよりよく理解するために、 this セクションを数回通過しました。ここで確認しましょう:
# evaluate "os.getpid()" asynchronously
res = pool.apply_async(os.getpid, ()) # runs in *only* one process
print res.get(timeout=1) # prints the PID of that process
# launching multiple evaluations asynchronously *may* use more processes
multiple_results = [pool.apply_async(os.getpid, ()) for i in range(4)]
print [res.get(timeout=1) for res in multiple_results]
前の例を見て最後の例を理解しようとすると、apply_async
の連続した呼び出しが複数ある場合、それは確かにmay同時にそれらの多くを実行する可能性があります。これはおそらく、その時点でPool
内のプロセスがいくつ使用されているかによって異なります。それが彼らがmayと言う理由です。