今天在编程基础中开一个新的系列,程序中的任务调度,也算是对程序执行有更深入的了解.同时也是因为我工作的需要,也是要了解这方面的知识.

进程和线程

首先要讲的是大多数人都很了解的进程和线程,它们都属于系统级别的任务调度.

进程的定义:进程是正在运行的程序的实例,进程是内核分配资源的最基本的单元,而线程是内核执行的最基本的单元,进程内可以包含多个线程,只要记住这三个要点,就可以很清楚的理清进程和线程的行为模式.

程序在运行的时候,是需要操作系统分配内存和其他硬件资源,所以将运行的程序抽象为进程,一开始操作系统只能执行单一进程,后来使用分时间片来运行多个进程产生了多任务系统.

而线程的出现,是由于进程开销比较大,还有就是进程之间的资源隔离,导致数据沟通复杂.所以产生了线程.

进程和进程之间是的资源都是相互隔离的,所以一个进程的崩溃不会影响到其他进程,但是由于线程是包含在进程之内的,现成的崩溃就会引发进程的崩溃,而在同一进程内的线程也会继而崩溃.

并发和并行

在这里在多讲一些,并发和并行是得从物理硬件方面来考虑.在以前电脑是单核的时候,一个cup核心只能进行单个任务,将单个cup运行时间分配给多个任务运行,这就是并发,让你看起来像是多个任务同时执行,本质上还是一个任务一个任务的执行.

而并行,是在多核cup电脑上,为每一个cup核心分配一个任务,是真正的多任务执行.

同步,异步,协程,回调

本来不想一次性说那么多,但是同步,异步,协程,回调,但是这四个师出同门,放到一起讲会比较好.

同步

同步呢.就是程序一个语句一个语句顺序执行,很符合人得思维,是线性执行.

异步

异步的特性就是执行起来不会阻塞,说到异步就不能不说到javascript.

结合javascript来说明异步会更好一些.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var pf = function (num) {
console.log('print: ',num);
};
pf(1111);
setTimeout(function () {
pf(2222);
}, 2000);
pf(3333);
// -----结果-----
// print: 1111
// print: 3333
// print: 2222

按照同步编程来理解的话,本应该结果是:

1
2
3
4
// -----结果-----
// print: 1111
// print: 2222
// print: 3333

异步编程的特点就出来了:非阻塞,原理的话很多,后面还会另开一篇细讲.

协程

协程的话相当于语言自己实现一个函数调度,在一个函数运行时,中断函数,并且保存函数上下文,之后在运行其他函数,之后再返回运行原函数.

这是一个用协程实现的一个典型的生产者-消费者模型.

python 2.x generator 不能使用return,所以使用了raise Exception,python 3.x可以直接使用return.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# -*- coding:utf-8 -*-
def consumer():
n = 0
print "consumer init"
while True:
n = yield n
if not n:
raise Exception('no production')
n -= 1
print "consuption 1,left %d" % n
def produce(c):
n = 0
next(c)
while n < 6:
n +=2
print "produce 2,left %d" % n
n = c.send(n)
print "left %d" % n
c.close()
c = consumer()
produce(c)

每次生产一次,中断生产函数,运行消费者函数,之后再生产,如此下去.

回调

回调是在等待某一件事情完成之后,在运行一个回调函数.

1
2
3
4
function (dothings, callback) {
after dothings;
callback;
}

回调算是弥补异步函数的缺点.

比如说:

1
2
3
4
5
6
7
8
9
var data = [];
setTimeout(function (){
data.push(1);
},2000);
console.log(data[0]);
// 结果
// undefined

因为data还没push,由于异步的关系就提前使用了data导致,输入为undefined.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var data = [];
var cb = function(){
console.log(data[0]);
};
var pushData = function(callback){
data.push(1);
callback();
};
setTimeout(function () {
pushData(cb);
},2000);

这时候才会输出成功.

由于同步编程都是等待前面运行完才会接着运行下去,所以不用担心依赖的变量不存在,或者是其他.

由于异步编程非阻塞特点,所以有变量依赖的时候都得写到回调函数里面去,回调算是异步函数中为了同步执行而加入的特性.

总结

写到这里算是把所有的概念都简单介绍了一遍,对这写概念都做了一下简单的介绍,后面的博客我会对这里概念做详细的深究,探寻内部原理.

之后会写javascriptevent loop事件机制.