如何让 Python 像 julia python一样快地运行

IBM Bluemix
点击按钮,开始云上的开发!
developerWorks 社区
从本文展示的几个小型基准测试可以得出:通过优化 Python 代码以及借助各种可用于让代码更快运行的 Python 工具,能够使 Python 的性能与 Julia 的性能不相上下。
, 首席架构师,
Jean Francois Puget,IBM 分析解决方案首席结构师。
Julia 与 Python
的比较我是否应丢弃 Python 和其他语言,使用 Julia 执行技术计算?在看到
上的基准测试后,人们一定会这么想。Python
和其他高级语言在速度上远远有些落后。但是,我想到的第一个问题有所不同:Julia 团队能否以最适合 Python 的方式编写 Python 基准测试?我对这种跨语言比较的观点是,应该根据要执行的任务来定义基准测试,然后由语言专家编写执行这些任务的最佳代码。如果代码全由一个语言团队编写,则存在其他语言未得到最佳使用的风险。Julia 团队有一件事做得对,那就是他们将发布到了 github 上。具体地讲,Python 代码可在找到。第一眼看到该代码,就可以证实我所害怕的偏见。该代码是以 C 风格编写的,在数组和列表上大量使用了循环。这不是使用 Python 的最佳方式。我不会责怪 Julia 团队,因为我很内疚自己也有同样的偏见。但我受到了残酷的教训:付出任何代价都要避免数组或列表上的循环,因为它们确实会拖慢 Python
中的速度,请参阅 。考虑到对 C 风格的这种偏见,一个有趣的问题(至少对我而言)是,我们能否改进这些基准测试,更好地使用 Python 及其工具?在我给出答案之前,我想说我绝不会试图贬低 Julia。在进一步开发和改进后,Julia 无疑是一种值得关注的语言。我只是想分析 Python
方面的事情。实际上,我正在以此为借口来探索各种可用于让代码更快运行的 Python 工具。在下面的内容中,我使用 在 Jupyter Notebook 中使用 Python 3.4.3,其中已安装了所有的 Python 科学工具组合。我还会通过
Windows 机器上的 Python 2.7.10,使用
来运行代码。计时是对 Python 3.4.3 执行的。包含下面的所有基准测试的完整代码的 Notebook 可在找到。鉴于各种社交媒体上的评论,我添加了这样一句话:我没有在这里使用 Python 的替代性实现。我没有编写任何 C
代码:如果您不信,可试试寻找分号。本文中使用的所有工具都是 Anaconda 或其他发行版中提供的标准的 Cython 实现。下面的所有代码都在中运行。我尝试过使用来自
的 Julia 微性能文件,但不能使用 Julia 0.4.2 原封不动地运行它。我必须编辑它并将 @timeit 替换为
@time,它才能运行。在对它们计时之前,我还必须添加对计时函数的调用,否则编译时间也将包含在内。我使用的文件位于。我在用于运行 Python 的同一个机器上使用 Julia 命令行接口运行它。计时代码Julia 团队使用的第一项基准测试是 Fibonacci 函数的一段简单编码。def fib(n):
return fib(n-1)+fib(n-2)此函数的值随 n 的增加而快速增加,例如:fib(100) = 可以注意到,Python 任意精度 (arbitrary precision) 很方便。在 C 等语言中编写相同的函数需要花一些编码工作来避免整数溢出。在 Julia
中,需要使用 BigInt 类型。所有 Julia 基准测试都与运行时间有关。这是 Julia 中使用和不使用 BigInt 的计时: 0.000080 seconds (149 allocations:10.167 KB)
0.012717 seconds (262.69 k allocations:4.342 MB)在 Python Notebook 中获得运行时间的一种方式是使用神奇的 %timeit。例如,在一个新单元中键入:%timeit fib(20)执行它会获得输出:100 loops, best of 3:3.33 ms per loop这意味着计时器执行了以下操作: 运行 fib(20) 100 次,存储总运行时间 运行 fib(20) 100 次,存储总运行时间 运行 fib(20) 100 次,存储总运行时间 从 3 次运行中获取最小的运行时间,将它除以 100,然后输出结果,该结果就是 fib(20) 的最佳运行时间这些循环的大小(100 次和 3 次)会由计时器自动调整。可能会根据被计时的代码的运行速度来更改循环大小。Python 计时与使用了 BigInt 时的 Julia 计时相比出色得多:3 毫秒与 12 毫秒。在使用任意精度时,Python 的速度是 Julia 的 4
倍。但是,Python 比 Julia 默认的 64 位整数要慢。我们看看如何在 Python 中强制使用 64 位整数。使用 Cython 编译一种编译方式是使用
编译器。这个编译器是使用 Python
编写的。它可以通过以下命令安装:pip install Cython如果使用 Anaconda,安装会有所不同。因为安装有点复杂,所以我编写了一篇相关的博客文章:安装后,我们使用神奇的 %load_ext 将 Cython 加载到 Notebook 中:%load_ext Cython然后就可以在我们的 Notebook 中编译代码。我们只需要将想要编译的代码放在一个单元中,包括所需的导入语句,使用神奇的 %%cython 启动该单元:%%cython
def fib_cython(n):
return fib_cython(n-1)+fib_cython(n-2)执行该单元会无缝地编译这段代码。我们为该函数使用一个稍微不同的名称,以反映出它是使用 Cython
编译的。当然,一般不需要这么做。我们可以将之前的函数替换为相同名称的已编译函数。对它计时会得到:1000 loops, best of 3:1.22 ms per loop哇,几乎比最初的 Python 代码快 3 倍!我们现在比使用 BigInt 的 Julia 快 100 倍。我们还可以尝试静态类型。使用关键字 cpdef 而不是 def 来声明该函数。它使我们能够使用相应的 C 类型来键入函数的参数。我们的代码变成了:%%cython
cpdef long fib_cython_type(long n):
return fib_cython_type(n-1)+fib_cython_type(n-2)执行该单元后,对它计时会得到:10000 loops, best of 3:36 us per loop太棒了,我们现在只花费了 36 微秒,比最初的基准测试快约 100 倍!这与 Julia 所花的 80 毫秒相比更出色。有人可能会说,静态类型违背了 Python
的用途。一般来讲,我比较同意这种说法,我们稍后将查看一种在不牺牲性能的情况下避免这种情形的方法。但我并不认为这是一个问题。Fibonacci
函数必须使用整数来调用。我们在静态类型中失去的是 Python 所提供的任意精度。对于 Fibonacci,使用 C 类型 long
会限制输入参数的大小,因为太大的参数会导致整数溢出。请注意,Julia 计算也是使用 64 位整数执行的,因此将我们的静态类型版本与 Julia 的对比是公平的。缓存计算我们在保留 Python 任意精度的情况下能做得更好。fib 函数重复执行同一种计算许多次。例如,fib(20) 将调用 fib(19) 和
fib(18)。fib(19) 将调用 fib(18) 和 fib(17)。结果 fib(18) 被调用了两次。简单分析表明,fib(17) 将被调用 3
次,fib(16) 将被调用 5 次,等等。在 Python 3 中,我们可以使用 functools 标准库来避免这些重复的计算。from functools import lru_cache as cache
@cache(maxsize=None)
def fib_cache(n):
return fib_cache(n-1)+fib_cache(n-2)对此函数计时会得到:1000000 loops, best of 3:910 ns per loop速度又增加了 40 倍,比最初的 Python 代码快约 3,600 倍!考虑到我们仅向递归函数添加了一条注释,此结果非常令人难忘。Python 2.7 中没有提供这种自动缓存。我们需要显式地转换代码,才能避免这种情况下的重复计算。def fib_seq(n):
for i in range(n-1):
a,b = a+b,a
return a请注意,此代码使用了 Python 同时分配两个局部变量的能力。对它计时会得到:1000000 loops, best of 3:1.77 us per loop我们又快了 20 倍!让我们在使用和不使用静态类型的情况下编译我们的函数。请注意,我们使用了 cdef 关键字来键入局部变量。%%cython
def fib_seq_cython(n):
for i in range(n-1):
a,b = a+b,a
cpdef long fib_seq_cython_type(long n):
cdef long a,b
for i in range(n-1):
a,b = a+b,b
return a我们可在一个单元中对两个版本计时:%timeit fib_seq_cython(20)
%timeit fib_seq_cython_type(20)结果为:1000000 loops, best of 3:953 ns per loop
loops, best of 3:51.9 ns per loop静态类型代码现在花费的时间为 51.9 纳秒,比最初的基准测试快约 60,000(六万)倍。如果我们想计算任意输入的 Fibonacci 数,我们应坚持使用无类型版本,该版本的运行速度快 3,500 倍。还不错,对吧?使用 Numba 编译让我们使用另一个名为
的工具。它是针对部分 Python 版本的一个即时
(jit) 编译器。它不是对所有 Python 版本都适用,但在适用的情况下,它会带来奇迹。安装它可能很麻烦。推荐使用像
这样的 Python 发行版或一个已安装了 Numba 的 。完成安装后,我们导入它的 jit 编译器:from numba import jit它的使用非常简单。我们仅需要向想要编译的函数添加一点修饰。我们的代码变成了:@jit
def fib_seq_numba(n):
(a,b) = (1,0)
for i in range(n-1):
(a,b) = (a+b,a)
return a对它计时会得到:1000000 loops, best of 3:225 ns per loop比无类型的 Cython 代码更快,比最初的 Python 代码快约 16,000 倍!使用 Numpy我们现在来看看第二项基准测试。它是快速排序算法的实现。Julia 团队使用了以下 Python 代码:def qsort_kernel(a, lo, hi):
while i & hi:
pivot = a[(lo+hi) // 2]
while i &= j:
while a[i] & pivot:
while a[j] & pivot:
if i &= j:
a[i], a[j] = a[j], a[i]
if lo & j:
qsort_kernel(a, lo, j)
return a我将他们的基准测试代码包装在一个函数中:import random
def benchmark_qsort():
lst = [ random.random() for i in range(1,5000) ]
qsort_kernel(lst, 0, len(lst)-1)对它计时会得到:100 loops, best of 3:18.3 ms per loop上述代码与 C 代码非常相似。Cython 应该能很好地处理它。除了使用 Cython 和静态类型之外,让我们使用 Numpy
数组代替列表。在数组大小较大时,比如数千个或更多元素, 数组确实比
Python 列表更快。安装 Numpy 可能会花一些时间,推荐使用
或一个已安装了 Python 科学工具组合的 。在使用 Cython 时,需要将 Numpy 导入到应用了 Cython 的单元中。在使用 C 类型时,还必须使用 cimport 将它作为 C 模块导入。Numpy
数组使用一种表示数组元素类型和数组维数(一维、二维等)的特殊语法来声明。%%cython
import numpy as np
cimport numpy as np
cpdef np.ndarray[double, ndim=1] \
qsort_kernel_cython_numpy_type(np.ndarray[double, ndim=1] a, \
long lo, \
double pivot
while i & hi:
pivot = a[(lo+hi) // 2]
while i &= j:
while a[i] & pivot:
while a[j] & pivot:
if i &= j:
a[i], a[j] = a[j], a[i]
if lo & j:
qsort_kernel_cython_numpy_type(a, lo, j)
cpdef benchmark_qsort_numpy_cython():
lst = np.random.rand(5000)
qsort_kernel_cython_numpy_type(lst, 0, len(lst)-1)对 benchmark_qsort_numpy_cython() 函数计时会得到:1000 loops, best of 3:1.32 ms per loop我们比最初的基准测试快了约 15 倍,但这仍然不是使用 Python 的最佳方法。最佳方法是使用 Numpy 内置的 sort()
函数。它的默认行为是使用快速排序算法。对此代码计时:def benchmark_sort_numpy():
lst = np.random.rand(5000)
np.sort(lst)会得到:1000 loops, best of 3:350 us per loop我们现在比最初的基准测试快 52 倍!Julia 在该基准测试上花费了 419 微秒,因此编译的 Python 快 20%。我知道,一些读者会说我不会进行同类比较。我不同意。请记住,我们现在的任务是使用主机语言以最佳的方式排序输入数组。在这种情况下,最佳方法是使用一个内置的函数。剖析代码我们现在来看看第三个示例,计算 Mandelbrodt 集。Julia 团队使用了这段 Python 代码:def mandel(z):
maxiter = 80
for n in range(maxiter):
if abs(z) & 2:
z = z*z + c
return maxiter
def mandelperf():
r1 = np.linspace(-2.0, 0.5, 26)
r2 = np.linspace(-1.0, 1.0, 21)
return [mandel(complex(r, i)) for r in r1 for i in r2]
assert sum(mandelperf()) == 14791最后一行是一次合理性检查。对 mandelperf() 函数计时会得到:100 loops, best of 3:4.62 ms per loop使用 Cython 会得到:100 loops, best of 3:1.94 ms per loop还不错,但我们可以使用 Numba 做得更好。不幸的是,Numba 还不会编译列表推导式 (list
comprehension)。因此,我们不能将它应用到第二个函数,但我们可以将它应用到第一个函数。我们的代码类似以下代码。@jit
def mandel_numba(z):
maxiter = 80
for n in range(maxiter):
if abs(z) & 2:
z = z*z + c
return maxiter
def mandelperf_numba():
r1 = np.linspace(-2.0, 0.5, 26)
r2 = np.linspace(-1.0, 1.0, 21)
return [mandel_numba(complex(r, i)) for r in r1 for i in r2]对它计时会得到:1000 loops, best of 3:503 us per loop还不错,比 Cython 快 4 倍,比最初的 Python 代码快 9 倍!我们还能做得更好吗?要知道是否能做得更好,一种方式是剖析代码。内置的 %prun 剖析器在这里不够精确,我们必须使用一个称为
的更好的剖析器。它可以通过
pip 进行安装:pip install line_profiler安装后,我们需要加载它:%load_ext line_profiler然后使用一个神奇的命令剖析该函数:%lprun -s -f mandelperf_numba mandelperf_numba()它在一个弹出窗口中输出以下信息。Timer unit:1e-06 s
Total time:0.003666 s
File:&ipython-input-102-e&
Function: mandelperf_numba at line 11
Line # Hits Time Per Hit % Time Line Contents
==============================================================
11 def mandelperf_numba():
54.4 r1 = np.linspace(-2.0, 0.5, 26)
13 1 267 267.0 7.3 r2 = np.linspace(-1.0, 1.0, 21)
38.3 return [mandel_numba(complex(r, i)) for r in r1 for i in r2]我们看到,大部分时间都花费在了 mandelperf_numba() 函数的第一行和最后一行上。最后一行有点复杂,让我们将它分为两部分来再次剖析:def mandelperf_numba():
r1 = np.linspace(-2.0, 0.5, 26)
r2 = np.linspace(-1.0, 1.0, 21)
c3 = [complex(r, i) for r in r1 for i in r2]
return [mandel_numba(c) for c in c3]剖析器输出变成:Timer unit:1e-06 s
Total time:0.002002 s
File:&ipython-input-113-ba7b044b2c6c&
Function: mandelperf_numba at line 11
Line # Hits Time Per Hit % Time Line Contents
==============================================================
11 def mandelperf_numba():
12 1 678 678.0 33.9 r1 = np.linspace(-2.0, 0.5, 26)
13 1 235 235.0 11.7 r2 = np.linspace(-1.0, 1.0, 21)
14 1 617 617.0 30.8 c3 = [complex(r, i) for r in r1 for i in r2]
15 1 472 472.0 23.6 return [mandel_numba(c) for c in c3]我们可以看到,对函数 mandel_numba() 的调用仅花费了总时间的 1/4。剩余时间花在 mandelperf_numba()
函数上。花时间优化它是值得的。再次使用 Numpy使用 Cython 在这里没有太大帮助,而且 Numba 不适用。摆脱此困境的一种方法是再次使用 Numpy。我们将以下代码替换为生成等效结果的 Numpy
代码。 return [mandel_numba(complex(r, i)) for r in r1 for i in r2]此代码构建了所谓的二维网格。它计算由 r1 和 r2 提供坐标的点的复数表示。点 Pij 的坐标为 r1[i] 和 r2[j]。Pij 通过复数 r1[i] +
1j*r2[j] 进行表示,其中特殊常量 1j 表示单个虚数 i。我们可以直接编写此计算的代码:@jit
def mandelperf_numba_mesh():
width = 26
height = 21
r1 = np.linspace(-2.0, 0.5, width)
r2 = np.linspace(-1.0, 1.0, height)
mandel_set = np.zeros((width,height), dtype=int)
for i in range(width):
for j in range(height):
mandel_set[i,j] = mandel_numba(r1[i] + 1j*r2[j])
return mandel_set请注意,我将返回值更改为了一个二维整数数组。如果要显示结果,该结果与我们需要的结果更接近。对它计时会得到:10000 loops, best of 3:140 us per loop我们比最初的 Python 代码快约 33 倍!Julia 在该基准测试上花费了 196 微秒,因此编译的 Python 快 40%。向量化让我们来看另一个示例。老实地讲,我不确定要度量什么,但这是 Julia 团队使用的代码。def parse_int():
for i in range(1,1000):
n = random.randint(0,2**32-1)
s = hex(n)
if s[-1]=='L':
s = s[0:-1]
m = int(s,16)
assert m == n实际上,Julia 团队的代码有一条额外的指令,用于在存在末尾的 'L' 时删除它。我的 Anaconda 安装需要这一行,但我的 Python 3
安装不需要它,所以我删除了它。最初的代码是:def parse_int():
for i in range(1,1000):
n = random.randint(0,2**32-1)
s = hex(n)
if s[-1]=='L':
s = s[0:-1]
m = int(s,16)
assert m == n对修改后的代码计时会得到:100 loops, best of 3:3.33 ms per loopNumba 似乎没什么帮助。Cython 代码运行速度快了约 5 倍:1000 loops, best of 3:617 us per loopCython 代码运行速度快了约 5 倍,但这还不足以弥补与 Julia 的差距。我对此基准测试感到迷惑不解,我剖析了最初的代码。以下是结果:Timer unit:1e-06 s
Total time:0.013807 s
File:&ipython-input-3-1d&
Function: parse_int at line 1
Line # Hits Time Per Hit % Time Line Contents
==============================================================
1 def parse_int():
2 .7 5.1 for i in range(1,1000):
66.3 n = random.randint(0,2**32-1)
7.4 s = hex(n)
5 999 863 0.9 6.3 if s[-1]=='L':
6 s = s[0:-1]
9.7 m = int(s,16)
8 999 738 0.7 5.3 assert m == n可以看到,大部分时间都花费在了生成随机数上。我不确定这是不是该基准测试的意图。加速此测试的一种方式是使用 Numpy 将随机数生成移到循环之外。我们一次性创建一个随机数数组。def parse_int_vec():
n = np.random.randint(0,2**32-1,1000)
for i in range(1,1000):
s = hex(ni)
m = int(s,16)
assert m == ni对它计时会得到:1000 loops, best of 3:848 us per loop还不错,快了 4 倍,接近于 Cython 代码的速度。拥有数组后,通过循环它来一次向某个元素应用 hex() 和 int() 函数似乎很傻。好消息是,Numpy 提供了一种向数组应用函数的方法,而不必使用循环,该函数是
numpy.vectorize() 函数。此函数接受一次处理一个对象的函数。它返回一个处理数组的新函数。vhex = np.vectorize(hex)
vint = np.vectorize(int)
def parse_int_numpy():
n = np.random.randint(0,2**32-1,1000)
s = vhex(n)
m = vint(s,16)
np.all(m == n)
return s此代码运行速度更快了一点,几乎像 Cython 代码一样快:1000 loops, best of 3:703 us per loop我肯定 Python 专家能够比我在这里做得更好,因为我不太熟悉 Python 解析,但这再一次表明避免 Python 循环是个不错的想法。结束语上面介绍了如何加快 Julia 团队所使用的 4 个示例的运行速度。还有 3 个例子: pisum 使用 Numba 的运行速度快 29 倍。 randmatstat 使用 Numpy 可将速度提高 2 倍。 randmatmul 很简单,没有工具可应用到它之上。包含所有 7 个示例的完整代码的 Notebook 可在获得。我们在一个表格中总结一下我们的结果。我们给出了在最初的 Python 代码与优化的代码之间实现的加速。我们还给出了对 Julia
团队使用的每个基准测试示例使用的工具。 时间以微秒为单位
Python 优化后的代码
Python 初始代码
Julia / Python 优化后的代码
Fibonacci64 位
Fib BigInt
Mandelbrodt
randmatmul
randmatstat
X 这个表格表明,在前 4 个示例中,优化的 Python 代码比 Julia 更快,后 3 个示例更慢。请注意,为了公平起见,对于
Fibonacci,我使用了递归代码。我认为这些小型的基准测试没有提供哪种语言最快的明确答案。举例而言,randmatstat 示例处理 5x5 矩阵。使用 Numpy
数组处理它有点小题大做。应该使用更大的矩阵执行基准测试。我相信,应该在更复杂的代码上对语言执行基准测试。中提供了一个不错的示例。在该文章中,Julia 似乎优于 Cython。如果我有时间,我会使用 Numba
试一下。无论如何,可以说,在这个小型基准测试上,使用正确的工具时,Python 的性能与 Julia 的性能不相上下。相反地,我们也可以说,Julia 的性能与编译后的
Python 不相上下。考虑到 Julia 不需要对代码进行任何注释或修改,所以这本身就很有趣。补充说明我们暂停一会儿。我们已经看到在 Python 代码性能至关重要时,应该使用许多工具: 使用 line_profiler 执行剖析。 编写更好的 Python 代码来避免不必要的计算。 使用向量化的操作和通过 Numpy 来广播。 使用 Cython 或 Numba 编译。使用这些工具来了解它们在哪些地方很有用。与此同时,请谨慎使用这些工具。分析您的代码,以便可以将精力放在值得优化的地方。重写代码来让它变得更快,有时会让它难以理解或通用性降低。因此,仅在得到的加速物有所值时这么做。Donald
Knuth 曾经恰如其分地提出了这条建议:“我们在 97% 的时间应该忘记较小的效率:不成熟的优化是万恶之源。”但是请注意,Knuth 的引语并不意味着优化是不值得的,例如,请查看和。Python 代码可以优化,而且应该在有意义的时间和位置进行优化。我们最后给出一个讨论我所使用的工具和其他工具的有趣文章列表:。scipy 团队的一篇简短的优化指南。其中还讨论了内存剖析。。各种剖析工具的简短介绍。. 和。来自 Jake Vanderplas
的三篇有趣的文章。在最后一篇中,他展示了如何结合使用 Python 与 Numba,得到仅比高度优化的 Fortran 代码慢 30% 的代码。 pandas 文档中的。一篇讲述如何让 pandas 代码更快的实用指南。 Cython 文档中的和。。标题不言自明。。2015 年 12 月 16 日更新。Python 3.4 拥有一个能显著加速 Fibonacci() 函数的内置缓存。我更新了这篇文章来展示它的用途。2015 年 12 月 17 日更新。在运行 Python 的相同机器上 运行 Julia 0.4.2 会导致时间增加。
参考资料 :查找丰富的操作信息、工具和项目更新,帮助您掌握开源技术并将其用于 IBM 产品。
加入 ,查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
免费下载、试用软件产品,构建应用并提升技能。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Open sourceArticleID=1025932ArticleTitle=如何让 Python 像 Julia 一样快地运行publish-date=如何能够让外行或初学者快速准确地理解 Python 是一种什么样的..._百度知道用户定义的类型和内建类型一样快 Automatic generation of efficient, specialized code for different argument types 美观可扩展的类型转换与提升 高效支持 , 包括且不只
免费开源()
高性能的JIT编译器 通过使用类型推断和 即时(JIT)编译 ,以及 LLVM , Julia 具有可选的类型声明,重载,高性能等特性。为了能让您对Julia的性能和其它语言在数值计算和科学计算中有一个更好的比较,我们为多种不同语言写了一些简单的标准测试程序:
FortranJuliaPythonRMatlabOctaveMathe-maticaJavaScriptGoLuaJITJava gcc 5.1.1 0.4.0 3.4.3 3.2.2 R2015b 4.0.0 10.2.0 V8 3.28.71.19 go1.5 gsl-shell 2.3.1 1.8.0_45
fib0.702.1177.76533.5226.899324.35118.533.361.861.711.21 parse_int5.051.4517.0245.73802.529581.4415.026.061.205.773.35 quicksort1.311.1532.89264.544.921866.0143.232.701.292.032.60 mandel0.810.7915.3253.167.58451.815.130.661.110.671.35 pi_sum1.001.0021.999.561.00299.311.691.011.001.001.00 rand_mat_stat1.451.6617.9314.5614.5230.935.952.302.963.273.92 rand_mat_mul3.481.021.141.571.121.121.3015.071.421.162.36
Figure: 基准测试时间是相对于C 语言的(时间越短越好, C 的用时为单位1).
C 和 Fortran 语言使用了 gcc 5.11 编译, 使用最佳的优化 (从-O0到 -O3)。 C,Fortran,Go和Julia都使用了 v0.2.14.Python 3 通过
安装。rand_mat_stat 和 rand_mat_mul 算法在Python中通过numpy(v1.9.2)中的函数实现,其它部分均为纯Python语言实现。
function mandel(z)
maxiter = 80
for n = 1:maxiter
if abs(z) & 2
return n-1
z = z^2 + c
return maxiter
function randmatstat(t)
v = zeros(t)
w = zeros(t)
for i = 1:t
a = randn(n,n)
b = randn(n,n)
c = randn(n,n)
d = randn(n,n)
P = [a b c d]
Q = [a b; c d]
v[i] = trace((P.'*P)^4)
w[i] = trace((Q.'*Q)^4)
std(v)/mean(v), std(w)/mean(w)
上面的代码是很简洁,并且对于任何一个使用过其它编程语言的人来说都很熟悉。Julia对randmatstat的实现也是相较于同样的极其简单的, 并且没有很多性能上的牺牲。计划中的编译器优化将会在未来弥补这一点点在性能上的不足(相较于C语言)。通过语言本身的设计,Julia将使得你能够仅以牺牲少量的性能就可以编写底层的循环,到高级的编程风格应用,用简单的方式实现复杂的算法。 This continuous spectrum of programming levels is a hallmark of the Julia approach to programming and is very much an intentional feature of the language. 为分布式与云计算设计 Julia并没有给 Julia does not impose any particular style of parallelism on the user. Instead, it provides a number of , making it flexible enough to support a number of styles of parallelism, and allowing users to add more. The following simple example demonstrates how to count the number of heads in a large number of coin tosses in parallel. nheads = @parallel (+) for i=1:
int(randbool())
end This computation is automatically distributed across all available compute nodes, and the result, reduced by summation (+), is returned at the calling node. Here is a screenshot of a web-based interactive
session, using .
provides a way to run IJulia notebooks in your browser on Docker sandboxed containers provisioned on demand.
This paves the way for fully cloud-based operation, including data management, code editing and sharing, execution, debugging, collaboration, analysis, data exploration, and visualization. The eventual goal is to let people stop worrying about administering machines and managing data and get straight to the real problem.
can produce various plots with various rendering backends in the browser (SVG, PDF, PNG and various other backends are also supported). Interactivity can be added to graphs and plots with the
package. A small sampling of the capabilities of Gadfly is presented below.
Free, Open Source and Library-Friendly The core of the Julia implementation is licensed under the . Various libraries used by the Julia environment include their own licenses such as the , , and
(therefore the environment, which consists of the language, user interfaces, and libraries, is under the GPL). The language can be built as a shared library, so users can combine Julia with their own C/Fortran code or proprietary third-party libraries. Furthermore, Julia makes it
in C and Fortran shared libraries, without writing any wrapper code or even recompiling existing code. You can try calling external library functions directly from Julia’s interactive prompt, getting immediate feedback. See
for the full terms of Julia’s licensing.

我要回帖

更多关于 京香julia豹纹快递 的文章

 

随机推荐