【发布时间】:2015-10-31 00:18:42
【问题描述】:
几个月前我开始使用 Julia,在听到人们对它的各种功能赞不绝口后决定试一试。我对它了解得越多,我就越喜欢它的风格,它将高级语言中易于表达的概念与注重速度和可用性相结合。我在 Julia 中实现了一个我也用 C++ 和 R 编写的模型,发现 Julia 版本的运行速度比 R 版本快得多,但仍然比 C++ 稍慢。即便如此,Julia 中的代码也比其他两种语言都更清晰。这很有价值,特别是当我对模型进行概括时,为扩大 Julia 代码的范围所做的工作量远远少于其他语言可能面临的可比工作量。
最近,我一直专注于让我的 Julia 代码运行得更快,因为我需要运行这个模型数万亿次。在这样做的过程中,我受到@code_warntype、@time、@profile 和ProfileView 以及track-allocation 标志的指导。伟大的。这个工具包不如其他一些语言的分析工具好,但它仍然指出了很多瓶颈。
我发现我的代码中恰好具有我喜欢 Julia 的高级表达能力,当我重写这种表达能力以避免不必要的分配时,我失去了这种表达能力。作为一个简单的例子,我最近更改了一行代码,如下所示
sum([x*y for x in some_list, y in similar_list])
到一个遍历列表并添加到状态变量的循环。不是火箭科学,我理解为什么不必分配数组会快一点。实际上,它比 很多 更快。所以我做了类似的事情,避免使用字典或“感觉”适合问题的复合类型,当我可以手动跟踪临时并行数组中的索引时,我讨厌这种编码风格,但显然运行当我多次重复创建和简要使用小型数据结构的特定操作时,速度要快得多。
总的来说,这在很大程度上很好,因为我已经将编写短方法的说明牢记在心,因此构成我自己的短方法行为的高级方法不需要“担心”短方法如何方法有效;较短的代码读起来会很笨重,但不会让我的程序的核心读起来很笨拙。
但这让我想知道我是否“遗漏了什么”。如果该语言的全部意义(对于我作为一个不关心理论的最终用户而言)部分是将速度与易于开发/思考/阅读/维护等结合起来,即成为一种可写和可用的技术计算语言,那么这是否意味着我不应该花时间思考将一堆数字相加的最快方法,不应该重写“易于阅读”或优雅的代码,利用映射、过滤器和高级函数概念转化为“笨拙”的代码,重新发明轮子来表达这些东西,以跟踪无处不在的低级数组索引? (我的某些部分期望一种在其设计背后具有如此多智能的语言足够聪明,以“弄清楚”当我编写 sum([x*y]) 时它实际上不需要分配一个新数组,并且我只是太迟钝了,无法找出正确的词来告诉语言,除了手动“告诉它”整个循环业务。有一次我什至考虑写 @macros 将一些快速表达的代码“转换”成长但更快的循环表达式,但我认为如果我本质上试图扩展编译器的功能只是为了解决相当简单的问题,那么我一定是在考虑错误的问题,这就是导致我写这个问题的原因。)
也许答案是“如果你想要真正高性能的代码,无论如何你都要付出代价”。或者换一种说法,读取循环、数组、跟踪索引等令人讨厌的快速代码处于速度-易读性权衡空间的有效前沿。如果是这样,那是完全正确的,因此我不会说我对 Julia 的看法有所减少。我只是想知道这种编程风格是否真的处于前沿,或者我的经验是否是因为我只是没有用这种语言“很好”地编程。 (以此类推,请参阅问题 What is your most productive shortcut with Vim? ,其中公认的优秀答案本质上是 OP 只是没有“得到”它。)我怀疑即使我已经成功地让语言做很多事情我想要什么,我只是没有“得到”一些东西,但我不知道该要求什么,因为我担心我没有得到的东西对我来说是一个未知的未知数。
TL;DR: 是否期望 Julia 的最佳实践是我花费大量时间将我的高级函数调用“分解”为循环和数组方面的原始实现,以便更快性能,还是这表明我没有考虑正确使用/使用该语言进行编程?
【问题讨论】:
-
嗨@Philip,您还在使用 Julia,您能否报告一下问题中的情况现在是否以及如何发生了变化?我相信已经努力使向量化代码更快,并且现在有更多基于宏和基于类型的功能进行优化,所以我想知道现在将高级代码“分解”为原始实现的需求是否减少了,如果所以多少。
-
我仍然使用它,尽管我没有能力回答您的问题,因为我自己的需求已经从代码性能转向代码清晰度。所以我现在不知道 Julia 让编写“自动”执行良好的清晰代码变得多么容易——我只知道我一直在使用它,因为编写清晰代码很容易! :)
标签: performance coding-style julia