Python 进程
因为GIL的限制,一个进程中只能有一个线程获取到资源,因此在有些场景下会显得很鸡肋。一种解决方法就是利用多进程,通过开多个进程就可以绕开GIL的限制。
多进程
python提供了一个包,multiprocess ,使用方法跟多线程的一样
from multiprocessing import Process
plist = []
def addProcess(i):
plist.append(i)
print 'process %d ----'%i
print plist
for i in range(5):
p = Process(target=addProcess,args=(i,))
p.start()
结果
process 0 ----
[0]
process 1 ----
[1]
process 2 ----
[2]
process 3 ----
[3]
process 4 ----
[4]
从结果上面我们能看出来,每个进程都有自己独立的一片数据空间,不会受到其它进程的影响。
多进程的数据共享
虽然多进程能够开辟多个数据空间,但是这些数据空间的数据确实独立的,无法进行共享。因此很多场景下并不能符合我们的要求。好在我们可以通过别的方式进行资源的共享,例如Queue,Array和Manager这三个类来实现功能
Array
from multiprocessing import Process
from multiprocessing import Array
plist = Array('i',10)
def addProcess(i):
plist[0] += 200
print 'process %d ----'%i
print [item for item in plist]
for i in range(5):
p = Process(target=addProcess,args=(i,))
p.start()
process 0 ----
[200, 0, 0, 0, 0, 0, 0, 0, 0, 0]
process 1 ----
[400, 0, 0, 0, 0, 0, 0, 0, 0, 0]
process 2 ----
[600, 0, 0, 0, 0, 0, 0, 0, 0, 0]
process 3 ----
[800, 0, 0, 0, 0, 0, 0, 0, 0, 0]
process 4 ----
[1000, 0, 0, 0, 0, 0, 0, 0, 0, 0]
这里我们使用的是multiprocess提供的Array,Array初始化的时候至少传入两个参数,第一个参数为元素类型,这个指的是内部全部元素的类型,第二个参数为初始值或者长度
源码
def Array(typecode_or_type, size_or_initializer, **kwds):
'''
Returns a synchronized shared array
'''
from multiprocessing.sharedctypes import Array
return Array(typecode_or_type, size_or_initializer, **kwds)
元素类型对应表
‘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
Queue
这里的队列就跟多线程中的队列用法是一样的,但是如果不加锁的话,也是会出现一些脏数据的情况
Manager
源码
def Manager():
'''
Returns a manager associated with a running server process
The managers methods such as `Lock()`, `Condition()` and `Queue()`
can be used to create shared objects.
'''
from multiprocessing.managers import SyncManager
m = SyncManager()
m.start()
return m
实例
http://www.jb51.net/article/57663.htm
进程锁
multiprocess中实现了跟多线程中一样的锁,如Lock,Rlock,SEMAPHORE,EVENT,CONDITION http://www.iotxing.com/2018/05/13/159/python-thread/
进程池
既然有线程池,那必然也有进程池。但是,python给我们内置了一个进程池,不需要像线程池那样需要自定义,你只需要简单的from multiprocessing import Pool。
# -*- coding:utf-8 -*-
from multiprocessing import Pool
import time
def f1(args):
time.sleep(1)
print(args)
if __name__ == '__main__':
p = Pool(5)
for i in range(30):
p.apply_async(func=f1, args= (i,))
p.close() # 等子进程执行完毕后关闭进程池
# time.sleep(2)
# p.terminate() # 立刻关闭进程池
p.join()
进程池内部维护一个进程序列,当使用时,去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有以下几个主要方法:
apply:从进程池里取一个进程并执行
apply_async:apply的异步版本
terminate:立刻关闭进程池
join:主进程等待所有子进程执行完毕。必须在close或terminate之后。
close:等待所有进程结束后,才关闭进程池。