为什么严格会使 Haskell 中的性能变差
Why strictness makes performance worse in Haskell
我玩了严格的评估、向量和矩阵,得到了一个相当奇怪的结果。有如下代码:
module Test where
import qualified Data.Vector as V
import qualified Data.Matrix as M
import Control.DeepSeq
matrixCtor :: Int -> Int -> Int -> M.Matrix Int
matrixCtor x y size = M.matrix size size $ \(i,j) -> x*i+y*j
f :: M.Matrix Int -> M.Matrix Int
f b = c
where
n = M.nrows b
bt' = V.generate n $ \j -> M.getCol (j+1) b
c = M.matrix n n $ \(i,j) -> V.sum (V.unsafeIndex bt' (j-1))
我将其加载到 ghci 并执行以下操作:
*Main Test> :set +s
*Main Test> a = matrixCtor 1 2 800
(0.02 secs, 0 bytes)
*Main Test> f a `deepseq` 1
1
(6.69 secs, 8,684,393,584 bytes)
然后我试了一下:
*Main Test> a = matrixCtor 1 2 800
(0.00 secs, 0 bytes)
*Main Test> a `deepseq` 1
1
(0.35 secs, 220,646,904 bytes)
*Main Test> f a `deepseq` 1
1
(9.72 secs, 8,484,723,352 bytes)
*Main Test>
在第二个版本中,我提前计算了矩阵,在我看来应该加速函数f
的执行,但这并没有发生。我不明白为什么。
如果您真的想努力提高 GHCi 的性能,那么我对此表示赞赏,但是 GHCi 中的基准测试基本上不能用来推断代码在任何其他设置中的性能。您看到的性能数据仅在您的一个狭窄范围内有意义。
例如,当您将代码转换为标准基准并进行优化编译时,您会发现严格版本的性能更好,而不是更差:
benchmarking first
time 5.808 s (4.995 s .. 6.718 s)
0.996 R² (0.995 R² .. 1.000 R²)
mean 5.237 s (4.931 s .. 5.452 s)
std dev 325.5 ms (0.0 s .. 374.0 ms)
variance introduced by outliers: 19% (moderately inflated)
benchmarking second
time 5.276 s (4.576 s .. 6.089 s)
0.997 R² (0.990 R² .. 1.000 R²)
mean 5.070 s (4.817 s .. 5.212 s)
std dev 224.0 ms (0.0 s .. 244.9 ms)
variance introduced by outliers: 19% (moderately inflated)
我玩了严格的评估、向量和矩阵,得到了一个相当奇怪的结果。有如下代码:
module Test where
import qualified Data.Vector as V
import qualified Data.Matrix as M
import Control.DeepSeq
matrixCtor :: Int -> Int -> Int -> M.Matrix Int
matrixCtor x y size = M.matrix size size $ \(i,j) -> x*i+y*j
f :: M.Matrix Int -> M.Matrix Int
f b = c
where
n = M.nrows b
bt' = V.generate n $ \j -> M.getCol (j+1) b
c = M.matrix n n $ \(i,j) -> V.sum (V.unsafeIndex bt' (j-1))
我将其加载到 ghci 并执行以下操作:
*Main Test> :set +s
*Main Test> a = matrixCtor 1 2 800
(0.02 secs, 0 bytes)
*Main Test> f a `deepseq` 1
1
(6.69 secs, 8,684,393,584 bytes)
然后我试了一下:
*Main Test> a = matrixCtor 1 2 800
(0.00 secs, 0 bytes)
*Main Test> a `deepseq` 1
1
(0.35 secs, 220,646,904 bytes)
*Main Test> f a `deepseq` 1
1
(9.72 secs, 8,484,723,352 bytes)
*Main Test>
在第二个版本中,我提前计算了矩阵,在我看来应该加速函数f
的执行,但这并没有发生。我不明白为什么。
如果您真的想努力提高 GHCi 的性能,那么我对此表示赞赏,但是 GHCi 中的基准测试基本上不能用来推断代码在任何其他设置中的性能。您看到的性能数据仅在您的一个狭窄范围内有意义。
例如,当您将代码转换为标准基准并进行优化编译时,您会发现严格版本的性能更好,而不是更差:
benchmarking first
time 5.808 s (4.995 s .. 6.718 s)
0.996 R² (0.995 R² .. 1.000 R²)
mean 5.237 s (4.931 s .. 5.452 s)
std dev 325.5 ms (0.0 s .. 374.0 ms)
variance introduced by outliers: 19% (moderately inflated)
benchmarking second
time 5.276 s (4.576 s .. 6.089 s)
0.997 R² (0.990 R² .. 1.000 R²)
mean 5.070 s (4.817 s .. 5.212 s)
std dev 224.0 ms (0.0 s .. 244.9 ms)
variance introduced by outliers: 19% (moderately inflated)