【问题标题】:How can I prevent the parent from blocking when writing to a child?如何防止父母在给孩子写信时阻止?
【发布时间】:2010-11-01 10:27:01
【问题描述】:

最近,当我想在两个进程之间进行通信时,我在使用 (pipe |-) 时遇到了问题。 基本上,子进程无法像父进程那样快速处理 STDIN。这导致父级等待 STDIN 空闲并使其运行缓慢。

STDIN 可以有多大,是否可以修改它。如果是,最佳实践规模是多少?

这里有一些代码示例来说明我的意思:

if ($child_pid = open($child, "|-"))
{
    $child->autoflush(1);

    # PARENT process
    while (1)
    {

             # Read packet from socket save in $packet
             process_packet($packet);

             # forward packet to child
             print $child $packet;
     }
}
else
{
     die "Cannot fork: $!" unless defined $child_pid;
     # CHILD process
     my $line;  

     while($line = <STDIN>)
     {
         chomp $line;
         another_process_packet($line);
     }
}

在此示例中,another_process_packetprocess_packet 慢。我这样写代码的原因是,我想使用来自套接字的相同数据并实际获取一次。

提前致谢。

【问题讨论】:

  • 你能发布你的生产者和消费者脚本的缩短版本吗?
  • brain d foy,感谢您的更改。犯了这么多错误有点尴尬……

标签: perl ipc interprocess


【解决方案1】:

大小在内核中设置。您可以使用更高限制的recompile the kernel 或使用intermediary buffer process

【讨论】:

    【解决方案2】:

    你当然可以在父进程中缓冲,只有当子进程的fd可写时才写入子进程(即写入不会阻塞)。您可以自己使用正确的 args 进行 syswrite,或使用事件循环:

    use AnyEvent;
    use AnyEvent::Handle;
    
    # make child, assume you write to it via $fh
    
    my $done = AnyEvent->condvar;
    my $h = AnyEvent::Handle->new( fh => $fh );
    
    while( you do stuff ){
        my $data = ...;
        $h->push_write($data); # this will never block
    }
    
    $h->on_drain(sub { $done->send });
    $done->wait; # now you block, waiting for all writes to actually complete
    

    编辑:这曾经是未经测试的,但我测试过它,它可以工作。 (我使用perl -ne "sleep 1; print $_" 作为慢孩子。)如果可能,在while 循环期间继续写入,但不要阻塞循环。最后,您实际上会阻塞,直到所有写入完成。

    我的测试脚本在 gist.github 上:http://gist.github.com/126488

    您可以看到孩子如何阻塞阻塞循环,但它如何不阻塞非阻塞循环。当你这样说时很明显;)

    (最后,作为一般经验法则;如果您正在与网络或其他进程交互,您可能应该使用事件循环。)

    【讨论】:

    • 谢谢顺便说一句,但我不想以任何理由阻止父母。可能我需要阅读更多关于 AnyEvent 的信息。谢谢。
    • 好吧,那就不要屏蔽了。我只在最后阻塞,因为进程即将退出,如果你带着未写入的数据退出,孩子将永远看不到它。如果这是一个长时间运行的过程,则无需阻止。
    • 好吧,看来 AnyEvent::Handle 工作得很好,但我仍然有一些问题。在我停止孩子一段时间以使 STDIN 缓冲区满后,父母将数据推送到 wbuf 中,这就是它应该做的事情,但事情是在我释放孩子之后,孩子只处理它保存在 STDIN 缓冲区中的那些数据,并且永远不会触摸 wbuf。然后强制 wbuf 将其数据推送到 STDIN,我使用 on_drain(sub {$done->send}) 和我使用 $done->recv 后的一行让父母等待,但在此期间我丢失了一些数据,因为他们来自插座。知道如何处理这个问题吗???
    【解决方案3】:

    进程句柄包含一个名为“blocking”的成员函数。只需将阻塞设置为0,父进程就不会被阻塞。

    if ($child_pid = open($child, "|-"))
    {
        $child->blocking(0);    # Key to the solution.
        $child->autoflush(1);
    
        # PARENT process
        while (1)
        {
    
                 # Read packet from socket save in $packet
                 process_packet($packet);
    
                 # forward packet to child
                 print $child $packet;
         }
    }
    else
    {
         die "Cannot fork: $!" unless defined $child_pid;
         # CHILD process
         my $line;  
    
         while($line = <STDIN>)
         {
             chomp $line;
             another_process_packet($line);
         }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-08-24
      • 1970-01-01
      • 1970-01-01
      • 2011-11-10
      • 2021-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-26
      相关资源
      最近更新 更多