Python の超お手軽のネットワーク分散コンピューティングライブラリSCOOP

Python
スポンサーリンク

SCOOPとは

  • ssh とPython の設定を適切にするだけで、簡単にネットワーク間での分散処理が実行できる。
    • ネットワーク分散に対応していないライブラリに便利。
    • 関数の処理を分散して行い、返り値をまとめて返してくれる。
  • Core 数に応じた Worker 数の設定が可能
  • Docker との相性が抜群

基本動作

python 標準の map 関数の使い方で ssh で繋いだ先(ノード)でも分散処理してくれる。multiprocessing.Pool.map のネットワーク処理に対応した版。

map 関数に配列を渡すと配列の各要素を引数に関数を実行する。その際の各処理を各ノードでマルチプロセスで実行して、ホストPCに変数を返す。

通信には pickle 化された情報を送信している。

ssh で接続先の通信用ポートを開けて、ポートの情報をホストに送って通信。--tunnelオプションを使えば、localhost 上に port fowarding する。この際のホストIPの解決には、ssh 上の host name が使われる。

サンプルコード

import random
import time
import scoop
import os
from uuid import getnode as get_mac
data = [random.randint(-1000, 1000) for r in range(1000)]

class MyClass(object):
    def __init__(self):
        pass

    def my_method(self, data):
        time.sleep(0.01)
        return((os.getpid()))

if __name__ == '__main__':
    # SCOOP's parallel function
    t = MyClass()
    process_list = list(scoop.futures.map(t.my_method, data))
    unique_process = set(process_list)
    p_nums = {}
    for pid in unique_process:
        p_nums[pid] = len([tmp_pid for tmp_pid in process_list if tmp_pid == pid])

    scoop.logger.info("last_value : %s"%(p_nums))

scoop.futures.map という関数で並列したい関数と、並列したい引数を配列で渡す。

実行スクリプト

python -m scoop --host docker-host1 docker-host2 docker-host3 -n 16 --tunnel scoop_test.py

実行結果

[2017-02-12 14:27:32,585] launcher  INFO    SCOOP 0.7 1.1 on linux2 using Python 2.7.12 (default, Feb  7 2017, 14:01:56) [GCC 5.4.0 20160609], API: 1013
[2017-02-12 14:27:32,585] launcher  INFO    Deploying 16 worker(s) over 3 host(s).
[2017-02-12 14:27:32,585] launcher  INFO    Worker distribution:
[2017-02-12 14:27:32,585] launcher  INFO       docker-host1:      5 + origin
[2017-02-12 14:27:32,586] launcher  INFO       docker-host2:      5
[2017-02-12 14:27:32,586] launcher  INFO       docker-host3: 5
[2017-02-12 14:27:34,415] __main__  INFO    Worker(s) launched using /bin/bash
[2017-02-12 14:27:35,551] scoop_test (127.0.0.1:58127) INFO    last_value : {18305: 77, 3842: 45, 18307: 77, 3835: 47, 18309: 77, 18311: 78, 18313: 78, 18314: 51, 3837: 47, 10199: 65, 10201: 66, 10203: 66, 3841: 48, 10205: 65, 10206: 67, 3839: 46}
[2017-02-12 14:27:35,879] launcher  (127.0.0.1:41977) INFO    Root process is done.
[2017-02-12 14:27:33,542] __main__  INFO    Worker(s) launched using /bin/bash
[2017-02-12 14:27:34,092] __main__  INFO    Worker(s) launched using /bin/bash
[2017-02-12 14:27:36,533] launcher  (127.0.0.1:41977) INFO    Finished cleaning spawned subprocesses.

last_value: の出力で、16個の pid 上で処理されているのが確認できる。

使い方

説明はウェブサイト上にもあるが、動かないサンプルコードも多くはまるので注意。

1. 分散処理をしたいPCでPythonの実行環境を揃える。

標準ではホストPC での Python の実行環境が接続先に渡されて分散処理されることになる。そのため、pyenv 等で /home/user ディレクトリ下に実行環境があると user 名が一致しないためちゃんと動かない。/usr/local/bin/python に統一しておく等の処置が必要になる。

処理に必要なファイル等があれば、それも同一のパスとして各ノードに配置。

Docker との相性が良いのもこのあたり。Docker であれば、容易に同一環境を構築できる。

2. ssh サーバーの設定

パスワードなしの認証キー認証にする。パスワードありには対応していない。

3. ホストPCと各ノードでの ssh config の設定

ssh config での host name が ノードの PC の名前かIPでないと、エラーが出る。このあたりの説明がまったくなくて、ソースコードを追っかけるはめになった。

Docker上で実行したければ、--tunnel オプションをつければ大丈夫。--tunnelオプションを付けていれば、host name の問題は気にしなくていい。--tunnel オプションに関する説明もドキュメントにはないので注意。

4. 実行時

python -m scoop --host docker-host1 docker-host2 docker-host3 -n 16 --tunnel scoop_test.py
  • --host ssh config 上での host name
  • -n 合計のワーカー数
  • --tunnel ssh tunnel を使う

他にもホストごとにワーカー数を設定したりできるが、そのあたりは公式ドキュメントを参照してください。

導入の上での注意

  • python の実行環境をすべて一致させておく必要がある。
    • ここでの実行環境とは、フルパスでの実行パス。
    • 各ライブラリ、実行ファイルともに同一パスに保存していること。
    • Docker を使おう。
  • 読み込むファイル等があれば、そのファイルはすべてのノード上に置く
  • 使用するポートは予め開けておくか、--tunnel オプションを使う。
  • ssh の設定名とホストPC の名前を一致、もしくはIPアドレスにしておく。
    • 一致しない場合は --external-hostname オプションを使うが、一致させた専用のconfigファイルを作って置くほうが良い
    • IP の取得を PC の名前から取得しようとする。ローカルネットワーク内のみ、この方法が使える。
    • /etc/host を編集して、ssh config の host name に IP を割り当ててもいけるはず。

雑感

分散処理したいメソッド内でshell command を叩いて、返り値を得たり等をすれば、Python 以外の言語の並列化にも使える。システムトレードのバックテストの並列化にはおすすめ。

コメント

タイトルとURLをコピーしました