简单聊聊并发编程

近期在看 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。
Continue Reading…