Julia を始める人へ向けた MyWorkflow.jl の紹介

# 本日は

- 数ヶ月ぶりにQiitaを更新します．
- Julia アドベントカレンダー２０２０の記事です．これは [jl.devもくもく会](https://jldev.connpass.com/event/193927/) の活動で作られました．

# 前置き

- 任意のプログラミング言語を触るにあたって最初の壁になるのは環境構築だと思います．多くの人は Python, R との連携するために PyCall.jl, PyPlot.jl, SymPy.jl, Pandas.jl, RCall.jl といった言語間の連携をするパッケージ及び Jupyter Notebook/Lab の上で Julia を動かすためのパッケージとして IJulia.jl を導入することが多いでしょう．Twitterで `#Julia言語`　というハッシュタグを見るとつまづいている人が多く見られます．とりあえず，サクッと試したいのにそういうところでつまづいて成功体験を得られずに挫折しまう人いないでしょうか？

# MyWorkflow.jl の紹介

- [MyWorkflow.jl](https://github.com/terasakisatoshi/MyWorkflow.jl) ではそのような作業を済ませた Julia 動作環境を提供しています．厳密に言えば binder という Jupyter Notebook を動かすサービスに環境を作るスクリプトと Julia のサンプルコードを集めたGitHubのリポジトリです．

# まずは動かしてみよう.

- [MyWorkflow.jl](https://github.com/terasakisatoshi/MyWorkflow.jl)の先にあるREADMEを見ると `launch binder` というアイコンが見えます．
 
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/terasakisatoshi/MyWorkflow.jl/v0.19.2) 

- それをクリックするだけで Jupyter Notebook の上で Julia が動く環境ができます．ブラウザを閲覧できる環境であれば，PCに限らずスマホ，タブレット端末でも実行できます．アイコンをクリックするとした図のような画面が出ますのでしばらくお待ちください．

- 動作環境は binder という Jupyter Notebook を動かすWebサービスを使いますので手元に Julia をインストールしなくても動作します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/576e9039-e183-499f-c9e9-f2073d4e58fc.png)

しばらく待つと次のような画面がでます．Pythonなどで Jupyter Notebookを使ったことがある人には馴染みのある画面だと思います．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/acf91d20-3ee0-12cb-5daf-516834f0aaac.png)

`example.jl` というのをクリック・タップしてみましょう．画面が移り変わり次の図のようになると思います．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/366568f7-1b62-23ca-36f2-9cb40f9ae1b7.png)

パソコンでみている方は Shift キーと Enter を同時に押すことでセル(`In []:` で始まっているプログラムの塊）を実行することができます．スマホユーザーの場合は画面上にある `Run` というボタンを押すことで実行できます．動かした後は次のような画面になります．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/aa5015ab-2536-1549-449d-8e6ea1e5619e.png)

やった！ `Hello, World` できましたね．ここでは `example.jl` というファイルを開きましたが，末尾が `.jl` で終わるファイルならば同様に実行できるはずです．たとえば，

- `pyplot.jl` は `PyPlot.jl` という Python の `matplotlib` を Julia から呼び出す例を
- `pyjulia.jl` は Python から Julia を呼び出す例

を提供しています．お時間がある時に触ってみてください．しばらく放置するとサーバーとの接続が切れます．また，改変したデータは残らないので，必要に応じてテキストをコピペして各自の手元に保存してください．

# 手元でも動かしてみたい．

上記の説明では binder という web サービスを使って Julia を走らせましたが，CPUリソースに一定の制限があります．手元のPCが充実しているのであればそちらで動作した方が良いかもしれません．

ひとまず https://github.com/terasakisatoshi/MyWorkflow.jl.git をクローンします. GitHub に慣れていればリポジトリをフォークするというのもありですね．

```console
$ git clone https://github.com/terasakisatoshi/MyWorkflow.jl.git
```

## Docker を使う場合

- いきなり Docker かよ・・・．と思われるかもですが，この業界は怠け者が多いのでちょうど良いのではないでしょうか（この感想を持つ人はわかっている人だと思うので）．Docker を使うと環境構築がローカル上に Julia をインストールしてパスを通して・・・というような作業も不要です．

```console
$ make build
```

することで Docker を使って環境を構築することができます．これは `Makefile` を見るとわかりますが

```console
$ rm -f Manifest.toml
$ docker build -t myworkflojl .
$ docker-compose build
$ docker-compose run --rm julia julia --project=/work -e 'using Pkg; Pkg.instantiate()'
```

とほぼ同じことをしています．このビルド作業はそれなりに時間がかかります．もっとサボりたい人は

```console
$ make pull
```

