Python 多进程multiprocess
阅读 (184) |
发布于 2020-05-19 14:47:26
Python中的multiprocess提供了Process类,实现进程相关的功能。但是它基于fork机制,因此不被windows平台支持。
在multiprocess模块中有 process 和 Process 两个类,大家使用过程中一点要注意区别二者。
multiprocess.Process 类用法:
通过以下示例,可以发现多进程语法上和多线程几乎是一样的。#!/usr/bin/env python
#coding=utf-8
import os
import multiprocessing
def foo(i):
# 当前进程名
print("Current pname:", multiprocessing.current_process().name)
#当前进程的父进程id
print("parents pid:", os.getppid())
#当前进程id
print("Current pid:", os.getpid())
if __name__ == '__main__':
for i in range(3):
p = multiprocessing.Process(target=foo, args=(i,))
p.start()
进程间共享数据
在linux中, 每个进程都是由父进程的。最大的用户进程为1号进程。子进程的数据都是由父进程提供的,每启动一个子进程就从父进程克隆一份数据。
进程的创建需要很大的开销,每个进程都有独立的内存空间。进程之间通常是不能直接共享数据。
进程如果需要数据共享,就要通过中间件来实现。
下面的代码试图用全局列表来实现 进程的数据共享:#!/usr/bin/env python
#coding=utf-8
import multiprocessing
import os
lis = []
def foo(i):
lis.append(i)
print("Pid: %d addr: %s, lis: %s" % (os.getpid(), id(lis), lis))
if __name__ == '__main__':
for i in range(3):
p = multiprocessing.Process(target=foo, args=(i,))
p.start()
print("The End. Pid:%s, addr: %s lis:%s"%(os.getpid(), id(lis), lis))
得到如下结果, 每个进程的lis都是独立的,全局列表并没有改变。Pid: 8974 addr: 20094344, lis: [0]
Pid: 8975 addr: 20094344, lis: [1]
The End. Pid:8973, addr: 20094344 lis:[]
Pid: 8976 addr: 20094344, lis: [2]
multiprocess模块提供了三个类来实现进程之间的数据共享Queues
Array
Manager
Queues类
Queues类的导入方式是 from multiprocessing.queues import Queue。它在multiprocessing包的queues模块中。#!/usr/bin/env python
#coding=utf-8
import os
import multiprocessing
from multiprocessing.queues import Queue
from multiprocessing import Process
def func(i, q):
print("Pid: %s get: %s then put:%s" % (os.getpid(),q.get(), i))
q.put(i)
if __name__ == "__main__":
lis = Queue(1, ctx=multiprocessing)
lis.put(10)
for i in range(5):
p = Process(target=func, args=(i, lis))
p.start()
multiprocessing自己还有一个Queue类,一样能实现queues.Queue的功能,导入方式是from multiprocessing import Queue。
Array类
Array数组类,语法:
arr = Array('i', 5)
'i' 表示内部元素为int类型 ,5表示数组的长度。更多类型 :'c': ctypes.c_char, 'u': ctypes.c_wchar,
'b': ctypes.c_byte, 'B': ctypes.c_ubyte,
'h': ctypes.c_short, 'H': ctypes.c_ushort,
'i': ctypes.c_int, 'I': ctypes.c_uint,
'l': ctypes.c_long, 'L': ctypes.c_ulong,
'f': ctypes.c_float, 'd': ctypes.c_double
示例:#!/usr/bin/env python
import os
from multiprocessing import Process
from multiprocessing import Array
def func(i,temp):
temp[0] += 100
print("Pid:",os.getpid(),"array:", temp[0])
if __name__ == '__main__':
temp = Array('i', [1, 2, 3, 4])
for i in range(5):
p = Process(target=func, args=(i, temp))
p.start()
Manager类
Manager实例化返回一个服务进程,其他进程可以通过代理的方式操作Manager对象。
Manager 支持list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value ,Array等多种格式。#!/usr/bin/env python
import os
import time
import threading
from multiprocessing import Process
from multiprocessing import Manager
def func(i, dic):
dic["num" + str(i)] = 100+i
print("Pid:", os.getpid(), dic.items())
time.sleep(3)
if __name__ == '__main__':
dic = Manager().dict()
process_lis = []
for i in range(5):
p = Process(target=func, args=(i, dic))
p.start()
process_lis.append(p)
for p in process_lis:
p.join()
注意: 这里在启动子进程时用了join(), 这是必须的。这个join和线程的作用是一样的。是要父进程等所有子进程结束后再结束。
如果没有join()父进程执行完释放了内存。dic也就不存在。其他用到dic的子进程就会报错。
进程锁
与线程锁一样,进程中也有同名的锁,并且用法和作用都是一样的。
在multiprocessing 有锁类: RLock可重入锁, Lock互斥锁,Event事件锁, Condition条件锁,Semaphore信号锁。
这里不多做解释了, 用一个简单的例子来看一下进程锁的使用。#!/usr/bin/env python
import os
import time
from multiprocessing import Array
from multiprocessing import Process
from multiprocessing import RLock, Lock, Event, Condition, Semaphore
def func(i,lis,lc):
lc.acquire()
if i%2 ==0:
lis[0] = lis[0] - 1
else:
lis[0] = lis[0] + 1
lc.release()
if __name__ == "__main__":
array = Array('i', 1)
array[0] = 10
lock = RLock()
process_lis = []
for i in range(1000):
p = Process(target=func, args=(i, array, lock))
p.start()
process_lis.append(p)
for i in process_lis:
p.join()
print(array[0])
以上例子中,枷锁后结果为10, 不加锁 结果不定。
Pool类(进程池类)
创建进程开销较大,频繁的创建销毁进程会消耗大量的内存空间。同线程一样,进程也可以使用进程池来控制开销。
python 给我们内置了一个进程池,导入:from multiprocessing import Pool
Pool类里面的常用方法:apply() 同步执行 (串行)
apply_async() 异步执行 (并行)
terminate() 立刻关闭进程池(强制)
join() 主进程等待进程池内所有进程执行完毕。 (必须在close或terminate之后使用)
close() 等待所有进程池结束后,关闭进程池。
以下示例是异步执行的方式,并行线程数5#!/usr/bin/env python
from multiprocessing import Pool
import time
def func(args):
time.sleep(1)
print("running", args)
if __name__ == '__main__':
p = Pool(5)
for i in range(30):
p.apply_async(func=func, args=(i,))
p.close()
# p.terminate()
p.join()
print("end")