Hatena::Groupangelos

Angelos in Action RSSフィード

Fork me on GitHub
 | 

2009-07-18

Coroのthreadがどうもわからない件

11:21 | Coroのthreadがどうもわからない件 - Angelos in Action を含むブックマーク はてなブックマーク - Coroのthreadがどうもわからない件 - Angelos in Action Coroのthreadがどうもわからない件 - Angelos in Action のブックマークコメント

#!/usr/bin/env perl
use strict;
use warnings;
use Coro;
use Perl6::Say;

my @coros = (); 

push @coros, async {
    while (1) {
        say 'Yasako';
    }   
};

push @coros, async {
    while (1) {
        say 'Densuke';
    }   
};

$_->join for @coros;

期待する動作としては、YasakoとDensukeがまじって表示されるイメージなんだけど、Yasakoのほうしか表示されない。二つのスレッドつくって実行するというシンプルなコードなんだけど、何か勘違いしてるのかなぁ。いったい、Densukeはどこにいってしまったやら...

javaのthreadとは違うもののようだなぁというのはわかりました。

以下の場合は、Yasako, Daisukeという順番で表示されるようになる。

#!/usr/bin/env perl
use strict;
use warnings;
use Coro;
use Coro::Select;

my @coros = (); 

push @coros, async {
    while (1) {
        print "Yasako\n";
        select undef, undef, undef, 1;
    }   
};

push @coros, async {
    while (1) {
        print "Densuke\n";
        select undef, undef, undef, 1;
    }   
};

$_->join for @coros;

ふむぅ。少しわかってきたかも。非同期にするってところは、Coro::Selectselectメソッドでの置き換え部分が肝なのかな。

# Coroのコードそのものは、まぁ読めるレベルだなぁ。ただ、AnyEventのほうはむずい!

# 追記: miyagawaさんに教えてもらいました。miyagawa++

Coroは基本cooperative threadがということで、自分で次のスレッドに処理を移すために、明示的にユーザーが示す必要があると。そのときに、使うのがcedeになると。

以下のようにすると、Yasako, Densukeと順番に表示されるようになりました。

#!/usr/bin/env perl
use strict;
use warnings;
use Coro;

my @coros = (); 

push @coros, async {
    while (1) {
        print "Yasako\n";
        cede;
    }
};

push @coros, async {
    while (1) {
        print "Densuke\n";
        cede;
    }   
};

$_->join for @coros;

# 一瞬わかった気になったものの、co-operative threadだと考えると、どういうときにCoro::RWLockとかCoro::Semaphoreとかが必要になるのかがいまいちよくわからず。pre-emptiveなものだと、明らかに必要なのはわかるのだけれど。Coroについては、全然理解しきれてなす...

Coro::Semaphoreが必要なのは、Coroの同時実行オブジェクト数を制限したいときにシンプルにコードがかけるようにするための仕組みなのだなぁと。

http://subtech.g.hatena.ne.jp/mala/20090710/1247193428

あとは、Coro::RWLockが必要な理由がわかれば、Coro自身の理解は結構進みそう。write中にreadされてしまうケースがあるから、Coro::RWLockが必要なはずなのだけれど、co-operativeなスレッドでユーザーが明示的にスレッドを切り替える場合、なんでwrite中にreadされてしまうケースがあるのだろうというのがわからないなぁと。明示的にスレッドを切り替える場合、一つ一つのスレッドは、同時に一つしか動かないように思えるので、なんでロックが必要なんだろうというのがいまいちわからないなぁと。

# RWLockが必要なケース

下記のようにする場合に、書き込むところが非同期なI/Oの場合には、RWLockが必要になるケースがありうると。

thread1: 複数行書き込み(非同期) -> スレッドきりかえ

thread2: 複数行書き込み(非同期) -> スレッドきりかえ

上記の非同期I/Oには、Coro::HandleやAIOがありうると。

要するに、co-operativeなスレッドでも、そのスレッド内で非同期なI/Oを実行した後で別のスレッドに処理移動させれば、他のスレッドではそのI/Oが終わるまで待つ必要もあるわけで、その場合にあhRWLock必要なケースもあると。

http://www.google.co.jp/codesearch/p?hl=ja&sa=N&cd=2&ct=rc#RXON3DE8hQw/lib/VCS/Git/Torrent/Peer/Async/Connection.pm&q=recv_lock&exact_package=git://github.com/Br3nda/vcs-git-torrent.git

miyagawa++, tokuhirom++

# この2日間で一気に理解がすすみました! あとは、このgdgdなエントリを綺麗にまとめなおすかどうか...

 |