2014-11-23 85 views
5

我正在运行Delphi RAD Studio XE2。最近我一直在玩文件流,发现一些有趣的结果,导致我这个问题。Delphi中的文件流 - 最佳缓冲区大小

Delphi中TStreamReader的最佳缓冲区大小是多少?例如,我正在以doubleTABdoubleTABdouble的形式加载一个200万行的1GB文件。如果使用下面的代码将它加载到TStringList中,对于不同的缓冲区大小,我会得到显着不同的结果。结果我的意思是处理速度和内存使用量。

reader := TStreamReader.Create(fileLocation, TEncoding.UTF8, True, NumBytes); 
try 
    stringList.BeginUpdate; 
    try 
    stringList.Clear; 
    while not reader.EndOfStream do 
     stringList.Add(reader.ReadLine); 
    finally 
     stringList.EndUpdate; 
    end; 
    finally 
    reader.Free; 
    end; 
end; 

最佳缓存大小似乎是1024和4096之间。如果将它设置低于1024似乎线性放慢脚步,似乎使用更多的内存。如果它设置在4096以上,它似乎会呈指数级下降。

为什么我会看到这些行为,以及如何确定任务的最佳缓冲区大小?另外,最大缓冲区大小是多少?

编辑

我跑下面的代码使用上述文件大小来提取运行时间:

startTime := Now(); 
myStreamReader := TStreamReader.Create(fileLocation, TEncoding.UTF8, True, numBytes); 
myStringList := TStringList.Create; 
try 
    myStringList.BeginUpdate; 
    try 
    myStringList.Clear; 
    while not myStreamReader.EndOfStream do 
     myStringList.Add(myStreamReader.ReadLine); 
    finally 
     myStringList.EndUpdate; 
    end; 
    finally 
    myStreamReader.Free; 
    end; 
processTime := Now() - startTime; 
myStringList.Free; 

实施例的运行时间被提取为:

Buffer Size 32. Done in 69s 
Buffer Size 64. Done in 69s 
Buffer Size 96. Done in 69s 
Buffer Size 128. Done in 70s 
Buffer Size 160. Done in 60s 
Buffer Size 192. Done in 57s 
Buffer Size 224. Done in 52s 
Buffer Size 256. Done in 50s 
Buffer Size 512. Done in 44s 
Buffer Size 768. Done in 40s 
Buffer Size 1024. Done in 39s 
Buffer Size 1280. Done in 41s 
Buffer Size 1536. Done in 44s 
Buffer Size 1792. Done in 40s 
Buffer Size 2048. Done in 39s 
Buffer Size 2304. Done in 41s 
Buffer Size 2560. Done in 41s 
Buffer Size 2816. Done in 42s 
Buffer Size 3072. Done in 43s 
Buffer Size 3328. Done in 43s 
Buffer Size 3584. Done in 45s 
Buffer Size 3840. Done in 44s 
Buffer Size 4096. Done in 45s 
Buffer Size 4352. Done in 47s 
Buffer Size 4608. Done in 46s 
Buffer Size 4864. Done in 46s 
Buffer Size 5120. Done in 48s 
Buffer Size 5376. Done in 49s 
Buffer Size 5632. Done in 51s 
Buffer Size 5888. Done in 51s 
Buffer Size 6144. Done in 52s 
Buffer Size 6400. Done in 54s 
Buffer Size 6656. Done in 53s 
Buffer Size 6912. Done in 55s 
Buffer Size 7168. Done in 55s 
Buffer Size 7424. Done in 56s 
Buffer Size 7680. Done in 57s 
Buffer Size 7936. Done in 65s 
Buffer Size 8192. Done in 62s 
Buffer Size 8448. Done in 63s 
Buffer Size 8704. Done in 64s 
Buffer Size 8960. Done in 64s 
Buffer Size 9216. Done in 66s 
Buffer Size 9472. Done in 66s 
Buffer Size 9728. Done in 68s 
Buffer Size 9984. Done in 68s 
Buffer Size 10240. Done in 69s 

至于RAM使用率,256以下的缓冲区大小导致总共使用5GB RAM和大于1024的缓冲区,总共使用大约3.5GB。例如使用2kb,4kb和8kb缓冲区的RAM使用情况;请参考:

this image

+1

请参阅[TStreamReader - 性能不佳](http://qc.embarcadero.com/wc/qcmain.aspx?d=114824)。 – 2014-11-23 07:56:26

+0

如果较大的缓冲区较慢,则会出错。这很奇怪。你真的需要加载到一个字符串列表吗?如果你能避免这种情况,你仍然会更快。 – 2014-11-23 08:01:43

+1

@DavidHeffernan,在XE7上进行了测试,可以确认TStreamReader的性能不佳。使用'stringList.LoadFromFile()'快5倍。 – 2014-11-23 21:03:56

回答

1

@Trojanian,你上面提到的代码类似于雷米勒博在以前的帖子,TStringList.LoadFromFile - Exceptions with Large Text Files答案。我也在摆弄雷米的例子,它可能会载入更大的文件,但小文件的性能大约是TStrings.LoadFromFile的一半。我自己试图切换缓冲区大小并不能提升性能。

然后我发现下面的代码示例,Alternative to TStrings.LoadFromFile or TStringList.LoadFromFile,它采用了128KB缓冲区,减少了一半的我的大文件的加载时间相比TStrings.LoadFromFile,即X4比你更快的代码上面,当我使用XE3。

+0

谢谢你 - 我会看看。 :-) – Trojanian 2014-11-23 23:33:51

+2

该代码中有一些问题需要注意。其一,它在每个循环迭代中执行3个流的查找,这对于大文件流可能是昂贵的。在进入循环之前,最好将当前的'Position'和'Size'检索到局部变量,然后在循环时使用它们。此外,循环使用'TStream.Read()',但不检查失败,并假定总是读取“ReadSize”字节数。最好使用'TStream.ReadBuffer()'代替。 – 2014-11-23 23:56:58

+0

谢谢雷米的反馈! – Lars 2014-11-24 00:41:52