Archive for July, 2010

Ruby GIL test

July 29th, 2010  |  Published in CS

ruby 1.9 で、スレッドはネイティブスレッドを使うようになったけど、 GIL があるためにけっきょく実行は serialize されてしまう、マルチコアを活かせないよというのは、まぁ聞いて知ってたんだけど、ほんとにそうなのか試した。

ruby 1.9.2dev on Core 2 Duo な Mac OS X 10.6.2 で動かして ActivityMonitor.app で眺めていたところ、たしかに CPU 使用率は 99% くらい。1つのコアでがんばってなさる。

ちなみに GIL がないという MacRuby 0.6 リリース版で試したところ、以下のような assertion にひっかかっていた。 GCD かな? ソース追ってみないと。

Assertion failed: ((b->flags & flags) == flags), function rb_vm_prepare_block, file dispatcher.cpp, line 1773.

さしあたり、 ticket きっておいた


追記 2010-07-30 09:24 JST

最新版では治ってるよということで ticket が瞬殺されていた。じっさい latest nightly build で試すと、ちゃんと 2 コアを使って計算が行われいるのを確認できた。

M=10000 で、 time $RUBY_VM gil_test.rb として計測した結果:

  • ruby 1.8.7 : 100%, 69.3s
  • ruby 1.9.2dev : 100%, 22.6s
  • MacRuby 0.7 : 191%, 6.85s
  • JRuby 1.5.1 : 178%, 21.9s

MacRuby が圧倒的な速度である。まあほんとうは VM の起動時間とかを含めないように、 time じゃなくて benchmark.rb とか使うべきなのかもだけれど、ユーザの体感時間という意味で。

Tags: ,

PHP, Concurrency

July 29th, 2010  |  Published in CS

PHP もずぶの素人なのでつっこみ歓迎です。

PHP には、スレッドがない。 fork/exec などのプロセス操作 API を使ってプロセスを使い、プログラムのうち並行実行したいところを別プロセスとして動かすそうな。

そもそも、 PHP で並列処理をしたいことってあるのかなぁという。どこかあちこちにあるサーバからデータをひっぱってきて、元リクエストのためのページをひとつつくる、というシチュエーションで、あちこちのサーバごとにリクエストを投げるところを並行実行したい、というところくらいだろうか今のところ。未来の PHP が、受け取ったパラメータをもとにレイトレーシングなんかしてみて、その結果画像をクライアントに返す、とかいうストーリーがあると、 PHP でももう少しかんたんに並行処理を書きたいよね、とかじゃぁ新しい言語 (方言) をつくるぜ! みたいな流れができてくるのかもしれないな。

まとめてしまうと、 PHP のスレッドサポートは特になく、プロセス単位で create /fork などしろと。うむむ… 重そうである。まだあんまし、進んでいないのかなぁというのと、実際のアプリで並列処理するものがまだ少ないんだろうかなぁというのと、 PHP のユーザ層がライトなものだからかなぁというのと。


関連エントリ:

  • Perl, Concurrency

元ネタ:

let GCD deadlock

July 28th, 2010  |  Published in CS

夏だし、 Grand Central Dispatch (GCD) をデッドロックさせてみたい。

さらっとぐぐって見つけた、デッドロックさせるコードはこんなかんじ:

  void deadlock_1()
  {
     dispatch_queue_t q = dispatch_queue_create("org.deadbeaf.gcd3", NULL);
     dispatch_sync(q, ^{
        printf("in 1\n");
        dispatch_sync(q, ^{
           printf("in 2\n");
        });
     });
  }

で、まぁたしかに処理がすすまなくなる。

でもこのコードからはなんだか、デッドロックというか自分を追い越せないだけな感じを受ける。ひとつのキューがあって、そこにつっこまれた人が、自分が終わる前に他のものをつっこんでいて、無限に待つという。

デッドロックというのは、2つ以上の共有資源があるときに、かたっぽ (A) を自分 (α) のものにしていながら、もうかたっぽのもの (B) をとろうとして、でも B はだれか (β) さんがロックしていて、で β さんは A がほしくて、というすくみの状況を言うんじゃなかったっけか。

というのを踏まえて、以下のように書いてみた。共有資源は 2 つ、 GCD の serial queue は、リソースを占有したいときに使うはず なので、 queue もそれぞれ用に 2 つ。

  void deadlock_2()
  {
     __block int shared_resource_1 = 0;
     __block int shared_resource_2 = 0;

     dispatch_queue_t q1 = dispatch_queue_create("org.deadbeaf.gcd1", NULL);
     dispatch_queue_t q2 = dispatch_queue_create("org.deadbeaf.gcd2", NULL);

     dispatch_group_t group = dispatch_group_create();
     dispatch_queue_t the_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

     dispatch_group_async(group, the_q, ^{
        dispatch_sync(q1, ^{
           printf("in q1\n");
           dispatch_sync(q2, ^{
              printf("hello from q1->q2\n");
              shared_resource_2 = 3;
           });
           shared_resource_1 = 5;
        });

     });

     dispatch_group_async(group, the_q, ^{
        dispatch_sync(q2, ^{
           printf("in q2\n");
           dispatch_sync(q1, ^{
              printf("hello from q2->q1\n");
           shared_resource_1 = 11;
           });
           shared_resource_2 = 7;
        });
     });

     dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
     dispatch_release(group);
     dispatch_release(q1);
     dispatch_release(q2);
  }

これだと、うまくいくときは


%  ./gcd_deadlock
in q1
hello from q1->q2
in q2
hello from q2->q1

となるんだけど、タイミングによっては


./gcd_deadlock
in q1
in q2
....

と無限に待つ。デッドロックが起きているのだ。


まとめると、 GCD でもデッドロックはわりと容易に起こりうるなぁと。で、それがかんたんに検出できるんだったらいいんだけど、そこは pthread mutex における検出のむずかしさとあまり変わらないんじゃないかなぁというところ。

Tags: ,

Perl, Concurrency

July 28th, 2010  |  Published in CS

Perl をつかった並行プログラミングをしらべていた。 Perl はずぶの素人なのでつっこみ希望です。

歴史

  • 5.005-5.6 までは thread パッケージをつかっていた。 green | native ?
  • 5.6 から ithread (interpreter thread) が入り、 thread ごとに VM が割り当てられるように。 native thread で、共有変数は明示的に shared とつけないといけない。 default で shared nothing.
  • 6.0 から STM が入るらしい。 atomic 構文。他に、 async block という構文ができて、どこかのスレッドで非同期実行させることができる (これは 5.10 でも use Thread qw(async) とすれば使えるな..)。 hyper, cross, reduction operator はデータ並列として扱えるようになっていて、コンパイラが並列実行するコードを出力できる
  • 最近の流行りは、サーバサイドでたくさんのリクエストを高速にさばくための非同期 I/O で、イベントを処理する POE, AnyEvent, Coro といったライブラリ/フレームワークがある

5.005-5.6 ではスレッドが並行処理の道具としてあった。5.6 で入った ithread は shared nothing なのがグー。 6.0 からは野心的な構文ががが。ライブラリ方面では、非同期 I/O まわりがホット、といったところでしょうか。

印象

ithread の multi VM のつくりは、 Ruby でいう GIL, Python でいう GVL がないそうでスケールしそう。 VM をまたいだやりとりは shared な変数を使うんではなくてメッセージパッシングでやるのがいいんじゃないかなぁとか。アクター、アクター。

情報元

Tags: , perl