简单聊聊并发编程

近期在看 Golang 相关的资料,虽然这门语言的类型后置让我这个 C 出身的人感到很难受,但是 Go 的种种特性确实让我眼前一亮。其中特别是并发,在云计算大数据如火如荼,分布式计算热火朝天的今天,这个特性让 Go 语言一下成为了明星语言。并发编程是面向对象编程中一种最合适的程序控制方式,因为在现实世界中,各个对象的各种操作都是并发的,其间通过消息传递来进行数据同步。

所以我们今天就来简单聊聊并发编程。

我们先了解一些并发编程中的概念:

1.延续性

并发编程中最关键的一个概念就是延续性(Continuation),这是一种对程序控制流程/状态的抽象表现形式。 延续性以数据结构的形式表现了程序在运行过程中某一点的计算状态,相应的数据内容能被编程语言访问并且不会被运行时环境所隐藏掉。
延续性包含了当前程序的栈以及当前运行的位置。一个延续的实例可以在将来被用作控制流,被调用时它从所表达的状态开始恢复执行。

延续性,其实就是一种函数调用机制。我们最常见的函数调用方法是使用堆栈,采用 Activation record 或者叫 Stack frame 来记录从最顶层函数到当前函数的所有 context 。一个 frame/record 就是一个函数的局部上下文信息,包括所有的局部变量的值和SP,PC指针的值。函数的调用前往往通过 push 来保存 context 信息,函数结束调用退出时则是取消当前的 record/frame,并恢复到上一个调用者的 record/frame 。这是一种后入先出的方式,上层函数需要获得下层函数返回的数据才能完成,因此你需要从顶层函数一层一层的往下调用,一直到最底层函数完成后,再逐层 return 依次完成。C/BASIC/PASCAL以及我们熟知的大部分语言就是采用这种方式。

而延续调用,不采用堆栈来保存上下文,而是把这些信息保存在 continuation record 中。这些 continuation record 和堆栈的 activation record 的不同,并不采用后入先出的堆栈存储方式,而是以节点的形式存放在树或者图中,从一个函数调用另一个函数就等于给当前节点生成一个子节点并系统寄存器移动到这个子节点上。
这样的好处是什么,就是我们不需要按照线性的顺序来完成函数,我们完全可以自由的在不同的节点间进行跳转,不需要像堆栈一样一层一层的 return。这里的 return 更像是一个带参数的 goto。

2.协程/通道

协程的概念可能大部分人都不是很清楚。协程是一种程序组件,是由子例程(过程、函数、例程、方法、子程序)的概念泛化而来的。其中最大的区别在于子例程只有一个入口点且只返回一次,而协程允许多个入口点,可以在指定位置挂起和恢复执行。调用一个协程的时候,不需要等待其执行完,函数便会立即返回。这个特点十分适合用在并发编程中。在普通平台下创建多个协程不会对性能造成多大的影响,因为不需要像多个线程运行一样会频繁的在程序上下文中切换。

而如果只有协程,只能说这是个不错的设计,但是加上通道以后我不得不感慨这设计堪称完美。

通道是协程之间的数据传输通道,用来在众多的协程之间传递数据,数据本身可以值也可以是个引用。协程和通道是如何一起工作的?以最简单的读写操作为例:

1)协程试图向通道放入数据,如果通道满了,会挂起协程,直到通道可以为他放入数据为止。
2)协程试图向通道索取数据,如果通道没有数据,会挂起协程,直到通道返回数据为止。

这是一种很完美的实现。你可以创建多个读协程和多个写协程,各个协程间不进行直接的信息传递而是对共同的通道进行操作,各自直接不会相互影响。而且由于协程的特性,随时可以挂起然后在任意时刻在原先挂起的位置继续。

//稍后会用专门的文章补充相关的知识和图示,以及介绍在 Python/Golang 中的一些实现。

Python 中并发编程的实现

说到 Python,我们肯定都不陌生,这是一种面向对象的解释型编程语言,吉多·范罗苏姆在1989年的圣诞期间,决心开发一种新的简单易学的脚本语言来打发在阿姆斯特丹的时间。于是在参考 C 和其他多门语言后,Python 诞生了。
Python 作为一种语言规范,有着多种不同的实现。我们平时接触到的多是 CPython,这是 Python 软件基金会的实现版本,解释器用 C 语言开发,是 Python 的官方解释器。
CPython 解释器是 C 语言实现,所以不可避免的使用了和 C 语言一致的在堆栈上保存状态。 Python 的另一种实现 — Stackless Python,则是一种不在 C 堆栈上保存状态的 Python 实现。

Stackless Python 提供了一种基于线程的编程方式,并尽量避免传统线程所带来的性能与复杂度的问题。

“ Stackless Python 是一种不在 C 堆栈上保存状态的 Python 实现。它的确有堆栈 — 要多少有多少 — 但这些是 Python 堆栈。 C 堆栈不能从例如 C 这样的语言以干净的方式进行修改,除非以预期的顺序进行。它对您施加了很大限制:您必须回到这里,与您离开的方向正好相反。“普通的”程序员一开始不会认为这是个限制。他们必须从开始就要学会将想法转向堆栈。堆栈没有什么坏处,并且通常它们施加的执行顺序就是实际上的顺序,但这并不意味着我们必须等待一个这样的堆栈序列完成才能运行另一序列。 程序员在必须执行非阻塞调用和回调时意识到这一点。堆栈突然挡住去路,我们必须使用线程,或将状态明确存储在对象中,或者构建显式的可切换堆栈等等。Stackless 的目的是帮助程序员避免这些问题。 ” — Christian Tismer,Stackless Python 作者

参考资料
可爱的 Python:Python实现内幕

如无注明,均为原创。转载请注明: 转载自MITGAI`S THINKING
本文链接地址: 简单聊聊并发编程

知识共享许可协议本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

如果本文对您生活或工作产生了积极影响,那我非常高兴。
如果您愿意为文章的内容或想法提供支持,欢迎点击下边的捐赠按钮,资助作者创作更多高价值高品质的内容。
支付宝捐赠
anyShare分享到:

发表回复