perl多线程使用
原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun
<<=========================threads===========================>>
#!/usr/bin/perluse threads ('yield', 'stack_size' => 64*4096, 'exit' => 'threads_only', 'stringify');sub start_thread { my @args = @_; print('Thread started: ', join(' ', @args), "\n");}##创建线程的方法# my $thr = threads->create('func_name', ...);# my $thr = threads->create(sub { ... }, ...);# my $thr = threads->create(\&func, ...);# The "->new()" method is an alias for "->create()".my $thr = threads->create('start_thread', 'argument1', 'argument2'); #通过create创建线程。返回线程实例$thr->join(); #等待线程结束threads->create(sub { print("I am a thread\n"); })->join(); #创建一个线程,没有返回值。那这个线程实例如何访问呢?my $thr2 = async { foreach (@ARGS) { print"$_\n"; } }; #通过async使用匿名子例程创建线程$thr2->join();if (my $err = $thr2->error()) { warn("Thread error: $err\n");}# 在隐式的列表环境中调用threadmy $thr3 = threads->create(sub { return (qw/a b c/); });# 在显式的列表环境中调用threadmy $thr4 = threads->create({'context' => 'list'}, sub { return (qw/a b c/); });# 由于创建线程时使用的子例程返回的是列表,所以这里的join函数返回的也是列表my @results = $thr3->join();print "@results\n";# 把线程从主线程中分离出来# $thr->detach(); ##报错:Cannot detach a joined thread,因为$thr已经调用过join()$thr4->detach(); ##$tid = $thr4->tid();print "线程4ID:$tid\n";# Get a thread's object$thr6 = threads->self();$thr7 = threads->object($tid);# Get a thread's ID$tid = threads->tid();$tid = "$thr7"; #根据线程实例获得线程ID# 给其他线程一个运行的机会threads->yield();yield();# 返回未分离的线程列表my @threads = threads->list();my $thread_count = threads->list();my @running = threads->list(threads::running);my @joinable = threads->list(threads::joinable);# 判断两个线程是相同if ($thr4 == $thr2) { print "thread4 equals to thread2.\n";}# 管理线程栈大小$stack_size = threads->get_stack_size();$old_size = threads->set_stack_size(32*4096);# Create a thread with a specific context and stack sizemy $thr5 = threads->create({ 'context' => 'list', 'stack_size' => 32*4096, 'exit' => 'thread_only' }, \&start_thread);# Get thread's contextmy $wantarray = $thr->wantarray();print $wantarray,"\n";# Check thread's stateif ($thr5->is_running()) { sleep(1);}if ($thr5->is_joinable()) { $thr5->join();}# Send a signal to a thread$thr5->kill('SIGUSR1');# Exit a threadthreads->exit(); |
<<=========================Thread========================>>
$thread = Thread->new(\&start_sub)
$thread = Thread->new(\&start_sub,@args)
start_sub指定线程要执行的子例程,args是传给子例程的参数。
lock VARIABLE
给变量加锁,直到锁超出范围。给变量加锁只影响到lock函数的调用--即一个线程lock var1后,另一个线程再调用lovk var1时线程就会阻塞,但lock VARIABLE并不影响正常的对变量的访问。
如果锁往的是一个容器(如哈希或数组),那么其中的每一个元素并没有全部被锁住。比如一个线程中调用lock @arr,在另一个线程中调用lock $arr[3]时并不会阻塞。
async BLOCK;
async函数创建并返回一个线程实例,该线程要执行的代码全在BLOCK中,这里BLOCK是个匿名子例程,所以其后一定加分号。
Thread->self
返回调用Thread->self函数的线程实例。
Thread->list
返回non-joined和non-detached线程实例。
cond_waitLOCKED_VARIALBLE
cond_signal LOCKED_VARIALBLE
cond_broadcast LOCKED_VARIALBLE
上面3个函数主要用于线程问同步,都以一个已加锁的变量作为输入参数。当一个线程调用cond_wait后阻塞自己;当一个线程发出cond_broadcast后所有阻塞的线程得救;当一个线程发出cond_signal后只有一个阻塞的线程得救,至于是哪一个由系统内部决定。当然只有LOCKED_VARIALBLE参数相同时才为一组,大家才可以在一起玩同步。
yield
把CPU控制权交给另外一个线程,至于是哪个线程依赖于当时的运行环境。
join
等待一个线程结束并返回该线程结束时的返回值。
detach
分离的线程不允许被join。
equal
判断两个线程是否相同。
tid
返回线程的tid。tid是递增的,main线程的tid为0。
done
判断线程是否已经结束。
下面这3个函数在5005threads中还可以用,但是在ithreads中已经不可用了。
lock(\&sub) eval flags
<<============================threads::shared============================>>
默认下数据都是线程私有的,新创建的线程获得已有变量的一份私有拷贝。threads::shared用于在线程之间共享数据结构,可共享的数据类型只有6种,标量数据、数组、散列、以及它们的引用。
声明共享变量:
my ($scalar, @array, %hash);
share($scalar);
share(@array);
share(%hash);
share函数返回共享的值,这通常是一个引用。
也可以在编译时标记变量为共享变量:
my ($var, %hash, @array) :shared;
my ($var, %hash, @array) :shared; my $bork; # Storing scalars $var = 1; $hash{'foo'} = 'bar'; $array[0] = 1.5; # Storing shared refs $var = \%hash; $hash{'ary'} = \@array; $array[1] = \$var; # 不能把非共享变量的引赋给一个共享变量,下面这3句是错误的 # $var = \$bork; # ref of non-shared variable # $hash{'bork'} = []; # non-shared array ref # push(@array, { 'x' => 1 }); # non-shared hash ref |
shared_clone REF
my $obj = {'foo' => [qw/foo bar baz/]};
bless($obj, 'Foo');
my cpy=sharedclone(obj);
# Object status (i.e., the class an object is blessed into) is also cloned.
print(ref($cpy), "\n"); # Outputs 'Foo'
对于克隆空的数组或散列,下面用法是等价的:
var = &share([]); # Same asvar = shared_clone([]);
var = &share({}); # Same asvar = shared_clone({});
is_shared VARIABLE
判断变量是否为共享变量,如果是则返回变量的内部ID(类似于refaddr函数),如果不是返回undef。
如果is_shared参数是数组或散列,它并不检查容器中的元素是否为共享变量。如下
my %hash :shared; if (is_shared(%hash)) { print("\%hash is shared\n"); } $hash{'elem'} = 1; if (is_shared($hash{'elem'})) { ##返回undef print("\$hash{'elem'} is in a shared hash\n"); } |
lock VARIABLE
不能对容器内部的变量进行加锁:
my %hash :shared;
$hash{'foo'} = 'bar';
#lock($hash{'foo'}); # Error
lock(%hash); # Works
cond_wait VARIABLE
cond_signal VARIABLE
cond_broadcast VARIABLE
这3个函数就不说了,跟threads里的一样。
cond_wait CONDVAR, LOCKVAR
当有其他线程signal第一个参数变量CONDVAR时,第二个参数变量LOCKVAR被解锁。
cond_timedwait VARIABLE, ABS_TIMEOUT
cond_timedwait CONDVAR, ABS_TIMEOUT, LOCKVAR
如果signal未到达,而timeout了,同样会把变量解锁。
# 创建一个共享的'Foo' object my $foo :shared = shared_clone({}); bless($foo, 'Foo'); # 创建一个共享的 'Bar' object my $bar :shared = shared_clone({}); bless($bar, 'Bar'); # 把'bar' 放到 'foo'里面 $foo->{'bar'} = $bar; # 通过线程重新bless the objects threads->create(sub { # Rebless the outer object bless($foo, 'Yin'); # 不能直接 rebless the inner object #bless($foo->{'bar'}, 'Yang'); # 重新取回然后 rebless the inner object my $obj = $foo->{'bar'}; bless($obj, 'Yang'); $foo->{'bar'} = $obj; })->join(); print(ref($foo), "\n"); # Prints 'Yin' print(ref($foo->{'bar'}), "\n"); # Prints 'Yang' print(ref($bar), "\n"); # Also prints 'Yang' |
注意:如果你还想使用threads,那么你必须在"use threads::shared"之前就"use threads",否则会报告异常。
如果你把一个数组、散列或它们的引用share以后,那么容器中的元素都会丢失。
my @arr = qw(foo bar baz); share(@arr); # @arr is now empty (i.e., == ()); # Create a 'foo' object my $foo = { 'data' => 99 }; bless($foo, 'foo'); # Share the object share($foo); # Contents are now wiped out print("ERROR: \$foo is empty\n") if (! exists($foo->{'data'})); |
所以正确的做法是你应该先把一个空的容器share,然后再往里面添加元素。
<<========================Thread::Semaphore=============================>>
use Thread::Semaphore; my $s = Thread::Semaphore->new(); $s->down(); # P操作 # The guarded section is here $s->up(); # V操作 # Decrement the semaphore only if it would immediately succeed. if ($s->down_nb()) { # 邻界区在此 $s->up(); } # 强制降低信号量即使他成为负数 $s->down_force(); # 创建信号量时指定·初始值 my $s = Thread::Semaphore->new($initial_value); $s->down($down_value); $s->up($up_value); if ($s->down_nb($down_value)) { ... $s->up($up_value); } $s->down_force($down_value); |
<<===========================Thread::Queue===================================>>
直接看程序是学习语言的快速方法,注释得很清楚:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
use strict; use warnings; use threads; use Thread::Queue; my $q = Thread::Queue->new(); # 创建一个空的线程队列 # Worker线程 my $thr = threads->create(sub { while (my $item = $q->dequeue()) { #处理$item } })->detach(); # 向线程发送 work $q->enqueue($item1, ...); # 计算队列中有多少项 my $left = $q->pending(); # 非阻塞地出队 if (defined(my $item = $q->dequeue_nb())) { # 处理 $item } # 获取队列中的第2项,注意并没有进行出几队操作 my $item = $q->peek(1); # 在队头后面插入两个元素 $q->insert(1, $item1, $item2); # 提取队列中的最后两个元素 my ($item1, $item2) = $q->extract(-2, 2); |
上面代码中出现过的函数我就不介绍了。
下面的数据类型可以放入队列:
普通标题数据;
标量引用;
数组引用;
哈希引用;
以上对象的组合。
my @ary = qw/foo bar baz/;
q->enqueue(\@ary); ##copy the elements 'foo', 'bar' and 'baz' from @ary intoq。
而对于共享变量,是它的引用进入队列,而没有发生元素的深复制。
my @ary :shared = qw/foo bar baz/; $q->enqueue(\@ary); my $obj = &shared({}); $$obj{'foo'} = 'bar'; $$obj{'qux'} = 99; bless($obj, 'My::Class'); $q->enqueue($obj); |
->new() ##创建新队列
->new(LIST) ##创建队列时压入元素
->enqueue(LIST) #入队
->dequeue() #从队中取出一个元素
->dequeue(COUNT) #从队中取出COUNT个元素,如果COUNT大于队列长度,则阻塞,下面的方法不会阻塞。
->dequeue_nb()
->dequeue_nb(COUNT)
->pending()
返回队列中元素的个数。
{ lock($q); # 销往队列,以防止其他线程中修改和删除队列元素 my $item = $q->peek(); if ($item ...) { ... } } # 离开块之后,队列变量自动解锁 |
->peek() #取出队首元素,并没有出险
->peek(INDEX) #取出指定下标的队列元素,INDEX为负数时是从队尾开始数起
->insert(INDEX,LIST) #在指定的位置上插入一组元素,队首元素的INDEX为0
->extract()
->extract(INDEX)
->extract(INDEX, COUNT)
删除并返回指定的元素。
perl多线程使用的更多相关文章
- Perl 多线程模块 Parallel::ForkManager
Perl 多线程模块 Parallel::ForkManager 一个简单的并行处理模块.这个是用来对付循环的多线程处理. 放在循环前面. Table of Contents 1 Synops内容简介 ...
- perl多线程tcp端口扫描器(原创)
perl多线程tcp端口扫描器(原创) http://bbs.chinaunix.net/thread-1457744-1-1.html perl socket 客户端发送消息 http://blog ...
- perl多线程理解
Thread:在使用多线程处理比较大的数据量的扫描,遇到读写文件可能死锁的问题. Perl 线程的生命周期 1.使用 threads 包的 create() 方法: use threads; sub ...
- Perl多线程(1):解释器线程的特性
线程简介 线程(thread)是轻量级进程,和进程一样,都能独立.并行运行,也由父线程创建,并由父线程所拥有,线程也有线程ID作为线程的唯一标识符,也需要等待线程执行完毕后收集它们的退出状态(比如使用 ...
- Perl多线程(2):数据共享和线程安全
线程数据共享 在介绍Perl解释器线程的时候一直强调,Perl解释器线程在被创建出来的时候,将从父线程中拷贝数据到子线程中,使得数据是线程私有的,并且数据是线程隔离的.如果真的想要在线程间共享数据,需 ...
- [ Perl ] 多线程并发编程
https://www.cnblogs.com/yeungchie/ 记录一些常用的 模块 / 方法 . 多线程 使用模块 threads use 5.010; use threads; sub fu ...
- 2.Perl 多线程:Threads(线程返回值)
use warnings; use strict; use threads; sub TEST{ print "Hello, World!\n"; 'a'/); } #返回列表方法 ...
- 3.Perl 多线程:Threads(exit thread_only)
还可以在导入threads模块时设置: use threads ('exit' => 'thread_only');
- 1.Perl 多线程:Threads
详情可查看: perldoc threads 调用线程的方法: $thr = threads->create(FUNCTION, ARGS) #This will create a new th ...
随机推荐
- How to get table pg_stat_user_functions.
修改配置文件postgres.conf track_functions = all # none, pl, all 或者 在当前事物中设置 postgres=# s ...
- Linux中如何恢复rm命令误删除的文件之extundelete编译安装及使用
1.下载extundelete包,安装依赖 我用的是Centos系统,在安装extundelete之前需要安装e2fsprogs,e2fsprogs-libs,e2fsprogs-devel. yum ...
- Python入门经典 以解决计算问题为导向的Python编程 待完好
1.4.2:python将代码分为两类:表达式和语句 表达式和语句:: 表达式(值和运算符的结合,将产生新值--返回值. 假设在python shell中输入表达式将显示返回值.也就是说,假设x的 ...
- 基于C++11的线程池
1.封装的线程对象 class task : public std::tr1::enable_shared_from_this<task> { public: task():exit_(f ...
- LINUX6安装Oracle10g无法启动安装界面解决
***********************************************声明*************************************************** ...
- Java项目中使用Redis缓存案例
缓存的目的是为了提高系统的性能,缓存中的数据主要有两种: 1.热点数据.我们将经常访问到的数据放在缓存中,降低数据库I/O,同时因为缓存的数据的高速查询,加快整个系统的响应速度,也在一定程度上提高并发 ...
- linux(ubuntu) 搭建java程序运行环境
一:简介 ubuntu 系统的和linux差不多,我们需要在系统上搭建java程序运行环境,需要安装jdk,mysql这两个软件,tomcat是绿色版,直接通过taz -zxvf tomcat 就可以 ...
- json api
from flask import Flask, redirect, url_for, jsonify, request app = Flask(__name__) users = [] ''' RE ...
- ImportError: No module named 'request'
使用系统自带的Python 2.7执行python时出现ImportError: No module named 'request'这样的报错,这是系统自带的Python没有requests库,这里可 ...
- iOS支付宝支付相关问题
支付宝实现以及相关问题:http://www.jianshu.com/p/f81578954974 1.支付宝支付流程 1.用户点击支付2.客户端请求服务器用户支付3.服务器接收请求生成金额订单等要给 ...