Contents

3.2 多进程编程

3.1 并发编程基础

并发这个概念由来已久,其主要思想是使多个任务可以在同一时间段内执行以便更快得到结果。

3.1.2 并发程序与并行程序

并发程序是指可以被同时发起执行的程序,而并行程序则被设计成可以在并行的硬件上执行的并发程序。也就是说,并发程序代表了所有可以实现并发行为的程序,它是一个比较宽泛的概念,其中包括了并行程序。

3.1.3 并发程序与并发系统

首先,并发程序属于程序,即使它被划分为多个部分,只要这些部分之间是紧密关联在一起的,并且可以看作一个整体,那么它就属于一个程序,也可以称为一个内聚的软件单元。另一方面,程序与程序之间可以通过协商一致的协议通信,并且它们之间是松耦合的。它们可以看作一个系统,而不是程序。并发程序和并发系统中的并发是同一个含义。但是,并发系统更有可能是并行的,因为其中的多个程序一般可以同时在不同的硬件环境上运行。因此,并发系统也常常称为并行系统。

3.1.4 并发程序的不确定性

串行程序中所有代码的先后顺序都是固定的,而并发程序中只有代码部分是有序的。 也就是说,其中一些代码的执行顺序并没有明确指定。这一特性叫做不确定性,这导致并发程序每次执行的代码执行路径都是不同的。即便是在输入数据相同的前提下,也是如此。

3.1.5 并发程序内部的交互

根据同步的原则,程序如果想使用一个资源,就必须先请求该资源并获取到对它的访问权。当程序不再需要某个资源的时候,应该放弃对它的访问权(也就是释放资源)。一个程序对资源的请求不应该导致其他正在访问该资源的程序中断,而应该等到那个程序释放该资源之后再进行请求(锁机制的概念)。也就是说,在同一时刻,某个资源应该只被一个程序占用。

传递数据是并发程序内部的另一种交互方式,也称为并发程序内部的通信。实际上协调这种内部通信的方式还有异步。利用异步的方式对通信进行管理,使数据可以不加延迟的发送给接收方,即使接收方还没准备好接收数据,也不会造成发送方的等待。数据被临时存到一个通信缓存的数据结构中。通信缓存是一个特殊的资源,可以同时被多个程序使用。

3.2 多进程编程

进程间的通信被称作IPC,在linux系统中使用的IPC方法有很多种。从处理机制的角度看,可以分作三大类:基于通信的IPC方法基于信号的IPC方法基于同步的IPC方法

其中,基于通信的IPC方法又分为 以数据传送为手段 的IPC方法和 以共享内存为手段 的IPC方法,前者包括了管道(pipe)和消息队列(message queue)。管道可以用来传送字节流, 消息队列可以用来传送结构化的消息对象。

以共享内存为手段的IPC方法主要以 共享内存区(shared memory) 为代表,这是最快的一种方法。

基于信号的IPC方法就是我们常说的操作系统的信号机制(signal),这是唯一一种异步IPC方法。在基于同步的IPC方法中,最重要的就是信号量(semaphore)。

go支持的IPC方法有管道,信号和socket。

3.2.1 进程

1.进程的定义

进程是unix系统的根本,因为所有的代码都是在进程中执行的。通常,我们把一个程序的执行称为一个进程。也就是说,进程用于描述程序的执行过程。因此,程序和进程是一对概念,它们分别描述了一个程序的静态形式和动态特征。除此之外,进程还是操作系统进行资源分配的一个基本单位。

2.进程的衍生

进程使用fork(一个系统调用函数)可以创建若干个新的进程(子进程),前者称为后者的父进程,后者称为前者的子进程。每个子进程都源自它的父进程的一个副本,它会获得父进程的数据段,堆,栈的副本,与父进程共享代码段。每一个副本都是独立的,子进程对属于它的副本的修改对其父进程和兄弟进程都是不可见的,反之亦然。全盘复制是一种很低效的做法,linux内核使用**写时复制(Copy of Write)**等技术来提高创建的效率。刚创建的子进程也可以通过系统调用exec把一个新的程序加载到自己的内存中,而原先在其内存中的数据段、堆、栈以及代码段就会被替换掉。在这之后,子进程执行的就会是那个刚刚加载进来的新程序。