放弃Python拥抱Mojo?鹅厂工程师真实使用感受
# 每周1 | 鹅厂工程师带你审判技术
# 第1期 | 李志瑞:AI 届新语言 Mojo 要火?🔥
虽然 Python 很好,但它有一个众所周知的问题,那就是太慢了。而机器学习本身又需要繁重的计算,因此 Python 生态中大量库的底层其实都是用高性能的语言(如 C/C++)进行实现,然后再提供一个 Python 接口供用户调用,典型的如 numpy 这种数学库。在这种情况下,Python 事实上是被作为一个胶水语言来使用,这造成了开发的碎片化,如果一个用户只是简单调一下库那还好说,但一旦到了工业界,开发过程中不可避免地就要涉及一些底层库的修改,甚至直接换语言来实现同样的功能以提高性能,这种割裂不止增加了开发成本和精神负担,而且考虑到众多擅长 C/C++ 语言的开发者也并不是 AI 领域专家,这种开发人员能力的不适配也对整个 AI 生态的发展形成了一定阻碍。
因此,Mojo 的目的就是要在 Python 生态的基础上,让用户能用一个语言,从使用易用的接口,到开发复杂的库,再到实现底层黑科技,统一实验和生产环境所用的语言。为了实现这个目的,Mojo 扩展了 Python 语法,支持了紧凑的内存布局,并引入了一些现代的语言特性(例如 Rust 的安全性检查),使得这个语言能够渐进式地在 AI 界立足。说起来 Chris Lattner 在这方面可以算是经验丰富了,不管是在 gcc/msvc 的统治下实现 clang,还是在 objective-c 的统治下为苹果实现 swift,都是一个逐步蚕食对手市场的过程。
说了这么多,该来看看 Mojo 长什么样了。现在 Mojo 还不能直接下载使用,如果想要尝鲜,需要在官网申请,然后在 playground 页面中试用,这是一个基于 Jupyter 的页面,可以混合笔记和可执行的 Mojo 代码。
前面提到,Mojo 的语法是 Python 的超集,因此 Mojo 的 Hello World 也跟 Python 一样简单:
print("Hello World") #> Hello World
fn foo():
var x: Int = 1
x += 1
let y: Int = 1
print(x, y) #> 2 1
foo()
fn foo():
x = 1
print(x)
# error: Expression [12]:6:5: use of unknown declaration 'x', 'fn' declarations require explicit variable declarations
# x = 1
# ^
class MyClass:
def foo():
pass
# error: Expression [15]:17:5: classes are not supported yet
# class MyClass:
# ^
struct MyIntPair:
var first: Int
var second: Int
fn __init__(inout self, first: Int, second: Int):
self.first = first
self.second = second
fn __lt__(self, rhs: MyIntPair) -> Bool:
return self.first < rhs.first or
(self.first == rhs.first and
self.second < rhs.second)
let p1 = MyIntPair(1, 2)
let p2 = MyIntPair(2, 1)
if p1 < p2: print("p1 < p2") #> p1 < p2
def foo(lst):
lst[0] = 5
print(lst)
x = [1, 2, 3]
foo(x)
print(x)
from PythonInterface import Python
let np = Python.import_module("numpy")
ar = np.arange(15).reshape(3, 5)
print(ar.shape) #> (3, 5)
fn foo(borrowed a: SomethingBig, b: SomethingBig):
a.use()
b.use()
fn swap(inout lhs: Int, inout rhs: Int):
let tmp = lhs
lhs = rhs
rhs = tmp
fn test_swap():
var x = 42
var y = 12
print(x, y) #> 42, 12
swap(x, y)
print(x, y) #> 12, 42
test_swap()
var x = 42
swap(x, x)
从这也可以看出 Mojo 确实还处在比较早期的发展阶段。
另一个重要的内存安全概念是对象的所有权,当一个函数获取了对象的所有权后,调用方就不应该再去使用这个对象了,例如我们实现了一个只支持移动的类型 UniquePtr:
struct UniquePtr:
var ptr: Int
fn __init__(inout self, ptr: Int):
self.ptr = ptr
fn __moveinit__(inout self, owned existing: Self):
self.ptr = existing.ptr
fn __del__(owned self):
self.ptr = 0
fn use_ptr(borrowed p: UniquePtr):
print(p.ptr)
fn take_ptr(owned p: UniquePtr):
print(p.ptr)
fn test_ownership():
let p = UniquePtr(100)
use_ptr(p) #> 100
take_ptr(p^) #> 100
test_ownership()
fn test_ownership():
let p = UniquePtr(100)
take_ptr(p^)
use_ptr(p) # ERROR!
test_ownership()
# error: Expression [13]:23:12: use of uninitialized value 'p'
# use_ptr(p) # ERROR: p is no longer valid here!
# ^
alias OurTrue: OurBool = __mlir_attr.`true`
alias OurFalse: OurBool = __mlir_attr.`false`
@register_passable("trivial")
struct OurBool:
var value: __mlir_type.i1
fn __init__() -> Self:
return OurFalse
fn __init__(value: __mlir_type.i1) -> Self:
return Self {value: value}
fn __bool__(self) -> Bool:
return Bool(self.value)
let t: OurBool = OurTrue
if t: print("true") #> true
# ...
struct OurBool:
# ...
fn __eq__(self, rhs: OurBool) -> Self:
let lhsIndex = __mlir_op.`index.casts`[_type : __mlir_type.index](
self.value
)
let rhsIndex = __mlir_op.`index.casts`[_type : __mlir_type.index](
rhs.value
)
return Self(
__mlir_op.`index.cmp`[
pred : __mlir_attr.`#index<cmp_predicate eq>`
](lhsIndex, rhsIndex)
)
# ...
struct OurBool:
# ...
fn __invert__(self) -> Self:
return OurFalse if self == OurTrue else OurTrue
let f = OurFalse
if ~f: print("false") #> false
虽然 Mojo 反复强调它是为 AI 设计的新语言,但以目前 Mojo 的设计方向来看,它的发展前景并不止于 AI。本质上 Mojo 提供了一个能够兼容 Python 生态的高性能语言,且这个语言可以让 Python 开发者几乎无痛地切换过去,那 Python 开发者何乐而不为呢?对于使用 Mojo 的开发者来说,上层业务可以将 Mojo 当 Python 一样使用,享受到简明的语法带来的高开发效率,当出现性能瓶颈的时候,也不用切换语言去进行优化,直接使用 Mojo 重构模块即可。虽然现在还没法在生产环境中验证这个想法,但这个未来听起来确实非常美好。关于 Mojo 和 Python 开发性能的对比,您可浏览 Mojo 发布会上的 Jeremy Howard demo for Mojo launch 视频。
目前 Mojo 还在比较早期的阶段,不仅许多语言特性都还没实现,而且连本地开发的套件都没有提供。不过其发展路线和设计思路都非常务实 ,又有一个足够专业的领导者和公司作为背景支撑,可以说是未来可期,也非常希望这个语言能在其他领域得到更广泛的应用。