python进程

概念

        进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。显然,程序是死的(静态的),进程是活的(动态的)。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程,它们就是处于运行状态下的操作系统本身;用户进程就不必我多讲了吧,所有由你启动的进程都是用户进程。进程是操作系统进行资源分配的单位。

        它的思想简单介绍如下:在操作系统的管理下,所有正在运行的进程轮流使用CPU,每个进程允许占用CPU的时间非常短(比如10毫秒),这样用户根本感觉不出来CPU是在轮流为多个进程服务,就好象所有的进程都在不间断地运行一样。但实际上在任何一个时间内有且仅有一个进程占有CPU。

多进程和线程的区别:

  • 多线程使用的是cpu的一个核,适合io密集型
  • 多进程使用的是cpu的多个核,适合运算密集型

组件

        Python提供了非常好用的多进程包,multiprocessing,我们在使用的时候,只需要导入该模块就可以了。

        Multiprocessing支持子进程,通信,共享数据,执行不同形式的同步,提供了Process,Pipe, Lock等组件

多进程

  1. 创建一个Process对象
1
p = multiprocessing.Process(target=worker_1, args=(2, ))
  • target = 函数名字
  • args = 函数需要的参数,以tuple的形式传入

        注意:单个元素的tuple的表现形式

        multprocessing用到的两个方法

  • cpu_count():统计cpu总数
  • active_children() :获得所有子进程
  1. Process的常用方法
  • is_alive(): 判断进程是否存活
  • run() : 启动进程
  • start() : 启动进程,会自动调用run方法,这个常用
  • join(timeout) :等待进程结束或者直到超时
  1. Process的常用属性
  • name : 进程名字
  • pid: 进程的pid

        代码例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import multiprocessing
import time
def work(interval, method):
print("start work_" + method)
time.sleep(interval)
print("end work_" + method)
if __name__ == "__main__":
p1 = multiprocessing.Process(target=work, args=(1, "1"))
p2 = multiprocessing.Process(target=work, args=(2, "2"))
p3 = multiprocessing.Process(target=work, args=(3, "3"))
p1.start()
p2.start()
p3.start()
print("The number of CPU is:") + str(multiprocessing.cpu_count())
for p in multiprocessing.active_children():
print("The name of active child is: " + p.name + ", pid is: " + str(p.pid) + "is alive: " + str(p.is_alive()))
print("MAIN IS END!")

        结果:

1
2
3
4
5
6
7
8
9
10
11
12
C:\Python27\python.exe E:/python/12process/demon1.py
The number of CPU is:4
The name of active child is: Process-3, pid is9788is alive: True
The name of active child is: Process-1, pid is6936is alive: True
The name of active child is: Process-2, pid is3052is alive: True
MAIN IS END!
start work_2
start work_1
start work_3
end work_1
end work_2
end work_3

多进程锁

        Lock组件

        当我们用多进程来读写文件的时候,如果一个进程是写文件,一个进程是读文件,如果两个文件同时进行,肯定是不行的,必须是文件写结束以后,才可以进行读操作。或者是多个进程在共享一些资源的时候,同时只能有一个进程进行访问,那就要有一个锁机制进行控制。

        需求:

        一个进程写入一个文件,一个进程追加文件,一个进程读文件,同时启动起来

        我们可以通过进程的join()方法来实现,但是为了学习Lock,用Lock来实现。

        先看不加锁程序,在看加锁程序,最后比较两个程序的区别

        代码例子:

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
28
29
30
31
32
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import multiprocessing
import time
def add1(lock, value, number):
with lock:
print("start add1 number = {0}".format(number))
for i in xrange(1, 5):
number += value
time.sleep(0.3)
print("number = {0}".format(number))
def add3(lock, value, number):
lock.acquire()
print("start add3 number = {0}".format(number))
try:
for i in xrange(1, 5):
number += value
time.sleep(0.3)
print("number = {0}".format(number))
finally:
lock.release()
if __name__ == "__main__":
lock = multiprocessing.Lock()
number = 0
pw = multiprocessing.Process(target=add1, args=(lock, 1, number))
pa = multiprocessing.Process(target=add3, args=(lock, 3, number))
pw.start()
pa.start()
print("main process end.")

        结果:

1
2
3
4
5
6
7
8
9
10
11
main process end.
start add1 number = 0
number = 1
number = 2
number = 3
number = 4
start add3 number = 0
number = 3
number = 6
number = 9
number = 12

多进程共享内存

        python的multiprocessing模块也给我们提供了共享内存的操作

        一般的变量在进程之间是没法进行通讯的,multiprocessing给我们提供了Value和Array模块,他们可以在不通的进程中共同使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from multiprocessing import Process, Value, Array
def f(n, a,m):
n.value = 3.1415927
m = 20
for i in range(len(a)):
a[i] = -a[i]
print(m)
if __name__ == '__main__':
num = Value('d', 0.0)
arr = Array('i', range(10))
m = 10
p = Process(target=f, args=(num, arr, m))
p.start()
p.join()
print(num.value)
print(arr[:])
print(m)

        结果:

1
2
3
4
20
3.1415927
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
10

多进程Manager

        以上实现的数据共享的方式只有两种结构Value和Array。Python中提供了强大的Manage专门用来做数据共享的,其支持的类型非常多,包括,Value, Array,list,dict, Queue, Lock等。

        下面看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
# -*- coding:utf-8 -*-
rom multiprocessing import Process, Manager
def func(dt, lt):
for i in range(10):
key = 'arg' + str(i)
dt[key] = i * i
lt += range(11, 16)
if __name__ == "__main__":
manager = Manager()
dt = manager.dict()
lt = manager.list()
p = Process(target=func, args=(dt, lt))
p.start()
p.join()
print(dt)
print(lt)

进程池

        Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程。

        下面我们先来看一个进程池非阻塞的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import multiprocessing
import time
def fun(msg):
print("######start###### {0}".format(msg))
time.sleep(3)
print("######end###### {0}".format(msg))
if __name__ == "__main__":
pool = multiprocessing.Pool(processes=3)
for i in xrange(1, 6):
msg = "hello {0}".format(i)
pool.apply_async(fun, (msg,))
print("##########start main#########")
pool.close()
pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
print("##########end main#########")
`

        阻塞和非阻塞的区别:

  • Pool.apply_async:非阻塞,定义的进程池进程最大数可以同时执行。
  • Pool.apply:一个进程结束,释放回进程池,下一个进程才可以开始