Perl的Capture :: Tiny :: capture()是否避免使用system()时需要的磁盘io?

时间:2018-03-28 13:54:33

标签: perl io

从Perl脚本调用外部程序时,Capture :: Tiny是否在使用system()时避免使用磁盘io?使用任何一种时,我的性能基本相同。一位同事正在使用我的代码并告诉我它正在锤击他的磁盘。我(也许)在我的本地计算机上运行并写入本地磁盘时没有这个问题。

我以前这样做过:

open($fhStdin, ">stdin.txt");
print $fhStdin "some text\n";
close($fhStdin);
system("cmd < stdin.txt 1> stdout.txt 2> stderr.txt"); 
# open and read stdout.txt
# open and read stderr.txt

改为:

($stdout, $stderr, $exit) = capture {
    open($fhStdin, '| cmd');
    print $fhStdin "some text\n";
    close($fhStdin);
};

但NYTProf告诉我他们运行的时间基本相同(但NYTProf会从子程序时间中删除磁盘io开销)。所以我想知道capture()是否正在写入引擎盖下的临时文件? (我试着阅读Tiny.pm源代码,但我很惭愧地说我无法分辨出来。)

感谢您的任何提示。

1 个答案:

答案 0 :(得分:4)

Capture::Tiny::capture的文档说明确实使用了文件

  

通常对匿名临时文件句柄进行捕获。

这可以在_capture_tee sub的源代码中看到,用作所有方法的通用例程。在这个子程序的大约一半时间内,我们发现call to File::Temp->new正在发生,除非使用命名文件(见下文)。其余的处理可以小心追踪。

文档继续提供一种通过命名文件来监视所有这些的方法

  

要通过命名文件捕获(例如,从外部监视长时间运行的捕获),请提供自定义文件句柄作为选项对的尾随列表:

my $out_fh = IO::File->new("out.txt", "w+");
my $err_fh = IO::File->new("out.txt", "w+");
capture { ... } stdout => $out_fh, stderr => $err_fh;  
     

文件句柄必须是可读/写且可搜索的。在捕获操作期间修改文件或文件句柄将产生不可预测的结果。它们上的现有IO层可能会被捕获更改。

(如果这样做,那么对File::Temp的调用就没有了,如上所述。参见来源。)

如果此磁盘活动有问题,您可以使用管道open来读取cmd的输出 (首先将其输入写入文件),或使用qx(反引号)。但是你必须合并或重定向STDERR并通过更多的箍来检查和处理错误。

另一种选择是使用IPC::Run3。虽然它也uses files它提供了更多的选项,可以利用它们来减少磁盘I / O,或者完全避免磁盘。 (使用文件句柄打开到标量(内存中)调用的想法不起作用,因为这不是真正的文件句柄。

“核”选项是更复杂的IPC::Run,它可以在不使用磁盘的情况下获取输出。

粗略草图

_capture_tee的所有方法的“调度”已完成in the beginning,其中unshift@_获取goto &func之前将capture标记为1,1,0,0离开,区分方法。对于$do_stdout,这是$do_stderr,在_capture_tee中设置变量captureFile::Temp。然后,这些用于设置%do hash,其中的密钥为iterated over to set up $stash

如果将额外参数传递给$stash(对于命名文件),则传递$stash->{capture} is set,否则会分配run3 \@cmd, \my $in, \my $out, \my $err; 个对象。 my @cmd = qw(ls -l .); open my $fh, '>', \my $cmd_out; # not a real filehandle ... run3 \@cmd, \undef, $fh; # ... so this won't work 后来passed to _open_std发生了重定向。

还有很多,但主要与操纵本地化的球和层有关。

最常见的调用写入标量

open

但是这会使用文件,如How it works下的文档中所述。

尝试通过写入打开到标量的文件句柄来欺骗它不使用文件

Capture::Tiny

中止
run3(): Invalid argument redirecting STDOUT at ...

这是因为标量的df[df['Event'].isin(['event1', 'event2', 'event3'])] 没有设置真正的文件句柄。请参阅this post

如果文件句柄打开到文件,则按预期工作,写入该文件。与import pandas as pd df = pd.DataFrame([['event1','01:22:52.134'],['event2','03:21:31.123'], ['event1','21:12:52.544'],['event3','23:12:31.216'],['event1','10:22:02.134'],['event2','06:52:48.184'], ['event3','12:52:46.188'], ['event3','06:52:46.184'], ['event1','13:33:46.235'], ['event2','14:35:12.235'], ['event3','14:59:12.177']], columns=["Events",'Time']) df 的操作相比,这可能会导致更高效的磁盘I / O操作。