web-dev-qa-db-ja.com

分散されたDaskで大きな引数を持つタスクを効率的に送信するにはどうすればよいですか?

大きな(ギガバイトスケール)引数を持つDaskを使用して関数を送信したいと思います。これを行うための最良の方法は何ですか?この関数をさまざまな(小さな)パラメーターで何度も実行したいと思います。

例(悪い)

これはconcurrent.futuresインターフェースを使用します。 dask.delayedインターフェースも同じように簡単に使用できます。

x = np.random.random(size=100000000)  # 800MB array
params = list(range(100))             # 100 small parameters

def f(x, param):
    pass

from dask.distributed import Client
c = Client()

futures = [c.submit(f, x, param) for param in params]

しかし、これは私が予想するよりも遅いか、メモリエラーが発生します。

16
MRocklin

さて、ここで問題なのは、各タスクに大きな配列xが含まれていることです。送信する100個のタスクごとに、xをシリアル化し、スケジューラーに送信し、ワーカーに送信する必要があります。

代わりに、アレイをクラスターに1回送信します。

[future] = c.scatter([x])

これで、futureは、クラスター上に存在する配列xを指すトークンになります。これで、ローカルクライアントのnumpy配列の代わりに、このリモートフューチャーを参照するタスクを送信できます。

# futures = [c.submit(f, x, param) for param in params]  # sends x each time
futures = [c.submit(f, future, param) for param in params]  # refers to remote x already on cluster

これにより、はるかに高速になり、Daskがデータの移動をより効果的に制御できるようになりました。

すべての労働者にデータを散布する

最終的に配列xをすべてのワーカーに移動する必要があると予想される場合は、配列をブロードキャストして開始することをお勧めします。

[future] = c.scatter([x], broadcast=True)

DaskDelayedを使用する

先物はdask.delayedでも問題なく機能します。ここにはパフォーマンス上の利点はありませんが、このインターフェイスを好む人もいます。

# futures = [c.submit(f, future, param) for param in params]

from dask import delayed
lazy_values = [delayed(f)(future, param) for param in params]
futures = c.compute(lazy_values)
21
MRocklin