当前位置: 首页 > 知识库问答 >
问题:

为什么我的promise(启动块)中的所有shell进程都不运行?(这是一个错误吗?)

蔺霄
2023-03-14

我想运行多个shell进程,但当我尝试运行63个以上时,它们会挂起。当我将线程池中的最大线程数减少到n时,它会在运行shell命令后挂起。

正如您在下面的代码中所看到的,问题不在于启动块本身,而在于包含shell命令的启动块:

#!/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\u items foo bar baz给出以下输出,在处理条形图之后挂起,该输出正好位于使用shell运行的th(此处为2)线程之后:

Planning on processing foo
Planning on processing bar
Planning on processing baz
processing foo
processing bar

我做错了什么?还是这是一个bug?

在CentOS 7上测试的Perl 6发行版:

对于Rakudo Star 2019.03-RC2,使用v6。c与使用v6相比。d没有任何区别。

共有1个答案

凌钊
2023-03-14

shell和run子脚本使用Proc,这是根据异步实现的。这在内部使用线程池。通过使用对shell的阻塞调用填充池,线程池将耗尽,因此无法处理事件,从而导致挂起。

直接使用Proc::Async来完成这个任务会好得多。使用shell和大量真实线程的方法不能很好地扩展;每个操作系统线程都有内存开销、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块自然结束。

 类似资料:
  • 我从分区中读取,并对我读取的每个ConsumerRecord执行consumer.commitasync(在理解行为之前,在这一点上故意不对提交进行批处理)。 我在commit async回调中放置了一个每个主题的计数器来度量它被调用的次数,总数为100万次。 在应用程序稳定下来并停止之后,我使用Kafka CLI工具查看我的偏移量,我得到如下内容: 为什么我还会有这种滞后?什么可能导致这一切?

  • 我在Windows 7上运行的是ActiveState的32位ActivePerl 5.14.2。我想用Git预提交钩子来检测被检入的程序是否有语法错误。(不知何故,我只是设法做了这样一个糟糕的promise。)所以作为一个测试程序,我随机记下了这个: 但是,它编译和执行时没有警告,退出时errorlevel为零。这是怎样的有效语法?

  • 我正在尝试登录数据库。我有一个带有属性url、用户名和密码的bean;带有登录参数的html页面(带有url的组合框,以及用户名和密码的输入文本字段);和一个jsp来处理请求。当我运行jsp时,bean中的所有属性都保持为空。我已经通过调试器运行了它,我可以看到它们都是空的。 以下是相关的HTML: 以下是我的观点: 和JSP: 在尝试初始化B()时,我不明白为什么我的所有属性都为null。编辑:

  • 问题内容: 注意到今天在我们的代码库中有一行代码,我认为肯定会因语法错误而使构建失败,但是测试通过了,显然它实际上是有效的python(在2.x和3中)。 条件表达式有时不需要空格: 如果LHS是变量,则不起作用: 但是它似乎仍然可以与其他类型的文字一起使用: 这是怎么回事,出于某种原因,它是否有意成为语法的一部分?这个奇怪的怪癖是已知/记录的行为吗? 问题答案: 令牌之间的空白 除逻辑行的开头或

  • 我正在将代码从Processing移植到Netbeans Java。我在运行多个java类时遇到问题。我的代码分为14个类,其中我的主要类仅包括这组代码: 无论项目何时运行,都只会弹出一个灰色背景的小屏幕,然而,仅此而已。在我看来,它无法读取其他13个类的所有代码。有什么想法吗?

  • 我正在尝试用Java制作一个与OpenGL(使用LWJGL 2)的窗口。当我尝试运行时,Eclipse BuiltInclassLoader出现了ClassNotFoundException错误。 我期望输出显示一个窗口,这是真正的输出: 线程“main”java.lang.noClassDeffounder中的异常错误:org/lwjgl/lwjglexception在enginetester.