aaahd 发表于 2015-12-26 01:08:03

Perl语言的多线程(二)

  很多时候使用perl多线程可以达到很不错的效果,可以节约很多时间完成很复杂的工作。但通过perl threads模块的描述文件可以看到,它也有很多缺点。比如说在使用perl多线程的时候,必须的保证所有引用的模块都是支持thread。而在实际应用中,我们很难做到这样。比如我们要多线程,但同时要应用OLE模块去操作activex。 此用例应该是一种很常见的用例。那是不是意味着此时我们不得不放弃使用多线程呢。 非也, 本文介绍一种可以使用多线程和ole的例子。
  在http://www.cpan.org/官方网站上对这种情况给出的方案是:

  If the module will only be used inside a thread, you can try loading the module from inside the thread entry point function using require (and import if needed):

   sub thr_func
{
require Unsafe::Module
# Unsafe::Module->import(...);
....
}
  If the module is needed inside the main thread, try modifying your application so that the module is loaded (again using require and ->import()) after any threads are started, and in such a way that no other threads are started afterwards。


  再次,主要讨论一下第二种情况,既主要是该非thread模块放到方法中引用。下面是一个demo。


  


Code
use threads;
use threads::shared;
use Thread::Queue;
no warnings 'threads';
# Time out const
my $TIMEOUT : shared;
$TIMEOUT = 1;
# the sig for end thread
my $TERM : shared;
$TERM = 0;
#my $excel;
$SIG{'INT'} = $SIG{'TERM'} = sub{ print("\n>>> Terminating <<<\n"); $TERM=1;};
$SIG{'KILL'} = sub{ printf("%3d <- Killed\n", threads->tid());
                  threads->detach() if !threads->is_detached();
                  threads->exit(); };
sub ThreadWatcher
{
    my $queue = shift;
    my %timers;
    while(!$TERM)
    {
      #print "ThreadWatcher -- TERM : $TERM\n";
      while(my $tid = $queue->dequeue_nb())
      {
            if (! defined($timers{$tid}{'timeout'} = $queue->dequeue()) ||
                ! defined($timers{$tid}{'thread'}= threads->object($tid)))
            {
                # No timeout - unregister thread
                delete($timers{$tid});
            }
      }
      
      foreach my $tid (keys(%timers))
      {
            #print "$timers{$tid}{'thread'} \n";
            if(--$timers{$tid}{'timeout'} < 0)
            {
                print "thread $timers{$tid}{'thread'} will be killed.\n";
                $timers{$tid}{'thread'}->kill('KILL');
                delete($timers{$tid});
            }
      }
      # tick tock
      sleep(1);
    }
}
sub Worker
{
    #eval {use Win32::OLE::Variant;};
    my ($queue, $dataqueue) = @_;
    # get the thread id and register with watch
    my $tid = threads->tid();
    printf("Working -> %3d\n", $tid);
    $queue->enqueue($tid, $TIMEOUT);
    print "Worker -- TERM : $TERM\n";
    while(!$TERM)
    {
      #my $App = $dataqueue->dequeue();
      my $data = $dataqueue->dequeue();
      #deal with the data
      #print "Worker -- DATA : $App\n";
      print "Worker -- DATA : $data\n";
      #my $var = Win32::OLE::Variant->new(VT_BSTR, $data);
      #print "Worker VAR: $var\n";
    }
    # Remove signal handler
    $SIG{'KILL'} = sub {};
    # Unregister with timer thread
    $queue->enqueue($tid, undef);
    # Tell user we're done
    printf("%3d <- Finished\n", $tid);
    threads->detach() if ! threads->is_detached();
    threads->exit();
}
# create time thread
my $watchQueue = Thread::Queue->new();
threads->create('ThreadWatcher', $watchQueue)->detach();
# create work thread
my $dataQueue = Thread::Queue->new();
threads->create('Worker', $watchQueue, $dataQueue);
NoneSafeModelScript('C:\Joe_Chen\Perl_Projects\Threads\update.xlsx');
WairLongTime(10);

sub WairLongTime
{
    my $temp = $_;
    $temp = $temp * 10000000;
    for(my $index = 0; $index < $temp; $index++)
    {
      $index * $index;
    }
    return $index;
}
sub NoneSafeModelScript
{
    eval 'use Win32::OLE';
    eval 'use Win32::OLE::Variant';
    my $excel;
    for(my $index = 0; $index < 600; $index++)
    {
      print "Getting the Excel ActiveObject. Try # $index \n";
      WairLongTime(1);
      eval
      {
            $excel = Win32::OLE->GetActiveObject('Excel.Application') || Win32::OLE->new('Excel.Application', 'Quit');
      };
      if($@ or $excel == undef)
      {
            print "Unsuccessful: $@ \n";
            if($index == 599)
            {
                print "ERROR:Don\'t got the Excel Application";
            }
      }
      else
      {
            last;
      }
    }
    my $path = $_;
    my $book = $excel->workbooks->open($path);
    my $sheet = $book->worksheets(1);
    my $values = $sheet->Range("A1:D5")->{Value};
    my $row_counts = $sheet->Range("A1:C3")->{Rows}->{Count};
    my $column_counts = $sheet->Range("A1:C3")->{Columns}->{Count};
    print "NoneSafeModelScript : $row_counts \n";
    print "NoneSafeModelScript : $column_counts \n";
    for(my $row=1; $row<$row_counts + 1; $row++)
    {
      my $array_ref = $sheet->Cells($row,1)->{Value};
      print "NoneSafeModelScript : $array_ref \n";
      my $var = Variant(Win32::OLE::Variant->VT_BSTR, $array_ref);
      my $v = ref($var);
      #my $v = $var->Type();
      print "NoneSafeModelScript VAR: $var\n";
      print "NoneSafeModelScript VAR: $v\n";
      #$dataQueue->enqueue($var);
      $dataQueue->enqueue($array_ref);
      WairLongTime(2);
    }
    my $v = Variant(VT_DATE, "April 1 99");
    print $v->Type, "\n";
    print $v->Date(DATE_LONGDATE), "\n";
    print $v->Date("ddd',' MMM dd yy"), "\n";
    print Win32::OLE::Variant->VT_BSTR , "\n";
    $book->Close;
    $excel->Quit;
}
sub Wrap
{
    my $value = $_;
    my $var = Variant(VT_DATE, 'Jan 1,1970');
    print "Wrap : $var \n";
    return $var;
}

  
  在此例子中,用到了queue,它的作用是将非thread 安全的数据通过管道传输,这样能避免他们互相调用。
页: [1]
查看完整版本: Perl语言的多线程(二)