多进程编程--模块multiprocessing
import multiprocessing #引入多进程编程模块
进程的生命周期:
1、创建进程---multiprocessing.Process()#参数 group=None【windows中可忽略,linux、unix中使用用户分组】,target=None【进程要做的事情,通常为函数名】,name=None【进程名称,可自定义】,args=()【数组参数】,kwargs={}【字典参数】
2、启动进程--start()
3、判断进程状态--is_alive()
4、主进程等待--join()
5、进程的返回值--exitcode()
6、结束进程 --terminate()#不推荐使用
多进程编程例1:
import multiprocessing
def func(msg):
time.sleep(2)
return msg
if __name__ == '__main__':
p1= multiprocessing.Process(target=func,name='he',args=('hello,word',))#创建进程
print(p1.is_alive())#判断进程的存活状态
p1.start() #启动进程
print(p1.is_alive())
p1.join() #主进程等待
print(p1.exitcode) #获取进程的返回值
print(p1._name)
多进程编程例2:
import multiprocessing
import urllib2
def func1(url):
response = urllib2.urlopen(url)
html = response.read()
print(html[1:20],'------func1')
time.sleep(2)
def func2(url):
response = urllib2.urlopen(url)
html = response.read()
print(html[1:20],'------func2')
time.sleep(2)
if __name__ == '__main__':
p1=multiprocessing.Process(target=func1,args=('http://www.baidu.com',))
p2=multiprocessing.Process(target=func2,args=('http://www.sogou.com',))
p1.start()
p2.start()
p1.join()
p2.join()
print('done')
练习1:
写一个多进程,程序针对全局变量count,默认值是0,完成加10的操作。采用10个进程并发操作,最后统一join,之后打印出全局变量count的值。
count = 0
def func1(num=10):
global count
count +=num
print('------',count,'------')
return count
if __name__ == '__main__':
ap = []
for i in range(10):
p = multiprocessing.Process(target= func1)
ap.append(p)
for i in ap:
i.start()
for i in ap:
i.join()
print('done')
print(count)
#执行结果
('------', 10, '------')
('------', 10, '------')
('------', 10, '------')
('------', 10, '------')
('------', 10, '------')
('------', 10, '------')
('------', 10, '------')
('------', 10, '------')
('------', 10, '------')
('------', 10, '------')
done
0#count
练习2:解释为何count的值还是0。
进程占用的内存空间:1、文本区域2、数据区域3、堆栈空间。对于当前py主进程来讲count为全局变量,在创建10个子进程时,复制了10个(文本区域、数据区域)内存占用。由于进程间相互独立,每个进程都有自己的全局变量count,每个加10操作都是针对自己的count值操作,没有操作到主进程的count。及子进程的count为10,主进程的count为0.
练习3:进程间共享变量
import multiprocessing
def f(n,a):
n=3.14
for i in range(len(a)):
a[i] = -a[i]
if __name__ =='__main__':
num = 0
arr = range(10)
p = multiprocessing.Process(target=f,args=(num,arr))
p.start()
p.join()
print(p.exitcode)
print(num)
print(arr[:])
#执行结果
0
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
进程间共享数据
1、Value--单个变量(浮点型:Value('d',1.0)\整数型:Value(‘i’,2)\字符串型:Value(c_char_p,'hello'))【共享内存】
2、Array --数组列表 【共享内存】
3、Manager 【共享进程】
例1
def f(n,a):
n.value=3.14
for i in range(len(a)):
a[i] = -a[i]
if __name__ =='__main__':
num = multiprocessing.Value('d',1.0) #Value的参数类型,数组参数、字典参数
arr = multiprocessing.Array('i',range(10))#Arr的元素类型,数组参数、字典参数
p1 = multiprocessing.Process(target=f,args=(num,arr)) #arr和value在进程间可以共享,共享内存的方式
p1.start()
p1.join()
# print(p1.exitcode)
print(num)
print(num.value)
print(arr[:])
# 执行结果
# <Synchronized wrapper for c_double(3.14)>
# 3.14
# [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
p2 = multiprocessing.Process(target=f,args=(num,arr))
p2.start()
p2.join()
# print(p.exitcode)
print(num)
print(num.value)
print(arr[:])
# 执行结果
# <Synchronized wrapper for c_double(3.14)>
# 3.14
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 进程1和进程2操作的是同一组数据
练习:把count变量封装成Count类,实现增1方法increment及getValue的方法。
class Count:
def __init__(self,count=0):
self.__count=count
def increment(self):
self.__count+=1
def getVlaue(self):
return self.__count
if __name__ =='__main__':
c=Count()
for i in range(10):
c.increment()
print(c.getVlaue())
练习:把类Count中的属性count,使用Value表示,并且使用多进程进行count的自增操作,50个进程进行操作。
写法一:
import multiprocessing
class Count:
def __init__(self,count=0):
self.__count=count
def increment(self):
self.__count+=1
def getVlaue(self):
return self.__count
if __name__ =='__main__':
c=Count()
num = multiprocessing.Value('i',c.getVlaue())
procs =[multiprocessing.Process(target=c.increment(),args=(num,)) for i in range(50)]
for i in procs:
i.start()
for i in procs:
i.join()
print(c.getVlaue())
写法二
from multiprocessing import Process,Value
import time
class Count:
def __init__(self,count):
self.__count=Value('i',count)
def increment(self):
self.__count.value+=1
def getVlaue(self):
return self.__count.value
def func(counter):
time.sleep(0.5)#等待时间
counter.increment()
if __name__ =='__main__':
c=Count(0)
procs =[Process(target=func,args=(c,)) for i in range(100)]
for i in procs:
i.start()
for i in procs:
i.join()
print(c.getVlaue())
疑问:为什么加上等待时间0.5后,实际执行的进程数比预期要少;sleep的时间越长,出错概率高,并发进程数越多,出错的概率越高?
共享内存,多个进程同时可以对同一个内存进行写操作。先读后写,导致某一个进程读到时,加一加到7,刚好此时有另外一个进程也写到+1也加到7。