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

标签 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 源代码,但很惭愧地说我无法从中看出。)

感谢您的任何提示。

最佳答案

Capture::Tiny::capture 的文档表明文件确实被使用

Captures are normally done to an anonymous temporary filehandle.

这可以在 _capture_tee 的源代码中看到sub,用作所有方法的通用例程。大约在这个子程序的中间,我们发现了一个 call to File::Temp->new除非使用命名文件(见下文),否则会发生这种情况。其余的处理过程可以仔细追踪。

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

To capture via a named file (e.g. to externally monitor a long-running capture), provide custom filehandles as a trailing list of option pairs:

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;  

The filehandles must be read/write and seekable. Modifying the files or filehandles during a capture operation will give unpredictable results. Existing IO layers on them may be changed by the capture.

(如果完成此操作,则不会调用 File::Temp,如上所述。请参阅源代码。)

如果此磁盘事件是一个问题,您可以使用管道 open读取cmd的输出 (首先将其输入写入文件),或使用 qx (反引号)。但随后您就必须合并或重定向 STDERR 并经过更多步骤来检查和处理错误。

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

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


粗略的草图

所有方法到_capture_tee的"dispatch"已完成in the beginning ,其中一组标志在 goto &func 取走之前被 unshift 编辑为 @_,以区分方法。对于capture,这是1,1,0,0,它在中设置变量$do_stdout$do_stderr _capture_tee。然后使用它们来设置 %do hash ,哪些键是 iterated over to set up $stash .

如果将额外的参数传递给 capture (对于命名文件),则 $stash->{capture} is set ,否则分配一个 File::Temp 对象。 $stash 稍后出现 passed to _open_std重定向发生的地方。

还有很多事情正在发生,但主要与局部球体和图层的操作有关。


最常见的调用写入标量

run3 \@cmd, \my $in, \my $out, \my $err;

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

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

my @cmd = qw(ls -l .);
open my $fh, '>', \my $cmd_out;  # not a real filehandle ...
run3 \@cmd, \undef, $fh;         # ... so this won't work

中止

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

这是因为对标量的open 并未设置真正的文件句柄。请参阅this post .

如果文件句柄打开到一个文件,则按预期工作,写入该文件。与 Capture::Tiny 相比,这很可能会导致更高效的磁盘 I/O 操作。

关于perl - Perl 的 Capture::Tiny::capture() 是否避免了使用 system() 时所需的磁盘 io?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49536450/

相关文章:

python - Linux 上 python 中的程序间通信

java - Java 中的缓冲和非缓冲流

mysql - 如何匹配两个数据库表中的相关值?

html - 为什么匹配运算符不匹配任何东西?

python - 如何使用正则表达式删除括号内的文本?

Haskell ReplicateM IO

Perl从html文件中提取模式

multithreading - 在perl中使用并发线程的简单方法?

c# - 从硬盘快速读取

c - 尝试在 Ubuntu 中打开相对路径不起作用