当前位置: 首页 > 面试题库 >

如何在Perl中设置文件读取缓冲区大小以针对大型文件进行优化?

贺奕
2023-03-14
问题内容

我知道Java和Perl都非常努力地在读取文件时找到一种适合所有默认缓冲区大小的大小,但是我发现他们的选择越来越过时,并且在更改默认选择时遇到问题Perl。

对于Perl,我认为默认情况下会使用8K缓冲区(类似于Java的选择),我无法使用perldoc网站搜索引擎(确实是Google)找到关于如何增加默认文件输入缓冲区大小的参考,例如,
64K。

通过上面的链接,显示8K缓冲区如何不扩展:

如果每行通常大约包含60个字符,则10,000行的文件中包含大约610,000个字符。使用缓冲逐行读取文件仅需要75个系统调用和75个等待磁盘的时间,而不是10,001。

因此,对于一个具有每行60个字符(包括末尾的换行符)且具有8K缓冲区的5000万行文件,它将进行366211系统调用以读取2.8GiB文件。顺便说一句,您可以通过在任务管理器进程列表中查看磁盘I
/ O读取增量(至少在Windows中,* nix的顶部也以相同的方式显示相同的东西)来确认此行为,作为您的Perl程序读取文本文件需要10分钟:)

有人问有关在perlmonks上增加Perl输入缓冲区大小的问题,有人在这里回答说,您可以增加“
$ /”的大小,从而增加缓冲区的大小,但是来自perldoc:

将$ /设置为对整数的引用,包含整数的标量或可转换为整数的标量将尝试读取记录而不是行,最大记录大小为引用的整数。

因此,我假设在使用典型值时,这实际上并不会增加Perl从磁盘读取的缓冲区大小:

while(<>) {
    #do something with $_ here
    ...
}

“逐行”的成语。

现在,上面代码的不同版本“一次读取一条记录然后将其解析为行”的版本通常会更快,并且绕过标准习语的根本问题,并且无法更改默认缓冲区大小(如果确实不可能),因为您可以将“记录大小”设置为所需的任何值,然后将每条记录解析为单独的行,并
希望
Perl做正确的事情并最终对每条记录执行一次系统调用,但是增加了复杂性,我真正想做的就是通过将上面示例中使用的缓冲区增加到相当大的大小(例如64K),或者甚至将该缓冲区大小调整为最佳大小,以使用测试进行长时间读取,来轻松获得性能提升我的系统上的脚本,无需额外的麻烦。

就直接增加缓冲区大小的支持而言,Java的情况要好得多。

在Java中,我相信java.io.BufferedReader当前使用的默认缓冲区大小也是8192字节,尽管JDK文档中的最新引用是模棱两可的,例如1.5文档只说:

可以指定缓冲区大小,也可以接受默认大小。对于大多数用途,默认值足够大。

幸运的是,使用Java,您不必信任JDK开发人员为您的应用程序做出正确的决定,并且可以设置自己的缓冲区大小(在此示例中为64K):

import java.io.BufferedReader;
[...]
reader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"), 65536);
[...]
while (true) {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }
                /* do something with the line here */
                foo(line);
}

即使有巨大的缓冲区和现代化的硬件,您一次也只能从解析一行中挤出太多的性能,而且我敢肯定,有一些方法可以通过读取大文件来获得读取文件中每一盎司的性能。多行记录并将每个记录分成令牌,然后每条记录一次处理这些令牌,但是它们会增加复杂性和边缘情况(尽管如果纯Java中有一个优雅的解决方案(仅使用JDK
1.5中提供的功能),那会很酷知道)。在Perl中增加缓冲区大小至少可以解决Perl 80%的性能问题,同时保持直截了当。

我的问题是:

有没有一种方法可以针对上述典型的“逐行”习惯调整Perl中的缓冲区大小,类似于Java示例中如何增加缓冲区大小?


问题答案:

如果您在支持的操作系统上运行,则可能会影响缓冲setvbuf。请参阅的文档IO::Handle

如果您使用的是Perl
v5.10或更高版本,则无需IO::Handle按照文档中的说明显式创建对象,因为IO::Handle自该版本发布以来,所有文件句柄都隐式地添加到对象中。

use 5.010;
use strict;
use warnings;

use autodie;

use IO::Handle '_IOLBF';

open my $handle, '<:utf8', 'foo';

my $buffer;
$handle->setvbuf($buffer, _IOLBF, 0x10000);

while ( my $line = <$handle> ) {
    ...
}


 类似资料:
  • 如何在标准C++/C++11(无POSIX函数)中优化std::ifstream和std::ofstream的读写速度?(1<-由于有几个问题,这些数字标识了不同点) 我不知道缓冲区的确切作用,所以你能确认一下吗: 用于读取:文件的大部分预加载在内存中(因此缓冲区大小定义了这大部分的大小)(2) 写入:数据写入内存,一旦缓冲区满了,数据就从内存传输到文件系统(3) 如何设置std::ifstrea

  • 我正在学习Java I/O。因此,使用缓冲流可以减少读取或写入所需的时间,因为如果使用普通的FileInputStream,每次调用读取时都会获取一个字节,但如果使用缓冲区,则会获取指定大小的数据并将其存储在内存中。所以我试着在实践中看到这一点。 我已将BufferedInputStream的缓冲区大小设置为512,8192,65536。每次需要87秒才能完成执行。所以我尝试使用FileInput

  • 本文向大家介绍在Python中打开文件时如何指定缓冲区大小?,包括了在Python中打开文件时如何指定缓冲区大小?的使用技巧和注意事项,需要的朋友参考一下 如果看一下open-open(name [,mode [,buffering]])的函数定义,您会发现在Python 2中它需要3个参数,第三个是缓冲。可选的buffering参数指定文件所需的缓冲区大小:0表示未缓冲,1表示行缓冲,任何其他正

  • 问题内容: 该文件规定,对于缓冲的默认值是: 。我目前在Red Hat Linux 6上,但是我无法弄清楚为系统设置的默认缓冲。 谁能指导我如何确定系统的缓冲? 问题答案: 由于您链接到2.7文档,因此我假设您使用的是2.7。(在Python 3.x中,这一切都变得更加简单,因为在Python级别上公开了更多的缓冲。) 所有实际上做(在POSIX系统)是调用,然后,如果你已经通过了什么,。由于您没

  • 问题内容: 我有一个平面文件,其中包含339276行文本,大小为62.1 MB。我试图读取所有行,根据我所具有的某些条件解析它们,然后将它们插入数据库。 我最初尝试使用bufio.Scan()循环和bufio.Text()来获取行,但我的缓冲区空间不足。我切换到使用bufio.ReadLine / ReadString / ReadByte(我尝试了每种方法),并且每种方法都有相同的问题。我没有足

  • 问题内容: 当我使用一些线程将数据写入单个文件时遇到问题。 我设置的缓冲区大小,但是无论设置多少,当缓冲区为8192(默认缓冲区大小)而不是我设置的大小(此处为16384)时,它都会将数据刷新到磁盘。我的代码有问题吗? 这就是我构建的方式: 这是完整的代码: 问题答案: 我通过使用OutputStream而不是writer解决了问题,这是代码: