2014年6月27日金曜日

Rake Part 7: MultiTask 翻訳

Avdi GrimmLearn Advanced Rake in 7 Episodesを、本人の許可を得て翻訳します。以下、Part 7の翻訳です。



もしあなたがRubyプログラマーなら、Rake(故Jim Weirichによって作られたビルドユーティリティー)をほぼ確実に使ったことがあるだろう。しかし、Rakeがいかにパワフルでフレキシブルなツールになりうるかということは理解していないかもしれない。実際、私は、Quarto(自作のe-book製作ツールチェーン)の土台としてRakeを使うと決めるまで理解していなかった。

この投稿はRakeについてのシリーズの一部で、基本から始めて高度な使用法に進む。2013年の8月から9月に購読者に向け公開されたRubyTapasビデオのシリーズのひとつをもとにしている。各投稿はビデオから始まり、ビデオより文字を好む人のためにスクリプトが続く。

これらのエピソードを無料で公開するにあたり、より多くの人々が、この広く行き渡っているが過小評価されているツールのすべての能力を知り愛するようになることを願う。もしあなたがRakeに感謝するのであれば、Jimへの追悼としてthe Weirich Fundへの寄付を検討して欲しい。






このRakeの連続シリーズは終わりに向かって進んでいます。前回までのいくつかのビデオを通して、私がそうであったように、Rakeのパワーのすごさが分かってくるようになってきたと思います。しかしおそらく、素のRubyやシェルスクリプトを利用することに対するRakeを使用することの利点については、まだ懐疑的でしょう。もしそうであれば、今日がその印象を変える日だと思います。Rakeが、ただ同然で与えてくれる驚くほどパワフルな能力をお見せしたいと思います。


電子書籍を作るとします。pygmentizeユーティリティを使ってシンタックスハイライトされたHTMLに変換するために準備した、テキストを取り除いた数百のコード目録が含まれたディレクトリがあります。


これは、このタスクを行う小さなRakefileです。目録のリスト、“highlights”のリスト(これは、HTMLの最終成果物です)、そしてhighlightと呼ばれるすべてを生成するタスクを定義しています。最後に、pygmentizeを実行して目録ファイルから.htmlファイルを生成するルールを定義しています。また、highlightタスクに依存するデフォルトタスクも定義しています。

 
require "rake/clean"

task :default => :highlight

LISTINGS   = FileList["listings/*"]
HIGHLIGHTS = LISTINGS.ext(".html")
CLEAN.include(HIGHLIGHTS)

task :highlight => HIGHLIGHTS

rule ".html" => ->(f){ FileList[f.ext(".*")].first } do |t|
  sh "pygmentize -o #{t.name} #{t.source}"
end

pygmentizeタスクを使ったソースコードのハイライトは時間が掛かります。たくさんのソースファイルがある場合、多くの時間が掛かります。もしrakeをtimeコマンドの下で実行すると、そのプロセスに48秒かかることがわかります。

 
$ time rake
...
pygmentize -o listings/fd673484d50a66ea67fcd20e0c55f038a729e4d7.html listings/fd673484d50a66ea67fcd20e0c55f038a729e4d7.rb
pygmentize -o listings/ff6e24090e794c4db847b10ca993c872ca804101.html listings/ff6e24090e794c4db847b10ca993c872ca804101.rb

real    0m47.961s
user    0m41.912s
sys     0m4.852s

今のところ、これらのハイライトされたファイルは1つずつビルドされています。しかし、今は2013年で、2つの物理コアが載ったコンピュータを私は持っていて、ハイパースレッディングにより4つの仮想コアがあることになります。どうして2つ以上のファイルを同時にビルドできないのでしょうか?


それは実際に可能です。我々がすべきことは、rakefileの1行をtaskからmultitaskに変えるだけです。

 
multitask :highlight => HIGHLIGHTS

これは、:highlightタスクの事前条件を並行に処理できることをRakeに告げます。並列化したいタスクそのものではなく、並列化したいタスクに依存するタスクにこの変更を行っている点に注意してください。


Rakeをもう一度実行します。Rakeが数百のRakeサブプロセスを同時に並列で起動し、それらが同じSTDOUTに出力を行うため、かなりみだれた出力になります。


25秒を少し超えてたところで、ビルドが完了します。この1つの変更により、処理時間をおよそ半分にカットしました!

 
$ time rake
...

real    0m25.701s
user    1m13.492s
sys     0m8.272s

何個のタスクを並列で実行するかを微調整したい場合は、同時に実行できるプロセスの最大数をRakeに告げるために-jオプションを使用できます。各仮想コアにたいして1つ、すなわち4を指定してみます。


興味深いことに、今度はほんの少し時間がかかります。どうしてかはよく分かりません。

 
$ time rake -j 4

real    0m26.752s
user    1m10.300s
sys     0m7.208s

先程述べたように、並列に実行するにはコードに1行変更を加えればよいといいましたが、それは少し嘘です。本当は、コードにまったく変更を加えずにタスクを並列に実行するよう、Rakeに命令することができます。multitasktaskに戻して、-mオプションつきでrakeを実行します。これは、すべてのタスクをmultitaskとして扱うよう、Rakeに告げます。


再び、歪んだ出力が確認できます。そして一段落すると、合計時間が25秒超であることが再び確認できます。

 
$ time rake -m

real    0m25.606s
user    1m13.060s
sys     0m7.856s

Rakeの並列化は賢くもあります。もし他のタスクが:highlightタスクに依存していれば、次のフェーズに進む前に、すべてのpygmentizeプロセスが完了するまで待機します。


では、Rakeを使ったビルドの自動化から得たものは何でしょう?タスクを達成するための複雑な依存関係やルールを宣言するための簡単な方法だけではありません。ファイル操作のための便利なメソッドのセットだけではありません。扱いやすいコマンドラインのフロントエンドだけではありません。それらすべてに加え、繰り返し行われるタスクの並列化がただで手に入ります。そして、それが私の言うハッピーハッキングです!




Rakeについてのエピソード・文章を楽しんでいただけたことを願っている。もし今日、何かしら学んだのであれば、Jimの遺産である教育プログラムの継続を支援するため、the Weirich Fundに寄付することにより「恩送りすること(訳注:原文は"paying it forward")」を検討して欲しい。もし、今回のようなビデオをもっと見たければ、RubyTapasをじっくり見てほしい。シリーズが完結するまで、ほぼ毎日公開していくつもりなので、ほどなくご確認を!

P.S. 特に興味深い方法でRakeを使っているなら、連絡して欲しい

関連する投稿:
  1. Rake Part 1: Files and Rules
  2. Rake Part 6: Clean and Clobber
  3. Rake Part 3: Rules

0 件のコメント:

コメントを投稿