SUMTEC -- There's a thing in my bloglet.

But it's not only one. It's many. It's the same as other things but it exactly likes nothing else...

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  263 随笔 :: 19 文章 :: 3009 评论 :: 74万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
不知道大家有没有对我上面写的那个程序在.NET CF上面跑一遍?怎么样?感觉如何?
大家肯定完全没有耐心完成整个过程,大概看到第一个输出之后,就基本上“死机”了。等了五六分钟时在不耐烦了,断点调试一看,fs.Position才到xxKB到xxxKB之间,基本上绝望了,这就是我当时的感觉。但是千万不要放弃,请把while语句直接读FileStream的那一段去掉,重新来一遍。这一次怎么样呢?奇怪吧,绕了一个大弯,申请了一块巨大的内存,然后再用MemoryStream来读,速度远比FileStream快很多。我猜大家刚才还在注意那个BinaryReader,觉得那是一个累赘,一个可能的效率瓶颈。其实问题不在那个BinaryReader身上,相信大家已经知道问题在FileStream的Position属性上面了。用Reflector一看,果然问题多多:FileStream上面的Position计算非常麻烦,尤其是如果你一遍写一遍读的话问题会更加严重(不过本来问题已经够严重了,估计你不会觉得会有什么差别,麻木了)。

public override long get_Position()
{
      
if (this._handle == HostNative.INVALID_HANDLE_VALUE)
      
{
            __Error.FileNotOpen();
      }

      
if (!this.CanSeek)
      
{
            __Error.SeekNotSupported();
      }

      
this.VerifyOSHandlePosition();
      
return (this._pos + ((this._readPos - this._readLen) + this._writePos));
}

首先需要经过两个判断,虽然没有多大的性能损失,但是我还是觉得不雅观。要命的就在那个VerifyOSHandlePosition里面:

private void VerifyOSHandlePosition()
{
      
if (this.CanSeek)
      
{
            
long num1 = this._pos;
            
long num2 = this.SeekCore((long0, SeekOrigin.Current);
            
if (num2 != num1)
            
{
                  
this._readPos = 0;
                  
this._readLen = 0;
            }

      }

}

到这里层次还嫌不够深,还要调用一个SeekCore。我真是佩服写这段代码的人,也许这是一个无可奈何的事情,但是这么写我还是觉得比较让人感到难受得——明明是要得到当前的位置,却不得不首先调用一下Seek(0, SeekOrigin.Current)把位置“重新定位到当前位置”。也许是因为操作系统会缓冲,或者是操作系统会跑飞?这个十分有趣的写法给我非常深刻的印象,有点像看到了脑白金的广告一样。让我们继续跟踪下去:

private long SeekCore(long offset, SeekOrigin origin)
{
      
int num1;
      
int num2 = PAL.File_Seek(this._handle, (int) offset, (int) origin, out num1);
      
if (num2 != 0)
      
{
            __Error.WinIOError(num2);
      }

      
this._pos = num1;
      
return (long) num1;
}

终于看到PAL的东西了……不是仙剑奇侠传的PAL,确切是什么意思我也不知道,金山词霸说是太平洋航空图书馆,我猜可能是什么抽象层的意思,反正我知道PAL里面都是执行引擎里面的Native方法的P/Invoke。也就是说每次我们想得到当前的Position之前,首先要通过三次调用进入执行引擎,才能够得到确切位置。这就是造成IO效率的罪魁祸首。

待续……
posted on   Sumtec  阅读(967)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
点击右上角即可分享
微信分享提示