如何使用alarm perl函数为Windows上运行的Python命令设置超时?

问题描述 投票:0回答:1

在 Perl 脚本中,我想运行一个 Python 命令,如果 5 秒后仍未结束,则将其终止。这是我使用的代码:

use strict;
use warnings FATAL => 'all';

use autodie qw(open);

my $fcmd;
my $status;
my $child_pid;

eval {
    # If we receive a ALRM signal, we kill the child process (which will be Python)
    $SIG{ALRM} = sub { kill( 9, $child_pid ); die("alarm\n"); };
    # Set the timeout to 5 seconds
    alarm(5);
    
    # Run infinite loop in Python
    $child_pid = open( $fcmd, "python -c \"while True: 1+1\" 2>&1 |" );
    
    # Looping on $fcmd also acts as waitpid
    # This is blocking while the child process does not end
    while ( my $line = <$fcmd> ) {
        print("PRINT: $line\n");
    }
    
    close $fcmd;
    alarm(0); 
    $status = $?;
};

if ($@) {
    print("timeout\n");
}

在此脚本中,我将警报设置为 5 秒,并使用

open
在 Python 进程内运行无限循环(我添加了一些重定向和管道以便能够读取输出)。 然而,脚本永远不会结束,我的输出中没有任何内容。

为什么指令没有被警报信号停止?

注意:我不能使用任何其他 Perl 模块。


阅读@Bork评论后,我更改了Python命令来打印一些东西:

$child_pid = open( $fcmd, "python -c \"while True: print('Hello')\" 2>&1 |" );

这成功了!我正确地在输出中包含“Hello”,并且在 5 秒后停止。 如果命令在

open
输出数据中执行,则行为似乎有所不同。我怎样才能修复这个问题以在两种情况下具有相同的行为?

windows perl
1个回答
0
投票
alarm   (Win32) Emulated using timers that must be explicitly polled
        whenever Perl wants to dispatch "safe signals" and therefore
        cannot interrupt blocking system calls.

perldoc perlport

Windows 没有 SIGALRM,并且不能依赖 Perl 模拟它的方式来中断 I/O 阻塞的进程。

最明显的解决方法 - 使用非阻塞 I/O 和

select
等待,直到收到一些输入或达到超时,似乎也不起作用,因为
select
被标记为“仅在套接字上实现”。

暴力解决方法可能是分叉另一个子进程,该子进程会休眠,然后尝试杀死第一个子进程,但使用 IPC::Run 或异步框架会更好。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.