近況 2021-09-30

今月の活動 (ミローネ言語)

ミローネ言語

https://github.com/vain0x/milone-lang

ML: 並列化

パスの並列化を試している。

目的の1つはコンパイルの高速化。プロジェクト単位でコンパイルを並列化してもいいが、依存関係のグラフにおいて末端のプロジェクトだとモジュール単位での並列化にも一定の効果があるはず。

もう1つの目的はドッグフーディングのようなもの。イミュータブルなデータは並列化と相性がいいという話はよくみるが、実際にやったことはなかったので、やってみている。

Cで並列処理をするのはpthreadを使えばできそうだけど、よく分かっていないので、まず.NET版で試す。

はじめにソースファイルを読み込んで構文解析する部分を並列化してみた。 ソースファイルを読む→構文解析する→openをみて依存しているソースファイルを読みに行く (再帰) という流れ。

スレッドの生成やチャネルの送信などで並行処理を記述すると泥臭くなるので、こういうプリミティブを考えた。

let mpscConcurrent
  (consumer: 'S -> 'A -> 'S * 'T list)
  (producer: 'S -> 'T -> Future<'A>)
  (initialState: 'S)
  (initialCommands: 'T list)
  : 'S = ...

(mpscConcurrentのシグネチャ)

  • consumerはステートマシンを更新するための状態遷移のようなもの。これは単一のスレッドで動く
  • コマンドは並列化すべき処理を表す
    • 最初に与えられたコマンドをワーカースレッドで並列に処理する
    • コマンドの処理の結果として、状態の変更 (アクション) と、追加のコマンドを生成する
    • アクションがステートマシンを更新した後、追加のコマンドは再びワーカースレッドで処理される
  • 処理すべきコマンドがなくなったら終了、最後の状態を返す

これにより状態更新が一定の条件を満たしていればコマンドが並列で処理されても順番に処理されても結果が同じになる。(コマンドの処理が副作用を起こしているので結局純粋ではないけど)

同期的実行と比べて10%ぐらい速くなった

同様に名前解決も並列化を試した。モジュールが相互再帰的に依存しないことを利用して、モジュールをレイヤーに分けて (下のレイヤーにだけ依存する)、レイヤーごとに名前解決を行うことで並列化できた。

ML: Windows版

まだ途中だけど、Windows版でもbuild/runサブコマンドが動くようにしている。

  • 以前はmiloneコマンドのソースすべてがC言語の標準ライブラリの範囲で書かれていたので、プロジェクトファイルだけ用意すればWindowsでもビルドできた
  • build/runサブコマンドを実装するとき、ディレクトリの生成やサブプロセスの生成などの、C言語の標準ライブラリの範囲ではできないことをするために、Unixのライブラリを使うようになった
  • そのためWindowsではmiloneコマンドをビルドできなくなっていた
  • OSの違いを吸収するライブラリを使おうかと思って探した
    • libuv
      • イベントループ型でIOとかができる
    • subprocess.h
      • これ自体はすごくいいけど、似たようなもののファイルシステム版がほしかった
    • ランタイムをRustで書いてリンクすることも考えていたが、ミローネ言語のコードを共有ライブラリか何かにコンパイルする仕組みがいる
  • 検討してばかりで進んでない感じがしたので、とりあえずAPI直叩きで実装することにしてる
  • プロジェクトファイルを生成してMSBuildを呼べばビルドできるというのを実際にやってみて何らかの安心感を得られた

その他

関連記事