をすると GitHubActions をトリガーにして作られた Docker のイメージが降ってきます．(ただし，リポジトリの `master` の物が降ってきますので特定のコミットの状態を利用する場合は`make build`  を用いてDockerイメージを作ってください．)

#### Tip

- `binder` の環境は `MyWorkflow.jl/binder/Dockerfile` の Dockerfile を用いて構築される
- 手元の環境は `MyWorkflow.jl/Dockerfile` を用いて作られる

### コンテナを利用する

- REPL を使う

```console
$ docker-compose run --rm julia
Creating myworkflowjl_julia_run ... done
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.5.3 (2020-11-09)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> # ここで色々試す
```

- Jupyter Notebook を使う場合

```console
$ docker-compose up jupyter
```

この時

```
...
... 色々メッセージが出てくる
...
mylab      |     To access the notebook, open this file in a browser:
mylab      |         file:///root/.local/share/jupyter/runtime/nbserver-1-open.html
mylab      |     Or copy and paste one of these URLs:
mylab      |         http://19431004d7e8:8888/?token=xxxxxxxxxxxxxx
mylab      |      or http://127.0.0.1:8888/?token=xxxxxxxxxxxxx
```

というログが流れますので `http://127.0.0.1:8888/?token=xxxxxxxxxxxxx` をウェブブラウザURLの入力欄に貼り付けるとコンテナ内に作成されたカーネルにアクセスできます．

- Jupyter Lab を使う場合

```console
$ docker-compose up lab
```

のようにし上記の Jupyter Notebook の使う場合と同様の手順を踏んでください.

Julia ユーザーのためのノートブックである Pluto.jl を使う場合

```console
$ docker-compose up pluto
```

```
Creating mypluto ... done
Attaching to mypluto
...
...色々メッセージが出てくる
...
mypluto    | Go to http://0.0.0.0:9999/?secret=xxxxxx in your browser to start writing ~ have fun!
mypluto    |
mypluto    | Press Ctrl+C in this terminal to stop Pluto
mypluto    |
```

Jupyter と同様に `http://0.0.0.0:9999/?secret=xxxxxx` をウェブブラウザのURL入力欄に貼り付けてください．

他にも Atom/Juno とコンテナを連携する機能も作っていますが，詳細は README.md をご覧ください.

## Dockerを使いたくない人向け

