这个编译成JavaScript的Haskell程序怎么能比JavaScript本身更快呢?

这个编译成JavaScript的Haskell程序怎么能比JavaScript本身更快呢?,javascript,haskell,ghc,ghcjs,Javascript,Haskell,Ghc,Ghcjs,我一直认为,与手动编写和优化的代码相比,GHCJS生成的JavaScript程序速度非常慢,原因显而易见。不过,在进行实验时,我注意到它并没有我预期的那么糟糕。我决定运行一系列小的基准测试来掌握真正的性能,这一点让我特别惊讶。程序只需用“1”填充一个数组,然后将它们相加 哈斯克尔: import Data.Array.Repa len = 1024*1024*64 arr = fromFunction (Z :. len) (const 1) :: Array D DIM1 Float ma

我一直认为,与手动编写和优化的代码相比,GHCJS生成的JavaScript程序速度非常慢,原因显而易见。不过,在进行实验时,我注意到它并没有我预期的那么糟糕。我决定运行一系列小的基准测试来掌握真正的性能,这一点让我特别惊讶。程序只需用“1”填充一个数组,然后将它们相加

哈斯克尔:

import Data.Array.Repa
len  = 1024*1024*64
arr  = fromFunction (Z :. len) (const 1) :: Array D DIM1 Float
main = sumAllP arr >>= print
JavaScript:

var len = 1024*1024*64
var arr = [];
var sum = 0;
for (var i=0; i<len; ++i)
    arr[i] = 1;
for (var i=0; i<len; ++i)
    sum += arr[i];
console.log(sum);

GHCJS如何能比纤薄、干净的本机for loop运行得更快?考虑到生成的代码应暴露于的框的数量,这应该是不可能的。

数组D DIM1 Float
是一个错误。它只表示为函数
const 1
加上数组的边界。任何地方都没有存储6400万个浮点数的数组


JavaScript程序实际上创建了一个6400万倍的数组,使用512MB的内存。读取和写入如此大的数组的成本是不可忽略的(分配它的成本也是不可忽略的;请注意大量的系统时间)。

您确定Haskell编译器没有优化代码以只打印最终结果吗?在任何情况下,我们都可能需要查看生成的代码,以了解其速度更快的原因。请提供ghcjs的输出.js。这就是问题的答案。是js的输出。也一样,只是它在打印总和后打印整个数组,以确保数组已填充。展开JavaScript循环以加快速度。@karakfa:这真的有帮助吗?我试着将其展开到几个不同的长度(即每次迭代增加2、4和16个),但这只是使它稍微慢了一点。也许我做错了什么?我尝试过的最开放的版本。啊,我明白了-我的错误是假设
sumAllP
以前计算过数组。调用
computeP
会使速度变慢,尽管仍有一小部分(4倍)的余量。但现在我发现了另一件意想不到的事情:长度加倍会导致JavaScript程序内存不足,而编译成JavaScript的Haskell程序(使用computeP)则不会。我确信computeP实际上是在计算数组,因为它会打印数组,所以。。。这对我来说是个谜,不是什么时候对数组求值的问题
arr
不会以数组的形式进行物理存储,无论您对其求值多少。如果您想要物理数组,可以使用其他存储格式之一,如
U
(而不是
D
)。是的,
computeP
生成一个
U
数组。
apple1$ ghcjs -O2 bench_fill.hs -funfolding-use-threshold10000 -funfolding-keeness-factor1000 -o bench_fill.js; time node bench_fill.js/all.js
Linking bench_fill.js (Main)
6.7108864e7

real    0m1.543s
user    0m1.512s
sys 0m0.033s

apple1$ time node benchfill.js
67108864

real    0m1.764s
user    0m1.173s
sys 0m0.583s