Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 优化创建过多垃圾(而不是堆栈溢出)的列表函数_Performance_List_Haskell_Garbage Collection_Automatic Differentiation - Fatal编程技术网

Performance 优化创建过多垃圾(而不是堆栈溢出)的列表函数

Performance 优化创建过多垃圾(而不是堆栈溢出)的列表函数,performance,list,haskell,garbage-collection,automatic-differentiation,Performance,List,Haskell,Garbage Collection,Automatic Differentiation,我有一个Haskell函数,它导致我的程序中超过50%的分配,导致我60%的运行时间被GC占用。我使用一个小堆栈(-K10K)运行,因此没有堆栈溢出,但是我可以用更少的分配使这个函数更快吗 这里的目标是计算矩阵与向量的乘积。例如,我不能使用,因为这是使用包的更大函数的一部分,所以我需要使用Num列表。在运行时,我假设使用Numeric.AD模块意味着我的类型必须是Scalar Double listMProd :: (Num a) => [a] -> [a] -> [a] li

我有一个Haskell函数,它导致我的程序中超过50%的分配,导致我60%的运行时间被GC占用。我使用一个小堆栈(
-K10K
)运行,因此没有堆栈溢出,但是我可以用更少的分配使这个函数更快吗

这里的目标是计算矩阵与向量的乘积。例如,我不能使用,因为这是使用包的更大函数的一部分,所以我需要使用
Num
列表。在运行时,我假设使用
Numeric.AD
模块意味着我的类型必须是
Scalar Double

listMProd :: (Num a) => [a] -> [a] -> [a]
listMProd mdt vdt = go mdt vdt 0
  where
    go [] _  s = [s]
    go ls [] s = s : go ls vdt 0
    go (y:ys) (x:xs) ix = go ys xs (y*x+ix)
基本上,我们循环遍历矩阵,相乘并添加累加器,直到到达向量的末尾,存储结果,然后再次继续重新启动向量。我有一个
quickcheck
测试,验证我得到的结果是否与hmatrix中的矩阵/向量积相同

我试过使用
foldl
foldr
等。我试过的任何东西都不能使函数更快(而且像
foldr
这样的东西会导致空间泄漏)

运行profiling告诉我,除了此函数是花费大部分时间和分配的地方之外,还有大量创建的内容,
Cells
ad
包中的一种数据类型

要运行的简单测试:

import Numeric.AD

main = do
    let m :: [Double] = replicate 400 0.2
        v :: [Double] = replicate 4 0.1
        mycost v m = sum $ listMProd m v 
        mygrads = gradientDescent (mycost (map auto v)) (map auto m)
    print $ mygrads !! 1000
这在我的机器上告诉我GC 47%的时间都很忙


有什么想法吗?

一个非常简单的优化是使
go
函数严格受其累加器参数的限制,因为它很小,如果
A
是原始函数,并且始终需要进行充分的评估,则可以解除其绑定:

{-# LANGUAGE BangPatterns #-}
listMProd :: (Num a) => [a] -> [a] -> [a]
listMProd mdt vdt = go mdt vdt 0
  where
    go [] _  !s = [s]
    go ls [] !s = s : go ls vdt 0
    go (y:ys) (x:xs) !ix = go ys xs (y*x+ix)
在我的机器上,它的加速比为3-4倍(用
-O2
编译)


另一方面,中间列表不应该很严格,这样就可以进行融合。

更多信息!你是如何运行这个程序的?你的测试线束在哪里?你用的是什么混凝土类型?Haskell编译器的标志和版本是什么?添加了一些信息。该函数通过ad grad函数调用,ad grad函数使用自己的类型(Num实例)。剖析显示了“单元格”的分配。一些半知半解的建议:您是否考虑使用“可变代码状态”和“代码> ST <代码>?和/?也许(?)甚至值得将向量列表转换为其他内容,例如?我对这些技术都没有经验,但这些链接可能会对你有进一步的帮助。排除一件显而易见的事情:如果你在
go
的最后一句中添加一个bang模式,例如
go(y:ys)(x:xs)!ix=go-ys-xs(y*x+ix)
你能给出一个最小的可执行示例吗?嗯,好主意,但在我的用例中根本没有帮助(在速度或GC使用方面没有改进)。我认为函数是通过ad库调用的,这一事实影响了性能(我看到一个单元格数据类型带有严格的Int字段)。