很多时候使用perl多线程可以达到很不错的效果,可以节约很多时间完成很复杂的工作。但通过perl threads模块的描述文件可以看到,它也有很多缺点。比如说在使用perl多线程的时候,必须的保证所有引用的模块都是支持thread。而在实际应用中,我们很难做到这样。比如我们要多线程,但同时要应用OLE模块去操作activex。 此用例应该是一种很常见的用例。那是不是意味着此时我们不得不放弃使用多线程呢。 非也, 本文介绍一种可以使用多线程和ole的例子。
很多时候使用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 = $_[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 安全的数据通过管道传输,这样能避免他们互相调用。