【发布时间】:2015-09-29 06:46:22
【问题描述】:
当一个人决定使用延迟初始化时,他通常需要为此付费。
class Loafer
{
private VeryExpensiveField field;
private VeryExpensiveField LazyInitField()
{
field = new VeryExpensiveField();
// I wanna here remove null check from accessor, but how?
return field;
}
property Field { get { return field ?? LazyInitField(); } }
}
基本上,他必须每次检查他的支持字段是否具有 null/nil 值。如果他能摆脱这种做法呢?成功初始化字段后,就可以去掉这个检查了,对吧?
不幸的是,大多数生产语言不允许您在运行时修改它们的函数,尤其是在函数体中添加或删除单个指令,尽管如果明智地使用它会有所帮助。但是,在 C# 中,您可以使用 delegates(最初我发现它们,后来意识到为什么本地语言具有函数指针)和 events 机制来模仿这种行为,因此缺乏性能,因为空检查只是移动到较低级别,但不会完全消失。一些语言,例如LISP 和 Prolog,让您可以轻松修改它们的代码,但它们几乎不能被视为生产语言。
在 Delphi 和 C/C++ 等本地语言中,最好编写两个函数,安全和快速,通过指针调用它们并在初始化后将此指针切换到快速版本。您甚至可以允许编译器或 IDE 生成代码来执行此操作,而无需额外头痛。但是正如@hvd 提到的,这甚至会降低速度,因为CPU 不会知道这些功能几乎相同,因此不会将它们预取到它的缓存中。
是的,我是个性能狂,只为满足我的好奇心,在没有明确问题的情况下寻求性能。有哪些常用方法来开发此类功能?
【问题讨论】:
-
"并在初始化后切换到快速"... - 使用与 getter 中相同的条件语句。你想保存什么?几个 CPU 周期?
-
调用函数代价高昂,至少与读取变量相比是这样。你知道 C 和 C++ 中的函数指针是什么吗?还是德尔福中的程序变量? IDE 如何与此处相关?你为什么提到它?性能问题通常需要比您提供的更多背景信息。
-
@Danatela 你衡量过它的影响吗?我问是因为我希望从内存中加载一个单词并将其与零进行比较比从内存中加载一个单词并将指令指针设置为该值稍微便宜一些,因为后者意味着处理器无法提前知道将执行哪些指令. (我也希望差异如此之小以至于很难衡量。)
-
@Danatela:在 C# 中,您可以以与本地语言中的函数指针相同的方式使用委托。但我怀疑是否会有任何性能提升。
-
间接很少能提高性能。我怀疑函数调用是否比空检查更快。你为什么不测量?编写一些您希望优化的真实代码。
标签: c# c++ delphi lazy-initialization self-modifying