Multithreading 如何在Perl中实现信号量线程通信?
我的Perl脚本需要同时运行多个线程 …这样的线程需要从web获取一些信息,所以使用了Multithreading 如何在Perl中实现信号量线程通信?,multithreading,perl,process,multiprocessing,semaphore,Multithreading,Perl,Process,Multiprocessing,Semaphore,我的Perl脚本需要同时运行多个线程 …这样的线程需要从web获取一些信息,所以使用了HTTP::Async 但有些线程只有在其他线程这样说时才需要访问web 可能有一个或多个线程等待“go”信号,并且可能有一个或多个这样的“go”信号可以发送的线程。开始时,信号量的状态为“等待”,一旦变为“开始”,它将保持这种状态 最后,应用程序检查最大运行时间。如果线程运行时间过长,将发送自终止信号 现在开门见山。我的问题是: 如何在脚本中最有效地编写等待“信号量”的代码(请参见上面脚本中的注释)。我是否
HTTP::Async
但有些线程只有在其他线程这样说时才需要访问web
可能有一个或多个线程等待“go”信号,并且可能有一个或多个这样的“go”信号可以发送的线程。开始时,信号量的状态为“等待”,一旦变为“开始”,它将保持这种状态
最后,应用程序检查最大运行时间。如果线程运行时间过长,将发送自终止信号
现在开门见山。我的问题是:
sleep
循环一起使用sleep
循环,以便让线程有时间进行自我销毁...
use Thread::Queue;
...
# In main body
my $q = Thread::Queue->new();
...
$thread = threads->create(
sub {
local $SIG{KILL} = sub { threads->exit };
my $url = shift;
if ($url ... ) {
# wait for "go" signal from other threads
my $mesg = $q->dequeue();
# you could put in some termination code if the $mesg isn't 'go'
if ($mesg ne 'go') { ... }
}
...
if ($data ... ) {
# send "go" signal to waiting threads
$q->enqueue('go');
}
}
}, $_);
...
需要等待“go”信号的线程将在dequeue方法上等待,直到有东西进入队列。消息进入队列后,一个线程(只有一个线程)将获取消息并对其进行处理
如果希望停止线程,使其无法运行,可以向队列的头部插入停止消息
$q->insert(0, 'stop') foreach (@threads);
Thread::Queue和CPAN发行版中的一些示例更详细地说明了这一点
对于你的第二个问题,答案是,不幸的是,这要视情况而定。当您继续终止线程时,需要什么样的清理才能实现干净的关闭?如果地毯被从线下拉出,最坏的情况是什么?您可能希望在任何时候计划进行清理。您可以做的另一个选择是等待每个线程实际完成
我的评论询问您是否可以删除detach
调用的原因是,此方法允许主线程退出,而不关心任何子线程发生了什么。相反,如果您删除此呼叫并添加:
$_->join() foreach threads->list();
在主块的末尾,这将要求主应用程序等待每个线程实际完成
如果将
detach
方法留在原位,那么如果需要线程执行任何类型的清理,则需要在代码结束时休眠。在线程上调用detach
时,您告诉Perl的是,当主线程退出时,您不关心线程在做什么。如果主线程退出,并且仍在运行的线程已分离,则程序将在没有警告的情况下完成。但是,如果您不需要任何清理,并且仍然调用detach
,请随时退出。试试这样的方法
#!/usr/bin/perl
use threads;
use threads::shared;
$|=1;
my ($global):shared;
my (@threads);
push(@threads, threads->new(\&mySub,1));
push(@threads, threads->new(\&mySub,2));
push(@threads, threads->new(\&mySub,3));
$i = 0;
foreach my $myThread(@threads)
{
my @ReturnData = $myTread->join ;
print "Thread $i returned: @ReturnData\n";
$i++;
}
sub mySub
{
my ($threadID) = @_;
for(0..1000)
{
$global++;
print "Thread ID: $threadID >> $_ >> GLB: $global\n";
sleep(1);
}
return( $id );
}
这个问题有一个公开的赏金价值+50声誉。请改进你的答案。我发现你的帖子很有趣,但是你没有回答我帖子中的第二个子问题(如果/如何等待线程自毁)@user1215106我注意到你的代码中有一个
$thread->detach代码>。通常,您使用它来忽略线程,而不关心它是否完成。你有理由把它放在那里吗?或者它可以被移除吗?我相信它可以被移除。我等不及了!无限的为了让线程完成,我必须为其他应用程序释放资源。如果没有按时完成,线程会在$response=$async->wait_for_next_response
行等待。@user1215106查看最后一段,让我知道这是否为第二个问题提供了更好的答案。我是否正确理解您使用的是单独的HTTP::async对象(由新线程复制,而不是共享)每个线程一次最多获取一个URL?@pilcrow-是的,看起来像。这是在浪费资源吗?它可能会或不会减少内存或时间效率,但真正的消耗是在程序员的周期上。:)设计很难理解,因此可能需要安全地更改/扩展,因为组件似乎不太正确。@pilcrow-所以建议在线程内部分配HTTP::Async?我相信没有理由分享这个目标。除非用这种方法会更优化。我不知道怎么评论。您向我们展示了您的实现的一个摘录,您是如何尝试做一些事情的,而不是您尝试做什么。我只能观察到HTTP::Async是一种用于并行单线程web请求的工具,这似乎与我们看到的设计部分不一致。
...
use Thread::Queue;
...
# In main body
my $q = Thread::Queue->new();
...
$thread = threads->create(
sub {
local $SIG{KILL} = sub { threads->exit };
my $url = shift;
if ($url ... ) {
# wait for "go" signal from other threads
my $mesg = $q->dequeue();
# you could put in some termination code if the $mesg isn't 'go'
if ($mesg ne 'go') { ... }
}
...
if ($data ... ) {
# send "go" signal to waiting threads
$q->enqueue('go');
}
}
}, $_);
...
$q->insert(0, 'stop') foreach (@threads);
$_->join() foreach threads->list();
#!/usr/bin/perl
use threads;
use threads::shared;
$|=1;
my ($global):shared;
my (@threads);
push(@threads, threads->new(\&mySub,1));
push(@threads, threads->new(\&mySub,2));
push(@threads, threads->new(\&mySub,3));
$i = 0;
foreach my $myThread(@threads)
{
my @ReturnData = $myTread->join ;
print "Thread $i returned: @ReturnData\n";
$i++;
}
sub mySub
{
my ($threadID) = @_;
for(0..1000)
{
$global++;
print "Thread ID: $threadID >> $_ >> GLB: $global\n";
sleep(1);
}
return( $id );
}