在perl中将数据从子进程返回到父进程

时间:2014-05-07 09:44:00

标签: perl background return fork parent

我正在使用Forks :: Super运行8个后台进程,这些进程应该在完成时将结果返回给父进程。我尝试了几种方法却没有成功。我目前正在尝试使用bg_eval方法。子进程返回Data :: Table引用。但是,当我尝试执行Data :: Table方法之一(nofRow)时,我收到以下错误:

  

找不到对象方法" nofRow"通过包"福克斯::超级:: LazyEval :: BackgroundScalar"在top_interest_per_sub_faster.pl第135行,第268行。

我的perl代码的相关部分如下。我运行一个方法" merge_summarize_tables"使用bg_eval并将结果推送到数组@summary_files_subset_results。

  use Forks::Super 'bg_eval';

  my $result = bg_eval{merge_summarize_tables(@spliced_files)};
  push(@summary_files_subset_results, $result);

稍后当我尝试执行其中一个表方法时,我得到了上面分享的错误:

my $hits_per_interest_per_subscriber = $summary_files_subset_results[0];
print("Rows merged " . commify($hits_per_interest_per_subscriber->nofRow) ."\n");

该方法的简化版本称为:

sub merge_summarize_tables
{  
  # removing a lot of irrelevant code here. In the end the function returns a table ...
  my $table_to_merge = Data::Table::fromCSV($file, 0, undef);
  return $table_to_merge;
}

3 个答案:

答案 0 :(得分:1)

在这种情况下,您似乎希望手动调用_fetch。它似乎超载了各种东西,如解除引用,添加,字符串连接等,但不适用于对象方法调用。

但这有效:

#!/usr/bin/env perl
use v5.14;
use warnings;

use Forks::Super qw(bg_eval);
use Data::Printer colored => 0;

package C {
        use Moo;

        has 'x' => (is => 'rw', required => 1);
};

sub c_one {
        my $c = C->new(x=>1);
        return $c;
}

# main
my $res = bg_eval { c_one(); };
say ref($res);
say "-----";

my $res2 = $res->_fetch();
p $res2;
say "x = ".$res2->x;
exit;

答案 1 :(得分:1)

我通过将整个解决方案迁移到线程而不是分支来实现我想要的结果。从分支进程中作为线程运行的子进程检索数据要容易得多。线程在不同的CPU上运行并使用所有内核。我也在屏幕上输出不像bg_eval。在这种情况下,这是一个更好,更简单的解决方案。

这是我更新的代码:

use threads;

# some code to create @spliced_file array of file names

push(@threads, threads->create(\&merge_summarize_tables, @spliced_files)); 

# the method merge_summarize_tables returns a data::table object

foreach (@threads) {
        push(@summary_files_subset_results, $_->join);
        print "Child finished\n";
}

my $hits_per_interest_per_subscriber = $summary_files_subset_results[0];
print("Rows merged " . commify($hits_per_interest_per_subscriber->nofRow) ."\n");

答案 2 :(得分:0)

Forks::Super作者在这里。 bg_eval的返回值必须是Forks::Super::LazyEval::BackgroundScalar对象,因此尝试直接返回其他类型的对象是一个问题。我会考虑如何解决这个问题。

一种解决方法是将对象包装在数组引用或哈希引用中,并从父进程中的引用中提取它。例如:

# with array reference
$result = bg_eval { [ merge_summarize_tables(@spliced_files) ] };
...
my $hits = $summary_files_subset_results[0];
print("Rows merged " . commify($hits->[0]->nofRow) ."\n");


# with hash reference
$result = bg_eval { { payload => merge_summarize_tables(@spliced_files) } };
...
my $hits = $summary_files_subset_results[0];
print("Rows merged " . commify($hits->{payload}->nofRow) ."\n");


# a scalar reference works too
$result = bg_eval { \merge_summarize_tables(@spliced_files) };
...
my $hits = $summary_files_subset_results[0];
print("Rows merged " . commify($$hits->nofRow) ."\n");