Julia改善性能的若干建议

10 篇文章 0 订阅

Julia是一门随便写写就有不错的效率的语言。但高性能和灵活性通常是矛盾的,Julia也不例外。当你想尽量榨取Julia的性能时,除了阅读官方文档的建议外,也可以看看本文总结的几条经验之谈。这些都是我最近编写CFD程序时踩过的坑。有些你可能已经熟悉了,仅供参考。

  • 尽可能使用内置函数或扩展包里的函数。例如算术平均数mean。你可能会发现新版本的Julia里没有内置的mean,于是自己随手写成sum()/length()。其实,如今mean位于Statistics包,效率比sum()/length()更高。另一个典型例子是LinearAlgebra包的normalize。总之,当你要写一个比较泛用的函数时,建议先找找有没有造好的轮子。
  • 避免使用拼接数组。例如,你可能会像这样把两个向量拼成一个更长的向量:v = [v1; v2]。这会显著降低性能。建议先创建一个固定长度的零向量,然后把v1v2赋给它,效率会提高一两个量级。
  • 避免对一个很大的数组的同一个元素做很多次重复索引。本来索引是很快的,但大量的重复索引也会相当耗时。可先把该元素赋给一个变量,然后调用这个变量,避免重复索引。例如:
julia> A = ones(Float64,1_000_000);

julia> a = A[1];

julia> @time for i = 1:1_000_000
      A[1] = 2
      end
 0.015121 seconds

julia> @time for i = 1:1_000_000
      a = 2
      end
 0.002962 seconds
  • 对于分布式数组DArray,应从程序设计层面上减少跨进程的元素访问。本质上就是进程间通信成本的问题。之所以要专门讲这个,是因为在DistributedArrays包里提供的DArray允许直接跨进程访问。这固然是极大地方便了编程,但成本也相当高昂。事实证明,哪怕Julia写并行程序很方便,也要好好斟酌一下怎么写才最优,否则性能恐怕达不到期望。
  • 使用DArray时, 除了跨进程访问外,在各进程内部localpart上的访问也应尽量减少次数。例如,假设你要对DArray的每个元素操作10次。如果每次操作都访问一次,会导致耗时随次数接近线性增长。建议先把该元素赋给一个变量,操作完再传回,这样至多访问两次。如果元素是数组或自定义类型,Julia会自动引用而无需传回,只访问一次。总之,要高度关注并减少DArray的访问次数。
  • 如果循环次数很大,而循环体较复杂,应尝试把整个循环体打包成一个函数,即具有如下形式:
for i = 1:N
   body_function()
end

function body_function()
   # 循环体
end

这有助于编译优化。我自己测试的一段代码快了20%多一点,不过相比前几条建议来说不是特别显著。

  • 使用close()d_closeall()显式回收DArray的内存。DistributedArrays.jl文档里是这么解释的:

当主进程触发 gc (garbage collection) 时,workers上的内存会随之被回收。但主进程只存储DArray对象而DArray对象本身是很小的(数据在workers上),所以在DArray用完之后通常不会立即触发主进程的gc,导致workers上的内存回收随之延迟。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值