web-dev-qa-db-ja.com

Python私がやっていることのためのマルチプロセッシングプロセスまたはプール?

私はPythonでマルチプロセッシングを初めて使用し、2つの関数を非同期で呼び出すためにプールまたはプロセスを使用すべきかどうかを判断しようとしています。2つの関数はcurl呼び出しを行い、情報を2インターネット接続によっては、各機能にそれぞれ約4秒かかる場合があります。ボトルネックはISP接続にあり、マルチプロセッシングではそれほど高速化されないことがわかりますが、両方を非同期で開始するのは良いことです。さらに、これは、後で使用するため、Pythonのマルチプロセッシングに入るための素晴らしい学習経験です。

Python multiprocessing.Pool:apply、apply_async、またはmapをいつ使用するか を読んで、それは有用でしたが、それでも私自身の質問がありました。

だから私がそれを行うことができる1つの方法は次のとおりです:

def foo():
    pass

def bar():
    pass

p1 = Process(target=foo, args=())
p2 = Process(target=bar, args=())

p1.start()
p2.start()
p1.join()
p2.join()

この実装に関する質問は次のとおりです。1)呼び出しプロセスが完了するまでブロックを結合するので、これは、p2プロセスが開始される前にp1プロセスが終了する必要があるということですか? .join()はpool.apply()およびpool.apply_sync()。get()と同じであることを常に理解していました。親プロセスは、現在実行中のプロセスが完了するまで別のプロセス(タスク)を起動できません。

他の選択肢は次のようなものです:

def foo():
    pass

def bar():
    pass
pool = Pool(processes=2)             
p1 = pool.apply_async(foo)
p1 = pool.apply_async(bar)

この実装に関する質問は次のとおりです。1)pool.close()、pool.join()が必要ですか? 2)pool.map()は、結果を得る前にそれらをすべて完了させますか?もしそうなら、彼らはまだ非同期で走っていますか? 3)pool.apply_async()はpool.apply()を使用して各プロセスを実行することとどのように異なりますか4)これはProcessを使用した以前の実装とどのように異なりますか?

37
dman

リストした2つのシナリオは、同じことをわずかに異なる方法で実行します。

最初のシナリオでは、2つの別個のプロセス(P1とP2と呼ばれる)を開始し、fooを実行するP1とbarを実行するP2を開始し、両方のプロセスがそれぞれのタスクを完了するまで待機します。

2番目のシナリオでは、2つのプロセス(Q1およびQ2と呼びます)を開始し、最初にQ1またはQ2でfooを開始し、次にQ1またはQ2でbarを開始します。その後、コードは両方の関数呼び出しが返されるまで待機します。

したがって、最終的な結果は実際には同じですが、最初のケースでは、foobarを異なるプロセスで実行することが保証されます。

並行性に関する特定の質問については、Process.join()メソッドは、プロセスが完了するまでブロックしますが、両方のP1で.start()を呼び出したためです。 (最初のシナリオで)P2を結合する前に、両方のプロセスが非同期に実行されます。ただし、インタープリターは、P1が終了するまで待機してから、P2の終了を待機します。

プールのシナリオに関する質問については、技術的にpool.close()を使用する必要がありますが、後で必要になる可能性のあるものに依存します(範囲外になった場合は、必ずしも閉じる必要はありません) )。 pool.map()はまったく異なる種類の動物です。これは、一連の引数を同じ関数に(非同期で)プールプロセス全体に分散し、すべての関数呼び出しが完了するまで待ってから結果のリストを返すためです。 。

30
lmjohns3

Curl呼び出しからデータを取得しているため、IOにバインドされています。そのような場合、 grequests が便利かもしれません。これらは実際にはプロセスでもスレッドでもありませんが、コルーチン-軽量スレッドです。これにより、非同期でHTTP要求を送信し、_multiprocessing.Pool_を使用してCPUにバインドされた部分を高速化できます。

1)呼び出しプロセスが完了するまでブロックを結合するので...これは、p2プロセスが開始される前にp1プロセスが終了する必要があることを意味しますか?

はい、p2.join()は_p1_が終了したことを意味するp1.join()が返された後に呼び出されます。

1)pool.close()、pool.join()が必要ですか

close()およびjoin()を実行せずに、孤立したプロセスになる可能性があります(プロセスが無期限に提供される場合)

2)pool.map()は、結果を得る前にそれらをすべて完了させますか?もしそうなら、彼らはまだ非同期で走っていますか?

これらは非同期に実行されますが、map()はすべてのタスクが完了するまでブロックされます。

3)pool.apply_async()は、pool.apply()を使用して各プロセスを実行することとどのように異なりますか

pool.apply()はブロックしているため、基本的には同期的に処理を行います。

4)これは、Processを使用した以前の実装とどのように異なりますか

おそらく、fooを適用する前にbarでワーカーが実行されるため、1人のワーカーがすべての作業を行うことになります。また、ワーカーの1人が死ぬと、Poolが自動的に新しいワーカーを生成します(タスクを再適用する必要があります)。

まとめるとPoolを選びます-生産者と消費者のケースに最適で、すべてのタスク分配を処理します論理。

11
Maciej Gol