Scala中的“拳击”原始类型的开销
-
09-10-2019 - |
题
假设我想参加像Java这样的课程 Date
. 。它唯一的数据成员是一个长期代表自1970年以来毫秒的长期。
仅制作新的Scala类型的任何性能好处是否会有所收益:
type PrimitiveDate = Long
然后,您可以通过使用隐式转换来添加方法,就像使用INT一样 RichInt
. 。原始类型的“拳击”是否涉及任何开销(班级创建)?基本上您只能有静态方法
def addMonth(date: PrimitiveDate, months: Int): PrimitiveDate = date + 2592000000 * months
并让类型系统弄清楚它必须在 d addMonth 5
出现在您的代码中。
编辑
看来您通过写作创建的别名 type PrimitiveDate = Long
不受Scala编译器强制执行。是创建一个适当的类,封闭长长的唯一方法来创建Scala中的强制类型吗?
您认为能够为原始类型创建强制性类型的别名如何有用?
解决方案
出色地, 逃生分析 应该意味着最新的JVM实际上不必创建您的 丰富的包装纸 为了致电 addMonth
方法。
这在多大程度上 实际上是在实践中发生的 显然将取决于运行时多少 热点 JVM决定这些方法正在添加在对象创建中。当没有发生逃生分析时,显然,JVM必须“盒子”(您说) Long
在包装器类的新实例中。它不涉及“类创建” - 它将涉及“创建类的实例”。此实例,短暂的寿命将立即为GC-D,因此开销(小)为:
- 实例的内存分配
- gc-ing实例
显然,如果您肯定要编写非常低的延迟代码,那么这些问题显然才是任何问题,您试图最大程度地减少垃圾的创造(在紧密的循环中)。只有您知道是否就是这种情况。
至于该方法是否适合您(逃避分析得到帮助),您必须在野外进行测试。众所周知,微基准很难为这种事情编写。
我不太喜欢这些类型别名的原因 成为公共API的一部分 是Scala并没有真正按照我的意愿强制执行它们。例如:
type PrimitiveDate = Long
type PrimitiveSpeed = Long
type Car = String
type Meeting = String
var maxSpeeds : Map[Car, PrimitiveSpeed] = Map.empty
//OOPS - much too easy to accidentally send the wrong type
def setDate(meeting : Meeting, date : PrimitiveDate) = maxSpeeds += (meeting -> date)
其他提示
您实际上并没有在给定的示例中创建一种新类型,它只是预先存在的长期类型的别名。
这是我经常使用的技术来处理笨拙的嵌套连接。例如,我别名 type Grid = Seq[Seq[Int]]
避免必须指定 Seq[Seq[Int]]
一遍又一遍地以获取各种参数。
你可以很高兴地通过 Long
采用一种方法 PrimitiveDate
方法,尽管你 做 有一个优势,即代码更好地记载。
如果您确实想创建具有强制类型安全和方便的图案匹配的新类型,我将使用一个案例类:
case class PrimitiveDate(value:Long)
而且,即使为方便起见,甚至可能提供一个隐性的长=>原始的转换。
问这个问题11个月后,迈尔斯·萨宾(Miles Sabin)发现了一种非常简单,优雅和表现的创建方式 未包装的新型 在Scala中。与类型的别名不同,类型标签被强制执行。原始类型需要最小的样板(每条原始线)才能提供专业化。
一年后,他添加了一个 更加抛光和健壮的版本 这是 无形. 。这个概念简单明了,可以在项目中复制,而不会添加无形状的话,如果您不希望其余的出色的库。
当然,您和回答您问题的人都可能知道这一点,但是值得在这里添加,因为这仍然是一个重要的问题。