加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

与Scala相比,Haskell Vector性能

发布时间:2020-12-16 18:25:33 所属栏目:安全 来源:网络整理
导读:我在 Haskell和 Scala中有一段非常简单的代码.此代码旨在以非常紧凑的循环运行,因此性能很重要.问题是Haskell比Scala慢大约10倍.这是Haskell代码. {-# LANGUAGE BangPatterns #-}import qualified Data.Vector.Unboxed as VUnewtype AffineTransform = Affin
我在 Haskell和 Scala中有一段非常简单的代码.此代码旨在以非常紧凑的循环运行,因此性能很重要.问题是Haskell比Scala慢大约10倍.这是Haskell代码.

{-# LANGUAGE BangPatterns #-}
import qualified Data.Vector.Unboxed as VU

newtype AffineTransform = AffineTransform {get :: (VU.Vector Double)} deriving (Show)

{-# INLINE runAffineTransform #-}
runAffineTransform :: AffineTransform -> (Double,Double) -> (Double,Double)
runAffineTransform affTr (!x,!y) = (get affTr `VU.unsafeIndex` 0 * x + get affTr `VU.unsafeIndex` 1 * y + get affTr `VU.unsafeIndex` 2,get affTr `VU.unsafeIndex` 3 * x + get affTr `VU.unsafeIndex` 4 * y + get affTr `VU.unsafeIndex` 5)

testAffineTransformSpeed :: AffineTransform -> Int -> (Double,Double)
testAffineTransformSpeed affTr count = go count (0.5,0.5)
  where go :: Int -> (Double,Double)
        go 0 res = res
        go !n !res = go (n-1) (runAffineTransform affTr res)

还有什么可以改进这个代码?

解决方法

主要问题是

runAffineTransform affTr (!x,!y) = (get affTr `VU.unsafeIndex` 0 * x
                                     + get affTr `VU.unsafeIndex` 1 * y
                                     + get affTr `VU.unsafeIndex` 2,get affTr `VU.unsafeIndex` 3 * x
                                     + get affTr `VU.unsafeIndex` 4 * y
                                     + get affTr `VU.unsafeIndex` 5)

产生一对thunk.调用runAffineTransform时不会评估组件,它们会保持不变,直到某些消费者要求对它们进行评估.

testAffineTransformSpeed affTr count = go count (0.5,Double)
        go 0 res = res
        go !n !res = go (n-1) (runAffineTransform affTr res)

不是那个消费者,关于res的爆炸只会将它评估到最外层的构造函数(,),并且你得到的结果是

runAffineTransform affTr (runAffineTrasform affTr (runAffineTransform affTr (...)))

当最终需要正常形式时,仅在最后评估.

如果强制立即评估结果的组件,

runAffineTransform affTr (!x,!y) = case
  (  get affTr `U.unsafeIndex` 0 * x
   + get affTr `U.unsafeIndex` 1 * y
   + get affTr `U.unsafeIndex` 2,get affTr `U.unsafeIndex` 3 * x
   + get affTr `U.unsafeIndex` 4 * y
   + get affTr `U.unsafeIndex` 5
  ) of (!a,!b) -> (a,b)

使用自定义严格的一对未装箱的Double#s对jtobin版本的主要区别在于,对于testAffineTransformSpeed中的循环,您使用盒装双打作为参数进行一次初始迭代,最后是组件结果是盒装的,这会增加一些不变的开销(我的盒子上每个循环大约5纳秒).循环的主要部分在两种情况下都采用Int#和两个Double#参数,并且当达到n = 0时,除了装箱之外,循环体是相同的.

当然,通过使用未装箱的严格对类型强制立即评估组件是更好的.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读