perl:一个父母,许多孩子 - 父母中有一个管道阅读器?
Posted
技术标签:
【中文标题】perl:一个父母,许多孩子 - 父母中有一个管道阅读器?【英文标题】:perl: one parent, many children - single pipe reader in parent? 【发布时间】:2018-10-09 14:31:12 【问题描述】:是否有可能在 perl 中以这样一种方式建立一个管道,即父级只有一个 READER 管道,而许多子级在它们开始/退出时写入它?
典型的食谱代码是:
#!/usr/bin/perl -w
# pipe2 - use pipe and fork so child can send to parent
use IO::Handle;
pipe(READER, WRITER);
WRITER->autoflush(1);
if ($pid = fork)
close WRITER;
chomp($line = <READER>);
print "Parent Pid $$ just read this: `$line'\n";
// do what you need
else
die "cannot fork: $!" unless defined $pid;
close READER;
print WRITER "Child Pid $$ is sending this\n";
close WRITER; # this will happen anyway
exit;
让我们假设我需要我的父母“阅读器”从多个孩子那里获取消息的情况,是否可以在不保留管道列表的情况下做到这一点,每个孩子一个?我无法在父级中关闭 WRITER,因为下一个子级将无法获得有效的句柄来写入。我还需要父级继续其常规操作,而不是阻止来自管道的任何客户端数据。
我需要的伪代码:
# parent code
pipe (READER, WRITER)
fork_random_number_of_children(READER,WRITER)
on_some_tick =>
my $data = read_from(READER, non_blocking)
if (data) print "Hey some child sent me: $data"
else print "No data, going back life"
do_other_things_before_next_tick()
child_job(R,W) # lets assume this is called for each child fork
close (R); # no problem, its a copy
sleep (random duration)
print W, "Message from child with pid $$"
exit 0
【问题讨论】:
一个简单的服务器可以很好地服务吗? (特别是那些回调。)在我看来,这位慢跑的教皇可能正在推动它。 【参考方案1】:我认为没有必要在父级中close WRITER
。这可能是一个很好的做法,但是由于在关闭它之后您不能为新的子进程重用相同的管道,所以这是一个不这样做的好借口。如果在完成启动所有子进程之前保持WRITER
处于打开状态,则可以将管道与多个子进程一起使用。这是一个概念证明:
use IO::Handle;
use POSIX ':sys_wait_h';
pipe(READER,WRITER);
WRITER->autoflush(1);
sub child_process
my $stage = shift;
close READER; # also a best but optional practice
srand($$);
do
sleep 1 + 5*rand();
print WRITER "Child Pid $$ ($stage) is sending this\n";
while (rand > 0.5);
exit;
# initial set of children
for (my $i=0; $i<5; $i++)
if (fork() == 0)
child_process("LAUNCH");
# parent
my ($rin,$rout) = ('');
vec($rin,fileno(READER),1) = 1;
while (1)
# non-blocking read on pipe
my $read_avail = select($rout=$rin, undef, undef, 0.0);
if ($read_avail < 0)
if (!$!EINTR)
warn "READ ERROR: $read_avail $!\n";
last;
elsif ($read_avail > 0)
chomp(my $line = <READER>);
print "Read in Parent $$: '$line'\n";
else
print STDERR "No input ... do other stuff\n";
# start some run-time child processes
if (time-$^T > 5 && time-$^T < 10)
# launch a few more children in the middle of the program
if (fork() == 0)
child_process("RUN");
sleep 1;
last if waitpid(-1,&WNOHANG) < 0; # no more children are alive
close WRITER; # now it is safe to do this ...
【讨论】:
谢谢。进行更多测试 - 似乎按我想要的方式工作!你说这是一个概念证明。作为练习,我需要调查哪些关键问题? 首先,您应该检查诸如pipe 之类的系统调用的返回值以及fork 是否返回undef 以指示失败。 使用词法文件句柄而不是全局裸词通常是一个好主意,以防止与其他地方的代码发生冲突,这也意味着它们会在超出范围时自动关闭,这样更易于管理。pipe(my $reader, my $writer) or die "pipe failed: $!";
你也应该使用strict
和warnings
。
您也可以使用像Mojo::IOLoop 或IO::Async 这样的事件循环,它们旨在完成这类事情(在类似的低级别,或者自己管理所有内容),而不是管理一个自己选择循环和waitpid。如果你有兴趣,我可以举个例子。
二阶问题:写入操作的同步,从管道读取太慢导致管道填充和写入器被阻塞,检查所有函数调用的返回值是否有错误。 @zdim - 在您确定不会再产生任何将使用写入端的子级之前,您无法关闭父级中的写入端。以上是关于perl:一个父母,许多孩子 - 父母中有一个管道阅读器?的主要内容,如果未能解决你的问题,请参考以下文章