都有Python了,还要什么编译器!
编译的目的是将源码转化为机器可识别的可执行程序,在早期,每次编译都需要重新构建所有东西,后来人们意识到可以让编译器自动完成一些工作,从而提升编译效率。
但“编译器不过是用于代码生成的软机器,你可以使用你想要的任何语言来生成代码”,真的是必要的吗?
作者 | Oleksandr Kaleniuk
译者 | 虎说
责编 | 仲培艺
来源 | CSDN(ID:CSDNnews)
诚然,编译器可以为你生成高性能的代码,但是你真的需要编译器吗?另一种方法是用 Assembly 编写程序,虽然有点夸大,但这种方法有两个主要缺陷:
1. 汇编代码不可移植;
2. 虽然在现代工具的辅助下变得容易了些,但 Assembly 编程仍然需要大量繁琐的工作。
值得庆幸的是,我们都生活在二十一世纪,这两个问题都已得到解决。第一个解决方案是 LLVM,最初,它意味着“低级虚拟机”,这正是我们可以确保可移植性的原因。简而言之,它需要用一些非常低级别的与硬件无关语言编写的代码,并为特定的硬件平台返回一些高度优化的原生代码。使用 LLVM,我们既具有低级编程的强大功能,又具有面向硬件微优化的自动化功能。
第二个问题的解决方法是使用“脚本”语言,Scheme、Python、Perl,甚至 bash 或 AWK 都可以消除繁琐的工作。
实验计划
首先,让我们生成一个完全内联展开的解决方案,并将其嵌入到基准测试代码中。该计划如下:
1. 使用 Clang 为基准生成 LLVM 中间代码,该基准用于测量 solve_5,一个不存在的函数;
2. 使 Python 在 LLVM 中生成线性求解器(linear solver)代码;
3. 使用 Python 脚本测试基准,用生成求解器替换 solve_5 调用;
4. 使用 LLVM 静态编译器将中间代码转换为机器代码;
5. 使用 GNU 汇编器和 Clang 的链接器将机器代码转换为可执行的二进制文件。
这就是它在 Makefile 中的样子:
Python 部分
我们需要 Python 中的线性求解器(linear solver),就像我们使用 C 和 C ++ 一样,此处代码为:
# this generates n-solver in LLVM code with LLVMCode objects.
# No LLVM stuff yet, just completely Pythonic solution
def solve_linear_system(a_array, b_array, x_array, n_value):
def a(i, j, n):
if n == n_value:
return a_array[i * n_value + j]
return a(i, j, n+1)*a(n, n, n+1) - a(i, n, n+1)*a(n, j, n+1)
def b(i, n):
if n == n_value:
return b_array[i]
return a(n, n, n+1)*b(i, n+1) - a(i, n, n+1)*b(n, n+1)
def x(i):
d = b(i,i+1)
for j in range(i):
d -= a(i, j, i+1) * x_array[j]
return d / a(i, i, i+1)
for k in range(n_value):
x_array[k] = x(k)
return x_array
当我们用数字运行时,我们可以得到数字。但我们想要代码,因此,我们需要制作一个假装成数字的对象(Object)来探测算法。该对象记录下算法想要执行的每一个操作,并准备好集成 LLVM 中间语言。
# this is basically the whole LLVM layer
I = 0
STACK = []
class LLVMCode:
# the only constructor for now is by double* instruction
def __init__(self, io, code = ''):
self.io = io
self.code = code
def __getitem__(self, i):
global I, STACK
copy_code = "%" + str(I+1)
copy_code += " = getelementptr inbounds double, double* "
copy_code += self.io +", i64 " + str(i) + "\n"
copy_code += "%" + str(I+2)
copy_code += " = load double, double* %" + str(I+1)
copy_code += ", align 8\n"
I += 2
STACK += [I]
return LLVMCode(self.io, copy_code)
def __setitem__(self, i, other_llvcode):
global I, STACK
self.code += other_llvcode.code
self.code += "%" + str(I+1)
self.code += " = getelementptr inbounds double, double* "
self.code += self.io +", i64 " + str(i) + "\n"
self.code += "store double %" + str(I)
self.code += ", double* %" + str(I+1) + ", align 8\n"
I += 1
STACK = STACK[:-1]
return self
def general_arithmetics(self, operator, other_llvcode):
global I, STACK
self.code += other_llvcode.code;
self.code += "%" + str(I+1) + " = f" + operator
self.code += " double %" + str(STACK[-2]) + ", %"
self.code += str(STACK[-1]) + "\n";
I += 1
STACK = STACK[:-2] + [I]
return self
def __add__(self, other_llvcode):
return self.general_arithmetics('add', other_llvcode)
def __sub__(self, other_llvcode):
return self.general_arithmetics('sub', other_llvcode)
def __mul__(self, other_llvcode):
return self.general_arithmetics('mul', other_llvcode)
def __div__(self, other_llvcode):
return self.general_arithmetics('div', other_llvcode)
接着,当我们使用这种对象运行求解器时,我们得到了一个用 LLVM 中间语言编写的全功能线性求解器。然后我们将其放入基准代码中进行速度测试(看它有多快)。
LLVM 中的指令有编号,我们希望保存枚举,因此将代码插入到基准测试中的函数很重要,但也不是很复杂。
# this replaces the function call
# and updates all the instructions' indices
def replace_call(text, line, params):
global I, STACK
# '%12 ' -> 12
I = int(''.join(
[xi for xi in params[2] if xi.isdigit()]
))
first_instruction_to_replace = I + 1
STACK = []
replacement = solve_linear_system(
LLVMCode(params[0]),
LLVMCode(params[1]),
LLVMCode(params[2]), 5).code
delta_instruction = I - first_instruction_to_replace + 1
for i in xrange(first_instruction_to_replace, sys.maxint):
not_found = sum(
[text.find('%' + str(i) + c) == -1
for c in POSSIBLE_CHARS_NUMBER_FOLLOWS_WITH]
)
if not_found == 4:
# the last instruction has already been substituted
break
new_i = i + delta_instruction
for c in POSSIBLE_CHARS_NUMBER_FOLLOWS_WITH:
# substitute instruction number
text = text.replace('%' + str(i) + c, '%' + str(new_i) + c)
return text.replace(line, replacement)
实现解算器的整段代码提供了 Python-to-LLVM 层,其中代码插入只有 100 行!
另附 GitHub 链接:
https://github.com/akalenuk/wordsandbuttons/blob/master/exp/python_to_llvm/exp_embed_on_call/substitute_solver_call.py
基准
基准测试本身在 C 中。当我们运行 Makefile 时,它对 solve_5 的调用被 Python 生成的 LLVM 代码所取代。
Step 1. Benchmark C source code
Step 2. LLVM 汇编语言
Step 3. 调用替换后的 LLVM
Step 4. 本地优化装配
最值得注意的是 Python 脚本生成的超冗长中间代码如何变成一些非常紧凑且非常有效的硬件代码。同时它也是高度标量化的,但它是否足以与 C 和 C++ 的解决方案竞争呢?
以下是三种情况的近似数字(带有技巧的 C、C++ 与基于 LLVM 的 Python 的性能对比):
1. C 的技巧对 Clang 来说并不适用,因此测量 GCC 版本,其平均运行大约 70 毫秒;
2. C++ 版本是用 Clang 构建的,运行时间为 60 毫秒;
3. Python 版本(此处描述的版本)仅运行 55 毫秒。
当然,这种加速并不是关键,但这表明你可以用 Python 编写出胜过用 C 或 C++ 编写的程序。这也就暗示你不必学习一些特殊语言来创建高性能的应用程序或库。
结论
快速编译语言和慢速脚本语言之间的对立不过是虚张声势。原生代码生成的可能不是核心功能,而是类似于可插拔选项。像是 Python 编译器 Numba 或 Lua 的 Terra,其优势就在于你可以用一种语言进行研究和快速原型设计,然后使用相同的语言生成高性能的代码。
高性能计算没有理由保留编译语言的特权,编译器只是用于代码生成的软机器。你可以使用你想要的任何语言生成代码,我相信如果你愿意,你可以教 Matlab 生成超快的 LLVM 代码。
本文涉及的所有测试均在 Intel(R)Core(TM)i7-7700HQ CPU @ 2.80GHz 上进行,代码使用 Clang 3.8.0-2ubuntu4 和 g++5.4.0 编译。
基准测试源代码:
https://github.com/akalenuk/wordsandbuttons/tree/master/exp/python_to_llvm
原文链接:
https://wordsandbuttons.online/outperforming_everything_with_anything.html
本文为 CSDN 翻译,如需转载,请注明来源出处。
(本文为 AI科技大本营转载文章,转载请联系原作者)
4 月13日-4 月14日,CSDN 将在北京主办“Python 开发者日( 2019 )”,汇聚十余位来自阿里巴巴、IBM、英伟达等国内外一线科技公司的Python技术专家,还有数百位来自各行业领域的Python开发者。目前购票通道已开启,早鸟票限量发售中,3 月15日之前可享受优惠价 299 元(售完即止)。
推荐阅读:
300道Python面试题,备战春招!
2018中国开发者真实现状:40岁不做开发,算法工程师最稀缺!
人生苦短,Python之父要解开这个困惑
从起源、变体到评价指标,一文解读NLP的注意力机制
女子偷师男子学校,变身区块链开发工程师,却说: “这次女人不会再缺席了!”
云漫圈 | 如何给女朋友解释什么是HTTP
从程序媛到全球研发副总裁,技术女神进击史!
杨超越杯编程大赛上热搜:不懂技术真不敢追星女子偷师男子学校,变身区块链开发工程师,却说: “这次女人不会再缺席了!”
为啥程序员下班后只关显示器从不关电脑?
❤点击“阅读原文”,查看历史精彩文章。
相关文章:
【Qt】Qt发布程序时,报错: could not find or load the Qt platform plugin xcb
问题描述 Qt程序在发布时,报错: This application failed to start because it could not find or load the Qt platform plugin “xcb” in “”. Reinstalling the application may fix this problem Aborted (core dumped) 原因 没有将libqxcb…
jsky使用小记
jsky是一款深度WEB应用安全评估工具,能轻松应对各种复杂的WEB应用,全面深入发现里面存在的安全弱点。 jsky可以检测出包括SQL注入、跨站脚本、目录泄露、网页木马等在内的所有的WEB应用层漏洞,渗透测试功能让您熟知漏洞危害。 打开——新建扫…
BSP场景管理方法简介
BSP(Binary Space Partition,二叉空间分割)方法,在大型3d游戏场景管理方面,可以认为是已经证明了的,最成熟的,最经得起考验的场景管理方法。诸如虚幻系列引擎(Unreal 1,2,3)…
【Qt】Qt样式表总结(一):选择器
官方资料 https://blog.csdn.net/u010168781/article/details/81868523 注释 qss文件中使用:/**/ 来注释 样式规则 样式表由样式规则序列组成。样式规则由选择器和声明组成。选择器指定受规则影响的部件;声明指定应在小部件上设置哪些属性。 如: QLabel { color: white;…
JVM-01:类的加载机制
本文从 纯洁的微笑的博客 转载 原地址:http://www.ityouknow.com/jvm.html 类的加载机制 1、什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.…
CVPR 2019 | 惊艳的SiamMask:开源快速同时进行目标跟踪与分割算法
作者 | 周强(CV君)来源 | 我爱计算机视觉(公众号id:aicvml)责编 | Jane上面这张Gif图演示了 SiamMask 的效果,只需要鼠标滑动选择目标的包围框,即可同时实现目标跟踪与分割。这种视频里目标的像…
看看Entity Framework 4生成的复杂的分页SQL语句
之前发现Entity Framework 4生成的COUNT查询语句问题,今天又发现它生成的分页SQL语句问题,而LINQ to SQL却不存在这个问题。 >>> 来看一看,瞧一瞧! 上代码: 看生成的SQL语句: 1. Entity Framework…
这份“插件英雄榜Top20”才是Chrome的正确打开方式!
作者 | zhaoolee整理 | Jane出品 | AI科技大本营(公众号id:rgznai100)前言”一入开源深似海”!给大家推荐优秀的开源项目、实用工具已经成为 AI科技大本营的固定节目。“我待开源如初恋”,逛淘宝,点收藏&am…
【Qt】Qt样式表总结(二):冲突和命名空间
Qt样式表总结(一):选择器 解决冲突 针对同一个控件的相同属性,使用多种选择器时,会出现冲突。如: QPushButton#okButton { color: gray } QPushButton { color: red } 解决冲突的规则是:更…
编程自动化,未来机器人将超越人类?
近年,创业者陈曦正专注于一个项目——编程自动化。即机器人可以自己编程,这到底意味着什么呢? 在美国科幻大片《终结者2》中,20世纪末的1997年7月3日,人类研制的全球高级计算机控制系统“天网”全面失控,机…
Repeater 嵌套 Repeater
作为一个刚入行的IT小鸟,每天学习,是必须的! 光自学肯定是不够的!由于本人IQ比较低,经常一个小问题都会想不明白。 还好有媳妇儿的帮助,才把这个功能给实现了。 现在就在这里总结下,以示敬意。o…
【Qt】Qt样式表总结(三):QObject 属性
【Qt】Qt样式表总结(一):选择器 【Qt】Qt样式表总结(二):冲突和命名空间 QObject 属性 可以使用 qproperty < 属性名称 > 语法,设置任何可以Q_PROPERTY的控件 MyLabel { qproperty-pixmap: url(pixmap.png); } MyGroupBox { qproperty-titleColor: rgb(100, 2…
CVPR2019 | 斯坦福学者提出GIoU,目标检测任务的新Loss
作者 | Slumbers,毕业于中山大学,深度学习工程师,主要方向是目标检测,语义分割,GAN责编 | Jane本文是对 CVPR2019 论文《Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression》的解…
ASP.NET页面之间传递值的几种方式
页面传值是学习asp.net初期都会面临的一个问题,总的来说有页面传值、存储对象传值、ajax、类、model、表单等。但是一般来说,常用的较简单有QueryString,Session,Cookies,Application,Server.Transfer。 一…
下一代安全威胁的内幕故事
当伊朗总统马哈茂德艾哈迈迪-内贾德在去年11月份宣布该国的核计划遭到软件***后,他证实了许多安全研究人员的猜测:原因是Stuxnet大爆发,篡改了控制处理铀所用的离心机电机的关键系统。 内贾德对这起***造成的影响轻描淡写…
国内少儿眼中的编程:“Coding即是代码”?
作者 | Greg Satell译者 | 刘旭坤责编 | Jane出品 | AI科技大本营(公众号id:rgznai100)【编者按】上一个时代流行从小学奥数,现在“编程要从宝宝抓起”已经开始疯狂流行。随着 2017 年国务院印发《新一代人工智能发展规划》&#…
西门子发布最新版NX软件 助力零件制造的数字化
SiemensPLMSoftware近日发布最新版NXTM软件,集成了用于增材制造、计算机数控(CNC)加工、机器人和质量检测等新一代工具,以实现在统一的、集成的、端到端的系统中实现零件制造的数字化。 其中,用于计算机辅助制造(CAM)的先进自动化功能&#x…
【Qt】Qt国际化
参考博客:https://blog.csdn.net/hebbely/article/details/69388763 Qt官网:http://doc.qt.io/qt-5/linguist-manager.html 使用的工具 lupdate --> linguist --> lrelease 使用步骤 tr 在程序中将需要翻译的文本使用tr()函数来处理 修改pro…
回到未来 – 大胆畅想如何追赶并超越腾讯模式
其实,明天是什么样子,它就会是什么样子。 我总是喜欢幻想,无论是对过去还是对未来,对生活或是对爱情。 不过憧憬多过幻想。 一直比较关注互联网的动态,想象如果某某公司的某件产品如果是自己的&…
Python如何爬取实时变化的WebSocket数据
作者 | 韦世东来源 | 进击的Coder(公众号id:FightingCode)一、前言作为一名爬虫工程师,在工作中常常会遇到爬取实时数据的需求,比如体育赛事实时数据、股市实时数据或币圈实时变化的数据。如下图:Web 领域中…
【Qt】Qt样式表总结(四):CSS盒子模型
官网:http://doc.qt.io/qt-5/stylesheet-customizing.html#box-model 【Qt】Qt样式表总结(一):选择器 【Qt】Qt样式表总结(二):冲突和命名空间 【Qt】Qt样式表总结(三):QObject 属性 盒子模型 先来张图片,引自Qt官网 使用样式表时, 每个小部件都被视为具有四个同…
1.试述大数据对思维方式的重要影响。 2.详细阐述大数据、云计算、物联网之间的区别与联系。 3.简述你对大数据应用与发展的看法,以及你在这次大数据浪潮中想扮演什么角色。...
1.大数称巨量资料,指的是需要新处理模式才能具有更强的决策力、洞察力和流程优化能力的海量、高增长率和多样化的信息资产。所以利用大数据的人们思维更加的敏锐,也会对人们的思维方式产生扩大化,通过大量的数据进行分析,从而形成…
有关GetPrivateProfileString的使用方法
函数返回值为string的长度(long型),而从ini文件获得的字符串则保留在目的缓冲器中 DWORD GetPrivateProfileString( LPCTSTR lpAppName, //配置文件的section名 LPCTSTR lpKeyName, //配置文件的key名 LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPC…
【Qt】QDebug和log4cplus的联合使用
问题描述 项目开始时,只使用QDebug将调试信息打印到终端上。后期添加了日志管理系统,比如log4cplus。如何在不修改打印语句,比如还使用qDebug,就能将日志打印到文件中。 解决方法 使用qInstallMessageHandler将调试消息重定向功…
75道常见AI面试题,看看你的知识盲点在哪?(附解析)
整理 | AI科技大本营出品 | AI科技大本营(公众号id:rgznai100)【导语】正值求职、跳槽季,无论你是换工作还是找实习,没有真本事都是万万不行的,可是如何高效率复习呢?之前我们给大家推荐了一份 …
Flex画流程图
<?xml version"1.0" encoding"utf-8"?><mx:Application xmlns:mx"http://www.adobe.com/2006/mxml" layout"absolute" creationComplete"initApp()"> <mx:Canvas id"paper" x"30" y&q…
【Qt】Qt信号与槽使用不当,使程序崩溃
问题描述 跨线程使用Qt信号和槽,信号发送时间间隔小于槽函数处理时间时,造成程序崩溃。 原因分析 跨线程使用Qt信号和槽时,connect默认是QueuedConnection,队列连接方式。 信号传递给槽函数的参数,分配内存后放入队…
70亿美金!英伟达欲竞购这家以色列芯片公司!
整理 | 琥珀出品 | AI科技大本营(公众号id:rgznai100)近日,据国外财经媒体 Calcalist 报道,英伟达已给出报价,竞购以色列芯片设计公司迈络思(MellanoxTechnologies)。实际上…
Mysql安全配置
zhangsan 2014/06/14 11:550x01 前言很多文章中会说,数据库的权限按最小权限为原则,这句话本身没有错,但是却是一句空话。因为最小权限,这个东西太抽象,很多时候你并弄不清楚具体他需要哪些权限。 现在很多mysql用着r…
【C++】Google C++编码规范(一):作用域
1、文件作用域: 在.cpp文件中,C使用匿名名字空间来表示文件作用域,C使用static来表示; 2、局部变量 局部变量在声明的同时,进行显示初始化;比起隐式初始化再赋值要高效; 局部变量的作用域要尽…