批量更改STUArray值的性能

时间:2015-03-12 06:04:00

标签: arrays performance sorting haskell graph

我正在Haskell中实现拓扑排序,要求尽可能高效。我已经描述了我当前的解决方案,并发现以下方法占用了总时间的60%(以及0额外空间量):

import Control.Monad.ST
import Control.Monad
import Data.Array.ST
import Data.Array.Unboxed
import Data.Word
import Data.Array.Base

zeroElementsAfterDecrement' :: (MArray a e m, Num e, Eq e) => a Int e -> [Int] -> m [Int]
zeroElementsAfterDecrement' arr is = foldr k (return []) is
  where k i a = do xs <- a
                   decremented <- liftM (subtract 1) (unsafeRead arr i)
                   unsafeWrite arr i decremented
                   if decremented == 0 then return (i:xs) else return xs

largenum :: Int
largenum = 10000000
test = runST $ do arr <- newArray (1, largenum) 100 :: ST s (STUArray s Int Word32)
                  zeroElementsAfterDecrement' arr [1..largenum]


main = (putStrLn . show) test

该函数接受一个数组(我使用未装箱的可变数组)和索引列表,按这些索引递减元素,并返回在此操作期间变为零的元素的索引。现在这比优化的C ++代码慢了10多倍,但与Python相比仍然相当不错(或者我可能不知道Python的优化方式)。我理解执行monadic代码会产生一些开销,但也许仍有优化方法我不知道?

修改

GHC:-O -fllvm:0.54s
GHC(使用unsafeWrite / unsafeRead和Word32):0.34s
g ++:0.24s
g ++ -O2:0.05s
python3:2.66s

此外,当我将foldr更改为foldl'时,它开始分配一些内存,结果慢了4倍,为什么会这样?

这是一个C ++版本我把它比作:

#include <iostream>
#include <vector>
using namespace std;
#define LARGENUM 10000000

int main()
{
    vector <int> arr; 
    for (int i = 0; i < LARGENUM; i++) {
        arr.push_back(100);
    }
    for (int i = 0; i < arr.size(); i++) {
        arr[i]--;
        if (arr[i] == 0)
            cout << i << endl;
    }
    return 0; 
}

和Python版本:

arr = [100] * 10000000

for x in range (0, 10000000 - 1):
    arr[x] = arr[x] - 1
    if arr[x] == 0:
        print x

0 个答案:

没有答案