Julia 1.7 版本发布,科学计算领域高性能语言

来源: OSCHINA
编辑: 罗奇奇
2021-12-02

Julia 编程语言 1.7 版本已发布,这是一种通用的高性能语言,在科学计算和数值分析中较为流行。Julia 1.7 是 1.x 系列版本中的第七个次要版本,添加了一些新特性和功能,主要更改如下:

新的 Xoshiro256 系列随机数生成器(RNG)

Julia 一开始使用流行的 Mersenne Twister 算法作为其默认的随机数生成器,但 Mersenne Twister 的计算周期较长,而且会带来较大的开销。1.7 版本引进了开销较小的 Xoshiro256 系列随机数生成器。

新的线程功能

解决了运行时中的大量竞争条件,追踪了同步错误,改进了对多线程调度工作负载的支持,使默认的随机数生成器对线程更加友好,并添加了原子atomic作为原始语言功能。

  • 现在为特定的字节大小定义了原子指针操作 ( #37847 )。
  • 支持声明和使用可变结构的单个字段作为原子;查看新的@atomic宏 ( #37847 )。
  • 如果 JULIA_NUM_THREADS 环境变量设置为auto,则线程数将设置为 CPU 线程数 ( #38952 )。
  • 每个 Task 对象都有一个本地随机数生成器状态,默认情况下提供并行模拟代码的可重复执行(独立于调度)。默认生成器的并行速度也明显快于以前的版本 ( #40546 )。
  • 任务现在可以在重新调度时在线程之间迁移。(以前任务始终在最先执行它的线程上运行)( #40715 )。

包管理器

自动安装包

如果注册表中有一个没有安装的包,那么当在 REPL 中尝试加载包时会自动安装。

之前:

julia> using Foo
ERROR: ArgumentError: Package Foo not found in current path:
- Run `import Pkg; Pkg.add("Foo")` to install the Foo package.

Stacktrace:
 [1] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:871

(@1.6) pkg> add Foo
...

julia> using Foo

julia> Foo
Foo

现在轻松安装

julia> using Foo
 │ Package Foo not found, but a package named Foo is available from a registry.
 │ Install package?
 │   (@v1.7) pkg> add Foo
 └ (y/n) [y]: y
 ...
julia> Foo
Foo

默认情况下,软件包将安装到当前活动环境中,通过 y  return 键选择。要取消选择用 n  Ctrl-c

新的清单格式

用户在 Julia 中添加包时,包管理器 (Pkg) 都会写出一个名为“清单("manifest")”的 TOML 文件,里面包含该包所有依赖项的准确版本。但不同的包版本可能与不同的 Julia 版本兼容,因此,之前不建议将在一个 Julia 版本中创建的清单与另一个 Julia 版本一起使用。

1.7 版中更改了此清单格式,以便所有依赖项都放在一个公共[deps]密钥下,这释放了全局命名空间,以便julia_version 可以添加条目 。读取新清单的能力也将向后移植到 Julia 1.6,因此在 Julia 1.6.2 及更高版本中,Pkg 将保留现有清单的格式,只有新建的清单才会采用新的清单格式。

推理改进

此版本附带了许多类型推断改进。通过这些改进,Julia 1.7 将更“聪明地”推断程序类型,以提高性能。

1.7 可以传播在过程间(inter-procedurally,即跨任何函数调用)派生的类型约束 isa  === 条件某些 Julia 程序的编写方式是:行为会根据运行时类型而改变,而这种改进的推论性能使这些程序运行得更快。例如,现在在 x === nothing和 isnothing(x) 之间没有推断性差异:

julia> code_typed((Union{Nothing,Int},); optimize=false) do x
           return isnothing(x) ? 0 : x
       end |> first
--- v1.6
+++ v1.7
@@ -1,6 +1,6 @@
 CodeInfo(
 1 ─ %1 = Main.isnothing(x)::Bool
 └──      goto #3 if not %1
 2 ─      return 0
-3 ─      return x
-) => Union{Nothing, Int64}
+3 ─      return x::Int64
+) => Int64

这种过程间约束传播适用于任意泛型函数:

julia> ispositive(a) = isa(a, Number) && a > 0;
julia> code_typed((Union{Nothing,Int},); optimize=false) do x
           return ispositive(x) ? x : 0
       end |> first
--- v1.6
+++ v1.7
@@ -1,6 +1,6 @@
 CodeInfo(
 1 ─ %1 = Main.ispositive(x)::Bool
 └──      goto #3 if not %1
-2 ─      return x
+2 ─      return x::Int64
 3 ─      return 0
-) => Union{Nothing, Int64}
+) => Int64

另一个显著变化是:Julia 1.7 可以用预先计算的常量替代更多的运行时计算,并通过在编译时解析条件分支来消除死代码。例如,在1.7中,特殊函数的计算可以在编译时完全折叠:

julia> code_typed((Int,)) do n
           n + sin(sum(sincos(42))) # no runtime computation of `sum(sincos(42))` in 1.7!
       end |> first
--- v1.6
+++ v1.7
@@ -1,32 +1,5 @@
 CodeInfo(
-1 ─ %1  = Base.muladd_float(0.16933292771007588, 2.7557313707070068e-6, -0.0001984126982985795)::Float64
-│   %2  = Base.muladd_float(0.16933292771007588, %1, 0.00833333333332249)::Float64
-│   %3  = Base.muladd_float(0.16933292771007588, 1.58969099521155e-10, -2.5050760253406863e-8)::Float64
-│   ... many runtime computations ...
-│   %27 = invoke Main.sin(%26::Float64)::Float64
-│   %28 = Base.sitofp(Float64, n)::Float64
-│   %29 = Base.add_float(%28, %27)::Float64
-└──       return %29
+1 ─ %1 = Base.sitofp(Float64, n)::Float64
+│   %2 = Base.add_float(%1, -0.9678422808766897)::Float64
+└──      return %2
 ) => Float64

以下是此版本的推理改进 PR 列表:

  • 过程间条件约束传播(#38905
  • 联合拆分调用站点的常量传播 ( #39305 )
  • invoke 呼叫站点的持续传播( #41383 )
  • 更多条件约束传播(#39936#40832

这些推理改进最初是由 JET.jl 的需求推动的,JET.jl 是 Julia 的静态分析器,由 Julia 编译器的类型推理实现提供支持。1.7 中的这些推理改进使 JET 能够更准确、更快地分析程序。

多维数组改进

多维数组,尤其是 3 维或更多维的数组,是科学编程和机器学习的有用结构。在 Julia v1.7 中添加了相关语法:能够为多维数组编写文字。这种新语法使 Julia 中的多维数组比以前更容易操作

Julia v1.7:
[1 2 ; 3 4 ;;; 5 6 ; 7 8]
or
[1 ; 3 ;; 2 ; 4 ;;; 5 ; 7 ;; 6 ; 8]

Python with Numpy:
import numpy as np
np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])

MATLAB:
A = [1 2; 3 4]
A(:,:,2) = [5 6; 7 8]

R:
array(c(1, 3, 2, 4, 5, 7, 6, 8), dim = c(2, 2, 2))

该语法是当前语法的直接扩展:一个额外的分号 == 一个额外的维度:

julia> [1 2 ; 3 4]
2×2 Matrix{Int64}:
 1  2
 3  4

julia> [1 2 ;;; 3 4]
1×2×2 Array{Int64, 3}:
[:, :, 1] =
 1  2

[:, :, 2] =
 3  4

julia> [1 2 ;;;; 3 4]
1×2×1×2 Array{Int64, 4}:
[:, :, 1, 1] =
 1  2

[:, :, 1, 2] =
 3  4

julia> using BenchmarkTools

julia> @btime [1 2 ;;;; 3 4];
  44.838 ns (2 allocations: 160 bytes)

julia (v1.6)> @btime cat([1 2], [3 4], dims = 4); # clear, but slow, and gets worse with more dimensions
  1.380 μs (23 allocations: 1.05 KiB)

julia (v1.6)> @btime reshape([1; 2; 3; 4], (1, 2, 1, 2)); # fast, but intent less clear
  65.884 ns (2 allocations: 192 bytes)

对于多维数组基本操作有性能的显着改进,随着涉及更多维度,差异会大大提高。

为了便于阅读较大的数组表达式,也可以接受换行符:

julia> [ 1 2
         3 4
         ;;;
         5 6
         7 8 ]
2×2×2 Array{Int64, 3}:
[:, :, 1] =
 1  2
 3  4

[:, :, 2] =
 5  6
 7  8

此语法还可以按列优先顺序而不是行优先顺序编写数组,使用;;行代替空格:

julia> [1 ; 2 ;; 3 ; 4 ;;; 5 ; 6 ;; 7 ; 8]
2×2×2 Array{Int64, 3}:
[:, :, 1] =
 1  3
 2  4

[:, :, 2] =
 5  7
 6  8

1.7 版本是一个大版本更新,除了以上内容,此版本还包含一些语言功能和语法的改动,更多亮点更新可阅览官方公告,完整修改列表可在 GitHub 查看

展开阅读全文
4 收藏
分享
加载中
精彩评论
我怎么总感觉这是一个人名。
2021-12-08 15:15
3
举报
R可以混淆代码,Julia是可以编译成二进制文件的,而且这个语言可以也可以写web端,数据库程序,还是比较强大的
2021-12-03 01:16
2
举报
无论是这个还是R,都有个很不专业但很现实的问题:无法隐藏源码发布程序,总有老板觉得代码送出去亏了。好在还有Cython这个救命草免去了用C重写的负担。
2021-12-02 11:17
1
举报
最新评论 (3)
我怎么总感觉这是一个人名。
2021-12-08 15:15
3
回复
举报
无论是这个还是R,都有个很不专业但很现实的问题:无法隐藏源码发布程序,总有老板觉得代码送出去亏了。好在还有Cython这个救命草免去了用C重写的负担。
2021-12-02 11:17
1
回复
举报
R可以混淆代码,Julia是可以编译成二进制文件的,而且这个语言可以也可以写web端,数据库程序,还是比较强大的
2021-12-03 01:16
2
回复
举报
更多评论
3 评论
4 收藏
分享
返回顶部
顶部