Perl:在完成执行之前移至循环中的下一个项目

Perl: Move to next item in loop before it is done executing

我有一个类似这样的 perl 脚本:

foreach my $addr ('http://site1.com', ...., 'http://site2.com') {
    my $script = `curl -m 15 $addr`;
    *do stuff with $script*
} 

-m 设置 15 秒的超时。如果用户按下一个键,有没有办法让它停止当前执行并移动到 foreach 中的下一个项目?我知道 last; 可以移动到下一个项目,但我不确定如何 link 将其移至被推送的键以及如何在 curl 脚本为 运行[=13= 时执行此操作]

编辑:所以根据答案,当 curl 是 运行 时似乎很难做到。是否可以在 curl 为 运行 时按下一个键,并让它跳到循环中的下一个项目 一旦 curl 脚本 returns (或15 秒后超时)?

基本上你有两个选择:

1.使用线程

创建一个新线程,在那里调用所需的系统函数。等待输出。在另一个线程中,检查用户输入。在输入时,您可以终止子进程。子进程完成后,您可以忽略用户输入。

这样的解决方案似乎相当复杂,需要大量同步,可能需要使用信号。有风险。

2。使用非阻塞 IO

请阅读 this 话题。它解释了如何从文件或管道进行非阻塞 IO 读取。您想要从管道(使用 open 创建)进行非阻塞读取,然后从 STDIN 进行非阻塞读取,循环。

似乎是一个可行的方法,但是,唉,也相当复杂。

你遇到的问题是,当你 运行 curl perl 交出控制权并等待完成时。它一直阻塞到 'done'。

所以要做到这一点并不像看起来那么容易。

正如另一张海报所暗示的那样 - 您可以使用多种并行处理选项。我建议最简单的方法是不再使用 'any' 键,而是需要 ctrl-c.

所以你会这样做:

foreach my $addr ('http://site1.com', ...., 'http://site2.com') {
     my $pid = open ( my $curl_fh, "-|", "curl -m 15 $addr" );
     $SIG{'INT'} = sub { print "Aborting fetch of $addr"; kill $pid };
     while ( <$curl_fh> ) {
         print;
     }
     #might want to set it to something else. 
     #undef means 'ctrl-c' will abort the whole program. 
     #IGNORE means exactly what it says on the tin.
     #important to change it though, as it has a specific pid it'll kill, 
     #and that might cause problems. 
     $SIG{'INT'} = undef;
} 

它所做的是配置 SIGINT(例如 ctrl-c),因此它不会终止您的程序,但会终止子进程。

如果您想查看其他选项,我会提供:

  • 多线程,在后台生成一个线程来[=44​​=] curl 获取并使用Thread::Queue 来回传递结果。 (Thread::Queue 支持非阻塞检查)。

  • 分叉 - 分叉一个子进程来执行 curl,并在按下某个键时使用您的 'main' 进程发送信号。

  • IO::Select 这样您就不会对进程进行阻塞读取。