放弃Python拥抱Mojo?鹅厂工程师真实使用感受
# 关注并星标腾讯云开发者
(资料图片)
# 每周1 | 鹅厂工程师带你审判技术
#第1期|李志瑞:AI 届新语言 Mojo 要火??
前段时间 Modular 发布了一个新语言 Mojo,这语言不止官网放了巨大的 emoji ?,而且它的标准文件后缀一个是「.mojo」另一个是「.?」,一副立马要火的样子呢。
说实话,这个用 emoji 做后缀名的操作其实挺无聊,也有点败好感,但如果说这个语言能在完全兼容 Python 的基础上大幅提高执行效率,并且作者是 LLVM 发起人 Chris Lattner,是不是突然又有兴趣继续了解它了呢?
Mojo 被设计为 Python 语言的超集,并增加了许多特性,包括:
▶︎ Progressive types:能利用类型信息获得更好性能和静态检查,但又不强制要求写类型。
▶︎ Zero cost abstractions:C++ 的核心设计准则,能够避免用户为了性能放弃合理设计的代码。
▶︎ Ownership + borrow checker:Rust 语言的安全性来源,在编译期避免许多错误的发生。
▶︎ The full power of MLIR:原生支持对 MLIR 的直接访问,能够从底层扩展系统。
在 Mojo 这个语言的介绍中反复提到 AI,官网也说它是「a new programming language for all AI developers」。那么为什么 AI 开发需要一个新语言呢?首先,我们知道在 AI 届具有统治地位的语言就是 Python,Python 是一个语法简单清晰,容易上手,且灵活度很高的语言,深受广大程序员喜爱,XKCD 上有就这么一幅漫画:
当然,受人喜爱的语言有很多,Python 成为 AI 届的统治语言除了本身易用之外,也有惯性的因素。由于 Python 上机器学习相关的库多,因此机器学习从业者用的就多,这又反过来令新的机器学习相关库优先为 Python 提供接口,进一步加强了其统治地位。因此,为了逐步渗透这个用户群,Mojo 兼容 Python 是很正确的一个选择。Mojo 不仅承诺语法是 Python 的超集,并且它还能直接调用 Python 的库,这意味着 Mojo 不需要从零开始构建自己的生态,本身就可以用上繁荣的 Python 生态了。
虽然 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与 Python 一样,Mojo 也使用换行符和缩进来定义代码块:
fn foo():var x: Int = 1x += 1let y: Int = 1print(x, y) #> 2 1foo()
上面的代码中使用 var 来声明变量 x,使用 let 来声明了不可变量 y。Mojo 像很多较新近的语言一样,让不可变量的声明变得简单,以鼓励开发者使用不可变的量。另外注意到这里定义函数使用了 fn 而非 Python 的 def,这是因为 Mojo 希望在兼容 Python 的基础上加入编译期的检查和优化,而 Python 过于动态的语法很难支持这一目标,因此,Mojo 同时支持使用 fn 和 def 两个关键字来声明函数,对于调用者来说,这两种方法声明出来的函数没有什么区别,但对于实现者来说,可以将 fn 看作「严格模式」下的 def,例如下面的代码会编译错误(如果改成用 def 则不会出错):
fn foo(): x = 1 print(x) #error:Expression[12]:6:5:useofunknowndeclaration"x","fn"declarationsrequireexplicitvariabledeclarations#x=1#^
虽然官方承诺 Mojo 的语法是 Python 的超集,但目前 Mojo 还在开发中,很多 Python 语法都还不支持,例如目前连 Python 的 class 都无法被编译通过:
class MyClass:def foo():pass# error: Expression [15]:17:5: classes are not supported yet# class MyClass:# ^
不过,Mojo 现在先提供了另一个用来组织数据的关键字 struct,相比于 class,struct 更加静态可控,便于优化。一方面,struct 支持类似 Python class 风格的函数声明和运算符重载。而另一方面,struct 又类似于 C++ 的 struct 和 class,内部的成员在内存中紧凑排布,而且不支持在运行时动态添加成员和方法,便于编译期进行优化,例如:
struct MyIntPair:var first: Intvar second: Intfn __init__(inout self, first: Int, second: Int):self.first = firstself.second = secondfn __lt__(self, rhs: MyIntPair) -> Bool:return self.first < rhs.first or(self.first == rhs.first andself.second < rhs.second)let p1 = MyIntPair(1, 2)let p2 = MyIntPair(2, 1)if p1 < p2: print("p1 < p2") #> p1 < p2虽然有点不同,但整体上看起来还是非常熟悉的对吧。说到这里,有一点需要提醒各位注意,尽管 Mojo 之后会令语法成为 Python 语法的超集,但其语义则有时会和 Python 不同,这意味着 Python 的代码直接拷到 Mojo 里可能会出现编译通过但执行结果不同的情况,这里简单提一个比较常见的例子:函数传参。在 Python 中,函数传参的语义类似于 C++ 的传指针,在函数内部虽然不能更改调用者指向的对象,但可以改变该对象内部的状态,例如下面的代码:
def foo(lst):lst[0] = 5print(lst)x = [1, 2, 3]foo(x)print(x)
在 Python 中,这段代码打印出来的结果是两次 [5, 2, 3]。但在 Mojo 中,使用 def 定义的函数默认的传递逻辑是复制值,也就是说,尽管在函数中能够修改参数内部的状态,但修改对于调用方来说是不可见的,因此上面这段代码在 Mojo 中打印的结果是 [5, 2, 3](foo 内部)和 [1, 2, 3](foo 外部)。
除了语法像 Python,Mojo 非常务实的一点在于它构建于 Python 的生态之上。因此即便 Mojo 还没能完整支持 Python 的语法,它还是优先支持了对 Python 库的调用,以便让开发者能受益于庞大完善的 Python 的生态。例如下面的代码就使用了 Python 的 numpy 库:
fromPythonInterfaceimportPythonlet np = Python.import_module("numpy")ar = np.arange(15).reshape(3, 5)print(ar.shape) #> (3, 5)Mojo 作为一个新语言,广泛吸收许多现代的程序语言设计思想,例如 Rust 的所有权和借用检查,以此提升代码的安全性。在 Mojo 中,使用 fn 定义的函数的参数默认传的是不可变的引用,即「借用」,调用方仍然拥有其所有权,因此在函数内部不可以对参数进行修改。Mojo 提供了一个 borrow 关键字来标注这样的参数传递情况,对于 fn 来说是可以省略的,也就是说下面 foo 函数中两个参数的传递方式相同:
fn foo(borrowed a: SomethingBig, b: SomethingBig):a.use()b.use()
在 Rust 中,传参的默认行为是移动,如果需要借用则需要在传入时加上 &,这两种方式倒是没有太大的优劣之分,Mojo 的行为可能更接近于 Python 这类高级语言的习惯。如果想要修改传入的参数,则需要手动注明 inout,例如:
fn swap(inout lhs: Int, inout rhs: Int):let tmp = lhslhs = rhsrhs = tmpfn test_swap():var x = 42var y = 12print(x, y) #> 42, 12swap(x, y)print(x, y) #> 12, 42test_swap()
按道理说,Mojo 应该像 Rust 一样规避一个变量同时被可变和不可变借用,也应该规避同时被可变借用,但目前 Mojo 编译器似乎还没实现这一特性,例如下面的代码还是能编译通过的:
var x = 42swap(x,x)
从这也可以看出 Mojo 确实还处在比较早期的发展阶段。
另一个重要的内存安全概念是对象的所有权,当一个函数获取了对象的所有权后,调用方就不应该再去使用这个对象了,例如我们实现了一个只支持移动的类型 UniquePtr:
struct UniquePtr:var ptr: Intfn __init__(inout self, ptr: Int):self.ptr = ptrfn __moveinit__(inout self, owned existing: Self):self.ptr = existing.ptrfn __del__(owned self):self.ptr = 0
同时,我们有两个函数,其中,use_ptr 使用了前面提到的 borrow 关键字,借用了 UniquePtr 对象,而 take_ptr 则使用 owned 关键字,指明它需要获取传入对象的所有权。那么,在调用 take_ptr 的时候,我们就需要在参数后面加上 ^ 后缀,用来表明我们将所有权转移给 take_ptr:
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) #> 100take_ptr(p^) #> 100test_ownership()
因此,如果我们将 use_ptr 和 take_ptr 的调用顺序调换一下,就会出现编译错误:
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!# ^
Mojo 的另一个强大之处在于它让对 MLIR>) 的操作变得更简单。MLIR 全称是 Multi-Level Intermediate Representation,是一个编译器开发框架,它存在的目的是通过定义多种方言来逐级将代码转换为机器码,以降低编译器的开发成本。在 MLIR 之前,一个广为人熟知的 IR 是 LLVM IR,一个语言的编译器作者可以通过将自己的语言编译为 LLVM IR 来接入 LLVM 的工具链,使得编译器作者不需要关心底层具体硬件的差别,实现了对底层编译工具链的复用:
但 LLVM IR 层级过低,难以进行特定于语言本身的优化,从上面的图中也能看出,各个语言为了实现语言本身的优化,都在编译为 LLVM IR 之前加入了自己的 IR。另外 LLVM IR 扩展起来也非常困难,难以适应复杂异构计算的要求,而异构计算在 AI 开发中又非常普遍。MLIR 相比于之前的 IR,更加模块化,仅保留了一个非常小的内核,方便开发者进行扩展。很多编译器将代码编译为 MLIR,而 Mojo 提供了直接访问 MLIR 的能力,这使得 Mojo 能够受益于这些工具。更多关于 MLIR 的内容可以参考这一系列文章:编译器与中间表示: LLVM IR, SPIR-V, 以及 MLIR,这里就不做过多赘述,我们主要关注在 Mojo 中可以如何操作 MLIR。举例而言,如果我们希望实现一个新的 boolean 类型 OurBool,我们可以这样实现:
alias OurTrue: OurBool = __mlir_attr.`true`alias OurFalse: OurBool = __mlir_attr.`false`@register_passable("trivial")struct OurBool:var value: __mlir_type.i1fn __init__() -> Self:return OurFalsefn __init__(value: __mlir_type.i1) -> Self:return Self {value: value}fn __bool__(self) -> Bool:return Bool(self.value)这里定义了一个类型为 OurBool 的类型,里面有一个直接使用 MLIR 内置类型 i1 的成员 value 。在 Mojo 中,我们可以通过 __mlir_type.typename 的形式来访问 MLIR 类型。接着,我们为这个类型提供了两个构造函数,默认情况下构造为 OurFalse 也可基于传入的参数进行构建。最下面的 __bool__ 也和 Python 的 __bool__ 一样,用于使该类型具有和内置 boolean 类型的性质,此时我们可以这样使用它:
let t: OurBool = OurTrueif t: print("true") #> true除了使用 MLIR 之外,Mojo 甚至可以允许开发者使用 MLIR 实现逻辑,例如下面的代码中通过应用 MLIR 的 index.casts 操作来实现类型转换,然后再通过 index.cmp 对值进行比较:
# ...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`](lhsIndex, rhsIndex))
基于封装好的 __eq__ 方法,我们可以很容易实现 __invert__ 方法:
# ...struct OurBool:# ...fn __invert__(self) -> Self:return OurFalse if self == OurTrue else OurTrue
此时,我们就可以对 OurBool 类型的对象使用 ~ 操作符了:
let f = OurFalseif ~f: print("false") #> false通过这个简单的例子我们可以看出,在 Mojo 中,开发者可以通过访问 MLIR 来实现和内置类型同等高效的类型。这使得开发者可以在 Mojo 上为新硬件的数据类型封装高效简单的 Mojo 接口而不需要切换语言。虽然大部分开发者并不需要接触 MLIR,但 Mojo 为更深入和更底层的优化提供了充分的可能性。
虽然 Mojo 反复强调它是为 AI 设计的新语言,但以目前 Mojo 的设计方向来看,它的发展前景并不止于 AI。本质上 Mojo 提供了一个能够兼容 Python 生态的高性能语言,且这个语言可以让 Python 开发者几乎无痛地切换过去,那 Python 开发者何乐而不为呢?对于使用 Mojo 的开发者来说,上层业务可以将 Mojo 当 Python 一样使用,享受到简明的语法带来的高开发效率,当出现性能瓶颈的时候,也不用切换语言去进行优化,直接使用 Mojo 重构模块即可。虽然现在还没法在生产环境中验证这个想法,但这个未来听起来确实非常美好。关于 Mojo 和 Python 开发性能的对比,您可浏览 Mojo 发布会上的 Jeremy Howard demo for Mojo launch 视频。
目前 Mojo 还在比较早期的阶段,不仅许多语言特性都还没实现,而且连本地开发的套件都没有提供。不过其发展路线和设计思路都非常务实 ,又有一个足够专业的领导者和公司作为背景支撑,可以说是未来可期,也非常希望这个语言能在其他领域得到更广泛的应用。
标签:
推荐文章
- 人机对话技术升级 之江实验室获2021年度浙江省科技进步二等奖
- 研究人员最新发现 单个细胞可同时处理成百上千个信号
- 陆军第73集团军某旅 创新升级模拟训练器材
- 长期暴露在光照下性能退化 科学家发现钙钛矿太阳能电池最大缺陷
- 宁夏启动双百科技支撑行动 构建高水平产业创新体系
- 陆军炮兵防空兵学院 毕业学员综合战术演习现地备课工作圆满完成
- 国内首颗以茶叶冠名遥感卫星 安溪铁观音一号发射成功
- 区域特色产业转型升级 四川屏山以“3+”模式推进科技创新工作
- 激发创新动能促进产业发展 无锡滨湖走出产业转型“绿色”路
- 绥化全域低风险!黑龙江绥化北林区一地调整为低风险
- 走访抗美援朝纪念馆:长津湖的寒冷,与战斗一样残酷
- 节后第一天北京白天晴或多云利于出行 夜间起秋雨或再上线
- 走近网瘾少年们:他们沉迷网络的病根何在?
- “双减”后首个长假:亲子游、研学游需求集中释放
- 获2021年诺奖的蛋白,结构由中国学者率先解析
- 他从一窍不通的“门外汉”,到重装空投“兵专家”
- 升旗、巡岛、护航标、写日志,他们一生守护一座岛
- 中国故事丨“沉浸式”盘点今年的教育好声音!
- 农业农村部:确保秋粮丰收到手、明年夏季粮油播种
- “双减”出台两个月,组合拳如何直击减负难点?
- 《山海情》里“凌教授”的巨菌草丰收啦
- 且看新疆展新颜
- 天山脚下,触摸丝路发展新脉动
- 160万骑手疑似“被个体户”?平台不能当甩手掌柜
- 网游新政下,未成年人防沉迷的“主战场”在哪?
- “辱华车贴”商家及客服被行拘,处罚要不放过每一环
- 沙害是自然界的恶魔,而他是荒沙碱滩的征服者
- 面对婚姻,“互联网世代”的年轻人在忧虑什么?
- IP类城市缘何吸引力强?玩法创新带动游客年轻化
- 国庆主题花坛持续展摆至重阳节
- 都市小资还是潮流乐享?花草茶市场呈爆发性增长
- 从1.3万元降到700元,起诉书揭秘心脏支架“玄机”
- 北京国庆7天接待游客超861万人次 冬奥线路受青睐
- 陈毅元帅长子忆父亲叮嘱:你们自己学习要好,就可以做很多事儿
- 报告显示:这个国庆假期,粤川浙桂赣旅游热度最高
- 中国科技人才大数据:广东总量第一,“北上”这类人才多
- 嘉陵江出现有记录以来最强秋汛
- 全国模范法官周淑琴:为乡村群众点燃法治明灯
- 线上教学模式被盯上,网络付费刷课形成灰色产业链
- 云南保山:170公里边境线,4000余人日夜值守
- 警方查处故宫周边各类违法人员12人
- 农业农村部:确保秋粮丰收到手、明年夏季粮油播种
- 受南海热带低压影响 海南海口三港预计停运将持续到10日白天
- 多地网友投诉遭遇旅游消费骗局,呼吁有关部门严查乱象
- 神经科学“罗塞塔石碑”来了:迄今为止最完整的大脑细胞图谱
- 汾河新绛段发生决口
- 陕西支援14省份采暖季保供用煤3900万吨
- 这场红色故事“云比拼”,穿越时空为我们指引方向
- 受琼州海峡封航影响 10月7日、8日进出海南岛旅客列车停运
- 辽宁省工信厅发布10月8日电力缺口橙色预警
- 广州10月8日至20日对所有从省外来(返)穗人员实施核酸检测
- 假期怎么过得这么快?国庆5.15亿人次出游,你咋过的?
- 国庆假期全国道路交通总体安全平稳有序
- 哈尔滨市南岗区爱达88小区将调整为低风险地区
- 新疆霍尔果斯市2例无症状感染者新冠病毒均为德尔塔变异株
- 百闻不如一见——北京大学留学生参访新疆
- 看,生机勃勃的中国
- 国庆假期中国预计发送旅客4.03亿人次
- 新疆兵团可克达拉市:195名密接者已全部隔离医学观察
- 山西平遥消防4天29次救援:拖着腿走路也要完成任务
- 国庆假期北京接待游客861.1万人次
- 冷空气自西向东影响中国大部地区 气温将下降4℃至6℃
- 新疆哈密市巴里坤县发生4.3级地震 震源深度9千米
- 国庆假期中国国内旅游出游5.15亿人次
- 公安部交管局:国庆假期日均出动警力18万余人次,5位交警辅警牺牲
- 受南海热带低压影响广东将暂别高温天气
- “数说”杭州无障碍改造:触摸城市“爱的厚度”
- 新疆霍尔果斯无症状感染者新冠病毒属德尔塔变异株 未发现高度同源的基因组序列
- 新疆伊犁州:妥善做好滞留旅客安置返回工作
- 国庆假期广西累计接待游客逾3611万人次 实现旅游消费272.41亿元
- 2021年MAGIC3上海市青少年三对三超级篮球赛落幕
- 新疆兵团第四师可克达拉市1名无症状感染者为餐饮从业人员
- 哥伦比亚遇上广州:洋茶人“云上”喫茶 传播中国茶“味道”
- 厦门同安区四区域调整为低风险 全市无中高风险地区
- 直径2米“面气球”亮相 山西首届“寿阳味道”美食大赛启幕
- 世界第一埋深高速公路隧道大峡谷隧道出口端斜井掘进完成
- 浙南沿海村村发展有妙招 搭乘共富快车打造“海上花园”
- 新疆霍尔果斯两例无症状感染者新冠病毒均属德尔塔变异株
- 南沙港铁路国庆假期不停工 力争今年年底开通
- 添加陌生人为好友 内蒙古两女子被骗126万
- 中国国庆假期出行热:数字改变“关键小事”
- 水能载物亦能“生金” 浙江遂昌山村以水为媒奔共富
- 铁路人国庆雨中巡查排险记:一身雨衣、一把铁锹保安全畅通
- 铁路迎返程高峰 西安局集团公司加开79趟高铁列车
- 受热带低压影响 琼州海峡北岸等待过海车辆排长龙
- 哈尔滨市学校有序恢复线下教学
- 哈尔滨一地风险等级调整为低风险
- 从进“培训班”到看《长津湖》
- 安徽黄山国庆假期迎客12万余人 旅游市场稳步复苏
- 山西解除持续近90小时的暴雨四级应急响应
- 科学拦峰错峰削峰 嘉陵江洪水过境重庆中心城区“有惊无险”
- 粤高速大湾区路段假期车流集中 跨珠江口通道尤甚
- 千年街区“非遗”风催热国庆假期本地游
- “颜值担当”里的中国,映照“万物和谐”新气象
X 关闭
资讯
- 放弃Python拥抱Mojo?鹅厂工程师真实使用感受
- 今后9月,四大生肖子女孝顺,财运大旺,财库大开
- 华映科技(000536):8月9日北向资金减持153.08万股
- 易点天下(301171.SZ)发布半年度业绩,净利润1.19亿元,同比下降32.99%
- 特斯拉在印度租赁办公楼,暗示将进入当地市场
- 裁决之镰怎么减刑(裁决之镰怎么解除)
- 恒大地产所持廊坊发展约7603万股股份被轮候冻结
- 曾黎个人资料简介图片(曾黎个人资料)
- 罗马诺:姆巴佩再次拒绝巴黎续约报价 纳赛尔对球员非常愤怒
- 创新医疗(002173.SZ):3642.09万股限售股份将于8月11日解禁
- 云鲸2023年扫地机新品将于8月发布,官方透露:搭载自集尘功能!
- 韩红评价那英及其作品,短短16个字,却字字珠玑!
X 关闭


