st11_day 进程和线程

进程和线程

每一个正在运行的程序都可以看作是一个进程,比如你打开了一个浏览器就是启动了一个浏览器进程,打开了QQ就是启动了一个QQ进程,打开两个QQ就是启动了两个QQ进程。
每个进程至少要干一件事,有的进程还不止干一件事,比如word文档,在你打字的同时,word程序本身还在进行拼写检查,字数统计等事情。在一个进程内部,要同时干很多不同的事情,就需要同时运行多个”子任务”,这些”子任务”称为线程。

multiprocessing

由于Windows上无法调用fork,所以需要引入multiprocessing这个多进程模块,multiprocessing模块提供了一个Process类来表示一个进程对象。

1
2
3
4
5
6
7
8
9
10
11
12
import os
from multiprocessing import Process
def run_proc(name):
print('Run child process %s (%s)...' % (name,os.getpid()))

if __name__ == '__main__':
print('Parent process %s.' % os.getpid())
p = Process(target=run_proc,args=('test',))
print('Child process will start.')
p.start()
p.join()
print('Child process end.')

执行结果

1
2
3
4
5
Parent process 12704.
Child process will start.
Run child process test (3928)...
Child process end.
[Finished in 1.2s]

start()方法用于启动一个子进程,join()方法可以等待子进程结束执行下一步。

Pool

1
Signature: Pool(processes=None, initializer=None, initargs=(), maxtasksperchild=None)

Pool中提供了以下几种方法

1
2
3
4
5
6
7
apply()
apply_async()
map()
map_async()
close()
terminal()
join()

apply

1
2
Signature: pool.apply(func, args=(), kwds={})
Docstring: Equivalent of `func(*args, **kwds)`.

apply函数主要用于传递不定参数,主线程会被阻塞到函数执行结束。也就是说只有执行完了apply里面的内容之后,才会执行主函数的内容。

apply_async

1
2
Signature: pool.apply_async(func, args=(), kwds={}, callback=None, error_callback=None)
Docstring: Asynchronous version of `apply()` method.

apply_async为异步非阻塞的,就是说不用等待当前进程执行完毕,随时根据系统调度来进行进程切换。

subprocess

subprocess模块可以启动一个子进程,然后控制其输入和输出。

进程间通信

进程之间是需要通信的,python的multiprocessing模块封装了很多操作系统底层进程通信机制,提供了Queue
Pipes等多种方式来交换数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from multiprocessing import Process,Queue
import os,time,random

def write(q):
print('Process to write:%s ' % os.getpid())
for value in ['A','B','C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random())


def read(q):
print('Process to read: %s' % os.getpid())
while True:
value = q.get(True)
print('Get %s from queue.' % value)

if __name__ == '__main__':
q = Queue()
#父进程创建Queue,并传给各个子进程
pw = Process(target=write,args=(q,))
pr = Process(target=read,args=(q,))
pw.start()
pr.start()
pw.join()
#pr是死循环,无法使用join()结束,只能强行终止
pr.terminate()

Queue模块主要是保证线程安全使用的。
基本FIFO队列
class Queue.Queue(maxsize=0)
即先进先出,如果参数为0或小于0,代表队列大小没有限制。
在Linux/Unix下,可以使用fork()调用实现多进程,
要实现跨平台的多进程,可以使用multiprocessing模块,
进程间通信是通过queue、pipes实现的。