惊蛰、魏子敏编译

Julia焦虑?这有份Facebook软件工程师的测试差评

近日,MIT CSAIL 实验室正式发布了 Julia 1.0,不少人称,该语言结合了C语言的性能和Python 的易上手性,被称为最聪明的一群大脑创造出的现代编程语言。

Julia 官网:

https://julialang.org/

Julia Github地址:

https://github.com/JuliaLang

自诞生之日起,Julia语言就备受关注。但是,这门“未来的语言”真的值得所有人学习吗?

在Julia初诞生之初,一位来自Facebook的软件工程师Victor Zverovich对这门语言做了一个性能测评,他从性能、语言、安全性、Library、发展上详细叙述了Julia的特质,最终得出了“give up on Julia”的结论。

尽管这份“买家秀”距离今天时间略久,Julia经过一年多的演进,在本周发布时已有了很大的进步,但是一门语言自诞生之日,其基因毕竟已经携带了某种特性,因此这篇文章现在读起来仍然有一些不错的参考价值。

作者Victor Zverovich个人主页:

http://www.zverovich.net/

当然,作为一门正在被追捧的语言,Julia还是值得了解。以下两个视频可以帮你迅速了解并安装尝试一下这门语言。

第一个视频向python使用者详细介绍了Julia的性能、特征。演讲来自IBM论坛,演讲者有1.5年Julia使用经验,也是杜克大学技术神经网络实验室研究员,感兴趣的同学可以戳视频观看


在官方发布后,也有人制作了一个详细的Julia安装使用手把手教学视频


最后,Victor Zverovich的这份Julia差评买家秀,可能可以部分缓解你的编程语言焦虑。

文章链接:

http://www.zverovich.net/2016/05/13/giving-up-on-julia.html

首次了解Julia编程语言时,我对它非常热衷。Julia语言的吸引力从官网上的功能列表就可见一斑:

  • 多分派:提供跨多种参数类型来组合定义函数的能力

  • 动态类型系统:文档,优化和分派的类型

  • 良好的性能,甚至能接近包括C语言在内的静态编译语言

  • 内置程序包管理器

  • 类似Lisp的宏和其他元编程工具

  • 可以通过使用PyCall包来调用Python函数

  • 不需要包装器或特殊API就能直接调用C函数:

  • 强大的类似shell的功能,用于管理其他进程

  • 专为并行和分布式计算而设计

  • 协同程序:轻量级“绿色”线程

  • 用户自定义的类型与内置函数一样快速、紧凑

  • 为不同的参数类型自动生成高效的专用代码

  • 针对数字和其他类型的优雅且可扩展的转换

  • 对Unicode的有效支持,包括但不限于UTF-8

  • MIT 开源许可(MIT license):免费+开源

然而,随着我对Julia语言的了解变得深入,亲自上手实验,我对它越来越不满意了。我将在这篇文章中解释为什么。

性能

当我看到Julia网站上报道的微基准测试时,我感受到了第一个次失望。粗浅浏览就能感受到其中的大问题

链接:

https://github.com/JuliaLang/julia/issues/4662

Julia比C或C++慢得多,这一点倒是没有什么可指责的,毕竟大多数语言都是。最令人失望的是其声称的表现与观察到的表现之间的显著差异。

例如,Julia中的一个简单的hello world程序运行速度比Python的版本慢约27x,比C语言慢约187x。这些性能是Linux上运行的结果,虽然我自己不使用Windows,但别人告诉我在那个环境下的差异更明显。

# test.jl println("Hello, World!")

# test.py print("Hello, World!")

#include <stdio.h> int main() {  printf("Hello, World!\n"); }

$ time julia test.jl Hello, World! real  0m0.371s user  0m0.240s sys  0m0.312s $ time python test.py Hello, World! real  0m0.014s user  0m0.004s sys  0m0.004s $ gcc -O3 test.c $ time ./a.out Hello, World! real  0m0.002s user  0m0.000s sys  0m0.000s

如果忽略启动时间,Julia在简单的数组运算、矩阵运算以及循环上性能尚佳,但我们已经知道怎么用Python或者其他语言来高效执行这些操作了。👇

https://www.ibm.com/developerworks/community/blogs/jfp/entry/Python_Meets_Julia_Micro_Performance

不仅仅是脚本,Julia的REPL的响应性优化需要很长时间才能启动,并且在使用JIT编译器(Just-in-Time Complier)时有明显滞后。更让人担忧的是,这一问题的解决上似乎没有太大进展。一年前使用时,REPL就是个大痛点,现在仍然如此。

除此之外,Julia程序的内存消耗过多。Julia上面hello world示例使用的内存比Python高18倍,比C高92倍。

可能的原因是Julia使用LLVM进行JIT编译。LLVM非常适合作为静态编译语言的编译器后端,但众所周知,它在动态语言环境中无法达到同样的效果。Unladen Swallow和最近从WebVM迁移的WebKit 就是值得注意的例子。👇

https://en.wikipedia.org/wiki/Unladen_Swallow

https://webkit.org/blog/5852/introducing-the-b3-jit-compiler/

语言

在语言设计中,Julia也保留了一些现代编程语言很好的功能,但其语法仍是一大诟病。颇为模糊的语法大概只有MATLAB的忠粉会习惯。

