我是否正确使用朱莉娅?

时间:2015-10-31 00:18:42

标签: performance coding-style julia

几个月前我开始使用朱莉娅,经过数周的听证会,人们赞美它的各种功能,决定尝试一下。我对它的了解越多,我就越喜欢它的风格,在高级语言中融合表达概念的易用性,注重速度和可用性。我实现了一个我用C ++和R在Julia编写的模型,发现Julia版本的运行速度比R版本快得多,但仍然比C ++略慢。即便如此,代码在Julia中比在其他语言中更清晰。这是值得的,特别是在我推广该模型时,为扩大Julia代码范围所做的工作量远远低于其他语言中可比的工作量。

最近,我一直专注于让我的Julia代码运行得更快,因为我需要运行这个模型数万亿次。在此过程中,我受@code_warntype@time@profileProfileView以及track-allocation标志的引导。大。这个工具包并不像其他一些语言一样好用。分析工具,但它仍然指出了很多瓶颈。

我发现,我在我的代码中恰好具有我喜欢的朱莉娅的高级表现力,当我重写表达性以避免不必要的分配时,我失去了那种表达能力。作为一个简单的例子,我最近更改了一行代码

sum([x*y for x in some_list, y in similar_list])

循环迭代列表并添加到状态变量。不是火箭科学,我理解为什么不必分配数组更快一点。实际上它更快很多。所以我做了类似的事情,避免使用Dicts或感觉"感觉"对于问题的权利,当我可以只是手动跟踪临时并行数组中的索引时,我厌恶的编码风格但是当我重复创建和简单使用小的特定操作时显然运行得更快数据结构很多很多次。

总的来说,这很好,因为我已经注意到编写简短方法的指令,因此构成我自己的较短方法行为的更高级别的方法并不需要&#34 ;担心"关于较短的方法如何工作;较短的那些可以笨拙地阅读而不会使我的程序的核心笨重地阅读。

但这让我想知道我是否会错过一些东西。"如果语言的整个要点(对我来说,作为一个非理论相关的最终用户)部分地将速度与易于开发/思考/阅读/维护等结合起来,即成为可写和可用的技术计算语言,然后并不意味着我不应该花时间考虑最快的方法来添加一堆数字,不应该重写"易于阅读"或优雅的代码,利用映射,过滤器和高级功能概念进入" clunky"代码重新发明轮子来表达那些在低级别跟踪阵列索引的地方? (我的某些部分期望在其设计背后具有如此多智能的语言足够聪明以及#34;当我写和时它实际上不需要分配新数组([x * y]),而且我太过于愚蠢地找出正确的词语来告诉语言除了字面意思"手动告诉它整个循环业务。有一点我甚至想过关于将@macros写入"将一些快速表达的代码转换为长而快的循环表达式,但我认为如果我本质上试图扩展,我必须考虑错误的问题编译器的功能只是为了解决相当简单的问题,这就是我写这个问题的原因。)

也许答案是"如果你想要真正高效的代码,无论如何都要付出代价。"或者换句话说,快速代码与令人讨厌的读取循环,数组,跟踪索引等令人不愉快的代码是速度易读性权衡空间的有效前沿。如果是这样,这完全有效,因此我不会说我认为朱莉娅更少。我只是想知道这种编程风格是否真的在前沿,或者我的体验是什么,因为我只是没有编程"嗯"在语言中。 (通过类比,请参阅问题What is your most productive shortcut with Vim?,其中接受且优秀的答案基本上是OP只是没有"得到"它。)我怀疑即使我已经成功地让语言完成了我想做的事情,我只是没有"得到"什么东西,但我不太了解要求的东西,因为我害怕我不知道的东西对我来说是未知的。

TL; DR:在Julia的最佳实践中,我花了很多时间"分解"我的高级函数在循环和数组方面调用它们的原始实现以获得更快的性能,或者是否表明我没有考虑正确编程/使用该语言?

4 个答案:

答案 0 :(得分:8)

我认为这个主题与Julia用户群Does Julia really solve the two-language problem?上的讨论密切相关,我想在这里引用一个段落:

@Stefan Karpinski:

  

每个人都有不同的编写代码的样式和级别   语言。有高度抽象的C ++,而且是低级的   指针追逐基本上是C的C ++。即使在C中也是如此   void * -style编程,有效地动态输入   没有安全。鉴于这一事实,我不确定是什么解决了这两个问题   语言问题看起来就像这篇文章的观点一样   冒充。仅执行一种编程风格听起来像是一个问题   对我来说,不是解决方案。相反,我认为朱莉娅之一   最大的优势是它能够适应各种各样的   编程风格和级别。

