perl多线程使用 perl多进程

   2023-02-09 学习力0
核心提示:原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun=========================threads===========================#!/usr/bin/perluse threads ('yield',            'stack_size' = 64*4096,          

原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun

<<=========================threads===========================>>

#!/usr/bin/perl
use 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");
}
 
# 在隐式的列表环境中调用thread
my $thr3 = threads->create(sub { return (qw/a b c/); });
# 在显式的列表环境中调用thread
my $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 size
my $thr5 = threads->create({ 'context'    => 'list',
                           'stack_size' => 32*4096,
                           'exit'       => 'thread_only' },
                         \&start_thread);
 
# Get thread's context
my $wantarray = $thr->wantarray();
print $wantarray,"\n";
 
# Check thread's state
if ($thr5->is_running()) {
   sleep(1);
}
if ($thr5->is_joinable()) {
   $thr5->join();
}
 
# Send a signal to a thread
$thr5->kill('SIGUSR1');
 
# Exit a thread
threads->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)

删除并返回指定的元素。

原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun
 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Linux下安装Perl和Perl的DBI模块
    今天在虚拟机测试shell脚本的时候,有些命令使用不了。比如说 mysqlhotcopy ,它提示Perl的版本太低。我用的 RedHat9 的Perl才5.8.0版本。。。(2002年以前的)严重过时。所以重新安装了新版本的 Perl,过程记录如下: 1、在官方网站下载新版本的源码包:http:
    03-16
  • Perl 与Form
    说明事项: 這個範例用來說明如何經由網頁上的HTML form 表單元件來呼叫伺服器端的perl 程式。这个范例用来说明如何经由网页上的HTML form 表单元件来呼叫伺服器端的perl 程式。首先在網頁上設計表單元件,這個範例是設計一個按鈕,其原始碼如下:首先在网页
    02-10
  • Perl学习 perl培训
    http://www.sun126.com/perl5/perl5-1.htm翻译: flamephoenix 第一章 概述一、Perl是什么?二、Perl在哪里?三、运行四、注释一、Perl是什么?  Perl是Practical Extraction and Report Language的缩写,它是由Larry Wall设计的,并由他不断更新和维护,用
    02-10
  • - calm_水手">Perl中的箭头符-> - calm_水手
    Perl中的箭头符-2012-05-21 17:14 calm_水手 阅读(623) 评论(0) 编辑 收藏 举报  有两种用法,都和解引用有关。第一种用法,就是解引用。根据 - 后面跟的符号的不同,解不同类型的引用,-[] 表示解数组引用,-{} 表示解散列引用,-() 表示解子程序引
    02-09
  • Regex in Perl
    Regex in Perl
    regex literal   代表正则文字, 就是 m/regex/ 部分中的 regex, 这部分有自己的解析规则. 用 Perl 的行话就是 "表示正则含义的双引号字符串(regx-aware double-quoted string)", 及处理后传递给正则引擎的结果. 正则文字支持的特性:  1. 变量插值.    
    02-09
  • perl脚本语言学习 perl脚本调用perl脚本
    来公司的第二个星期便看了一下perl语言,发现掌握一门脚本语言还是非常有用的。到现在为止已经入职两个月,用perl脚本做了这些活:1. 修改了公司的一个爬取网页源代码的脚本2. 改进了一个出特征库的脚本,根据svn status的状态,来优化,将只需要添加的DB的数
    02-09
  • Perl模块的安装方法 perl 安装模块
    1. 下载离线安装包 *.tar.gz的形式解包后,#perl Makefile.PL#make#make install2. 在联网的情况下,通过CPAN安装# perl -MCPAN -e shellcpan install PAR::Packer 
    02-09
  • Perl像C一样强大,像awk、sed等脚本描述语言一
    Perl是由Larry Wall设计的,并由他不断更新和维护的编程语言。Perl具有高级语言(如C)的强大能力和灵活性。事实上,你将看到,它的许多特性是从C语言中借用来的。Perl与 脚本语言一样,Perl不需要编译器和链接器来运行代码,你要做的只是写出程序并告诉Perl
    02-09
  • 27-Perl 进程管理
    1.Perl 进程管理Perl 中你可以以不同的方法来创建进程。本教程将讨论一些进程的管理方法。你可以使用特殊变量 $$ 或 $PROCESS_ID 来获取进程 ID。%ENV 哈希存放了父进程,也就是shell中的环境变量,在Perl中可以修改这些变量。exit() 通常用于退出子进程,主
    02-09
  • 在perl中简单的正则匹配 正则匹配或的使用
    (一)、在perl中关于元字符的匹配元字符代表含义点号( .)匹配处换行符以外的任何单字符星号(*)匹配前面的内容零次或多次反斜线屏蔽元字符的特殊含义。\\代表\,\.匹配点号.*匹配所有的字符串加号(+)匹配前一个条目一次以上问号(?)表示前面一个条目可
    02-09
点击排行