在Scala中使用类型类模式对性能有什么影响

在Scala中使用类型类模式对性能有什么影响,scala,optimization,implicit,scalac,Scala,Optimization,Implicit,Scalac,目前,我正在大量使用类型类模式,将其作为代码中与性能相关的部分。我发现了至少两个潜在的低效原因 隐式参数随消息调用传递。我不知道这是否真的发生了。也许scalac可以简单地在使用隐式参数的地方插入这些参数,并将它们从方法签名中删除。在手动插入隐式参数的情况下,这可能是不可能的,因为它们可能仅在运行时解析在传递隐式参数方面应用了哪些优化 如果类型类实例由def提供(与val相反),则必须在每次调用“类型类方法”时重新创建对象。JVM可以解决这个问题,它可以优化对象的创建。scalac也可以通过重用

目前,我正在大量使用类型类模式,将其作为代码中与性能相关的部分。我发现了至少两个潜在的低效原因

  • 隐式参数随消息调用传递。我不知道这是否真的发生了。也许scalac可以简单地在使用隐式参数的地方插入这些参数,并将它们从方法签名中删除。在手动插入隐式参数的情况下,这可能是不可能的,因为它们可能仅在运行时解析在传递隐式参数方面应用了哪些优化

  • 如果类型类实例由
    def
    提供(与
    val
    相反),则必须在每次调用“类型类方法”时重新创建对象。JVM可以解决这个问题,它可以优化对象的创建。scalac也可以通过重用这些对象来解决这个问题在创建隐式参数对象方面应用了哪些优化?


  • 当然,在应用类型类模式时,可能还有其他的低效来源。请告诉我有关它们的情况。

    如果您真的关心编写超高性能代码(您可能认为您这样做了,但在这一点上却大错特错),那么类型类将带来一些痛苦,原因如下:

    • 许多额外的虚拟方法调用
    • 原语的可能装箱(例如,如果对幺半群使用scalaz的TypeClass等)
    • 通过
      def
      创建对象,这是必需的,因为函数无法参数化
    • 对象创建以访问“pimped”方法
    在运行时,JVM可能会优化一些错误的创建(例如,创建
    MA
    来调用
    ),但是
    scalac
    没有太大帮助。通过编译一些使用TypeClass的代码并使用
    -Xprint:icode
    作为参数,您可以很容易地看到这一点

    下面是一个例子:

    import scalaz._; import Scalaz._
    object TC {
      def main(args: Array[String]) {
        println((args(0).parseInt.liftFailNel |@| args(1).parseInt.liftFailNel)(_ |+| _))
      }
    }
    
    这是图标:

    final object TC extends java.lang.Object with ScalaObject {
      def main(args: Array[java.lang.String]): Unit = scala.this.Predef.println(scalaz.this.Scalaz.ValidationMA(scalaz.this.Scalaz.StringTo(args.apply(0)).parseInt().liftFailNel()).|@|(scalaz.this.Scalaz.StringTo(args.apply(1)).parseInt().liftFailNel()).apply({
      (new anonymous class TC$$anonfun$main$1(): Function2)
    }, scalaz.this.Functor.ValidationFunctor(), scalaz.this.Apply.ValidationApply(scalaz.this.Semigroup.NonEmptyListSemigroup())));
    def this(): object TC = {
      TC.super.this();
      ()
    }
    };
    @SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2 extends scala.runtime.AbstractFunction0 with Serializable {
      final def apply(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.v1$1;
      final <bridge> def apply(): java.lang.Object = scala.Int.box(TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.apply());
      <synthetic> <paramaccessor> private[this] val v1$1: Int = _;
      def this($outer: anonymous class TC$$anonfun$main$1, v1$1: Int): anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2 = {
        TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.v1$1 = v1$1;
        TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.super.this();
        ()
      }
    };
    @SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1 extends scala.runtime.AbstractFunction0$mcI$sp with Serializable {
      final def apply(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.apply$mcI$sp();
      <specialized> def apply$mcI$sp(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.v2$1;
      final <bridge> def apply(): java.lang.Object = scala.Int.box(TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.apply());
      <synthetic> <paramaccessor> private[this] val v2$1: Int = _;
      def this($outer: anonymous class TC$$anonfun$main$1, v2$1: Int): anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1 = {
        TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.v2$1 = v2$1;
       TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.super.this();
      ()
      }
    };
    @SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1 extends scala.runtime.AbstractFunction2$mcIII$sp with Serializable {
      final def apply(x$1: Int, x$2: Int): Int = TC$$anonfun$main$1.this.apply$mcIII$sp(x$1, x$2);
      <specialized> def apply$mcIII$sp(v1$1: Int, v2$1: Int): Int = scala.Int.unbox(scalaz.this.Scalaz.mkIdentity({
    (new anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2(TC$$anonfun$main$1.this, v1$1): Function0)
    }).|+|({
        (new anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1(TC$$anonfun$main$1.this, v2$1): Function0)
    }, scalaz.this.Semigroup.IntSemigroup()));
    final <bridge> def apply(v1: java.lang.Object, v2: java.lang.Object): java.lang.Object = scala.Int.box(TC$$anonfun$main$1.this.apply(scala.Int.unbox(v1), scala.Int.unbox(v2)));
      def this(): anonymous class TC$$anonfun$main$1 = {
        TC$$anonfun$main$1.super.this();
        ()
       }
     }
    
    final object TC使用ScalaObject扩展java.lang.object{
    def main(args:Array[java.lang.String]):Unit=scala.this.Predef.println(scalaz.this.scalaz.ValidationMA(scalaz.this.scalaz.StringTo(args.apply(0)).parseInt().liftFailNel())。|@(scalaz.this.scalaz.StringTo(args.apply(1)).parseInt().liftFailNel()).apply)({
    (新的匿名类TC$$anonfun$main$1():Function2)
    },scalaz.this.Functor.ValidationFunctor(),scalaz.this.Apply.ValidationApply(scalaz.this.Semigroup.NonEmptyListSemigroup());
    def this():对象TC={
    TC.super.this();
    ()
    }
    };
    @SerialVersionUID(0)最终类TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2使用Serializable扩展了scala.runtime.AbstractFunction0{
    final def apply():Int=TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.v1$1;
    final def apply():java.lang.Object=scala.Int.box(TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.apply());
    private[this]val v1$1:Int=\uu0;
    定义此($outer:匿名类TC$$anonfun$main$1,v1$1:Int):匿名类TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2={
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2。此.v1$1=v1$1;
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.super.this();
    ()
    }
    };
    @SerialVersionUID(0)最终类TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1扩展了scala.runtime.AbstractFunction0$mcI$sp,可序列化{
    final def apply():Int=TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.apply$mcI$sp();
    def apply$mcI$sp():Int=TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.v2$1;
    final def apply():java.lang.Object=scala.Int.box(TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.apply());
    private[this]val v2$1:Int=\uux;
    定义此($outer:匿名类TC$$anonfun$main$1,v2$1:Int):匿名类TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1={
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1。此.v2$1=v2$1;
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.super.this();
    ()
    }
    };
    @SerialVersionUID(0)最终类TC$$anonfun$main$1使用Serializable扩展了scala.runtime.AbstractFunction2$mcIII$sp{
    最终def应用(x$1:Int,x$2:Int):Int=TC$$anonfun$main$1。此。应用$mcIII$sp(x$1,x$2);
    def apply$mcIII$sp(v1$1:Int,v2$1:Int):Int=scala.Int.unbox(scalaz.this.scalaz.mkIdentity({
    (新的匿名类TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2(TC$$anonfun$main$1.this,v1$1):函数0)
    }).|+|({
    (新的匿名类TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1(TC$$anonfun$main$1.this,v2$1):函数0)
    },scalaz.this.Semigroup.IntSemigroup());
    最终def apply(v1:java.lang.Object,v2:java.lang.Object):java.lang.Object=scala.Int.box(TC$$anonfun$main$1.this.apply(scala.Int.unbox(v1),scala.Int.unbox(v2));
    def this():匿名类TC$$anonfun$main$1={
    TC$$anonfun$main$1.super.this();
    ()
    }
    }
    
    }


    你可以看到这里正在进行大量的对象创建

    所以我从你的答案中读到的一个建议可能是用自己的专门化版本替换我正在使用的
    scalaz.Monoid
    ?虽然专业化看起来很麻烦。。。即使是
    Numeric
    似乎也不是专门化的。我会避开专门化tbh。如果我站在你的立场上,我会非常非常肯定我确实需要从代码中挤出最后一点性能。什么让你确信你会这么做?如果事情必须接近金属,那么我会说,您必须回到可变集合、命令式代码和while循环。真的没有其他答案,也不需要尽可能快。但我不想承受拳击对表现的影响。我目前正在使用基元数组(没有对它们进行变异)。关于这个问题,可以保持代码非常通用,以应用于大型问题空间