引用stream.Position会大大增加执行时间

时间:2013-12-02 16:41:44

标签: c# io

任何想法为什么引用流的Position属性会过度增加IO时间?

执行时间:

        sw.Restart();
        fs = new FileStream("tmp", FileMode.Open);
        var br = new BinaryReader(fs);
        for (int i = 0; i < n; i++)
        {
            fs.Position+=0; //Should be a NOOP
            a[i] = br.ReadDouble();
        }
        Debug.Write("\n");
        Debug.Write(sw.ElapsedMilliseconds.ToString());
        Debug.Write("\n");
        fs.Close();
        sw.Stop();
        Debug.Write(a[0].ToString() + "\n");
        Debug.Write(a[n - 1].ToString() + "\n");

比没有“fs.Position + = 0;”的等效循环慢约100倍。 通常,使用Seek(或操作Position属性)的意图是在不需要文件中的所有数据时加快速度。 但是,例如,如果你只需要文件中的每一个值,那么读取整个文件并丢弃你不需要的数据要快得多,而不是通过移动Stream.Position来跳过文件中的每一秒值

2 个答案:

答案 0 :(得分:4)

你正在做两件事:

  • 获取职位
  • 设置

完全有可能每个执行与底层Win32 API的直接交互,而通常您可以读取相当数量的数据而无需与本机代码互操作,因为缓冲

我对它的恶化程度感到有些惊讶,但我并不感到惊讶 更糟糕。我认为值得你做一些单独的测试,找出哪个更有效 - 读或写。因此,编写类似的代码,只是读取或只是写入。请注意,这应该会影响您稍后编写的代码,但它可能会进一步满足您的好奇心。

您也可以尝试

fs.Seek(0, SeekOrigin.Current);

......作为一个真正的无操作者,它更容易被忽视。但即便如此,使用fs.Seek(1, SeekOrigin.Current)跳过单个字节可能会再次成本高昂。

答案 1 :(得分:1)

来自反射器:

public override long Position {
  [SecuritySafeCritical]
  get {
    if (this._handle.IsClosed) {
      __Error.FileNotOpen();
    }
    if (!this.CanSeek) {
      __Error.SeekNotSupported();
    }
    if (this._exposedHandle) {
      this.VerifyOSHandlePosition();
    }
    return this._pos + (long)(this._readPos - this._readLen + this._writePos);
  }
  set {
    if (value < 0L) {
      throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    if (this._writePos > 0) {
      this.FlushWrite(false);
    }
    this._readPos = 0;
    this._readLen = 0;
    this.Seek(value, SeekOrigin.Begin);
  }
}

(自我解释) - 基本上每一组都会导致刷新,并且如果你为位置设置相同的值则不会检查;如果您对FileStream不满意,请创建自己的流代理,以更优雅地处理位置更新:)