【问题标题】:Perl: pipe a serialized hash to a forked processPerl:将序列化的哈希传递给分叉的进程
【发布时间】:2013-11-04 11:46:13
【问题描述】:

我不知道我的代码有什么问题。我正在尝试序列化父级内部的哈希并将其通过管道传输到应该反序列化的叉子。

#!/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;

...产生以下错误:

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

管道有问题吗? thaw 似乎没有反序列化检索到的标量值。可能检索到的标量值不正确。

我尝试在没有分叉或管道的情况下做一些半成品,并且它的工作原理:

#!/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";

逻辑上的区别不大,他?如果有人能向我解释更多这种行为,那就太好了。

【问题讨论】:

  • 检查发送和接收的字节数是否相同。

标签: perl serialization fork storable


【解决方案1】:

问题在于您尝试使用基于行的协议(在写入端附加"\n",在读取端使用&lt;&gt;chomp)但您的数据不是文本,并且可以包含自己的"\n"s,因此您的读者会在第一个处停下来将其删除。

您需要使用其他方法来发出序列化数据结束的信号,例如,您可以在写入端关闭管道并继续运行,直到读取端出现 EOF。事实上,Storable 有一对专门针对这种情况设计的函数:store_fdfd_retrieve。他们将在没有 EOF 的情况下检测结束的方式进行传输,因此您可以保持管道打开以进行更多传输。

这是使用来自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);

【讨论】:

  • 谢谢!这真的解释了很多,它现在正在工作。我已经有了一点线索,即字符串中的某些字符可能会干扰这种每行读取的使用。
  • 我并不想把我的调试 Data::Dumper 留在里面...但它没有造成任何伤害,所以我现在不会删除它。
  • 我没有将 Data::Dumper 行放入我的代码中;) - 但如果我需要进一步调试,我可能会使用它。
【解决方案2】:

问题是你假设散列是freezed 到一行。但情况并非总是如此,因为$hash_serialized 可能是一个包含多个\ns 的字符串。

因此,您应该阅读直到 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;

输出: val1

【讨论】:

  • 也谢谢,但我认为 Wumpus Q. Wumbley 的解决方案更好一些。尽管如此,它还是一个值得注意的替代方案,并进一步解释了整个事情。
猜你喜欢
  • 2020-06-14
  • 2011-02-01
  • 1970-01-01
  • 2013-09-27
  • 1970-01-01
  • 2020-09-24
  • 2017-02-19
  • 2023-03-28
相关资源
最近更新 更多