C语言在实际中比R语言快多少?

9
我曾经在R中编写了一个Gibbs采样器,现在决定将其移植到C语言中以测试它的速度是否更快。我发现许多网页声称使用C语言可以比R快50倍,但是每次我使用时,它只比R快5或6倍。我的问题是:这是预期的结果吗?还是有一些技巧我没有使用,可以使我的C代码显著地更快(就像使用向量化加速R代码一样)?我基本上是拿着代码,在C语言中重写了它,用for循环替换矩阵操作,并将所有变量都变成指针。

此外,有没有人知道一些从R程序员角度来看的C语言资源?有一本名为《R编程艺术》的优秀书籍,但似乎是从已经掌握C语言的人的角度来写的。

另外,当我的C代码在Windows标准R GUI中运行时,屏幕往往会冻结。它不会崩溃;当代码运行完毕后,它会恢复正常,但它会阻止我在GUI中做其他事情。有没有人知道如何避免这种情况?我是使用.C()函数调用该函数的。


5
除非你真正了解和理解C语言,否则很难提高性能。至于为什么会出现冻结,这完全与线程有关。我猜测R会自动在后台执行,而C绝对不会。 - Richard J. Ross III
1
这要看情况。只要你坚持使用基本操作,速度应该差不多。如果你编写三个嵌套的{i,j,k}循环来实现矩阵乘法,C语言会更快。(但如果你使用矩阵/向量基本操作,情况就不一样了) - wildplasser
5
补充一下 @RichardJ.RossIII 的话,永远记住你不只是在比较语言,同时也在比较自己在每种语言中编程的能力。将两者区分开来可能很困难。 - joran
2
请参见 https://dev59.com/Em855IYBdhLWcg3w3IVh,了解第二段内容。 - GSee
1
这里有一个例子展示了Rcpp相对于经过优化的R代码产生了巨大的加速,但最终结果是由于原语,正如@wildplasser所指出的那样。在这种情况下,速度优势是因为Rcpp修改了原始对象而不是修改复制的对象。当C(++)代码执行与R代码相同的基本操作时,它同样快,但C允许更多地控制哪些操作被执行。 - Ari B. Friedman
显示剩余3条评论
4个回答

15
许多现有的文章都有明确的示例代码,例如Darren Wilkinson在他的博客中有几篇分析不同编程语言和硬件(例如将高端笔记本电脑与便携式电脑和树莓派进行比较)的文章。其中一些文章如下:

他的网站上还有许多其他文章--这些文章通常比较C、Java、Python等编程语言的性能。

我也使用了Rcpp创建了一个版本--请参阅这篇博客文章。今年夏天我们还在useR会议上使用了同样的例子来比较Julia、Python和R/C++,因此您可以找到更多的例子和参考资料。MCMC被广泛使用,并且是优化速度的“低挂果”。

鉴于这些示例,我想补充一下对两位先前评论的不同看法。速度并不会相同,在这种情况下很容易做得更好,您的C/C++技能将在很大程度上决定您的提升。

最后,一个经常被忽视的方面是RNG的速度非常重要。运行循环并添加内容很便宜--做出“好”的随机抽样则不然,并且许多跨系统的变化也源自此。


感谢您提供那些带有真实世界例子的链接!我之前看到的例子大多都是人为构造的,例如计算前一百万个正整数的总和。 - Flounderer
关于你最后一段的问题,我并没有找到在C语言中生成均匀随机数的好方法,所以我在开始之前在R中生成了我需要的所有随机数,然后将该数组的指针作为C函数的一个参数传递。我不确定这比在C语言中生成它们更好还是更差? - Flounderer
请参见R扩展编写,第6.3节或任何好的数值库的文档。Rcpp为您提供了免费的功能,甚至是向量化的,即一次调用可获得N个随机数。并且可以在编译速度下实现。 - Dirk Eddelbuettel
你的意思是C语言在进行“peek和poke”操作时需要花费很多时间吗?这个操作应该避免吗? - Flounderer
函数调用有开销。调用次数越少,执行速度越快。 - Dirk Eddelbuettel
在C++中,函数调用开销非常小(大约为纳秒级别),但如果您进行数百万次调用,则会累加。 - hadley

2

我认为,如果正确使用,C语言比R语言快得多。

以下是一些简单的优化方法: 将编译器设置为更高的速度优化。 使用-march标志进行编译。 如果你使用的是VS,请确保你使用的是发布选项而不是调试选项。


2
关于GUI冻结的问题,您可能需要偶尔调用R_CheckUserInterruptR_ProcessEvents

1

你观察到的性能差异将取决于许多因素:你正在执行的操作类型,你如何编写C代码,你使用了什么类型的编译器级别优化,你的目标CPU架构等等。

你可以编写基本的、粗糙的C代码,并获得一个能够正常工作并具有良好效率的东西。你也可以微调你的代码,以适应目标CPU的独特特性——可能会调用专门的汇编指令——并从代码中挤出每一滴性能。你甚至可以编写比R版本运行得慢得多的代码。C给了你很大的灵活性。这里的限制因素是你想要花多少时间来编写和优化C代码。

反之亦然(重复上一段,但交换“C”和“R”)。

我并不是在说话玩笑,但实际上并没有一个简单明了的答案来回答你的问题。唯一确定你的C版本会快多少的方法就是编写两种方式的代码并进行基准测试。


1
“你甚至可以编写比 R 版本运行速度明显慢得多的代码。”-- 不,实际上不行。 - Dirk Eddelbuettel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接