Multithreading 从Perl线程运行bash脚本
我的脚本应该有n个子例程(My_proc)同时运行,每个子例程运行bash脚本,一个子例程(check_procs)检查子例程是否完成Multithreading 从Perl线程运行bash脚本,multithreading,bash,perl,Multithreading,Bash,Perl,我的脚本应该有n个子例程(My_proc)同时运行,每个子例程运行bash脚本,一个子例程(check_procs)检查子例程是否完成 use strict; use threads; use threads::shared; my %proc_status :shared; my %thr; foreach my $i (1,2,3,4) { $proc_status{$i}=0; } sub my_proc { my $arg=shift(@_); while
use strict;
use threads;
use threads::shared;
my %proc_status :shared;
my %thr;
foreach my $i (1,2,3,4) {
$proc_status{$i}=0;
}
sub my_proc {
my $arg=shift(@_);
while (1) {
sleep(2);
print "Proc $arg Started\n";
#exec("/bin/bash","sleep_for_10_sec.bash") or die("Can't exec"); # case 1
#`sleep_for_10_sec.bash &`; # case 2
print "Proc $arg Finished\n";
{
lock(%proc_status);
$proc_status{$arg}=1;
}
}
}
sub check_procs {
my $all_finished;
while (! $all_finished) {
sleep 5;
print "CHECK: \n";
$all_finished=1;
foreach my $num (1,2,3,4) {
if ($proc_status{$num} == 1) {
print "CHECK: procedure $num has finished\n";
} else {
$all_finished=0;
}
}
}
print "All jobs finished\n";
}
foreach my $num (1,2,3,4) {
$thr{"$num"} = new threads \&my_proc,$num;
}
my $thr_check= new threads \&check_procs;
$thr_check->join();
这是10秒狂欢的睡眠时间
ls
# bunch of other stuff
sleep 10
echo "finished sleep"
我不想我的_procsubs等待执行“sleep_等待_10秒bash”命令,浏览后我发现#case1或#case2都应该工作,但它们都失败了
#案例1的输出:
#案例2的输出:
但我希望这样:
Proc 1 Started
Proc 2 Started
Proc 3 Started
Proc 4 Started
Proc 1 Finished
Proc 1 Started
Proc 3 Finished
Proc 3 Started
Proc 4 Finished
Proc 4 Started
Proc 2 Finished
Proc 2 Started
CHECK:
CHECK:
CHECK:
CHECK: procedure 1 has finished
CHECK: procedure 2 has finished
CHECK: procedure 3 has finished
CHECK: procedure 4 has finished
实际上,如果将输出重定向到“>日志”,我会得到想要的结果,但无论如何,在:
Proc 1 Started
Proc 2 Started
Proc 3 Started
Proc 4 Started
它等待“睡眠等待10秒bash”完成
这是我第一个使用“线程”和“执行”的项目,有人能帮我吗
exec
不应与线程组合exec
在当前进程中启动一个新程序,因此当您从一个线程调用exec
时,线程正在执行的程序将消失。由于线程没有要执行的程序,exec
也会杀死线程
我不清楚为什么案例2不起作用(编辑:见下面ikegami的评论)。我认为它将启动进程,在后台运行,并允许Perl线程立即继续。它似乎没有这样做,但此代码将:
system("/bin/bash sleep_for_10_sec.bash &"); # case 3
exec(“/bin/bash”,“睡眠10秒bash”)或die(“不能执行”)#案例1
exec
用另一个程序替换当前进程中运行的程序。同时,现有线程被终止(因为它们想要执行的程序已经不在了),取而代之的是执行新程序的单个线程
这意味着exec
永远不会返回(出错时除外)。线程或无线程,exec
不是您想要的,因为您不希望程序停止运行
但我希望这样: 是否确实要按所需输出指示,每两秒启动
sleep\u 10秒bash
4次(意味着一次最多可以运行20次)
您确定不在乎bash的sleep\u 10秒
是否完成了所需的输出
如果是这样,为什么要使用线程呢?您可以简单地使用以下内容:
sub start {
my $num = shift;
say "Proc $num Started";
system('bash -c sleep_for_10_sec.bash &');
say "Proc $num Finished";
}
for my $pass (1..2) {
start($_) for 1..4;
sleep 2;
start($_) for 1..4;
sleep 2;
start($_) for 1..4;
sleep 1;
if ($pass == 1) {
say "CHECK:";
} else {
say "CHECK: procedure $_ has finished" for 1..4;
}
}
我想你想要
use threads;
use Thread::Queue qw( ); # 3.01+
use constant NUM_WORKERS => 4;
sub worker {
my $num = shift;
say "Job $num Started\n";
system("sleep_for_10_sec.bash"); # Make sure starts with #! and is executable.
say "Job $num Finished\n";
}
{
my $q = Thread::Queue->new();
for (1..NUM_WORKERS) {
while (defined( my $job = $q->dequeue() )) {
worker($job);
}
}
$q->enqueue(1..4, 1..4);
$q->end();
$_->join() for threads->list;
}
Backticks等待孩子的STDOUT关闭,因此它只有在后台程序退出后才会返回(除非你重定向后台程序的STDOUT)。运行
sh-c'/bin/bash sleep_10_sec.bash&'
(就像system()
调用那样)看起来很愚蠢——为什么要发射两个shell而不是一个呢?@Charles Duffy,因为你说这是一个bash
脚本。@ikegami,我不是OP。也就是说--Perl没有提供一种直接调用你想要的解释器的方法?(例如,在Python中,我可以直接subprocess.Popen(['bash','sleep_for_10_sc.bash'])
,只要我不传递shell=True
就没有隐式sh-c
)。@Charles Duffy,Python代码是不等价的。您忘记说明&
。现在,mob可以编写系统(“/bin/bash-c'sleep'u for_10'u sec.bash&'”
在这种情况下,可以使用系统('bash','c','sleep_for_10_sec.bash&')
创建两个shell,不过这两个shell都是bash
。感谢您的详细解释。我终于了解了exec的工作原理(我希望:)#@mob建议的案例3非常有效。不管怎样,你的回答很有启发性,我非常感谢,再次感谢。这是一个糟糕的选择!!!!!如果你同意案例3,那么你应该使用我发布的第一个片段。它只占用了一半的行(23行而不是50行),并且完全避免了使用线程的复杂性(这对您来说是完全无用的)。
sub start {
my $num = shift;
say "Proc $num Started";
system('bash -c sleep_for_10_sec.bash &');
say "Proc $num Finished";
}
for my $pass (1..2) {
start($_) for 1..4;
sleep 2;
start($_) for 1..4;
sleep 2;
start($_) for 1..4;
sleep 1;
if ($pass == 1) {
say "CHECK:";
} else {
say "CHECK: procedure $_ has finished" for 1..4;
}
}
use threads;
use Thread::Queue qw( ); # 3.01+
use constant NUM_WORKERS => 4;
sub worker {
my $num = shift;
say "Job $num Started\n";
system("sleep_for_10_sec.bash"); # Make sure starts with #! and is executable.
say "Job $num Finished\n";
}
{
my $q = Thread::Queue->new();
for (1..NUM_WORKERS) {
while (defined( my $job = $q->dequeue() )) {
worker($job);
}
}
$q->enqueue(1..4, 1..4);
$q->end();
$_->join() for threads->list;
}