https://www.cnblogs.com/yeungchie/
记录一些常用的 模块 / 方法 。
threadsuse 5.010;use threads;sub func { my $id = shift; sleep 1; print "This is thread - $id\n";}newsub start { my $id = shift; my $t = new threads \&func, $id; return $t;}createsub start { my $id = shift; my $t = new threads \&func, $id; return $t;}asyncsub start { my $id = shift; my $t = async { &func( $id ) }; return $t;}join&start( 'join' )->join;say 'Done';This is thread - join
Done
# 父线程被子线程阻塞,成功收尸。
detach&start( 'detach' )->detach;say 'Done';Done
# 由于非阻塞,父线程已经退出,子线程变成孤儿线程,无法收尸。
threads::shareduse threads::shared;有几种不同的写法
:sharedmy $scalar :shared;my @array :shared;my %hash :shared;:sharedmy ( $scalar, @array, %hash ) :shared;share()my ( $scalar, @array, %hash );share $scalar;share @array;share %hash;shared_clone向共享的变量中加入新的元素时,需要注意的地方。
my @newArray = qw( YEUNG CHIE 1 2 3 );my $clone = shared_clone [@newArray];push @array, $clone;$hash{ keyName } = $clone;lock多个线程同时编辑一个共享变量时,需要注意的地方。
经典的取钱问题:
1 - 输出额度$amount= 500
2 - func() 函数模拟取钱,每次取 300
3 - 当$amount< 300 时,则无法取钱
my $amount :shared = 500;sub func { unless ( $amount < 300 ) { sleep 1; # 睡眠一秒模拟延迟 $amount -= 300; }}# 这里两个线程模拟,两次取钱同时进行my $t1 = new threads \&func;my $t2 = new threads \&func;$t1->join;$t2->join;say $amount;-100
# 结果被取了两次,剩余额度为 -100
调整一下子函数 func(), 加个锁。
...sub func { lock $amount; unless ( $amount < 300 ) { sleep 1; $amount -= 300; }}...200
# 结果正确
Thread::Queueuse Thread::Queue;my $queue = new Thread::Queue;enqueuemy $var = 'YEUNG';$queue->enqueue( $var );$queue->enqueue( qw( CHIE 1 2 3 ) );dequeuesay $queue->dequeue;YEUNG
say for $queue->dequeue( 3 );CHIE
1
2
dequeue_nbmy $queue = new Thread::Queue qw( YEUNG CHIE );say while $_ = $queue->dequeue;YEUNG
CHIE
# 程序会卡在这里,等待队列中新的项目加入
my $queue = new Thread::Queue qw( YEUNG CHIE );say while $_ = $queue->dequeue_nb;YEUNG
CHIE
pendingpending 方法可以返回未出队的项目数量。
my $queue = new Thread::Queue qw( YEUNG CHIE );say $queue->dequeue;say $queue->pending;say $queue->dequeue;say $queue->pending;YEUNG
1
CHIE
0
peek只是看看但是不出队。
my $queue = new Thread::Queue qw( YEUNG CHIE );say $queue->peek;say $queue->pending;say $queue->peek( 2 );say $queue->pending;YEUNG
2
CHIE
2
end除了上面用 dequeue_nb 非阻塞出队,之外还可以用 end 方法来
my $queue = new Thread::Queue qw( YEUNG CHIE );$queue->end;say while $_ = $queue->dequeue;# 这样虽然没有用
dequeue_nb方法,程序也不会卡住了。
不过这个方法需要模块版本 >= 3.01,一般系统自带 Perl 是不支持的,但是我们也可以自己来实现这个效果:
共享变量
共享一个全局变量标记入队结束。
my $endFlag :shared;生产者线程
当入队结束时,$endFlag 赋值为真。
$endFlag = 1;消费者线程
循环操作非阻塞出队。
while ( 1 ) { my $item = $queue->dequeue_nb; if ( defined $item ) { say $item; } else { # 当出队失败且入队结束时,退出循环 last if $endFlag; }}Thread::Semaphoreuse Thread::Semaphore;Thread::Pooluse Thread::Pool;