我正在努力找出我正在构建的分析模型的最佳编程语言。主要考虑因素是它运行FOR循环的速度。
一些细节:
所有这些都说明了什么是FOR循环中最快的编程语言?从搜索SO和谷歌,Fortran和C泡沫到顶部,但在潜水前寻找更多建议在一个或另一个。
谢谢!
答案 0 :(得分:6)
当它到达CPU时,这个for循环看起来并不复杂:
for(int i = 0; i != 1024; i++)
转换为
mov r0, 0 ;;start the counter
top:
;;some processing
add r0, r0, 1 ;;increment the counter by 1
jne top: r0, 1024 ;;jump to the loop top if we havn't hit the top of the for loop (1024 elements)
;;continue on
正如您所知,这很简单,您无法真正优化它[1] ...重新聚焦算法级别。
问题的第一个问题是查看缓存局部性。查找矩阵乘法的经典示例并交换i
和j
索引。
编辑:作为第二个剪辑,我建议评估算法中迭代之间的数据依赖性和数据“矩阵”中的地点之间的数据依赖性。它可能是并行化的良好候选者。
[1]有一些微 - 优化可能,但那些不会产生你正在寻找的速度。
答案 1 :(得分:5)
~300k * ~150 * ~30 * ~12 = ~16G
次迭代,对吗?
在任何体面的CPU上,任何编译语言都应该在几分钟内(如果不是几秒钟)完成这些原始操作。
Fortran,C / C ++几乎同样应该这样做。即使是托管语言,例如Java和C#,也只会略微落后(如果有的话)。
如果你有一个运行55小时~16G迭代的问题,这意味着他们离原始的很远(每秒80k?这太荒谬了),所以也许我们应该知道更多。 (正如已经建议的那样,磁盘访问限制性能?是网络访问吗?)
答案 2 :(得分:5)
正如@Rotsor所说,16G操作/ 55小时约为每秒80,000次操作,或每12.5微秒一次操作。这是每次操作的大量时间。
这意味着你的循环不是性能不佳的原因,它是 in 最里面的循环,花费时间。 Octave是一种解释性语言。仅这一点意味着一个数量级的减速。
如果你想要速度,首先需要使用编译语言。然后,您需要进行性能调整(也称为分析),或者只需在指令级别的调试器中单步执行。这将告诉你它在心中的实际行动。一旦你把它带到不浪费周期的地方,更漂亮的硬件,内核,CUDA等将为你带来并行性加速。但是,如果您的代码花费了不必要的多个周期,那就太愚蠢了。 (Here's an example of performance tuning - a 43x speedup just by trimming the fat.)
我无法相信响应者谈论matlab,APL和其他矢量化语言的数量。那些是口译员。它们为您提供了简明的源代码,它与完全不同与快速执行相同。当涉及到裸机时,它们与其他所有语言都使用相同的硬件。
补充:为了向您展示我的意思,我只是在这台发霉的旧笔记本电脑上运行了这个16G操作的C ++代码,它花了94秒,或者每次迭代大约6ns。 (我不敢相信你宝贝 - 整整一天都坐了那个东西。)
void doit(){
double sum = 0;
for (int i = 0; i < 1000; i++){
for (int j = 0; j < 16000000; j++){
sum += j * 3.1415926;
}
}
}
答案 3 :(得分:3)
就绝对速度而言,可能是Fortran后跟C,然后是C ++。在实际应用中,使用下降编译器编译的三个编写良好的代码应该足够快。
编辑 - 通常情况下,使用编译语言与解释语言的任何类型的循环或分叉(例如if语句)代码都会看到更好的性能。
举一个例子,在我最近开展的一个项目中,数据大小和操作大约是你在这里讨论的大小的3/4,但是就像你的代码一样,它几乎没有用于矢量化的空间,并需要显着的循环。将代码从matlab转换为C ++后,运行时间从16-18小时缩短到大约25分钟。
答案 4 :(得分:3)
对于您正在讨论的内容,Fortran可能是您的首选。最接近的第二位是可能是 C ++。对于这种任务,一些C ++库使用“表达式模板”来获得超过C的速度。不完全可以确定那些对你有益的东西,但C ++至少可以和C一样快,并且可能更快。
至少在理论上,Ada也没有理由不具备竞争力,但是我用它做这样的事情已经有很长时间了,我犹豫推荐它 - 不是因为它不好,而是因为我还没有很好地跟踪当前的Ada编译器,以便对它们进行智能评论。
答案 5 :(得分:3)
任何编译语言都应该在大致相同的条件下执行循环。
如果您可以用其术语表达您的问题,您可能需要查看CUDA或OpenCL并在GPU上运行矩阵代码 - 尽管这对于具有大量条件的代码来说不太好。
如果您希望保留常规CPU,则可以根据SSE分散/收集和位掩码操作来制定问题。
答案 6 :(得分:2)
无论您的平台是什么,也可能是汇编语言。但是编译器(特别是专门针对单个平台的专用设备(例如,ADI或TI DSP))通常与人类一样好或更好。此外,编译器经常知道你没有的技巧。例如,上述DSP支持零开销循环,编译器将知道如何优化代码以使用这些循环。
答案 7 :(得分:1)
Matlab将进行基于元素的逻辑运算,它们通常非常快。
以下是我的计算机上的一个简单示例(AMD Athalon 2.3GHz w / 3GB):
d=rand(300000,150);
d=floor(d*10);
>> numel(d(d==1))
ans =
4501524
>> tic;d(d==1)=10;toc;
Elapsed time is 0.754711 seconds.
>> numel(d(d==1))
ans =
0
>> numel(d(d==10))
ans =
4501524
一般来说,我发现matlab的运算符非常快,你只需要找到直接用矩阵运算符表达算法的方法。
答案 8 :(得分:1)
C ++ 不快。事实上,C在这方面特别糟糕。请参阅good math bad math。
我听说C99有__restrict指针有帮助,但对它不太了解。
Fortran仍然是数值计算的转换语言。
答案 9 :(得分:0)
如何存储数据?您的执行时间可能更多地受I / O(尤其是磁盘或更糟的网络)的影响,而不是您的语言。
假设对行的操作是正交的,我会使用C#并使用PLINQ来利用我可能的所有并行性。
答案 10 :(得分:0)
使用手工编码的汇编插件可能不是最好的吗?当然,假设您不需要携带。
那和优化算法应该有帮助(也许重组数据?)。
您可能还想尝试多种算法并对其进行分析。
答案 11 :(得分:0)
APL。
即使它被解释,它的原始运算符本身都在数组上运行,因此你很少需要任何显式循环。您编写相同的代码,无论数据是标量还是数组,并且解释器负责内部所需的任何循环,因此具有最小的开销 - 循环本身采用编译语言,并且将针对特定进行大量优化正在运行的CPU的架构。
以下是APL中数组处理简单性的一个示例:
A <- 2 3 4 5 6 8 10
((2|A)/A) <- 0
A
2 0 4 0 6 8 10
第一行将A设置为数字向量。 第二行用零替换向量中的所有奇数。 第三行查询A的新值,第四行是结果输出。
请注意,不需要显式循环,因为标量运算符如“|” (余数)根据需要自动扩展到数组。 APL还具有用于搜索和排序的内置原语,这可能比为这些操作编写自己的循环更快。
Wikipedia有一个很好的article on APL,它还提供了与IBM和Dyalog等供应商的链接。
答案 12 :(得分:0)
任何现代编译或JITted语言都会渲染到几乎相同的机器语言代码,在现代处理器上,每次迭代会产生10 nano 秒或更少的循环开销。
引用@Rotsor:
如果你有一个运行55小时~16G迭代的问题,这意味着他们离原始的很远(每秒80k?这太荒谬了),所以也许我们应该知道更多。
每秒80k次操作每次大约12.5微秒 - 比您期望的循环开销大1000倍。
假设您的55小时运行时是单线程的,并且如果您的每项操作与建议的一样简单,您应该能够(保守地)实现100x的加速并且非常容易地将其减少到不到一小时。
如果您想要更快地运行,您将需要考虑编写多线程解决方案,在这种情况下,提供良好支持的语言将是必不可少的。我倾向于PLINQ和C#4.0,但那是因为我已经知道C# - YMMV。
答案 13 :(得分:-1)
像clojure这样的懒惰加载语言怎么样?它是一个口齿不清,所以像大多数lisp方言缺少一个for循环,但有许多其他形式,更惯用于列表处理。它也可能有助于缩放问题,因为操作是线程安全的,并且因为语言功能正常,所以副作用较少。如果你想找到列表中所有可以对它们进行操作的项目,你可能会做这样的事情。
(def mylist ["i" "j" "i" "i" "j" "i"])
(map #(= "i" %) mylist)
结果
(true false true true false true)