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

发布于 2024-07-23 22:40:12 字数 849 浏览 4 评论 0原文

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

提前致谢。

Recently I had a problem using (pipe |-) when I wanted to communicate between two processes.
Basically, the child process couldn't process STDIN as fast as it was filled up by parent. This caused parent to wait until STDIN was free and made it run slow.

How big can STDIN be and is it possible to modify it. If yes, what is the best practice size?

Here is some code sample to show what I mean:

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);
     }
}

In this sample another_process_packet slower than process_packet. The reason I write the code like this is, I want to use same data comes from socket and actually get it once.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

苏璃陌 2024-07-30 22:40:12

当然,您可以在父进程中进行缓冲,并且仅当子进程的 fd 可写时才写入子进程(即写入不会阻塞)。 您可以使用正确的 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

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

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

You can of course buffer in the parent process, and only write to the child when the child's fd is writable (i.e., writing won't block). You can do this yourself with the right args to syswrite, or use an event loop:

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

Edit: This used to be untested, but I tested it, and it works. (I used perl -ne "sleep 1; print $_" as the slow child.) Writes proceed during the while loop, if possible, but never block the loop. At the end, you actually block until all the writes have completed.

My test scripts are on gist.github: http://gist.github.com/126488

You can see how the child blocks the blocking loop, but how it doesn't block the non-blocking loop. Obvious when you put it that way ;)

(Finally, as a general rule of thumb; if you are interacting with the network or with other processes, you should probably be using an event loop.)

雨巷深深 2024-07-30 22:40:12

大小是在内核中设置的。 您可以重新编译内核 具有更高的限制或使用中间缓冲进程

The size is set in the kernel. You can either recompile the kernel with a higher limit or use an intermediary buffer process.

老街孤人 2024-07-30 22:40:12

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

Process handle contains a member function named 'blocking'. Just set the blocking to 0, and the parent process will not be blocked.

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);
     }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文