简体   繁体   English

Perl:将序列化哈希管道传递给分叉进程

[英]Perl: pipe a serialized hash to a forked process

I don't know whats wrong with my code. 我不知道我的代码有什么问题。 I'm trying to serialize a hash inside the parent and pipe it to the fork, where it should be deserialized. 我正在尝试序列化父级内部的哈希并将其传递给fork,它应该在其中进行反序列化。

#!/usr/bin/perl
use strict;
use warnings;
use Storable qw(freeze thaw);
use IO::Pipe;

my $pipe_to_fork = IO::Pipe->new();

my $fork = fork;
if ($fork == 0) { # actual fork scope
  $pipe_to_fork->reader();
  my $hash_serialized = <$pipe_to_fork>; # wait and retrieve the serialized hash from parent
  chomp $hash_serialized;
  my %hash_rebuild = %{thaw($hash_serialized)}; # deserialize the retrieved serialized hash
  exit;
}

my %hash = ('key1' => "val1", 'key2' => "val2");

$pipe_to_fork->writer();
$pipe_to_fork->autoflush(1);

my $hash_serialized = freeze(\%hash); # serialize the hash
print $pipe_to_fork $hash_serialized."\n";
sleep 5;

exit;

... produces the following error: ...产生以下错误:

Can't use an undefined value as a HASH reference at ./fork_serialize.pl line 14, <GEN0> line 1.

Is there something wrong with the pipe? 管道有问题吗? It seems that thaw doesn't deserialize the retrieved scalar value. 似乎thaw没有反序列化检索到的标量值。 Maybe the retrieved scalar value isn't correct. 也许检索到的标量值不正确。

I've tried to do some semilar things without forking or piping, and its working: 我试图做一些没有分叉或管道的半圆形东西,它的工作:

#!/usr/bin/perl
use strict;
use warnings;
use Storable qw(freeze thaw);

my %hash = ('key1' => "value1", 'key2' => "value2");
my $hash_serialized = freeze(\%hash);
my %hash_rebuild = %{thaw($hash_serialized)};

print $hash_rebuild{'key2'}."\n";

Not much of a logical difference, he? 没有太大的逻辑差异,他? It would be nice if anyone can explain me more of this behavior. 如果有人能够解释我更多这种行为,那就太好了。

The trouble is that you're trying to use a line-based protocol (appending the "\\n" on the write side, using <> and chomp on the read side) but your data is not text and can contain its own "\\n" s so your reader stops at the first one and chops it off. 麻烦的是你正在尝试使用基于行的协议(在写入端附加"\\n" ,在读取端使用<>chomp )但是你的数据不是文本而且可以包含它自己的"\\n"这么读者停在第一个和扒它关闭。

You need to use some other method of signaling the end of the serialized data, for example you could close the pipe on the write end and keep going until EOF on the read end. 您需要使用一些其他方法来发信号通知序列化数据的结尾,例如,您可以关闭写入​​端的管道并继续执行直到读取端的EOF。 In fact, Storable has a pair of functions designed for this exact situation: store_fd and fd_retrieve . 事实上, Storable有一对针对这种情况设计的功能: store_fdfd_retrieve They'll do the transfer in a way that detects the end without an EOF, so you can keep the pipe open for more transfers. 他们将以没有EOF的方式检测末端进行转移,因此您可以保持管道打开以进行更多转移。

Here's a version of the guts of your program using the fd functions from Storable : 这是使用Storablefd函数的程序内容的一个版本:

if ($fork == 0) { # actual fork scope
  $pipe_to_fork->reader();
  my %hash_rebuild = %{fd_retrieve($pipe_to_fork)}; # deserialize the retrieved serialized hash
  use Data::Dumper;$Data::Dumper::Useqq=1;print Dumper \%hash_rebuild;
  exit;
}

my %hash = ('key1' => "val1", 'key2' => "val2");

$pipe_to_fork->writer();
$pipe_to_fork->autoflush(1);

store_fd(\%hash, $pipe_to_fork);

The problem is that you're assuming the hash is freezed into one single line. 问题是你假设散列被freezed成一行。 But that's not always the case, since $hash_serialized could be a string containing multiple \\n s. 但情况并非总是如此,因为$hash_serialized可能是一个包含多个\\n s的字符串。

So instead of reading only one line in child side, you should read until the EOF and concatenate all the lines. 所以不要只读取子行中的一行,而应该读到EOF并连接所有行。

#!/usr/bin/perl
use strict;
use warnings;
use Storable qw(freeze thaw);
use IO::Pipe;

my $pipe_to_fork = IO::Pipe->new();

my $fork = fork;
if ($fork == 0) { # actual fork scope
  $pipe_to_fork->reader();
  my $hash_serialized;
  $hash_serialized .= $_ while (<$pipe_to_fork>);
  my %hash_rebuild = %{thaw($hash_serialized)}; # deserialize the retrieved serialized hash
  print $hash_rebuild{key1};
  exit;
}

my %hash = ('key1' => "val1", 'key2' => "val2");

$pipe_to_fork->writer();
$pipe_to_fork->autoflush(1);

my $hash_serialized = freeze(\%hash); # serialize the hash
print $pipe_to_fork $hash_serialized;

exit;

Output: val1 输出: val1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM