揭开AI编程语言Mojo比Pyhon快6.8万倍的5个秘密!

20240403133200

最近(2024年3月29日),号称比Python快6.8万倍的Mojo编程语言开源啦!6.8万倍?你敢相信这个数字是真的吗?不过,就连Mojo官网都把这个结果贴了出来(见下图),这就很难让你不对这个数字引起好奇。很显然,Mojo官方的结果难免有“自卖自夸”的嫌疑,但至少说明在某些特殊的场景下确实得到了这个数字,官网不会造假。那么,究竟是什么原因让Mojo能比Python快这么多呢?下面我们就揭开这一神秘的面纱,也借此机会让我们进一步了解Mojo这门比较火的编程语言。

20240403200358

Mojo简介

Mojo编程语言是由Modular公司开发的,旨在为人工智能领域提供统一的编程框架。它是基于Python语法的超集,结合了Python的易用性和C语言的性能,支持多核向量单元加速器单元等硬件功能。Mojo能够对大量低级AI硬件进行编程,模型扩展性更强,为开发者提供卓越的性能体验。Mojo的创始人是Chris Lattner,他是Swift语言的创始人,也参与了LLVM和Clang的开发。他与Google的机器学习产品经理Tim Davis共同创立了Modular公司,并在2022年推出了Mojo语言。

特殊的例子

可以猜想,这个6.8万倍的结果是在一个特殊的例子上完成,具体来说,它计算和绘制了Mandelbrot集,就是下面的分图案。这是一个非常简单但是又非常耗费计算资源的例子,测试者也给出了选择这个作为例子的理由:

  • 简单表达:只有很少的代码
  • 纯计算:曼德勃罗集没有内存开销
  • 容易并行
  • 可向量化

所以6.8万倍的第1个秘密就是这个计算场景非常适合发挥Mojo的所有优势,这是经典的以己之长比别人之短

20240403201325

# 代码示例:下面函数中z是复数
MAX_ITERS = 1000
def mandelbrot_kernel(c): z = cnv = 0for i in range(MAX_ITERS):if abs(z) > 2:breakz = z*z + cnv += 1return nv

编译语言vs解释语言

众所周知,Python是解释型语言,性能上天然会有一些劣势。Mojo是虽然语法上兼容Python(很多写法上是一样的),但却是一个编译语言。除此之外,Mojo除了像Python一样支持动态类型(在运行的时候才知道变量的类型),还支持另一种静态类型的写法(见下面代码示例),当使用静态类型的时候编译器可以提前对代码做出很多针对性的优化,提升性能。6.8万倍的第2个秘密就是这Mojo是一门支持静态类型的编译语言

fn mandelbrot_2(c: ComplexFloat64) -> Int:var z = cvar nv = 0for i in range(1, MAX_ITERS):if z.squared_norm() > 4:breakz = z.squared_add(c)nv += 1return nv

向量化

前面两个秘密其实还谈不上多神秘,很容易理解和想到。我认为接下来谈到的这个才算是Mojo真正厉害的地方。

正如宣传所说,Mojo是面向人工智能的语言,人工智能计算的特点是什么?大量的向量计算。于是Mojo对向量计算进行了针对性的优化,并且这种优化深入到了底层硬件。为此,Mojo内置了SIMD类型。

单指令多数据(SIMD)是一种并行处理技术,内置于许多现代CPU、GPU和定制加速器中。SIMD允许您一次对多个数据执行单个操作。例如,如果您想对数组中的每个元素求平方根,可以使用SIMD来并行化工作。

Mojo中的SIMD类型就是专门负责针对不同的CPU/GPU进行这种优化的,具体是实现细节在这里就不展开了。在原作者测试的机器上,CPU具有512bit长的向量寄存器,这意味着CPU可以一次操作512/64=8个双精度浮点数,理论上可以实现8x的加速,实测结果是实现了6x以上的加速。此外,原作者在SIMD的基础上还进行了进一步针对CPU的指令的优化:现代 x86 系统具有多个融合乘加(FMA)单元,使其能够在每个时钟周期执行多个 FMA。这一优化也将速度再原有基础上提升了一倍多,不过这一技巧很难适用于所有的计算场景,不多讨论。

鉴于Mojo内置了SIMD数据类型,所以实现上面的优化并不算复杂,这一向量化加速的技术还真是非常适合人工智能计算的场景呢。6.8万倍的第3个秘密就是SIMD向量化加速

多线程加速

Python实是单线程的,如果要利用多核CPU的特性还需要一些特殊的处理,很不方便。Mojo是原生支持多线程的,可以很方便利用多核CPU的特性。用多核CPU对比Python的单核CPU,这不是作弊吗?确实,不过在这里我们先不谈公平问题,先看看在Mojo中是如何实现多线程加速的。

fn compute_row(chunk_idx:Int):let y = chunk_size * chunk_idxlet cy = min_y + y * scale_y@parameterfn compute_vector[simd_width:Int](w:Int):let cx = min_x + iota[DType.float64, simd_width]() * scale_xoutput.simd_store[simd_width](Index(h,w), mandelbrot_kernel(ComplexSIMD[DType.float64, simd_width](cx,cy))vectorize[num_ports * simd_width, compute_vector](width)# !!! 重点代码在这里with Runtime(num_cores()) as rt:parallelize[compute_row](rt, height)

实事求是的说,在Mojo中实现并行确实方便的多啊!无论如何还是要为这一特性点个赞。所以6.8万倍的第4个秘密就是多线程并行加速

原作者测试的机器具有88个CPU,通过这一“作弊行为”,直接将性能在原有的基础上提升了 30 倍,效果那是相当明显😀。但是你可能好奇,为什么没有提升到88倍呢?

负载均衡和数据倾斜

我相信“负责均衡”和“数据倾斜”这两个概念至少有一个你是比较熟悉的,通俗点讲它们都反应了一个问题:分工不均,活都让少数人干了。这就是上面的例子中为什么88核CPU只实现了30倍加速的原因:计算在88个CPU中并不是均匀分布的。那么如何进一步优化呢?

方法其实也并不复杂,我们可以把任务进一步拆分成更小的单元,拆分的越细,平均分配给每个cpu之后越不容易产生“分工不均”的现象(如果你写过Spark,应该听过这个最佳实践:任务/Task的数量最好是Executor/Core数量的2-3倍,而不是等于)。值得庆幸的是,Mojo 包含一个高性能并发运行时,因此我们不必自己创建线程池或进行循环选择和执行。Mojo 的运行时包含高级功能,可以充分利用像这样的多核系统。

# 只需要对原来代码做很少改动
with Runtime(num_cores()) as rt:let partition_factor = 16 # Is autotuned.parallelize[compute_row](rt, height, partition_factor * num_cores())

6.8万倍的第5个秘密就是负载均衡

总结

以上每一个优化都会使得性能提升几倍到数十倍不等,这些数字相乘之后确实就得到了6.8万这一耸人听闻的数字。一路学习了解下来,我觉得Mojo确实是一门相当不错的编程语言,同时Mojo团队也是很懂营销啊!

关注【黑客悟理】,不错过任何奇奇怪怪的知识

参考资料

  1. https://www.modular.com/blog/how-mojo-gets-a-35-000x-speedup-over-python-part-1
  2. https://www.modular.com/blog/how-mojo-gets-a-35-000x-speedup-over-python-part-2
  3. https://www.modular.com/blog/mojo-a-journey-to-68-000x-speedup-over-python-part-3
  4. https://mojocn.org/

    如果你喜欢我的文章,欢迎到我的个人网站关注我,非常感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/790043.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线程池小项目【Linux C/C++】(踩坑分享)

目录 前提知识: 一,线程池意义 二,实现流程 阶段一,搭建基本框架 1. 利用linux第三方库,将pthread_creat线程接口封装 2. 实现基本主类ThreadPool基本结构 阶段二,完善多线程安全 1. 日志信息打印…

若依框架时间比较的坑(DATE_FORMAT)

背景 - 想做生日的比较 若依自带的比较 <if test"params.beginTime ! null and params.beginTime ! "><!-- 开始时间检索 -->AND date_format(u.create_time,%y%m%d) > date_format(#{params.beginTime},%y%m%d)</if><if test"params…

AJAX —— 学习(三)

目录 一、jQuery 中的 AJAX &#xff08;一&#xff09;get 方法 1.语法介绍 2.结果实现 &#xff08;二&#xff09;post 方法 1.语法介绍 2.结果实现 &#xff08;三&#xff09;通用型的 AJAX 方法 1.语法介绍 2.结果实现 二、AJAX 工具库 axios &#xff08;…

【进阶六】Python实现SDVRPTW常见求解算法——遗传算法(GA)

基于python语言&#xff0c;采用经典遗传算法&#xff08;GA&#xff09;对 带硬时间窗的需求拆分车辆路径规划问题&#xff08;SDVRP&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整2.1 需求拆分2.2 需求拆分后的服务时长取值问题 3. 求解结果4. 代码片段参…

【Qt】Ubuntu20.04.6+Qt5.15.2+QtCreator10.0.1无法输入中文

1、前提条件 1)已经安装了fcitx sudo apt install fcitx sudo apt install fcitx-pinyin sudo apt install fcitx-bin fcitx-table-all sudo apt install fcitx-qt52)系统已经配置fcitx 3)将系统下 /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/libfcitx…

计算机考研408有向无环图描述表达式可靠构造方法

目录 前言目标&#xff08;以王道书为例&#xff09;构造方法1. 建树2. 后序遍历1. a2. b3. 4. b5. c6. d7. 8. *9. *10. c 前言 对王道视频中的分层合并思想不是很满意&#xff0c;笔者提出自己的构造方法。 目标&#xff08;以王道书为例&#xff09; 构造方法 笔者通过王…

