写给程序员的编程语言科普——前言

就在前两个月,王垠的博客网站关闭了一段时间,并在重新开启时删除了所有旧文章,理由可以从他新发的版权声明中见到。对于王垠对待某些网站、某些网民以及他自己过往文章的态度,我不置可否。但至少一点让我感到惋惜的是我失去了一个非常好的学习机会。所幸他的多数博文我在网站关闭前都大致看过一遍,虽说被有一一细细品读也算是一种安慰了吧。

我写这篇文章以及接下来的一系列文章的目的是希望向国内广大程序员们进行一些编程语言相关的“科普”。说是科普是因为我意识到,对于绝大多数国内的程序员来说,他们对于编程语言的认识,随着项目经验的增加而增长得非常有限。很多经历过许多大项目、自称精通许多编程语言的程序员们其实对他们手边天天使用的语言并没有一个甚至基本的了解。他们依赖所谓的“编程范式”、信奉经验主义、用夜以继日的加班、过劳来试图修复他们代码中的众多问题,却没有思考过造成这些问题的基本问题,造成问题的问题,就如同描述数据的数据——元数据一样,这些“元问题”很多时候都能本质上地改变程序员的工作强度与工作方式。一旦解决了“元问题”,很多现有的问题将不复存在。

“科普”的另一层含义是在接下来的文章里我只管介绍,而不会指导你去如何学习,因此你大可抱着看热闹的心情去看我接下来的文章,但如果你想要系统地学习它,Sorry,我没有这个能力,你可以阅读相关的书籍,我的文章可能可以帮助你理解这些问题,但真的要深入了解、掌握编程语言的本质的话,还是需要你自己的努力。


要了解编程语言的本质,最直接的办法,就是去了解编程语言的解释器的运行机制。很多人会问,我知道PHP、Python是解释性语言,可以用解释器去运行它们的代码,但如果是C、C++、Objective-C这样的编译性语言呢?你的科普是不是就不通用了?

关于这一点,首先我想先阐明一个事实,没有一门编程语言可以被称为“解释性语言”或者“编译性语言”,编程语言仅仅是程序员和机器之间进行交流的一种规范的、有条理的、形式化的媒介。就好比自然语言是用于人与人之间交流的媒介一样。所谓的PHP、Python是解释性语言、C、C++是编译性语言,只不过是因为它们最主流的实现方式分别是边解释边执行(解释性,其实这一说法并不严密)、以及先编译后执行(编译性)。你大可以写出一个PHP的编译器或者C语言的解释器(其实这两种实现都存在),只不过它们不是最主流的实现方式而已。

其次,不管是用gcc、clang去编译C语言,还是用Zend引擎去解释PHP,它们在前期的工作都是类似的,都需要逐字逐句地解析程序员写的代码,并将其转换为一种内部的数据结构。所不同的是,在解析完代码之后,编译器会将这一种内部数据结构再次转换成新的一种代码,比如gcc的编译器将C代码转换为汇编代码,因此,编译的过程本质上就是一种转换的过程;而解释器则根据不同的数据结构来指挥机器做不同的工作,直到解释结束。

在实际的实现中,基于效率问题,多数语言的解释器都并不直接解释执行代码(包括PHP和Python),而是先将它们转换为一种便于机器理解、执行的中间代码,这本质上也是一种编译,再去执行。其此,实际上主流的编程语言实现中并不存在纯粹的“解释器”,只有先编译,稍后执行的解释器(也就是我们常说的编译器);以前先编译、之后立即执行的解释器。


其实,学习解释器的构造对一个程序员的成长来说是很有好处的,除了之前说的,你可以通过学习解释器来认识编程语言的本质之外,你还可以对你自己现在的或者将来的项目有着更好的掌控。这是因为随着现代软件的复杂性不断提高,很多程序与解释器已经越来越接近了,用户与程序交互的过程,就如同代码与解释器交互的过程;程序里的业务逻辑需要一系列例如生命周期、迭代、状态记录、中断流程与恢复之类的行为的实现,在解释器内部也有着相应的体现。有时候,你的工程虽然本身并不是一个解释器,却已经在无意识间实现了解释器的某些功能。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间。那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 1、假设现在是 2008-4-7 12:00:00.000,如果我调用一下 Thread.Sleep(1000) ,在 2008-4-7 12:00:01.000 的时候,这个线程会 不会被唤醒? 2、某人的代码中用了一句看似莫明其妙的话:Thread.Sleep(0) 。既然是 Sleep 0 毫秒,那么他跟去掉这句代码相比,有啥区别么? 我们先回顾一下操作系统原理。操作系统中,CPU竞争有很多种策略。Unix系统使用的是时间片算法,而Windows则属于抢占式的。 在时间片算法中,所有的进程排成一个队列。操作系统按照他们的顺序,给每个进程分配一段时间,即该进程 允许运行的时间。如果在 时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。调度程 序所要做的就是维护一张就绪进程列表,,当进程用完它的时间片后,它被移到队列的末尾。 所谓抢占式操作系统,就是说如果一个进程得到了 CPU 时间,除非它自己放弃使用 CPU ,否则将完全霸占 CPU 。因此可以看出,在抢 占式操作系统中,操作系统假设所有的进程都是“人品很好”的,会主动退出 CPU 。 在抢占式操作系统中,假设有若干进程,操作系统会根据他们的优先级、饥饿时间(已经多长时间没有使用过 CPU 了),给他们算出一 个总的优先级来。操作系统就会把 CPU 交给总优先级最高的这个进程。当进程执行完毕或者自己主动挂起后,操作系统就会重新计算一 次所有进程的总优先级,然后再挑一个优先级最高的把 CPU 控制权交给他。 我们用分蛋糕的场景来描述这两种算法。假设有源源不断的蛋糕(源源不断的时间),一副刀叉(一个CPU),10个等待吃蛋糕的人(10 个进程)。 如果是 Unix 操作系统来负责分蛋糕,那么他会这样定规矩:每个人上来吃 1 分钟,时间到了换下一个。最后一个人吃完了就再从头开始。于是,不管这10个人是不是优先级不同、饥饿程度不同、饭量不同,每个人上来的时候都可以吃 1 分钟。当然,如果有人本来不太饿,或者饭量小,吃了30秒钟之后就吃饱了,那么他可以跟操作系统说:我已经吃饱了(挂起)。于是操作系统就会让下一个人接 着来。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值