很多时候使用perl多线程可以达到很不错的效果,可以节约很多时间完成很复杂的工作。但通过perl threads模块的描述文件可以看到,它也有很多缺点。比如说在使用perl多线程的时候,必须的保证所有引用的模块都是支持thread。而在实际应用中,我们很难做到这样。比如我们要多线程,但同时要应用OLE模块去操作activex。 此用例应该是一种很常见的用例。那是不是意味着此时我们不得不放弃使用多线程呢。 非也, 本文介绍一种可以使用多线程和ole的例子。
在官方网站上对这种情况给出的方案是:
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 constmy $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 threadmy $watchQueue = Thread::Queue->new();threads->create('ThreadWatcher', $watchQueue)->detach();# create work threadmy $dataQueue = Thread::Queue->new();threads->create('Worker', $watchQueue, $dataQueue);NoneSafeModelScript('C:\Joe_Chen\Perl_Projects\Threads\update.xlsx');WairLongTime(10);sub WairLongTime{ my $temp = $_[0]; $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 = $_[0]; 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 = $_[0]; my $var = Variant(VT_DATE, 'Jan 1,1970'); print "Wrap : $var \n"; return $var;}
在此例子中,用到了queue,它的作用是将非thread 安全的数据通过管道传输,这样能避免他们互相调用。