Doris实践——同程数科实时数仓建设

目录 前言 一、早期架构演进 二、Doris和Clickhouse选型对比 三、新一代统一实时数据仓库 四、基于Doris的一站式数据平台 4.1 一键生成任务脚本提升任务开发效率 4.2 自动调度监控保障任务正常运行 4.3 安全便捷的可视化查询分析 4.4 完备智能的集群监控 五、收益与…

线控悬架系统分析

线控悬架系统分析 附赠自动驾驶学习资料和量产经验&#xff1a;链接 1 线控悬架系统系统发展现状 • 车辆驾乘过程中&#xff0c;操控性和舒适性是两个重要的评价指标&#xff0c;两者很难兼顾&#xff1b; • 线控悬架就是根据路况实际情况自动调节悬架的高度、刚度、阻尼实…

012_control_flow_in_Matlab中的控制流

Matlab中的控制流 虽然&#xff0c;我们说Matlab中的计算是向量化的&#xff0c;但是在某些情况下&#xff0c;作为一个“程序设计语言”&#xff0c;Matlab也提供了一些控制流结构&#xff0c;来帮助我们实现一些复杂的逻辑。 我会在介绍控制流的时候&#xff0c;提醒如何用…

Ansys Zemax | 如何将光栅数据从Lumerical导入至OpticStudio(上)

附件下载 联系工作人员获取附件 本文介绍了一种使用Ansys Zemax OpticStudio和Lumerical RCWA在整个光学系统中精确仿真1D/2D光栅的静态工作流程。将首先简要介绍方法。然后解释有关如何建立系统的详细信息。 本篇内容将分为上下两部分&#xff0c;上部将首先简要介绍方法工…

【Leetcode】top 100 技巧

136 只出现一次的数字 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 技巧&#xff1a…

LeetCode 96. 不同的二叉搜索树

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff1a;1提…

代码随想录算法训练营第二十二天| 235.二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

系列文章目录 目录 系列文章目录235. 二叉搜索树的最近公共祖先①递归法自己写的简洁版 ②迭代法不能这样写&#xff01;正确写法 701.二叉搜索树中的插入操作①递归法②迭代法 450.删除二叉搜索树中的节点递归法 235. 二叉搜索树的最近公共祖先 ①递归法 自己写的 class So…

书生·浦语大模型InternLM-Chat-1.8B 智能对话 Demo 第二期

文章目录 InternLM-Chat-1.8B 智能对话 Demo环境准备下载模型运行 InternLM-Chat-1.8B web 运行八戒 demo下载模型执行Demo InternLM-Chat-1.8B 智能对话 Demo 环境准备 在InternStudio平台中选择 10% A100(1/4) 的配置&#xff08;平台资源有限&#xff09;&#xff0c;如下图…

【c语言】自定义类型:联合体(公用体)【详解】

联合体 联合体类型的声明 像结构体⼀样&#xff0c;联合体也是由⼀个或者多个成员构成&#xff0c;这些成员可以不同的类型。但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫&#xff1a;共用体。 给联合体其中⼀个成…

2024阿里云域名优惠口令免费领取,COM、CN和xin域名口令

2024年阿里云域名优惠口令&#xff0c;com域名续费优惠口令“com批量注册更享优惠”&#xff0c;cn域名续费优惠口令“cn注册多个价格更优”&#xff0c;cn域名注册优惠口令“互联网上的中国标识”&#xff0c;阿里云优惠口令是域名专属的优惠码&#xff0c;可用于域名注册、续…

【QT入门】 自定义标题栏界面qss美化+按钮功能实现

往期回顾&#xff1a; 【QT入门】 鼠标按下和移动事件实现无边框窗口拖动-CSDN博客【QT入门】 设计实现无边框窗口拉伸的公用类-CSDN博客【QT入门】对无边框窗口自定义标题栏并实现拖动和拉伸效果-CSDN博客 【QT入门】 自定义标题栏界面qss美化按钮功能实现 一、最终效果 二、…

【JAVASE】学习类与对象的创建和实例化

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 目标&#xff1a; 1. 掌握类的定义方式以及对象的实例化 2. …

MVCC的实现原理

简介 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;即多版本并发控制。 MVCC的实现原理 我们在了解MVCC之前&#xff0c;首先先了解一下几个比较常见的锁。 **读锁&#xff1a;**也叫共享锁、S锁&#xff0c;若事务T对数据对象A加上S锁&#xff0c;则事务…

一维卷积神经网络的特征可视化

随着以深度学习为代表的人工智能技术的不断发展&#xff0c;许多具有重要意义的深度学习模型和算法被开发出来&#xff0c;应用于计算机视觉、自然语言处理、语音处理、生物医疗、金融应用等众多行业领域。深度学习先进的数据挖掘、训练和分析能力来源于深度神经网络的海量模型…