【问题标题】:C# System.IO.FileStream performance hangs badly (10+ seconds)C# System.IO.FileStream 性能严重下降(10 秒以上)
【发布时间】:2017-07-29 23:41:55
【问题描述】:

我遇到了一个问题,即在执行文件写入操作时出现明显的(10 多秒)延迟。它似乎只发生一次,并且总是在第二次(有时是第三次?)调用 WriteToFile() 函数期间发生。

我已经写出了 3 个不同的“WriteToFile”函数来展示我迄今为止尝试过的一些变体 + 在“OpenFileIfNecessary”中显示了我尝试过的其他行。

代码永远不会抛出错误,并且偏移量/计数都是有效的。一旦延迟发生一次,似乎就不会再有延迟了。

这对我来说已经痛苦了 2 多天了,我肯定正处于需要第二意见的时候。

    private void WriteToFile(byte[] data, long offset, int count)
    {
        lock (this.monitor)
        {
            this.OpenFileIfNecessary();
            this.fileStream.Seek(offset, SeekOrigin.Begin);  // <- Takes 10+ seconds for THIS line to execute
            this.fileStream.Write(data, 0, count);
        }
    }

    private void WriteToFile2(byte[] data, long offset, int count)
    {
        lock (this.monitor)
        {
            this.OpenFileIfNecessary();
            this.fileStream.Position = offset;    // <- Takes 10+ seconds for THIS line to execute 
            this.fileStream.Write(data, 0, count);
        }
    }

    private void WriteToFile3(byte[] data, long offset, int count)
    {
        lock (this.monitor)
        {
            var fileName = this.file.FullName;
            using (Stream fileStream = new FileStream(fileName, FileMode.OpenOrCreate))
            {
                fileStream.Position = offset;            //(instant execution of this line)
                fileStream.Write(data, 0, count);
                //Getting from HERE ->
            }
            //To HERE <- takes 10+ seconds
        }
    }

    private System.IO.FileStream fileStream = null;
    private System.IO.FileInfo file;  //value set during construction

    private void OpenFileIfNecessary()
    {
        lock (this.monitor) {
            if (this.fileStream == null) {
                //The following 3 lines all result in the same behavior described in this post

                //this.fileStream = this.file.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
                //this.fileStream = this.file.Open(FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write);
                //this.fileStream = this.file.OpenWrite();
                this.fileStream = this.file.Open(FileMode.OpenOrCreate);                    
            }               
        }
    }

【问题讨论】:

  • 尝试在不同的计算机上做同样的事情。或者在同一台计算机上处​​于安全模式,或者没有一些常驻应用程序(如防病毒)。
  • 在将流刷新到文件之前,您尝试将多少数据写入流?
  • x otikoruk x - 延迟发生前小于 10k 字节
  • 辩证法在其他机器上的行为相同

标签: c# file io filestream


【解决方案1】:

发现问题。值得一提的是,我们之前一直在使用较小的文件(

我们在不同的位置写入文件,也就是说,我们不是简单地从位置 0 开始并走到最后。这意味着(尤其是对于较大的文件),每次我们第一次进入文件深处的位置时,显然都有一个等待新扩展大小的等待期。

FileStream 混淆了许多底层内容的方式使得找到模式有点困难,一旦我们进行了一些更深入的分析并发现较小文件的延迟较小(之前从未注意到延迟),它就变成了清楚发生了什么。

未来的计划是做一些多线程,以允许在写入磁盘之前完全分配文件空间;我们可以在等待期间在内存中缓冲。

预分配整个文件的示例代码:

fileStream.Seek(size - 1, SeekOrigin.Begin);
fileStream.WriteByte(0);
fileStream.Flush();

【讨论】:

  • 您可能会发现使用 Sparse Files 的性能更好,在创建文件句柄时需要一点 P/Invoking,但这并不难。
【解决方案2】:

这是因为当您将文件位置设置为某个较大的值时,底层存储系统必须将已分配块的内容清零。我不相信 BCL 会让你绕过它,但实际上在 Win32 中有一种方法可以跳过需要运行程序具有管理员权限的功能(以非常不精确的方式)。

搜索 SetFileValidData() 文档。

【讨论】:

    猜你喜欢
    • 2018-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多