我自己在Julia编程方面的经验表明,它可以填补现代编程语言的空白框,可以在科学家,工程师和所有计算专家手中带来并行处理,套接字服务器等高级功能。希望以高效,可维护和可读的方式完成工作的实用程序员,使用一体化编程语言。
在我看来,你正在以正确的方式使用Julia,Julia像其他语言一样代表不同情况下的不同编程风格,你可以优化瓶颈以提高速度,并保持其他部分更具可读性。您也可以使用Devectorize.jl之类的工具来避免重写问题。

答案 1 :(得分:7)

这是一个难以回答的难以回答的问题。因此,我会尝试做一个简短的贡献,希望能有一个" pot"不同的意见可能足够好。所以这里有3个意见:#/ p>

  1. 编程语言可以比作具有动量的对象。用户群是它的质量和它们的风格对它施加的力量。初始用户/开发人员可以在某个方向上拉语言,因为它仍然具有较低的质量。即使非常流行(例如C / C ++),语言仍然可以发展,但它更难。朱莉娅的未来仍然是不成文的,但它的承诺是其创作者和早期用户所充满的最初方向。

  2. 最好延迟优化,直到测试正确性为止。 "过早优化是所有邪恶的根源" (D. Knuth)。再次记住这一点永远不会伤害。因此,保持代码可读性和正确性要好于优化阶段,这可能会混淆代码的有界区域。

  3. 表达式sum([x*y ...])可能要求编译器过于聪明,简单地定义sumprod(x,y)可能更好。这将允许sumprod利用Julia的通用函数多调度框架并保持针对xy的优化,并且可能稍后针对特定类型的x和{{进行更优化1}}。

  4. 现在就是这样。意见很多。所以让讨论继续下去。

答案 2 :(得分:1)

你能写一个为你抽象这些概念的类(即FastDict或FastList或其他)吗?然后,在具有高性能代码时,您将具有相同的易读性(如果多一点黑盒子)。

答案 3 :(得分:0)

背景:我是R / Rcpp程序员,已经使用Julia大约一个月了。至少我编写的R代码的一半调用了我编写的C ++代码。

结论:我认为Julia尽可能解决了两种编程语言问题。这并不意味着人们可以像编写本机R / Python一样编写高性能代码,但是它大大降低了编写易于他人使用的高性能代码所需的工作量。

进一步的讨论:首先,我认为,如果不担心C / C ++类型问题(即声明类型,考虑有效的数据结构),就无法编写高性能代码而不是可读的数据结构等。因此,我认为,如果人们希望它们具有一种不需要关心数据结构的高性能语言,那么它们就倒霉了。当然,我是统计学家,而不是CS人员,因此我承认我在这里可能是错的。

但是,我有点惊讶使用Julia减少了我的工作时间。特别是,我的许多工作涉及首先为一些计算密集型部分编写一些C ++代码。一旦启动并运行,我基本上就是在本机R中编写R包装器和数据处理器,以为我的C ++代码准备数据。预处理通常在计算上并不昂贵,并且R有很多不错的工具可以执行此操作。如果一切都经过精心计划,那么从理论上讲这并不是一个糟糕的过程。

但是,实际上,实际上发生的事情是我启动并运行了所有程序,然后我意识到我出于某种原因想要更改某些C ++代码。这就是令人头疼的地方。不幸的是,在这一点上,我经常以所有数据的两个版本结束。一个将事物传递给一系列本地R预处理工具,另一个将事物传递为C ++对象。对某些C ++对象进行处理可能会对所有R对象产生很多后果。老实说,我浪费太多时间试图解决所有这些问题。

到目前为止,我与Julia的经历使这种头痛消失了。我正在使用的数据不再有R版本和C ++版本。只是朱莉娅。这也意味着将其他人的代码引入我代码的高性能部分非常容易。就像最近的例子一样,我一直想使用Matern协方差函数。这是一个非常重要的功能,我不想自己实现。我可以发现很多人都用R包实现了R包,并在本机R中很好地记录了调用。但是,就我而言,我真的很想从C ++调用此程序,而没有所有本机R的开销。这意味着要么(a)我需要搜索每个人的文档(不一定有充分的文档),要么搜索他们R包中的用户友好的C ++代码,或者(b)重新发明轮子。另一方面,如果我使用的是Julia,那应该是如果有人编写了一个不错的Matern协方差函数供世界使用,那么我应该能够直接使用它,而不必在代码中深入了解我实际上要使用。

当我开始构建更复杂的Julia项目时,可能会发现一些我尚不了解的类似烦扰。但是到目前为止,它似乎确实改善了将易于使用的工具(即R,类似于Python的调用)与高性能代码相结合的过程。