Julia 是什么:既要写得爽,又要跑得快

科学计算领域一直有个矛盾:用 Python 写起来舒服,但算大矩阵慢;用 C/Fortran 跑得快,但写起来费劲、循环套循环。Julia 就是冲着这个矛盾来的——语法像 Python 一样干净,底层却通过 JIT 编译跑出接近 C 的速度。

它在 2012 年由 MIT 团队发布,现在广泛用在气候模拟、机器学习、量子物理、金融建模这些"既要灵活又要性能"的场景。数据科学圈里,它经常被拿来和 Python、MATLAB 比较——你不用为了性能把核心算法重写一遍。

Julia 的口号:"像 Python 一样写,像 C 一样跑"。它试图消灭科学计算里"原型用 Python,生产用 C"的两段式工作流。
本文核心知识点
  • 动态类型写起来像 Python,不用到处写类型声明。
  • 矩阵原生数组就是一等公民,下标从 1 开始。
  • 多派发同一个函数根据参数类型选不同实现,是 Julia 的灵魂。
  • JIT即时编译,第一次调用慢,之后跑得接近 C。
Julia 科学计算配图:蓝绿渐变背景上中央一个发光的三维立方体(矩阵),周围环绕多根发光的函数曲线与散点云,立方体向外延伸数据流到几个圆形节点,背景有网格与光晕
中央发光的三维矩阵,周围环绕函数曲线与散点——这正是 Julia 在科学计算里的工作对象。

基本语法:从 Python 过来很顺手

如果你写过 Python,Julia 入门几乎零阻力:变量不用声明类型、循环写法差不多、函数用 function 定义。几处小区别:下标从 1 开始、行尾不强制分号、赋值用 = 而判断用 ==。

# 定义函数
function add(a, b)
    return a + b
end

# 也可以一行写
f(x) = x^2 + 1

println(add(2, 3))   # 5
println(f(4))        # 17

注意 Julia 里函数后面加感叹号是约定俗成的"会修改入参"的函数,比如 sort!(arr) 直接改原数组、sort(arr) 返回新数组。这是一种代码风格约定,不是语法强制。

矩阵与数学:天生为计算而生

Julia 把数组和矩阵当成一等公民,语法比 MATLAB 还顺手。一维数组用方括号,矩阵用分号分行:

v = [1, 2, 3]                # 向量
M = [1 2; 3 4]               # 2x2 矩阵

# 矩阵运算直接写
M * v                        # 矩阵乘向量
M'                           # 转置,用单引号
inv(M)                       # 求逆

# 数组推导
squares = [i^2 for i in 1:5] # [1, 4, 9, 16, 25]

这种"数学写起来就是代码"的感觉,是 Julia 从 MATLAB 那里继承的基因。1:5 是一个区间,i^2 for i in 1:5 是数组推导——把数学公式直接翻译成代码。

多派发:Julia 的灵魂

Julia 最有特色的是多派发(multiple dispatch):同一个函数名,根据参数的具体类型,选不同的实现。这和面向对象里"根据对象类型选方法"是类似的,但 Julia 把它推广到了所有参数。

# 同一个函数 greet,根据参数类型走不同分支
greet(x::String) = "你好,$x"
greet(x::Int)     = "你今年 $x 岁"
greet(x)          = "你好,陌生的 $x"

greet("世界")    # 走 String 分支
greet(18)        # 走 Int 分支

编译器在跑的时候根据实际参数类型选最快的实现。这让 Julia 在写数值算法时既能保持"一个函数名"的简洁,又能针对不同类型做优化——这是它性能好的一个重要原因。

为什么快:即时编译 JIT

Julia 不像 Python 那样逐行解释,也不像 C 那样提前编译成机器码。它用的是 JIT(即时编译):第一次调用一个函数时,Julia 根据传入参数的具体类型,把这段代码编译成高效的机器码。下次再调就直接跑编译好的版本。

# 第一次跑慢(要编译),第二次就快了
@time my_heavy_computation(1000)   # 第一次,慢
@time my_heavy_computation(1000)   # 第二次,快很多

这就是为什么 Julia 新手第一次跑会觉得"怎么这么慢"——那是在编译。第二次开始就起飞了。写性能敏感的代码时,把核心逻辑包在函数里、别在全局作用域里堆循环,编译优化才能生效。

画图与包生态:Plots 与 Pkg

装包用内置的 Pkg,画图用 Plots 包。科学计算的常见工作流是:装包 → 写算法 → 画图看结果。

# 进入包管理器
using Pkg
Pkg.add("Plots")

using Plots
x = 0:0.1:2π
y = sin.(x)          # 注意这个点号:对数组逐元素算
plot(x, y, label="sin(x)")
savefig("wave.png")

注意 sin.(x) 那个点号:它告诉 Julia"把 sin 逐元素作用在整个数组上"。这是 Julia 和 MATLAB 的另一个小区别——运算默认是矩阵的,要逐元素就得加点。