如何在写信给孩子时阻止父母阻止?

时间:2009-06-09 09:59:58

标签: perl ipc interprocess

最近,当我想在两个进程之间进行通信时,我遇到了使用(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_packet慢于process_packet。我编写这样的代码的原因是,我想使用来自套接字的相同数据并实际获得它一次。

提前致谢。

3 个答案:

答案 0 :(得分:6)

当然,您可以在父进程中进行缓冲,并且只在子进程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

你可以看到孩子如何阻止阻塞循环,但是它如何阻止非阻塞循环。当你这么说时显而易见;)

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

进程句柄包含名为“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);
     }
}