我想运行多个 shell 进程,但是当我尝试运行超过 63 个时,它们会挂起。当我将线程池中的 max_threads
减少到 n
时,它在运行 n
th shell 命令后挂起。
正如您在下面的代码中看到的,问题不在于 start
block 本身,而在于包含 shell
的 start
block > 命令:
#!/bin/env perl6
my $*SCHEDULER = ThreadPoolScheduler.new( max_threads => 2 );
my @processes;
# The Promises generated by this loop work as expected when awaited
for @*ARGS -> $item {
@processes.append(
start { say "Planning on processing $item" }
);
}
# The nth Promise generated by the following loop hangs when awaited (where n = max_thread)
for @*ARGS -> $item {
@processes.append(
start { shell "echo 'processing $item'" }
);
}
await(@processes);
运行 ./process_items foo bar baz
给出以下输出,卡在 processing bar
之后,它就在 n
之后第 (此处为 2
nd)线程已使用 shell
运行:
Planning on processing foo Planning on processing bar Planning on processing baz processing foo processing bar
我做错了什么?或者这是一个错误?
在 CentOS 7 上测试的 Perl 6 发行版:
落语之星2018.06
乐道之星2018.10
乐道之星2019.03-RC2
落语之星2019.03
对于 Rakudo Star 2019.03-RC2,使用 v6.c
与 使用 v6.d
没有任何区别。
最佳答案
shell
和run
子程序使用Proc
,它是根据Proc::Async
实现的。这在内部使用了线程池。通过对 shell
的阻塞调用填满池,线程池会耗尽,因此无法处理事件,从而导致挂起。
直接使用 Proc::Async
来完成这个任务会好得多。使用 shell
和大量真实线程的方法无法很好地扩展;每个 OS 线程都有内存开销、GC 开销等等。因为生成一堆子进程不受 CPU 限制,所以这是相当浪费的;实际上,只需要一两个真正的线程。因此,在这种情况下,也许在做一些低效的事情时让你退缩并不是最糟糕的事情。
我注意到使用 shell
和线程池的原因之一是试图限制并发进程的数量。但这不是一种非常可靠的方法;仅仅因为当前的线程池实现设置了默认的最大 64 个线程并不意味着它总是会这样做。
这是一个并行测试运行程序的示例,它一次最多运行 4 个进程,收集它们的输出并将其封装。它可能比您需要的多一点,但它很好地说明了整体解决方案的形状:
my $degree = 4;
my @tests = dir('t').grep(/\.t$/);
react {
sub run-one {
my $test = @tests.shift // return;
my $proc = Proc::Async.new('perl6', '-Ilib', $test);
my @output = "FILE: $test";
whenever $proc.stdout.lines {
push @output, "OUT: $_";
}
whenever $proc.stderr.lines {
push @output, "ERR: $_";
}
my $finished = $proc.start;
whenever $finished {
push @output, "EXIT: {.exitcode}";
say @output.join("\n");
run-one();
}
}
run-one for 1..$degree;
}
这里的关键是当一个进程结束时调用run-one
,这意味着你总是用一个新的进程替换一个退出的进程,维护——只要有事情要做- 最多同时运行 4 个进程。当所有进程完成时,react
block 自然结束,因为订阅的事件数降为零。
关于raku - 为什么我的 promise (启动 block )中的所有 shell 进程都没有运行? (这是一个错误吗?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59035286/