将坐标存储为对象的性能与 C# 中的两个双精度
Posted
技术标签:
【中文标题】将坐标存储为对象的性能与 C# 中的两个双精度【英文标题】:Performance of storing a coordinate as an object vs two doubles in C# 【发布时间】:2015-07-15 09:51:57 【问题描述】:我正在尝试优化利用坐标列表的算法。我们遵循领域驱动设计原则——Coordinate
目前被定义为一个单独的 ValueObjects 项目中的一个类,由主项目使用。 Coordinate
类由两个double
s(纬度和经度)和构造函数中的一些验证组成,以确保写入时的有效坐标。
使用 Visual Studio 的分析工具,我发现我的大量处理最终都在 get_Longitude 和 get_Latitude 函数中。这可能只是由于拨打了大量电话。
将坐标存储为两个双精度而不是包含两个双精度作为属性的对象是否值得?或者这只会降低可读性而不提高性能?
【问题讨论】:
你考虑过用结构体代替类吗?这听起来像是对值类型的完全合理的使用...... 我们遵循 DDD 原则 - 我们的Coordinate
类(以及 Distance
、Speed
等)都在一个单独的 ValueObjects 项目中,编译成一个单独的 DLL。每个类都包含验证和转换方法,这就是为什么我们更喜欢类而不是结构。从结构中检索双精度值会比从类中检索更好吗?如果是这样,我可以在运行算法之前将坐标读入结构。
“每个类都包含验证和转换方法,这就是为什么我们更喜欢类而不是结构。”我根本不明白这是怎么回事。 DateTime
具有转换和验证方法,例如...您不应该只考虑一个方面(检索) - 考虑值类型与引用类型的所有方面。
感谢您的建议。我的印象是结构不应该包含这样的方法,但在阅读msdn.microsoft.com/en-us/library/ms229017(v=vs.110).aspx 后我相信你的观点。不过,本文主要讨论内存。就该算法而言,处理速度至关重要,比任何其他因素都更重要——包括严格遵循模式。从结构中检索双精度值会比从类中检索更快吗?
你应该自己测试一下。结构将具有引用局部性的好处,但是如果您通常对少数对象有很多引用,那么您将通过拥有结构来增加内存使用量。基本上,您应该仔细考虑所有的影响,然后运行测试以查看在您的特定场景中的影响。
【参考方案1】:
由于Coordinate
是一个值对象,它是不可变的。因此,使用两个 readonly public
字段是完全可以接受的(但请阅读其余部分)。
此外,使用结构可以进一步提高计算性能(正如 Jon Skeet 在 cmets 中指出的那样)。
从 DDD 的角度来看,这些是非常完美的实现细节。
此外:
为了验证,我会在Coordinate
定义中使用静态工厂方法
对于计算,我会在Coordinate
定义中编写操作闭包(但如果性能很重要,请避免运算符重载)
这两种 DDD 模式在您的上下文中可以很好地证明。
在结构中具有工厂方法(以及默认值的适当语义),使您能够删除构造函数中的验证逻辑,因为工厂方法本身将确保不变量(实际上除了默认一个)。
此外,假设您的Coordinate
s 形成additive group,则该结构可以公开实例方法Coordinate Add(Coordinate other)
。
在实现中,您不需要任何验证,但需要计算(基于对other
的私有字段的访问)和初始化,因为您知道当前实例是有效的,因此它是参数。
请注意,如果您关闭操作足够远,您将不需要任何公共字段或属性。
确实,如果您关心 OOP 设计,而不是公开任何内部信息(属性或字段,不会有太大变化),您可以公开如下几个方法而不违反封装
public void Eval(Action<double, double> action)
if(null == action)
throw new ArgumentNullException("action");
action(_lat, _long);
public T Eval<T>(Func<double, double, T> function)
if (null == function)
throw new ArgumentNullException("function");
return function(_lat, _long);
此外,如果您需要此类方法,但它们不属于您的通用语言,您可以将它们隐藏在 infrastructural interface
的显式实现之后。
【讨论】:
以上是关于将坐标存储为对象的性能与 C# 中的两个双精度的主要内容,如果未能解决你的问题,请参考以下文章