如何加快FileStream的创建速度

时间:2017-07-09 11:00:11

标签: c# performance filestream

我的应用程序需要打开很多小文件,比如1440个文件,每个文件包含1分钟的数据,以读取某一天的所有数据。每个文件只有几个KB大。这是一个GUI应用程序,所以我希望用户(==我!)不必等待太长时间。

事实证明打开文件的速度相当慢。经过研究,大多数时间都浪费在为每个文件创建FileStream(OpenStream = new FileStream)。示例代码:

// stream en reader aanmaken
FileStream OpenStream;
BinaryReader bReader;

foreach (string file in files)
{
    // bestaat de file? dan inlezen en opslaan
    if (System.IO.File.Exists(file))
    {
        long Start = sw.ElapsedMilliseconds;

        // file read only openen, anders kan de applicatie crashen
        OpenStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

        Tijden.Add(sw.ElapsedMilliseconds - Start);

        bReader = new BinaryReader(OpenStream);

        // alles in één keer inlezen, werkt goed en snel
        // -bijhouden of appenden nog wel mogelijk is, zonodig niet meer appenden
        blAppend &= Bestanden.Add(file, bReader.ReadBytes((int)OpenStream.Length), blAppend);

        // file sluiten
        bReader.Close();
    }
}

使用秒表计时器,我发现大多数(> 80%)的时间花在为每个文件创建FileStream上。创建BinaryReader并实际读取文件(Bestanden.add)几乎没有时间。

我对此感到困惑,无法找到加快速度的方法。我该怎么做才能加快FileStream的创建速度?

更新问题:

  • 在Windows 7和Windows 10上都会发生这种情况
  • 文件是本地的(在SSD磁盘上)
  • 目录中只有1440个文件
  • 奇怪的是,稍后再次阅读(相同)文件,创建FileStreams突然几乎没有时间。操作系统的某个地方 记住文件流。
  • 即使我关闭应用程序并重新启动它,再次打开文件""也几乎没时间花费。这使得很难找到 性能问题。我不得不制作很多目录副本 一遍又一遍地重现这个问题。

2 个答案:

答案 0 :(得分:2)

正如您在问题的评论中提到的那样FileStream通过创建对象将第一个4K读取缓冲区。您可以更改此缓冲区的大小以反映更好的数据大小。 (例如,如果文件小于缓冲区,则减少)。如果您按顺序读取文件,则可以通过FileOptions向OS提供有关此内容的提示。此外,您可以避免使用BinaryReader,因为您完全阅读了文件。

    // stream en reader aanmaken
    FileStream OpenStream;

    foreach (string file in files)
    {
        // bestaat de file? dan inlezen en opslaan
        if (System.IO.File.Exists(file))
        {
            long Start = sw.ElapsedMilliseconds;

            // file read only openen, anders kan de applicatie crashen
            OpenStream = new FileStream(
                file,
                FileMode.Open,
                FileAccess.Read,
                FileShare.ReadWrite,
                bufferSize: 2048, //2K for example 
                options: FileOptions.SequentialScan);

            Tijden.Add(sw.ElapsedMilliseconds - Start);

            var bufferLenght = (int)OpenStream.Length;
            var buffer = new byte[bufferLenght];
            OpenStream.Read(buffer, 0, bufferLenght);

            // alles in één keer inlezen, werkt goed en snel
            // -bijhouden of appenden nog wel mogelijk is, zonodig niet meer appenden
            blAppend &= Bestanden.Add(file, buffer, blAppend);
        }
    }

我不知道Bestanden对象的类型。但是,如果此对象具有从数组中读取的方法,则还可以为文件重用缓冲区。

    //the buffer should be bigger than the biggest file to read
    var bufferLenght = 8192;
    var buffer = new byte[bufferLenght];

    foreach (string file in files)
    {
        //skip 
        ...
        var fileLenght = (int)OpenStream.Length;
        OpenStream.Read(buffer, 0, fileLenght);

        blAppend &= Bestanden.Add(file, /*read bytes from buffer */, blAppend);

我希望它有所帮助。

答案 1 :(得分:0)

免责声明:这个答案只是一个(成熟的)推测,它是一个Windows bug,而不是你可以使用不同代码修复的东西。

因此,此行为可能与此处描述的Windows错误有关:"24-core CPU and I can’t move my mouse"

  

这些进程都是从NtGdiCloseProcess中释放锁。

因此,如果FileStream在操作系统中使用并保持这样一个关键锁定,那么它会等待几个μSecs用于每个文件,这将增加数千个文件。它可能是一个不同的锁,但上面提到的错误至少增加了类似问题的可能性。

为证明或反驳这一假设,有必要深入了解内核的内部工作原理。