当然,在可读性方面,Julia也很难与Python竞争。人们常说,代码被读比被写的次数多。从这一点来看,Julia肯定有改进的余地。表达式语法更合理了,但仍然有一些非正统的选择操作符,标点符号和多行注释的语法(例如#= \ // $?),这些注释会给使用者带来不少麻烦。

从1开始索引的设计决策也有待商榷。虽然在某些情况下它可能很方便,但在与所有使用基于0索引的主流编程语言进行互操作时,会增加错误的出现,也会增加额外工作。例如:

ret = @grb_ccall(delconstrs, Cint, (                 Ptr{Void},                 Cint,                 Ptr{Cint}),                  model, convert(Cint,numdel), idx.-1)

当然,有人可能会认为Julia并不是一种通用编程语言,而是一种数值计算语言。但是,正如现在的Python所展现的能力,编程语言并不必为了一个性能而在另一个性能上有所欠缺。

我想在本节中提到的最后一个问题是API文档。甚至与Doxygen相比,Julia标准文档系统都算得上退步,更不用说Sphinx了。它不依赖于语义标记,而采用基于Markdown的基本格式,更侧重于展示。除了明显的Markdown限制之外,这种格式也让编写异构项目的开发文档更麻烦了。

安全

当然,JNA-和ctypes类型的FFI确实很方便。然而,将其设置为与本机API接口的默认方式就会出现重大安全问题。C和C++都采用头文件是有其原因的。手动声明所有内容不仅耗时,而且容易出错。在C Call 上出一点点问题都可能造成段错误(segmentation fault)。有意思的是,当因为官方示例有问题,我把文档中的代码从libc更改为libc.so.6,就出现了段错误。

julia> val = ccall((:getenv, "libc.so.6"), Ptr{UInt8}, (Ptr{UInt8},), var) signal (11): Segmentation fault

这个性能上,Python甚至Java与C的API都更好用。

Libraries

Julia目前缺乏的另一个重要内容是库(Library),尤其是标准库。

例如,文本格式(.txt)是人们可能想到的最基本和最常用的语言形式之一,而Julia甚至落后于C++ 98。标准库提供了@printf和@sprintf,但这些都是无法扩展的。你甚至无法将它们对复数进行格式化。Julia确实有一个基本字符串插值,但目前来看,它似乎只对最基本的格式有用。

作为宏,@printf/ @sprintf为每个格式字符串生成自定义代码,希望它比在运行时解析它更有效。有人甚至说,Julia语言“要赶上C语言还需要一段时间,更不用说击败它了”👇。

http://stackoverflow.com/q/19783030/471164

举个例子,让我们看一下C中的一个简单的printf示例:

void f(char *buffer, const char *a, double b) {  sprintf(buffer, "this is a %s %g", a, b); }

它只汇编了几条指令:

f: .LFB23: .cfi_startproc movq  %rsi, %r8 movl  $.LC0, %ecx movq  $-1, %rdx movl  $1, %esi movl  $1, %eax jmp  __sprintf_chk .cfi_endproc

下面是julia版本:

function f(a, b)  @sprintf("this is a %s %g", a, b) end

运行code_native(f, (ASCIIString, Float64))并查看输出,您将看到将近500条指令。可以想象一下@(s)printf调用的次数。这个数量是相当巨大的。由于经常使用文本格式,这种指令方式可能会产生严重的代码冗长问题。C语言版本可能没有这么安全,但有一些安全的替代方案,也并不会牺牲代码的紧凑性。

用于单元测试的库也非常基础,至少与C++和Java中的库相比是这样。

发展

我对大型代码库并不陌生,但在考虑是否为Julia项目做开源贡献时,我发现代码库简直就是C,C++,Julia和Lisp的混搭,不得不望而却步,尽管我对LLVM在后端的使用有一些经验。原因并不是因为不喜欢混搭中的某一种语言,而是该项目要求开发人员同时精通数种编程语言。这相当于只有拥有独特专业知识或在特定领域内工作的开发者才有能力参与到项目中。正如Dan Luu所说:

Julia开发组是一个由才华横溢的人员构成的小团队。他们基本上可以将所有代码保存在各自大脑中,也可以取得很大的进步,然而代价是其他开发者更难以做出贡献。这值得吗?很难说。

我不确定这种方法是否可取,其他人报告Julia开发速度放缓 :

Julia的发展的确越来越慢。在过去的9个月里,我都没怎么见过它。

总结

总而言之,目前的Julia语言有如下问题尚待改进:

  • 性能问题,包括启动时间长和JIT编译的延迟

  • 与其他语言的互操作性问题,

  • 文本格式化工具不足,

  • 缺乏良好的单元测试框架,

  • 默认情况下不安全的本地API接口,

  • 不必要的复杂代码库,

  • 对bug修复的不够重视

尽管如此,我认为该语言可以作为matlab的开源替代品,因为这门编程语言的语法可能对matlab用户很有吸引力,甚至会撼动Python在数值计算的地位。

相关报道:

工程JuliaFacebook
1
相关数据
神经网络技术
Neural Network

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

分布式计算技术
Distributed computing

在计算机科学中,分布式计算,又译为分散式運算。这个研究领域,主要研究分布式系统如何进行计算。分布式系统是一组电脑,通过网络相互链接传递消息与通信后并协调它们的行为而形成的系统。组件之间彼此进行交互以实现一个共同的目标。

参数技术
parameter

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

大数据文摘
大数据文摘

秉承“普及数据思维,传播数据文化,助⼒产业发展”的企业⽂化,我们专注于数据领域的资讯、案例、技术,形成了“媒体+教育+⼈才服务”的良性⽣态,致⼒于打造精准数据科学社区。

大数据文摘
大数据文摘

秉承“普及数据思维,传播数据文化,助⼒产业发展”的企业⽂化,我们专注于数据领域的资讯、案例、技术,形成了“媒体+教育+⼈才服务”的良性⽣态,致⼒于打造精准数据科学社区。

返回顶部