使用 STDOUT(屏幕)与常规文件的性能
Performance using STDOUT (screen) vs regular file
我一直在做一些研究,我得到了这种情况。如果你想写入 STDOUT(屏幕),你将无法执行多线程脚本,它可以比简单的单线程脚本更快地打印数据。但是,如果您写入这样的文件:
myPrinter.perl > myPrint
结果发生了变化,您可以看到多线程方法获得了更好的时间。我的疑问是,由于 STDOUT(屏幕)或输出文件都是共享资源,访问时间不会相似吗? 为什么多线程方法只会更好地写入文件?
我在实验中使用的 perl 脚本是:
单线程
for my $i (1..100000000){
print("things\n");
}
多线程
use threads;
use Thread::Queue 3.01 qw( );
use constant NUM_WORKERS => 4;
sub worker {
for my $i (1 .. 25000000){
print("things\n");
}
}
my $q = Thread::Queue->new(); #::any
async { while (defined( my $job = $q->dequeue() )) { worker($job); } }
for 1..NUM_WORKERS;
for my $i (1 .. 4){
$q->enqueue($i);
}
$q->end();
$_->join for threads->list;
Credits:队列实现取自 ikegami 答案之一。
输出数据的速度受目标性能的限制。如果写入本地文件,则性能会受到底层 OS、文件系统和磁盘速度的限制。如果您写入网络文件系统上的文件,它会进一步受到网络速度和文件服务器性能等的限制。一些 OS 级别的缓冲有助于加快速度。
如果写入 STDOUT,则取决于 STDOUT 的目标是什么。 STDOUT 可以重定向到文件,通过管道传输到另一个进程,也可以打印到终端。在所有这些情况下,写入速度再次取决于目标介质。与本地文件相比,终端的写入速度通常非常慢。但同样,这不是 STDOUT 与文件的问题,而是 STDOUT 在哪里结束的问题。
一个例子,跟进我的评论。我从问题中了解到,您将终端上结束的 STDOUT
打印与重定向到文件的打印进行比较。
定时打印到控制台和文件
time perl -we'print "hello\n" for 1..1_000_000'
时间:0.209u 1.562s 0:17.65 9.9% 0+0k 0+0io 0pf+0w
(tcsh)
time perl -we'print "hello\n" for 1..1_000_000' > many_writes.out
时间:0.104u 0.005s 0:00.11 90.9% 0+0k 0+11720io 0pf+0w
即 17.65
秒对 0.11
秒。打印到终端非常非常慢。
对于多线程,我预计差异会更加明显。
这可以解释为写入 STDOUT 需要某种形式的内部锁定。
当 STDOUT 连接到终端时,输出在每个换行后刷新。否则,STDOUT 仅每 4 KiB 或 8 KiB 刷新一次(取决于您的 Perl 版本)。后一种情况可能需要更少或更短的锁。
您可以使用 |cat
而不是 >file
来获得相同的效果。
如果您的实际工作人员花费更少的时间写入 STDOUT,则此问题应该会消失。
我一直在做一些研究,我得到了这种情况。如果你想写入 STDOUT(屏幕),你将无法执行多线程脚本,它可以比简单的单线程脚本更快地打印数据。但是,如果您写入这样的文件:
myPrinter.perl > myPrint
结果发生了变化,您可以看到多线程方法获得了更好的时间。我的疑问是,由于 STDOUT(屏幕)或输出文件都是共享资源,访问时间不会相似吗? 为什么多线程方法只会更好地写入文件?
我在实验中使用的 perl 脚本是:
单线程
for my $i (1..100000000){
print("things\n");
}
多线程
use threads;
use Thread::Queue 3.01 qw( );
use constant NUM_WORKERS => 4;
sub worker {
for my $i (1 .. 25000000){
print("things\n");
}
}
my $q = Thread::Queue->new(); #::any
async { while (defined( my $job = $q->dequeue() )) { worker($job); } }
for 1..NUM_WORKERS;
for my $i (1 .. 4){
$q->enqueue($i);
}
$q->end();
$_->join for threads->list;
Credits:队列实现取自 ikegami 答案之一。
输出数据的速度受目标性能的限制。如果写入本地文件,则性能会受到底层 OS、文件系统和磁盘速度的限制。如果您写入网络文件系统上的文件,它会进一步受到网络速度和文件服务器性能等的限制。一些 OS 级别的缓冲有助于加快速度。
如果写入 STDOUT,则取决于 STDOUT 的目标是什么。 STDOUT 可以重定向到文件,通过管道传输到另一个进程,也可以打印到终端。在所有这些情况下,写入速度再次取决于目标介质。与本地文件相比,终端的写入速度通常非常慢。但同样,这不是 STDOUT 与文件的问题,而是 STDOUT 在哪里结束的问题。
一个例子,跟进我的评论。我从问题中了解到,您将终端上结束的 STDOUT
打印与重定向到文件的打印进行比较。
定时打印到控制台和文件
time perl -we'print "hello\n" for 1..1_000_000'
时间:0.209u 1.562s 0:17.65 9.9% 0+0k 0+0io 0pf+0w
(tcsh)
time perl -we'print "hello\n" for 1..1_000_000' > many_writes.out
时间:0.104u 0.005s 0:00.11 90.9% 0+0k 0+11720io 0pf+0w
即 17.65
秒对 0.11
秒。打印到终端非常非常慢。
对于多线程,我预计差异会更加明显。
这可以解释为写入 STDOUT 需要某种形式的内部锁定。
当 STDOUT 连接到终端时,输出在每个换行后刷新。否则,STDOUT 仅每 4 KiB 或 8 KiB 刷新一次(取决于您的 Perl 版本)。后一种情况可能需要更少或更短的锁。
您可以使用 |cat
而不是 >file
来获得相同的效果。
如果您的实际工作人员花费更少的时间写入 STDOUT,则此问题应该会消失。