- 諸事情で使えない，使いたくない人向けに (Dockerに依存しない）Julia 環境構築を書いておきます．

### Julia の環境構築（ダウンロードから）

- https://julialang.org/downloads に行きます．`Current stable release` と書いてあるテーブルから自分の環境に合わせた物をダウンロードします．32bit ?64bit ?どっち? と迷われた場合は場合はとりあえず `64bit` の方を選んでください.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/39080de4-5596-4782-c998-32a608eba41f.png)

- 補足すると現時点の `Long-term support (LTS) release` は `1.0.5` ですが ~~近々 `1.6` が次期の `LTS` となることになっています~~ (<-- これは候補かもっていうぐらいなのでまだ決まったわけではないです 2021/10月追記) またJuliaのパッケージ（いわゆるライブラリ）は 1.3 以降で出てきた機能を使うことが少なくないので 2021/10月 現在ではstable release の `1.6.x` を使うのが良いでしょう．軽微なバグフィックスされるごとに `x` の値が増えていきます(今は `x=3` です)
- 2021/10月現在は 1.7 は開発のステータス(DEV) になっています．もし 1.7 が安定版としてリリースされると 1.8 が開発のステータスになります．そして 1.6 はメンテナンスされなくなります．ですので，数ヶ月に一度の程度で定期的に Julia のホームページを見てリリース状態を確認するようにしてください．

### インストール

- [Platform Specific Instructions for Official Binaries](https://julialang.org/downloads/platform/) を見てください．Windowsユーザーの場合は `rundll32 sysdm.cpl,EditEnvironmentVariables` の存在を知ると幸せになるかもです．環境構築を設定するコントロールパネルのUIが一瞬で出てきます．
- そして Path を通してターミナルで `julia` と入力してREPLがひらくことを確認しましょう．

### MyWorkflow.jl の環境構築

ここでは MyWorkflow.jl を Julia のプロジェクトとしてみなし環境を構築することにします．今回紹介する MyWorkflow.jl だけでなく，自分でパッケージを開発したりするときにも役立つ tips が入っています．

```console
$ git clone https://github.com/terasakisatoshi/MyWorkflow.jl
$ cd MyWorkflow.jl
$ julia --project=@. -e 'ENV["PYTHON"]=Sys.which("python3"); ENV["JUPYTER"]=Sys.which("jupyter"); using Pkg; Pkg.instantiate(); Pkg.precompile()'
...
... しばらく待つ
...
```

この後は `jupyter notebook` で Jupyter Notebook を立ち上げます．これで MyWorkflow.jl に依存する Julia パッケージを導入することができます．

## 何をやっているか書いておく

Pythonでは， venv, poetry や Anaconda の conda activate など，プロジェクト毎に依存するライブラリを整理する機能がありますが，Julia 同様に特定のプロジェクトに対して必要なパッケージを導入する機能を持っています．Juliaがそのプロジェクトにおいてどのようなパッケージ，どのバージョンをインストールするのかは `Project.toml` という toml フォーマットのファイルの情報に従います．

### `--project=@.`

`--project=Project.tomlのパス` を指定することで `Project.toml` に対応する環境に入る準備ができます．指定しなければデフォルトの環境（npm などで言えば global なもの）としてみなされます．`--project` を指定せずに起動しても後から `using Pkg; Pkg.activate(".")` として切り替えることができます．今回の例では作業ディレクトリに `Project.toml` があるので `--project=.` でも良いです．`--project=@.` にすると作業ディレクトリに `Project.toml` がない場合は 親のディレクトリを遡り `Project.toml` を探しにいきます．

参考: https://stackoverflow.com/questions/53613663/what-is-in-julia-project-command-line-option

ちなみに `export JULIA_PROJECT=@.` のように環境変数を定義しておくと `--project=@.` の入力が省けます．

### `-e`

`-e　'文字列'` で文字列を Julia の式として評価します．`-E` もありますが違いは最後に評価した指揮の結果を出力するかしないかの違いです. たとえば `julia -E '1+1'` を試す．

```console
 -e, --eval <expr>         Evaluate <expr>
 -E, --print <expr>        Evaluate <expr> and display the result
```

Windows 環境だと -e オプションが使えない場合があるようなのでパワーシェルをつかったり REPL を開いて実行するという方法で回避することもできます．

### `ENV["xxx"]=...`

システムの環境変数を定義します．辞書データのように使うことができます．

`ENV["PYTHON"]=Sys.which("python3")` をすることで `PYTHON` という環境変数を `python3` の実行形式が住んでいるフルパスを示してくれます．シェルでの `which python3` のようなものです．これは PyCall.jl が Julia がよぶ Python どれなのかを明示的に指示するために使われます．もしローカルの環境に Python がない場合は `ENV["PYTHON"]` は空の文字列となります．その場合，Julia が `~/.julia/conda` 以下に Miniconda を導入しこれと連携するようにできています．もしも，連携する Python を変更したい場合は

```julia
julia> ENV["PYTHON"]="新しいPythonのフルパス"
julia> using Pkg; Pkg.build("PyCall") # buildするのが大事
```

としてください．ここら辺の話は PyCall.jl のREADMEに全て書いてあります．

Windows の場合は `path\\to\\something` のようにパスの区切りを `\\` にする必要があります．

### `Pkg.instantiate()`

`Project.toml` の情報をパースして，依存パッケージの依存関係などを詳細に記述された `Manifest.toml` を作り依存関係の解決を図ります．ローカルの環境にパッケージがなかった場合は（そのパッケージが公式パッケージであれば）ダウンロードが始まります．一度 `instantiate` をした後は `Manifest.toml` の情報を読みにいきます．もしもおかしな挙動があった場合は一度 `Manifest.toml` 手動で消して改めて `using Pkg; Pkg.instantiate()` すると良いかもしれません．

### `Pkg.precompile()`

Julia は JIT コンパイル方式で動作します．そのため `using ...` などで Julia パッケージをロードするとその度にコンパイルが走ります．そのオーバーヘッドを抑えるために Julia がコンパイル結果の一部をキャッシュするようになっています．

参考 https://docs.julialang.org/en/v1/manual/modules/#Module-initialization-and-precompilation

以上で ローカルでの環境構築の方法について述べました．色々手間があって大変ですね？ Docker の方法を使うとコマンド一発でできますよ．（お？Dockerを使う気持ちになれましたか？）

# まとめ

- `MyWorkflow.jl` に入門する機会を用いて とりあえず既存の環境を用いて Julia を試してみたい人から，Docker を使って環境構築する方法，ローカルに環境を構築する方法まで幅広いユーザーに対して Julia の利用方法，環境構築の方法を提示しました．一年前以上からどうしたら Julia の環境をスムーズに構築できるか，気軽に使ってもらえるように考えた結果 Docker を用いた現在のような方法に至りました．自分の作業ワークフローは人それぞれなので各々の事情に合わせて適切はスタイルを身につけられるといいのではと思います．この記事がその助けになれば幸いです．