Perl:写入速度之谜?

Posted

技术标签:

【中文标题】Perl:写入速度之谜?【英文标题】:Perl: write speed mystery? 【发布时间】:2010-11-26 08:03:04 【问题描述】:

输出速率怎么可能高于硬盘写入速率?

更新 1:我已更改以下内容:

    已关闭防病毒软件。没有变化。

    插入了新的物理磁盘并使用了第一个分区 为测试。 (初始测试的磁盘在 最后一个分区,与系统分区分开,但是 在同一个物理磁盘上。)。结果:有相同的 循环模式,但系统不再 测试期间无反应。写入速度为 稍高(可能是由于使用了第一个 分区和/或不再干扰系统 划分)。初步结论:有某种 系统分区的干扰。

    已安装 64 位 Perl。周期消失了 一切都在 2 秒的时间范围内稳定:55% CPU 开启 单核,写入速度约 65 MB/s。

    在原始驱动器上尝试使用 64 位 Perl。结果: 在。。。之间的某处。周期为 8 秒,CPU 20-50%, 35 - 65 MB/秒(而不是 0-100% 的深度循环,0 - 120 MB/秒)。系统只是轻微反应迟钝。 写入速度为 50 MB/秒。这支持了干涉理论。

    在 Perl 脚本中刷新。还没试过。


好的,我通过了first hurdle。我写了一个 Perl 可以生成非常大的文本文件(例如 20 GB)的脚本和 本质上只是一些:

print NUMBERS_OUTFILE $line;

其中 $line 是一个以“\n”结尾的长字符串。

当 Perl 脚本启动时,写入速率约为 120 MB/s (与脚本计算的内容一致, Process Explorer 和进程 Perl 的“IO 写入字节/秒” 在性能监视器中。)和单核上的 100% CPU 正在运行。我相信这个比率比写的要高 硬盘的速度。

然后在一段时间后(例如 20 秒和 2.7 GB 写入) 整个系统变得非常无响应,CPU 下降到 0%。这最后例如30秒。平均写入速度 这两个阶段的写入速度是一致的 硬盘。本文中提到的时间和大小 段落因运行而异。范围 1 GB 到目前为止,已经观察到第一阶段达到 4.3 GB。 这是transcript for the run with 4.3 GB。

一个 9.2 GB 的文本文件有几个这样的周期 测试中生成:

发生了什么事?


完整的Perl script 和BAT driver script(html 格式为 前标签)。如果两个环境变量 MBSIZE 和 OUTFILE 已设置,然后 Perl 脚本应该能够运行 在 Windows 以外的其他平台上保持不变。

平台:来自 ActiveState 的 Perl 5.10.0; (最初是 32 位,后来是 64 位);建造 1004。 Windows XP x64 SP2,无页面文件,8 GB RAM,AMD 四核 CPU, 500 GB Green Caviar 硬盘(写入速度 85 MB/s?)。

【问题讨论】:

【参考方案1】:

我和其他所有说问题是缓冲区填充然后清空的人一样。尝试打开 autoflush 以避免出现缓冲区(在 Perl 中):

#!/usr/bin/perl

use strict;
use warnings;

use IO::Handle;

my $filename = "output.txt";

open my $numbers_outfile, ">", $filename
    or die "could not open $filename: $!";

$numbers_outfile->autoflush(1);

#each time through the loop should be 1 gig
for (1 .. 20) 
    #each time though the loop should be 1 meg
    for (1 .. 1024) 
        #print 1 meg of Zs
        print $numbers_outfile "Z" x (1024*1024)
    

如果您要打印一点、做一些工作、打印一点、做一些工作等,缓冲区可能会很好。但是如果您只是要将数据爆破到磁盘上,它们可能会导致奇怪的行为。您可能还需要禁用文件系统正在执行的任何写入缓存。

【讨论】:

谢谢。我现在已经尝试了 64 位 Perl(请参阅更新的问题),但下一步将尝试打开 autoflush。 请记住,如果文件系统保留了缓冲区,您可能还需要修改文件系统。 autoflush 将在每个打印元素之后进行系统调用。在您的示例中,性能会很好,因为一次只有 1 MB。但是如果你打印 'a', 'b', 'c', 'd' 这将是非常糟糕的,因为这是四个系统调用,每个调用一个字符......注意这一点。【参考方案2】:

