3
0

More than 3 years have passed since last update.

【Python3】M1 Mac(Docker)で分散並列処理フレームワークRayのサンプルコードを動かす

Last updated at Posted at 2021-09-12

Rayとは

RayはPythonにおける分散並列処理を高速かつシンプルに書けるフレームワークで、既存のコードを並列化することも容易な設計となっています。

Rayを使うことでmultiprocessingなどに比べ簡単にプロセスレベルの並列処理を記述することができます。Rayは2021年9月現在MacOSとLinuxをサポートしています。Windowsのサポートは実験段階であり、開発中です。

ローカル環境を構築する予定でしたが、既知のバグがあるらしく動かなかったので、仕方なくDocker環境を構築します。

環境

macOS Big Sur 11.5.2
docker 20.10.7
python 3.7.7 (dockerコンテナ内)

M1MacにDockerDesktopをインストール

M1MacにDockerDesktopをインストールするには、上のリンクを踏んでダウンロードする必要があります。

さらに、Rosetta2もインストールしなければならないため、公式ページの指示に従って以下のコマンドをターミナルで叩きます。

Rosetta2 install
softwareupdate --install-rosetta

これでDockerが使用可能になります。

ちなみに、2021年8月31日にDocker社がDocker Desktopを有料化することを発表したようですね。個人開発なら無料で使えますが、面倒なことになりました。

RayのDocker ImageをPullする

DockerHubから公式のImageをローカルにPullします。

docker pull rayproject/ray

コンテナ内でjupyter notebookを実行する

まず、Docker Imageからコンテナを作成し、中に入ります。

docker run --shm-size=512M -p 8888:8888 -it  rayproject/ray

公式ページによると、shm-sizeには512M~2G程度の値を設定するようです。
また、jupyter notebookを使用する関係でポートを公開しています。
コンテナ上のポートとローカルのポートを接続するルールは、-p [ローカルのポート]:[コンテナのポート] です。
コンテナ内に入ったら、jupyter をインストール後、サーバを立てます。

pip install jupyter
jupyter notebook --ip=0.0.0.0 --allow-root

Docker上でjupyter notebookを実行する方法は以下を参考にしました。

ブラウザでnotebookにアクセス

ローカルPCのブラウザでコンテナで起動したnotebookにアクセスします。
ブラウザに下記URLを打ち込みます。

localhost:8888

するとJupyter Notebookの画面に遷移してPassword or token:と入力が求められます。

入力するためのtokenはコンテナ上でnotebookを起動したときに以下のようなURLが出るのでそこから取得します。

    Copy/paste this URL into your browser when you connect for the first time,
    to login with a token:
        http://5217807fea51:8888/?token=601c330c097e59cd7b69dcaa6ea336218583a492e4684bde&token=601c330c097e59cd7b69dcaa6ea336218583a492e4684bde

上の場合、601c330c097e59cd7b69dcaa6ea336218583a492e4684bdePassword or token:に入力すればいつものnotebookの画面に遷移します。

サンプルコードを動かし動作確認を行う

チュートリアルの解説に関しては以下のページが神です。

サンプルコードがエラーなく実行できれば成功です。

import ray
import time
# ray.init() のように明示的に指定しなかった場合自動的にリソース数が決定されます
ray.init(num_cpus=4)

# 時間計測をより正確にする都合上Rayの起動を少し待つ
time.sleep(1)

@ray.remote
def func(x):
    time.sleep(5)
    return x

begin_time = time.time()
res1, res2 = func.remote(1), func.remote(2)

print(ray.get(res1), ray.get(res2)) # 出力: 1 2

# ray.getはreturnをリストで受けとることもできる
print(ray.get([res1, res2])) # 出力: [1, 2]

end_time = time.time()
print(end_time - begin_time) # 5秒ぐらい

実行結果例

1 2
[1, 2]
5.051432132720947

終わりに

標準モジュールのmultiprocessingと比べるとコードが非常に簡単です。まだまだ発展途上のフレームワークですが、いずれ「マルチプロセスといえばRay」というようになっていくでしょう。

なお、コードを速くするという意味では、マルチプロセス化するのは最後の手段です。まずは既存のコードを整理し、充分にリファクタリングしたいところです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0