如何使用stdin.byLine,但使用缓冲区?

如何使用stdin.byLine,但使用缓冲区?,d,D,我正在读取数十亿字节的文件,并从stdin处理它们。我是这样读的 字符串行; foreach(第1行;标准署名){ line=to!字符串(第1行); ... } 有没有更快的方法?我尝试了一种线程方法 auto childTid=spawn(&fn,thisTid); 弦线; foreach(第1行;标准署名){ line=to!字符串(第1行); 仅接收!(int); 发送(childTid,line); } int x=0; 发送(childTid,x); 这允许它在我的进程运行时,以

我正在读取数十亿字节的文件,并从stdin处理它们。我是这样读的

字符串行;
foreach(第1行;标准署名){
line=to!字符串(第1行);
...
}
有没有更快的方法?我尝试了一种线程方法

auto childTid=spawn(&fn,thisTid);
弦线;
foreach(第1行;标准署名){
line=to!字符串(第1行);
仅接收!(int);
发送(childTid,line);
}
int x=0;
发送(childTid,x);
这允许它在我的进程运行时,以拷贝操作为代价从磁盘至少加载一行,但这仍然很愚蠢,我需要的是fgets,或者一种将stdio.byChunk(4096)与readline结合的方法。我试过fgets

char[]buf=新字符[4096];
fgets(buf.ptr,4096,stdio)

但是它总是失败,因为stdio是一个文件而不是流。不知道如何使它成为一条小溪。我们将以您认为最好的方式感谢您的任何帮助。我不太擅长D,为任何noob错误道歉。

实际上已经有两层缓冲(不包括硬件本身):C运行时库和内核都做了一层缓冲以最小化I/O成本

首先,内核将来自磁盘的数据保存在自己的缓冲区中,并将向前看,如果您遵循可预测的模式,则在单个调用中加载的数据将超过您的请求。这是为了降低与查找设备相关的低级别成本,并将跨进程缓存—如果您使用一个程序读取文件,然后使用第二个程序再次读取,则第二个程序可能会从内核内存缓存而不是物理磁盘获取文件,并且速度可能会明显快得多

第二,C库(D的std.stdio就是在它上面构建的)也保留了一个缓冲区
readln
最终调用C文件I/O函数,这些函数一次从内核读取一个块。(有趣的是,写操作也由C库缓冲,如果用户交互,则默认为行,否则默认为块。写操作非常慢,按块执行会产生很大的不同,但有时C库认为管道在交互时不交互,并导致常见问题:)

这些C-lib缓冲区甚至在发送到内核之前对它们进行批处理,从而降低了许多小型读写操作的成本。在readln的情况下,它可能会一次读取几千字节,即使您只要求一行或一个字节,其余的都会保留在缓冲区中以备下次使用

因此,您的readln循环已经将被自动缓冲,并应获得良好的I/O性能

不过,通过一些技巧,你自己可能会做得更好。在这种情况下,您可以尝试对内存映射文件使用
std.mmfile
,并像读取数组一样读取它,但您的文件太大,无法在32位上放入该文件。但可能在64位上工作。(请注意,内存映射文件不是一次性加载的,它只是映射到内存地址。当您实际触摸其中的一部分时,操作系统将按需加载/保存。)

当然,您也可以使用较低级别的操作系统函数,如
import core.sys.posix.unistd
中的
write
import core.sys.windows.windows中的
WriteFile
,这将绕过C库的层(当然,保留您想要的内核层,不要试图绕过它们)

如果您想了解有关使用这些函数的更多信息,可以查找任何win32或posix系统调用C教程。它在D中与在C中相同,只是有一些小的警告,比如导入而不是
#include

加载块后,您将希望扫描它以查找换行符,并尽可能对其进行切片,以形成要传递给循环或其他算法的范围。
std.range
std.algorithm
模块还具有搜索、分割和分块功能,这些功能可能会有所帮助,但您需要小心跨越缓冲区边缘的行,以保持正确性和效率


但是,如果您的性能足够好,我会说,就让它去吧——在大多数情况下,C lib+内核的缓冲做得相当好。

stdin已经在后台进行了缓冲。。。你确定这会给你带来不同吗?@AdamD.Ruppe你确定吗
ByLine.Impl
struct具有
buffer
,但它仍然在每次
popFront
调用时调用
file.readln
。它们最终都会调用缓冲设备输入的C fread函数。缓冲区在调用堆栈中的级别较低,但它在那里…。@AdamD.Ruppe感谢您的澄清。因此,如果操作系统可以预测您需要更多缓冲区,它也将开始从磁盘预加载。例如,如果您显然是按顺序阅读,它通常会提前缓冲。我猜你真正需要的只是一个更快的循环和署名——也许你在这里达到了其他极限。