mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-19 15:43:44 +08:00
mod
This commit is contained in:
69
极客时间专栏/编译原理实战课/课前必读/学习指南 | 如何学习这门编译原理实战课?.md
Normal file
69
极客时间专栏/编译原理实战课/课前必读/学习指南 | 如何学习这门编译原理实战课?.md
Normal file
@@ -0,0 +1,69 @@
|
||||
<audio id="audio" title="学习指南 | 如何学习这门编译原理实战课?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/91/1d/91186c66ff3e80b2113247194ae50b1d.mp3"></audio>
|
||||
|
||||
你好,欢迎来到《编译原理实战课》,我是专栏编辑王惠,很高兴认识你。
|
||||
|
||||
我们都知道,“编译原理”是一门特别硬核的计算机基础专业课。你是不是也觉得编译原理知识就像是一片望不到头的大海,任自己在里面怎么扑腾、怎么挣扎都游不到学成的对岸。但是没关系,现在我们可以跟着宫老师的脚步一起探索编译的旅程了。
|
||||
|
||||
不过在正式开始学习这门课程之前,我想先和你聊聊这门课程的一些设计思路和特设板块,帮你找到最适合自己的学习方式,让你后面的学习能达到事半功倍的效果。
|
||||
|
||||
## 我们有“学习委员”了
|
||||
|
||||
首先来说个好消息,咱这门课呢有学习委员陪伴我们一起学。担当学委的是我们的资深用户朱英达同学,他曾就职于百度,履任资深研发工程师,擅长Web前后端相关领域技术,对编译技术在业务场景下的应用也有自己的理解。
|
||||
|
||||
他的经历可能和你很相似:作为一名计算机科班出身的程序员,在大学课堂中学习过编译原理这门课,但面对教科书上庞杂的知识体系、晦涩的抽象概念、陈旧的代码用例,无奈只学了个一知半解;工作以后,作为一名一线的Coder,在大厂的环境里,看惯了层出不穷的“造轮子怪象”,最终才发现只有掌握像编译原理这样的底层技术,才是真正的精进之道。所以,他想把编译原理这门课重新捡起来,再学一次。
|
||||
|
||||
然而,目前市面上编译方面的技术资料却非常匮乏,被学界奉为经典的“龙书”“虎书”“鲸书”,对初学者来说又不够友好。后来,他遇到了宫老师的《编译原理之美》,跟着老师的思路重走了一遭编译之旅,发现自己之前对于编译技术的很多困惑点都迎刃而解了。比如说,宫老师在阐释虚拟机架构时,谈到了栈机和寄存器架构的优劣,这就对他理解V8引擎在虚拟机架构选型上提供了非常好的参考。
|
||||
|
||||
朱学委最终也发现,**编译技术的学习绝对不能纸上谈兵,只有把学到的理论知识与自己从事的相关技术领域结合起来,才会真正有所感悟。**
|
||||
|
||||
你看,编译原理或者说所有的技术,都有这么一个反复学习、反复印证的过程。所以在这门课程中,学委将会基于积累的编译原理基础,以及对这门新课程内容的学习,不定期地分享他学习编译原理的方法和思路,和你一起探讨课程要掌握的要点和难点。当然了,学委也会在留言区督促你交作业,和你一起交流讨论。
|
||||
|
||||
有了学委的陪伴,相信你再学习这门课,一定可以事半功倍。
|
||||
|
||||
## 如何学习预备知识模块?
|
||||
|
||||
接下来,我来说说怎么利用好预备知识模块。
|
||||
|
||||
那我先来交代下为什么要特别设计这个模块。就像老师在开篇词中所说的,这门课程会带你一起阅读真实语言编译器的源码,跟踪它们的运行过程,分析编译过程的每一步是如何实现的,并会对有特点的编译技术点加以分析和点评。
|
||||
|
||||
但在解析编译器的过程中,一定会涉及到很多编译原理的基础概念、理论和算法,如果你从来没有接触过或者不够了解这些编译原理知识,那必然会在一定程度上影响你后面的学习效果。所以,预备知识模块就是帮你先建立起一个初步的编译原理知识体系,打好基础,为后面的学习做好准备。
|
||||
|
||||
如果你已经学过老师的第一季课程[《编译原理之美》](https://time.geekbang.org/column/intro/219?utm_term=zeusGI5E3&utm_source=app&utm_medium=geektime&utm_campaign=219-end&utm_content=xuexizhinan0601),预备篇的内容也建议你不要跳过。和第一季课程相比,在这个模块里宫老师会以更加高屋建瓴的方式,来重新交付编译基础知识。所以,你一定要利用这个模块来查漏补缺。
|
||||
|
||||
那具体怎么做呢?**建议你先看每一讲的标题,然后回顾自己已经学过的、掌握了的知识要点,写下来,写好后再开始学习,学完后对比总结心得。**千万不要错过这个再学一次的机会。我们都知道重复是学习的关键一环,相信通过这个模块,你一定能在编译技术的理解上更上层楼。
|
||||
|
||||
你可以把预备知识理解为编译基础的一个串讲,涉及到的概念会比较多。所以学习这个模块的时候,我建议你每学完一讲都要自己动手画一下这一讲的知识地图。等8篇结束后,学习委员也会总结一张**编译原理的核心基础知识大地图**。到时候你可以对比来看,给自己一个直接的反馈。然后一定要利用这张图,在脑子里构建起编译原理的知识框架。这样,你就做好了进入下个模块的学习准备啦。
|
||||
|
||||
## 解析7种语言编译器的过程中,你需要做什么?
|
||||
|
||||
下面我来说说课程的重头戏,也就是解析7种语言的编译器,包括Java编译器(javac)、Java的JIT编译器(Graal)、Python编译器(CPython)、JavaScript编译器(V8)、Julia语言的编译器、Go语言的编译器(gc),以及MySQL的编译器。
|
||||
|
||||
这些编译器都是宫老师精选出来的,具有一定的代表性、采用了不同的编译技术,而且其中某一门语言也非常可能就是你在使用的。我们的课程就是从实战的角度切入,用你最擅长的方式(写代码、读代码)带你分析这些编译器。所以学好这门课的关键就是要**动手实践**,跟随老师的脚步来亲身体验不同编译器的实现机制。
|
||||
|
||||
我建议你最好在学习的过程中手边备着一台电脑,或者是一台能查看到源代码的其他设备,工具不重要,趁手最有效。你在自己上手修改源码的时候,就会发现对编译原理的概念理解得更加深入了。
|
||||
|
||||
## 期中复习周,停下来是为了跑得更快
|
||||
|
||||
接着来说说期中复习周。这一周安排在“真实编译器解析篇”之后,也就是建立在你已经学习并理解了7种不同语言编译器的运行机制之后。设置复习周的目的,就是想要让你能及时、系统地了解自己前半段课程内容的掌握情况,发现学习上的漏洞,并及时弥补。
|
||||
|
||||
在这一周,学委首先会帮你划出复习的重点,给你总结前面解析的7种语言编译器所涉及到的核心知识。总结复习的过程,也就是你在提高编译技术能力的过程。
|
||||
|
||||
接下来,老师会给你出一套考试题。通过这次测试,你可以验证一下自己的学习方式是否有效,希望你能够及时调整学习心态和方法,更有效率地进行下一阶段的学习。
|
||||
|
||||
另外,在消化知识的同时,你还可以通过其他同学分享的心得,去看看他是如何学习、掌握编译原理知识的,毕竟通过借鉴别人来完善自己也是一种很好的学习方法嘛。
|
||||
|
||||
## Learning by Sharing,分享了才知道自己那么优秀
|
||||
|
||||
再接下来,我必须得说说“一课一思”这个学习环节了。
|
||||
|
||||
一课一思是每一讲最后的固定模块,具体内容呢,要么是给你留了一道动手实践的作业,要么就是抛出一个开放性的问题,引导你发散思考。如果你对这些问题都有自己的见解或者看法,那就不妨在留言区分享出来。这样渐渐地,你会发现自己就能解答一些同学的问题了,这是非常好的自检学习成果的方式。
|
||||
|
||||
另外别忘记了,极客时间还有一个社区交流的版块“**部落**”。在日常工作中,你一定会经常接触各种代码,也一定有自己非常熟悉的一门或多门编程语言。那么在解析了不同语言的编译器以后,你可以在部落里分享自己对于熟悉的或不熟悉的语言编译器的理解。
|
||||
|
||||
比如说,你原来深耕在Java领域,那么在学完了javac编译器和Graal编译器以后,你对Java是不是就有更深刻的理解了?在学完了Python的编译器以后,你是不是对这两门语言之间的共性和特性都更加清晰了?这些思考你都可以分享在部落里,通过分享自己所习得的知识,你会获得更好的成长。
|
||||
|
||||
## 如何验收学习成果?
|
||||
|
||||
最后,在课程的收尾阶段呢,老师还会跟你一起关注一个热点话题,那就是华为的方舟编译器。相信很多同学对于国产的编译器,一直都是翘首以盼的。华为已经公开了一部分源代码,虽然资料仍然很缺乏,但是通过我们课程的学习,你是否有能力看懂华为的编译器呢?从掌握书本上的原理,到读懂流行的语言,再到理解方舟编译器的实现思路,这会是你能力一步步提升的过程。最终,你甚至可以参与到一款严肃的编译器的研发当中了。
|
||||
|
||||
好了,以上就是我想让你重点关注的课程设计和特设板块内容。编译原理是个难啃的硬骨头,但是我相信,只要你保有这份一定要吃透编译技术核心知识的决心,有计划、有重点,结合实践进行学习,就没有什么是看不懂、学不会的了。加油吧,祝你学有所成!
|
||||
99
极客时间专栏/编译原理实战课/课前必读/开篇词 | 在真实世界的编译器中游历.md
Normal file
99
极客时间专栏/编译原理实战课/课前必读/开篇词 | 在真实世界的编译器中游历.md
Normal file
@@ -0,0 +1,99 @@
|
||||
<audio id="audio" title="开篇词 | 在真实世界的编译器中游历" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d9/05/d9e55215151ee00a1c9f5c6ad15b3f05.mp3"></audio>
|
||||
|
||||
你好,我是宫文学,一名技术创业者,现在是北京物演科技的CEO,很高兴在这里跟你见面。
|
||||
|
||||
我在IT领域里已经工作有20多年了。这其中,我个人比较感兴趣的,也是倾注时间精力最多的,是做基础平台类的软件,比如国内最早一批的BPM平台、BI平台,以及低代码/无代码开发平台(那时还没有这个名字)等。这些软件之所以会被称为平台,很重要的原因就是拥有很强的定制能力,比如流程定制、界面定制、业务逻辑定制,等等。而这些定制能力,依托的就是编译技术。
|
||||
|
||||
在前几年,我参与了一些与微服务有关的项目。我发现,前些年大家普遍关注那些技术问题,比如有状态的服务(Stateful Service)的横向扩展问题,在云原生、Serverless、FaaS等新技术满天飞的时代,不但没能被很好地解决,反而更恶化了。究其原因就是,状态管理还是被简单地交给数据库,而云计算的场景使得数据库的压力更大了,数据库原来在性能和扩展能力上的短板,就更加显著了。
|
||||
|
||||
而比较好的解决思路之一,就是大胆采用新的计算范式,发明新的计算机语言,所以我也有意想自己动手搞一下。
|
||||
|
||||
我从去年开始做设计,已经鼓捣了一阵了,采用了一些很前卫的理念,比如云原生的并发调度、基于Actor的数据管理等。总的目标,是要让开发云原生的、有状态的应用,像开发一个简单的单机应用一样容易。那我们就最好能把云架构和状态管理的细节给抽象掉,从而极大地降低成本、减少错误。而为编程提供更高的抽象层次,从来就是编译技术的职责。
|
||||
|
||||
Serverless和FaaS已经把无状态服务的架构细节透明掉了。但针对有状态的服务,目前还没有答案。对我而言,这是个有趣的课题。<br>
|
||||
在我比较熟悉的企业应用领域,ERP的鼻祖SAP、SaaS的鼻祖SalesForce,都用自己的语言开发应用,很可惜国内的企业软件厂商还没有做到这一点。而在云计算时代,设计这样一门语言绕不过去的一个问题,就是解决有状态服务的云化问题。我希望能为解决这个问题提供一个新工具。当然,这个工具必须是开源的。
|
||||
|
||||
正是因为给自己挖了这么大一个坑,也促使我更关心编译技术的各种前沿动态,也非常想把这些前沿的动态、理念,以及自己的一些实战经验都分享出来。
|
||||
|
||||
所以去年呢,我在极客时间上开了一门课程[《编译原理之美》](https://time.geekbang.org/column/intro/219?utm_term=zeusGI5E3&utm_source=app&utm_medium=geektime&utm_campaign=219-end&utm_content=xuexizhinan0601),帮你系统梳理了编译技术最核心的概念、理论和算法。不过在做第一季的过程中呢,我发现很多同学都跟我反馈:我确实理解了编译技术的相关原理、概念、算法等,但是有没有更直接的方式,能让我更加深入地把知识与实践相结合呢?
|
||||
|
||||
## 为什么要解析真实编译器?
|
||||
|
||||
说到把编译技术的知识与实践相结合,无外乎就是解决以下问题:
|
||||
|
||||
- 我已经知道,语法分析有自顶向下的方法和自底向上的方法,但要自己动手实现的话,到底该选择哪个方法呢?是应该自己手写,还是用工具生成呢?
|
||||
- 我已经知道,在语义分析的过程中要做引用消解、类型检查,并且会用到符号表。那具体到自己熟悉的语言,这些工作是如何完成的呢?有什么难点和实现技巧呢?符号表又被设计成什么样子呢?
|
||||
- 我已经知道,编译器中会使用IR,但实际使用中的IR到底是什么样子的呢?使用什么数据结构呢?完成不同的处理任务,是否需要不同的IR呢?
|
||||
- 我已经知道,编译器要做很多优化工作,但针对自己熟悉的语言,这些优化是如何发生的?哪些优化最重要?又要如何写出便于编译器优化的代码呢?
|
||||
|
||||
类似的问题还有很多,但总结起来其实就是:**真实世界的编译器,到底是怎么写出来的?**
|
||||
|
||||
那弄明白了这个问题,到底对我们有什么帮助呢?
|
||||
|
||||
**第一,研究这些语言的编译机制,能直接提高我们的技术水平。**
|
||||
|
||||
一方面,深入了解自己使用的语言的编译器,会有助于你吃透这门语言的核心特性,更好地运用它,从而让自己向着专家级别的工程师进军。举个例子,国内某互联网公司的员工,就曾经向Oracle公司提交了HotSpot的高质量补丁,因为他们在工作中发现了JVM编译器的一些不足。那么,你是不是也有可能把一门语言吃得这么透呢?
|
||||
|
||||
另一方面,IT技术的进化速度是很快的,作为技术人,我们需要迅速跟上技术更迭的速度。而这些现代语言的编译器,往往就是整合了最前沿的技术。比如,Java的JIT编译器和JavaScript的V8编译器,它们都不约而同地采用了“Sea of Nodes”的IR来做优化,这是为什么呢?这种IR有什么优势呢?这些问题我们都需要迅速弄清楚。
|
||||
|
||||
**第二,阅读语言编译器的源码,是高效学习编译原理的重要路径。**
|
||||
|
||||
传统上,我们学习编译原理,总是要先学一大堆的理论和算法,理解起来非常困难,让人望而生畏。
|
||||
|
||||
这个方法本身没有错,因为我们学习任何知识,都要掌握其中的原理。不过,这样可能离实现一款实用的编译器还有相当的距离。
|
||||
|
||||
那么根据我的经验,学习编译原理的一个有效途径,就是阅读真实世界中编译器的源代码,跟踪它的执行过程,弄懂它的运行机制。因为只要你会写程序,就能读懂代码。既然能读懂代码,那为什么不直接去阅读编译器的源代码呢?在开源的时代,源代码就是一个巨大的知识宝库。面对这个宝库,我们为什么不进去尽情搜刮呢?想带走多少就带走多少,没人拦着。
|
||||
|
||||
当然,你可能会犯嘀咕:**编译器的代码一般都比较难吧?以我的水平,能看懂吗?**
|
||||
|
||||
是会有这个问题。当我们面对一大堆代码的时候,很容易迷路,抓不住其中的重点和核心逻辑。不过没关系,有我呢。在本课程中,我会给你带路,并把地图准备好,带你走完这次探险之旅。而当你确实把握了编译器的脉络以后,你对自己的技术自信心会提升一大截。这些计算机语言,就被你摘掉了神秘的面纱。
|
||||
|
||||
俗话说“读万卷书,行万里路”。如果说了解编译原理的基础理论和算法是读书的过程,那么探索真实世界里的编译器是什么样子,就是行路的过程了。根据我的体会,**当你真正了解了身边的语言的编译器是怎样编写的之后,那些抽象的理论就会变得生动和具体,你也就会在编译技术领域里往前跨出一大步了。**
|
||||
|
||||
## 我们可以解析哪些语言的编译器?
|
||||
|
||||
那你可能要问了,在本课程中,**我都选择了哪些语言的编译器呢?选择这些编译器的原因又是什么呢?**
|
||||
|
||||
这次,我要带你解析的编译器还真不少,包括了Java编译器(javac)、Java的JIT编译器(Graal)、Python编译器(CPython)、JavaScript编译器(V8)、Julia语言的编译器、Go语言的编译器(gc),以及MySQL的编译器,并且在讲并行的时候,还涉及了Erlang的编译器。
|
||||
|
||||
我选择剖析这些语言的编译器,有三方面的原因:
|
||||
|
||||
- 第一,它们足够有代表性,是你在平时很可能会用到的。这些语言中,除了Julia比较小众外,都比较流行。而且,虽然Julia没那么有名,但它使用的LLVM工具很重要。因为LLVM为Swift、Rust、C++、C等多种语言提供了优化和后端的支持,所以Julia也不缺乏代表性。
|
||||
- 第二,它们采用了各种不同的编译技术。这些编译器,有的是编译静态类型的语言,有的是动态类型的语言;有的是即时编译(JIT),有的是提前编译(AOT);有高级语言,也有DSL(SQL);解释执行的话,有的是用栈机(Stack Machine),有的是用寄存器机,等等。不同的语言特性,就导致了编译器采用的技术会存在各种差异,从而更加有利于你开阔视野。
|
||||
- 第三,通过研究多种编译器,你可以多次迭代对编译器的认知过程,并通过分析对比,发现这些编译器之间的异同点,探究其中的原因,激发出更多的思考,从而得到更全面的、更深入的认知。
|
||||
|
||||
看到这里,你可能会有所疑虑:**有些语言我没用过,不怎么了解,怎么办?**其实没关系。因为现代的高级语言,其实相似度很高。
|
||||
|
||||
一方面,对于不熟悉的语言,虽然你不能熟练地用它们来做项目,但是写一些基本的、试验性的程序,研究它的实现机制,是没有什么问题的。
|
||||
|
||||
另一方面,学习编译原理的人会练就一项基本功,那就是更容易掌握一门语言的本质。特别是我这一季的课程,就是要帮你成为钻到了铁扇公主肚子里的孙悟空。研究某一种语言的编译器,当然有助于你通过“捷径”去深入地理解它。
|
||||
|
||||
## 我是如何规划课程模块的?
|
||||
|
||||
这门课程的目标,是要让你对现代语言的编译器的结构、所采用的算法以及设计上的权衡,都获得比较真切的认识。其最终结果是,如果要你使用编译技术来完成一个项目,你会心里非常有数,知道应该在什么地方使用什么技术。因为你不仅懂得原理,更有很多实际编译器的设计和实现的思路作为你的决策依据。
|
||||
|
||||
为了达到本课程的目标,我仔细规划了课程的内容,将其划分为预备知识篇、真实编译器解析篇和现代语言设计篇三部分。
|
||||
|
||||
在**预备知识篇**,我会简明扼要地帮你重温一下编译原理的知识体系,让你对这些关键概念的理解变得更清晰。磨刀不误砍柴工,你学完预备知识篇后,再去看各种语言编译器的源代码和相关文档时,至少不会被各种名词、术语搞晕,也能更好地建立具体实现跟原理之间的关联,能互相印证它们。
|
||||
|
||||
在**真实编译器解析篇**,我会带你研究语言编译器的源代码,跟踪它们的运行过程,分析编译过程的每一步是如何实现的,并对有特点的编译技术点加以分析和点评。这样,我们在研究了Java、Java JIT、Python、JavaScript、Julia、Go、MySQL这7个编译器以后,就相当于把编译原理印证了7遍。
|
||||
|
||||
在**现代语言设计篇**,我会带你分析和总结前面已经研究过的编译器,进一步提升你对相关编译技术的认知高度。学完这一模块以后,你对于如何设计编译器的前端、中端、后端、运行时,都会有比较全面的了解,知道如何在不同的技术路线之间做取舍。
|
||||
|
||||
好了,以上就是这一季课程的模块划分思路了。你会发现,这次的课程设计,除了以研究真实编译器为主要手段外,会更加致力于扩大你的知识版图、增加你的见识,达到“行万里路”的目的。
|
||||
|
||||
可以说,我在设计和组织这一季课程时,花了大量的时间准备。因此这一季课程的内容,不说是独一无二的,也差不多了。你在市面上很少能找到解析实际编译器的书籍和资料,这里面的很多内容,都是在我自己阅读源代码、跟踪源代码执行过程的基础上梳理出来的。
|
||||
|
||||
## 写在最后
|
||||
|
||||
近些年,编译技术在全球范围内的进步速度很快。比如,你在学习Graal编译器的时候,你可以先去看看,市面上有多少篇围绕它的高质量论文。所以呢,作为老师,我觉得我有责任引导你去看到、理解并抓住这些技术前沿。
|
||||
|
||||
我也有一个感觉,在未来10年左右,中国在编译技术领域,也会逐步有拿得出手的作品出来,甚至会有我们独特的创新之处,就像我们当前在互联网、5G等领域中做到的一样。
|
||||
|
||||
虽然这个课程不可能涵盖编译技术领域所有的创新点,但我相信,你在其中投入的时间和精力是值得的。你通过我课程中教给你的方法,可以对你所使用的语言产生更加深入的认知,对编译器的内部结构和原理有清晰理解。最重要的是,对于如何采用编译技术来解决实际问题,你也会有能力做出正确的决策。
|
||||
|
||||
这样,这个课程就能起到抛砖引玉的作用,让我们能够成为大胆探索、勇于创新的群体的一份子。未来中国在编译技术的进步,就很可能有来自我们的贡献。我们一起加油!
|
||||
|
||||
**最后,我还想正式认识一下你。**你可以在留言区里做个自我介绍,和我聊聊,你目前学习编译原理的最大难点在哪?或者,你也可以聊聊你对编译原理都有哪些独特的思考和体验,欢迎在留言区和我交流讨论。
|
||||
|
||||
好了,让我们正式开始编译之旅吧!
|
||||
Reference in New Issue
Block a user