所有数据在被有效地放置在物理磁盘中之前都缓存在缓冲区中。一个来自系统的缓冲区,另一个位于磁盘本身的缓冲区(可能是 32MB 的缓冲区)。当您填充这些缓冲区时,您的程序会以全速和 100% CPU 运行。一旦缓冲区已满,您的程序就会等待磁盘,这比内存和缓冲区慢得多,而且这种等待使您停止消耗所有这些 CPU。

也许你可以让你的代码从一开始就“等待磁盘”,方法是使用一些 Perl 等价于 fflush()

【讨论】:

我希望有文件缓冲区。但不是几 GB(?) 在 Linux 系统上,缓冲区通常配置为传播到几乎所有空闲 RAM。【参考方案3】:

也许操作系统正在尽可能快地写入磁盘(85 MB/s),并将多余的 35 MB/s 放入缓冲区,当它填满时,正在暂停应用程序以刷新缓冲区。由于缓冲区以 85 MB/s 的速度排空,因此您预计排空时间是填充时间的 35/85 = ~0.4 倍。如果我足够眯眼的话,这与您的图表大致兼容。

您可以将缓冲区的大小估计为暂停时间和磁盘速度的乘积。

【讨论】:

【参考方案4】:

看图表! 绿线表示平均磁盘队列长度。在某一时刻,它达到一个峰值,然后 CPU 变为 0。 IO Writes 也变为 0。它会恢复正常,直到显示第二个峰值。然后 CPU 和 IO 写入恢复正常。然后 IO 和 CPU 再次下降,在下一个队列峰值再次上升。再往下,再往上……

可能是磁盘当时正在执行物理写入。但是,也可能是系统此时正在执行磁盘验证,读取它刚刚写入的数据以验证写入,确保数据写入正确。

我注意到的另一件事是 2.7 GB 大小。由于您在 Windows 系统上运行它,我变得有点怀疑,因为这是关于 Windows 可以处理的内存量,作为 32 位进程。 64 位 Windows 将为应用程序提供高达 3 GB 的 RAM(少一点),但随后需要再次释放它。您可能希望使用 Process Explorer 检查正在使用的 RAM 量和 IO 读取量。

也许使用 64 位 Perl 版本...

【讨论】:

关于 2.7 GB:我不知道是否可能超过 3 GB,但它已经可以在 1 GB 时发生。例如,在我写这篇文章之前,我再次运行它,第一阶段以 1.2 GB 结束(介于 1139 MB 和 1273 MB 之间)。 RAM 量是什么意思? Perl 进程的金额? Perl 进程的“私有字节”在运行期间保持在 4 MB 不变。脚本启动时大约有 6.3 GB RAM 可用。 我刚刚又试了一次。这次第一阶段以大约 4.3 GB 结束(介于 4.19 GB 和 4.41 GB [4288.3 MB;4513.7 MB] 之间)。以下是运行记录:pil.sdu.dk/1/until2039-12-31/PerlPerfTranscript_2009-09-07b.txt 我会尝试从 ActiveState 安装 64 位版本的 Perl 并进行测试。 32 位进程将无法使用超过 3 GB 的 Windows。 1 GB 始终为 Windows 保留,部分内存将由 Perl 本身使用,外加一些数据。可能是某些加载项/插件在分配此 RAM 时未将其报告给您的图表。尽管磁盘似乎报告了写入 IO,但它似乎只是在将其写入磁盘之前先填充了自己的内存缓冲区。

以上是关于Perl:写入速度之谜?的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl 中写入文件

Perl.com 域名劫持之谜

在 Perl 中写入文件时测试错误处理的最简单方法是啥?

Perl 在可存储写入期间是不是安全地延迟 INT 信号?

当子进程和父进程在 Perl 中写入同一个日志文件时进程卡住(在 Windows 中)

“无法识别的类型'员工'。忽略。C:/ .....”从.xml读取输入并将输出写入.xls文件+ perl时出错