昨天研究一个delegate的问题,研究了半天,找出了很多的东西来。但是就是有一点始终搞不清楚:为什么某个事件添加一次和添加两次,时间上会相差四倍呢?开始我觉得是递归调用的错,dudu说是运行时生成的问题。实际上现在我做的试验表明很可能大家都错了:
首先我们尝试一下1->2,我们会发现接口的时间增加成比例关系,也就是1->2,可是事件花费的时间则是1->4。这个就是我们觉得非常奇怪的地方,为什么会超出线形关系呢?我开始认为是递归调用的结果,后来发现不是这么回事,因为我做了一个模仿delegate/multicastdelegate的类(除了不是delegate之外,行为几乎一样),然后进行模拟。发现递归和循环之间的差别并不是很明显,基本上相差30%左右。但是同时你也能够发现,无论添加的事件是多少个,递归和循环一样,消耗的时间都保持着线形的关系。
看到这里我们非常的奇怪,既然不是递归的问题,那么难道是运行时产生代码的问题?那也不可能啊,因为那也应该保持着线形的关系啊。
好,现在我们继续做试验:如果我们继续添加事件,比如2->3,那么我们看到interface那边消耗的时间也是2->3,event呢,则是4->6。再比如3->4,interface消耗时间变化是3->4,event则是6->8。
好了,原因几乎就是一目了然了:event的问题仅仅出在1->2,其他地方实际上还是线形关系的。那么在1->2的时候到底发生了什么事情呢?联想一件事情,在昨天的几篇文章中的一篇提到:“由于是runtime的,所以executor会进行优化,但是这个特性并没有在现在的编译器里面很好的实现,只是未来的特性。同时我也不认为这个特性会被添加到1.1版本的运行库里面。”(大意如此)
所以我现在有理由假设一件事情:那就是如果一个委托只被分派了一次,那么这个委托的基类就是Delegate,或者用一个简化的函数实现Invoke。反之,如果这个委托被分派了多次,那么这个委托的基类就是MultiCaseDelegate,或者用一个比较复杂的函数实现Invoke。这就造成了1->2之间的超线性关系,而2->3、3->4则保持了线性关系的原因——仅仅是猜测。
由于目前也仅仅是一个猜测,我想还是需要更多的试验来证实这个想法。不过我最近可能要忙着做别的事情了,所以这个试验就留给各位来试验了。
注:这里面提到的“时间添加两次”的意思大概就是:
t.Event += new xxHandler(xx1);
t.Event += new xxHandler(xx2);
而不是:
t.Event1 += new xxHandler(xx1);
t.Event2 += new xxHandler(xx2);
首先我们尝试一下1->2,我们会发现接口的时间增加成比例关系,也就是1->2,可是事件花费的时间则是1->4。这个就是我们觉得非常奇怪的地方,为什么会超出线形关系呢?我开始认为是递归调用的结果,后来发现不是这么回事,因为我做了一个模仿delegate/multicastdelegate的类(除了不是delegate之外,行为几乎一样),然后进行模拟。发现递归和循环之间的差别并不是很明显,基本上相差30%左右。但是同时你也能够发现,无论添加的事件是多少个,递归和循环一样,消耗的时间都保持着线形的关系。
看到这里我们非常的奇怪,既然不是递归的问题,那么难道是运行时产生代码的问题?那也不可能啊,因为那也应该保持着线形的关系啊。
好,现在我们继续做试验:如果我们继续添加事件,比如2->3,那么我们看到interface那边消耗的时间也是2->3,event呢,则是4->6。再比如3->4,interface消耗时间变化是3->4,event则是6->8。
好了,原因几乎就是一目了然了:event的问题仅仅出在1->2,其他地方实际上还是线形关系的。那么在1->2的时候到底发生了什么事情呢?联想一件事情,在昨天的几篇文章中的一篇提到:“由于是runtime的,所以executor会进行优化,但是这个特性并没有在现在的编译器里面很好的实现,只是未来的特性。同时我也不认为这个特性会被添加到1.1版本的运行库里面。”(大意如此)
所以我现在有理由假设一件事情:那就是如果一个委托只被分派了一次,那么这个委托的基类就是Delegate,或者用一个简化的函数实现Invoke。反之,如果这个委托被分派了多次,那么这个委托的基类就是MultiCaseDelegate,或者用一个比较复杂的函数实现Invoke。这就造成了1->2之间的超线性关系,而2->3、3->4则保持了线性关系的原因——仅仅是猜测。
由于目前也仅仅是一个猜测,我想还是需要更多的试验来证实这个想法。不过我最近可能要忙着做别的事情了,所以这个试验就留给各位来试验了。
注:这里面提到的“时间添加两次”的意思大概就是:
t.Event += new xxHandler(xx1);
t.Event += new xxHandler(xx2);
而不是:
t.Event1 += new xxHandler(xx1);
t.Event2 += new xxHandler(xx2);
分类:
.NET 技术内幕
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 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——大语言模型本地部署的极速利器