Pythonの並列性
-
24-10-2019 - |
質問
Pythonで並列性を達成するためのオプションは何ですか?いくつかの非常に大きなラスターでCPUバウンド計算の束を実行したいので、それらを並列化したいと考えています。 Cの背景から来て、私は並列性への3つのアプローチに精通しています:
- おそらくクラスター全体に配布されるメッセージの通過プロセスなど MPI.
- どちらかを使用して、明示的な共有メモリの並列性 pthreads また フォーク(), パイプ(), 、et。アル
- 使用して、暗黙の共有メモリの並列性 OpenMP.
使用するアプローチを決定することは、トレードオフの演習です。
Pythonでは、どのようなアプローチが利用可能であり、それらの特性は何ですか?クラスタブルはありますか MPI クローン?共有メモリの並列性を達成するための好ましい方法は何ですか?の問題についての言及を聞いたことがあります ギル, 、および参照 タスクレット.
要するに、それらの間で選択する前に、Pythonのさまざまな並列化戦略について何を知る必要がありますか?
解決
一般に、CPUバウンド計算について説明します。これはPythonのForteではありません。歴史的にも、マルチプロセッシングではありません。
主流のPythonインタープリターのスレッドは、恐ろしいグローバルロックによって支配されています。新しい マルチプロセッシング APIはそれを回避し、ワーカープールにパイプやキューなどで抽象化します。
他のヒント
新しい(2.6) マルチプロセッシング モジュールは行く方法です。サブプロセスを使用します ギル 問題。また、ローカル/リモートの問題のいくつかを抽象化するため、コードをローカルで実行するか、クラスター上に広げるという選択を後で作成できます。私が上にリンクしたドキュメントはかなり噛むのにかなりのものですが、始めるために良い根拠を提供する必要があります。
レイ これを行うためのエレガントな(そして速い)ライブラリです。
Python関数を並列化するための最も基本的な戦略は、 @ray.remote
デコレーター。その後、非同期に呼び出すことができます。
import ray
import time
# Start the Ray processes (e.g., a scheduler and shared-memory object store).
ray.init(num_cpus=8)
@ray.remote
def f():
time.sleep(1)
# This should take one second assuming you have at least 4 cores.
ray.get([f.remote() for _ in range(4)])
ステートフルな計算を使用して並行することもできます 俳優, 繰り返します @ray.remote
デコレーター。
# This assumes you already ran 'import ray' and 'ray.init()'.
import time
@ray.remote
class Counter(object):
def __init__(self):
self.x = 0
def inc(self):
self.x += 1
def get_counter(self):
return self.x
# Create two actors which will operate in parallel.
counter1 = Counter.remote()
counter2 = Counter.remote()
@ray.remote
def update_counters(counter1, counter2):
for _ in range(1000):
time.sleep(0.25)
counter1.inc.remote()
counter2.inc.remote()
# Start three tasks that update the counters in the background also in parallel.
update_counters.remote(counter1, counter2)
update_counters.remote(counter1, counter2)
update_counters.remote(counter1, counter2)
# Check the counter values.
for _ in range(5):
counter1_val = ray.get(counter1.get_counter.remote())
counter2_val = ray.get(counter2.get_counter.remote())
print("Counter1: {}, Counter2: {}".format(counter1_val, counter2_val))
time.sleep(1)
それはより多くの利点があります マルチプロセッシング モジュール:
- 同じコードは、単一のマルチコアマシンと大きなクラスターで実行されます。
- データは、同じマシンのプロセス間で効率的に共有されます 共有メモリと効率的なシリアル化.
- Python関数(タスクを使用)を並列化でき、 Pythonクラス(俳優を使用).
- エラーメッセージはうまく伝播されます。
レイ 私が開発を支援してきたフレームワークです。
それを行うための多くのパッケージがありますが、他のと言われているように最も適切なのは、特にクラス「プール」を使用したマルチプロセッシングです。
同様の結果を得ることができます パラレルPython, 、さらに、クラスターで動作するように設計されています。
とにかく、私はマルチプロセッシングで行くと言います。
処理する必要があるデータの量と使用するCPU/マシンの数に応じて、場合によっては、Cでその一部を書く方が良い(またはJython/Ironpythonを使用する場合はJava/C#)
それから得られるスピードアップは、8 CPUで並行して物事を実行するよりも、パフォーマンスのために多くのことをするかもしれません。