---恢复内容开始---
前情提要:
一:进程Process
1:模块介绍 from multiprocessing import Process
from multiprocessing import Process # print(os.getpid()) #获取本线程id def fun1(): time.sleep(1) print('hello word',os.getpid(),os.getppid()) if __name__ =='__main__': for i in range(10): #通过for 循环开启多个子进程 Process(target=fun1).start() #开启一个新的子进程 time.sleep(1) print('hello2,',os.getpid(),os.getppid()) # # 子进程可以有返回值么? # 不能有返回值 # 因为子进程函数中的返回值无法传递给父进程,因为内存隔离的问题
二:join() 阻塞的使用,以及主进程与子进程的关系
1:p.start() 是非阻塞的模式,
所以先走主进程
之后子进程开始
from multiprocessing import Process import time def send_emil(n): time.sleep(0.1) print('发送邮件%s'%n) if __name__ == '__main__': for i in range(10): #创建10个进程 p =Process(target=send_emil,args=(i,)) #参数target+函数名, args +元祖参数 p.start() #非阻塞的模式 print('所有邮件都发送完了') #先走主进程
>>>>>>>>>>>>>>.
所有邮件都发送完了
发送邮件0
发送邮件3
发送邮件1
发送邮件5
发送邮件6
发送邮件4
发送邮件2
发送邮件7
发送邮件8
发送邮件9
2:在p.start() 开启进程后面增加p.join() 阻塞(阻塞直至子进程完全走完)
就会造成变成变行模式
from multiprocessing import Process import time def send_emil(n): time.sleep(0.1) print('发送邮件%s'%n) if __name__ == '__main__': for i in range(10): #创建10个进程 p =Process(target=send_emil,args=(i,)) #参数target+函数名, args +元祖参数 p.start() #开启一个, p.join() #阻塞直至子进程结束才停止阻塞 print('所有邮件都发送完了') >>>>>>>>>>>>> 发送邮件0 发送邮件1 发送邮件2 发送邮件3 发送邮件4 发送邮件5 发送邮件6 发送邮件7 发送邮件8 发送邮件9 所有邮件都发送完了
3:每一个p.start()生成的句柄放在一个列表中,在循环关闭
from multiprocessing import Process import time def send_emil(n): time.sleep(0.1) print('发送邮件%s'%n) if __name__ == '__main__': p_lis =[] for i in range(10): #创建10个进程 p =Process(target=send_emil,args=(i,)) #参数target+函数名, args +元祖参数 p_lis.append(p) p.start() # for p in p_lis: p.join() #阻塞,直至当前子进程执行完才结束 print('所有邮件都发送完了') >>>>>>>>>>>>>>> 发送邮件0 发送邮件1 发送邮件2 发送邮件3 发送邮件5 发送邮件6 发送邮件4 发送邮件7 发送邮件8 发送邮件9 所有邮件都发送完了
三: 进程之间的数据是相互隔离的
from multiprocessing import Process n = 100 def fun1(): global n n = n-1 if __name__ == '__main__': p_lis =[] for i in range(10): #开启10个子进程.然后每个子进程都拿到100 自行减1 不对原100有任何影响 p =Process(target=fun1) p.start() p_lis.append(p) for p in p_lis: p.join() print(n) # >>>>>>>>>>>> 100
四:用类的方式开启进程
1:简单方式
import os from multiprocessing import Process class MyProcess(Process): # 定义一个类,继承Process def __init__(self,arg): super().__init__() # 加入原来的__init__ 的东西 self.arg =arg def run(self): print(os.getpid(),os.getppid()) # 获取进程id ,获取爷进程id # if __name__ == '__main__': p =MyProcess(123) #这个123是给arg 传的 p.start() #开启进程 p.join() #阻塞 print('主进程',os.getpid()) >>>> 15012 14660 主进程 14660
2: p.terminate() 的用法,
from multiprocessing import Process import time class Myprocess(Process): def __init__(self,a,b): super().__init__() #原__init__ self.a =a self.b =b def run(self): print('start') time.sleep(0.5) print('end',self.a,self.b) if __name__ == '__main__': p =Myprocess(1,2) p.start() print(p.is_alive()) time.sleep(1) print(p.name,p.pid) p.terminate() #非阻塞 关闭进程 print(p.is_alive()) #判断进程是不是活着的 time.sleep(0.2) print(p.is_alive()) #p.terminate 需要响应时间,并不是说关就关,因为是非阻塞模式 >>>>>>>>>>>>>. True start Myprocess-1 13308 True False
五:守护进程,就是在主函数运行的时候附加一个函数并行,去做其他事情
比如客户端告诉服务器客户端的状况
from multiprocessing import Process import time def eye(): while 1: print('告诉server 端我活的很好') time.sleep(0.5) def mian(): #主函数 print('我想做的是事情') time.sleep(5) print('done') if __name__ == '__main__': p =Process(target=eye) p.daemon =True #将p设置守护进程 p.start() #子进程开始 mian() #主函数开始 , 子进程随着主进程结束而结束 >>>>>>>>>>>>> 我想做的是事情 告诉server 端我活的很好 告诉server 端我活的很好 告诉server 端我活的很好 告诉server 端我活的很好 告诉server 端我活的很好 告诉server 端我活的很好 告诉server 端我活的很好 告诉server 端我活的很好 告诉server 端我活的很好 done
from multiprocessing import Process import time def fun1(): print('kaishi') time.sleep(8) print('end') def eye(): while 1: print('告诉server 端我活的很好') time.sleep(0.5) def mian(): #主函数 print('我想做的是事情') time.sleep(5) print('done') if __name__ == '__main__': p =Process(target=eye) p1 =Process(target=fun1) p.daemon =True #将p设置守护进程 p.start() #子进程开始 p1.start() # p1.join() mian() #主函数开始 , 子进程随着主进程结束而结束
六:使用多进程的方式实现socket ,server多并发
import socket from multiprocessing import Process def fun1(conn): while 1: conn,send(b'hello') if __name__ == '__main__': sk = socket.socket() sk.bind(('127.0.0.1',9000)) sk.listen() while 1: conn,addr =sk.accept() p=Process(target=fun1,args=(conn,)) #将发送端设置为子进程 循环来一个我就送一个 p.start() >>>>>>>>>>>>>>
七:买票的小例子
# 多个进程 抢占同一个数据资源 会造成 数据不安全
# 我们必须要牺牲效率来保证数据的安全性
数据结构:
{"count": 0}
import json import time from multiprocessing import Lock from multiprocessing import Process def search(name): #查询票 with open('ticket.txt') as f : ticket_count =json.load(f) #解析句柄 if ticket_count['count'] >=1 : print('%s:有余票%s 张'%(name,ticket_count['count'])) else: print('%s:没票了'%name) def buy(name): #买票 with open('ticket.txt') as f : ticket_count = json.load(f) # 解析句柄 time.sleep(0.2) if ticket_count['count'] >= 1: print('%s:有余票%s 张' % (name, ticket_count['count'])) ticket_count['count']-=1 print('%s:买到票了'%name) else: print('%s:没票了' % name) time.sleep(0.2) with open('ticket.txt', 'w') as f: json.dump(ticket_count, f) def opt(lock,name): #设置锁函数 search(name) lock.acquire() #拿走钥匙 buy(name) lock.release() #归还钥匙 #总计就一把钥匙,第一个拿到的人可以操作其他人操作不了只能等着 if __name__ == '__main__': lock =Lock() #锁, 互斥锁 for i in range(10): p =Process(target=opt,args=(lock,'wzh'+str(i))) p.start() >>>>>>>>>>> wzh3:有余票3 张 wzh0:有余票3 张 wzh1:有余票3 张 wzh2:有余票3 张 wzh3:有余票3 张 wzh3:买到票了 wzh4:有余票3 张 wzh5:有余票2 张 wzh6:有余票2 张 wzh0:有余票2 张 wzh0:买到票了 wzh7:有余票1 张 wzh1:有余票1 张 wzh1:买到票了 wzh8:有余票1 张 wzh9:有余票1 张 wzh2:没票了 wzh4:没票了 wzh5:没票了 wzh6:没票了 wzh7:没票了 wzh8:没票了 wzh9:没票了
八:队列的概念
# 进程之间的通信
# IPC Iter Process Communication
# IPC :管道Pipe(没有锁,数据不安全的),管道 + 锁 == 队列
# 第三方工具(消息中间件) :memcache、redis、kafka、rabbitmq
# 队列的用法 + 模型
1:queque包
>
#队列 # 队列的作用, 队列的作用就是先进先出,后进后出 import queue #队列, 先进先出 q = queue.Queue() #实例化对象 # print(q) #<queue.Queue object at 0x009D4670> q.put(1) #按照顺序往队列里放 q.put(2) q.put(3) print(q.get()) #1 #按照顺序放队列里拿 print(q.get()) #2 print(q.get()) #3
>>>>>>>>>>
1
2
3
2:from multiprocessing import Queue #进程中的Queue 包
from multiprocessing import Process from multiprocessing import Queue #进程中的Queue 包 def son(q): msg =q.get() msg1 =q.get() msg2 =q.get() print(msg) print(msg1) print(msg2) if __name__ == '__main__': q =Queue() # 该方法是socket +pickle +Lock 实现的 pro =Process(target=son,args=(q,)) #创建进程里面扔进去队列 pro.start() q.put('hello') q.put('hello1') q.put('hello2') pro.join() >>>>>>>> hello hello1 hello2
十:生产者消费者模式
# 生产者消费者模型
# 为什么会有这个模型
# 使用队列来完成生产、消费的过程
# 生产者 是进程
# 消费者 是进程
# 生产者和消费者之间 传递数据 是需要一个 盘子(IPC)
# 队列
import time from multiprocessing import Process #导入进程包 from multiprocessing import Queue #导入对列包 Queue 里面包含了Lock def consumer(name,q): #q是管道, while True: #因为不知道要生产多少个,所以这里用while True food =q.get() # 从队列中拿出1个字符串 if not food: #如果拿不到那么 break break time.sleep(1.5) print('%s吃了一个%s'%(name,food)) def producter(q,food_name): for i in range(10): #总共生产10个 time.sleep(0.5) food ='%s%s'%(food_name,i) #生产食物几 print('制造了%s'%food) q.put(food) #把食物放在队列中,如果队列满了这里就开始堵塞了,直到队列中有空的位置才继续 if __name__ == '__main__': q =Queue(5) #qsize 是这个队列的容量, 一般设置为cpu数量加1 就够了 p1 =Process(target=consumer,args=('wzh',q)) #俩个消费者,消费者1号 p2 =Process(target=consumer,args=('zsf',q)) #消费者2号 p5 =Process(target=consumer,args=('Wf',q)) #消费者2号 p6=Process(target=consumer,args=('Lf',q)) #消费者2号 p3 =Process(target=producter,args=(q,'baozi')) #生产者1号 p4 =Process(target=producter,args=(q,'jiucai')) #生产者2号 p1.start() #启动消费者1号 p2.start() #启动消费者2号 p5.start() #启动消费者3号 p6.start() #启动消费者4号 p3.start() #启动生产1号 p4.start() #启动生产者2号 p3.join() #确定3号生产者生产完毕 p4.join() #确定4号生产者生产完毕 q.put(None) #让队列消费者停止使用 q.put(None) q.put(None) q.put(None)
>>>>
制造了baozi0
制造了jiucai0
制造了baozi1
制造了jiucai1
制造了baozi2
制造了jiucai2
wzh吃了一个baozi0
制造了baozi3
zsf吃了一个jiucai0
制造了jiucai3
Lf吃了一个baozi1
制造了baozi4
Wf吃了一个jiucai1
制造了jiucai4
制造了baozi5
制造了jiucai5
wzh吃了一个baozi2
制造了baozi6
zsf吃了一个jiucai2
制造了jiucai6
Lf吃了一个baozi3
制造了baozi7
Wf吃了一个jiucai3
制造了jiucai7
制造了baozi8
制造了jiucai8
wzh吃了一个baozi4
制造了baozi9
zsf吃了一个jiucai4
Lf吃了一个baozi5
制造了jiucai9
Wf吃了一个jiucai5
wzh吃了一个baozi6
zsf吃了一个jiucai6
Lf吃了一个baozi7
Wf吃了一个jiucai7
wzh吃了一个baozi8
zsf吃了一个jiucai8
Lf吃了一个baozi9
Wf吃了一个jiucai9
十一:数据之间的共享
# Manager提供很多数据共享的机制,但是对于一些基础数据类型来说,是数据不安全的 # 如何去解决问题呢?需要我们自己来做加锁的工作 from multiprocessing import Process from multiprocessing import Manager #进程之间数据共享 from multiprocessing import Lock def work(d,lock): # lock.acquire() # d['count']-=1 # lock.release() # with lock: #通过锁进行操作数据之间的共享 d['count'] -=1 if __name__ == '__main__': lock =Lock() #实例化锁的对象 m =Manager() #实例化数据共享模块 dic =m.dict({'count':100}) p_lis =[] for i in range(10): p =Process(target=work,args=(dic,lock)) p_lis.append(p) p.start() for p in p_lis: p.join() print(dic)
>>>>>>>>>>
{'count': 95}
{'count': 95}
{'count': 95}
{'count': 91}
{'count': 91}
{'count': 91}
{'count': 90}
{'count': 90}
{'count': 90}
{'count': 90}
十二:进程池的概念
# 起多进程的意义
# 1.为了更好的利用CPU,所以如果我们的程序中都是网络IO,文件IO就不适合起多进程
# 2.为了数据的隔离,如果我们的程序中总是要用到数据共享,那么就不适合使用多进程
# 3.超过了cpu个数的任务数,都应该使用进程池来解决问题,而不能无限的开启子进程
# 如果我们有多少个任务 就开启多少个进程 实际上对我们来说 是不划算的 # 由于我们计算机的cpu个数是非常有限的 # 所以我们起的进程数量是完全和CPU个数成比例的 import os import time from multiprocessing import Pool def fun1(i): time.sleep(1) print(i,os.getpid()) if __name__ == '__main__': p =Pool(4) #创建进程池 #经测试是4个4个处理的 for i in range(10): p.apply_async(fun1,args=(i,)) #传入方法名, 函数参数元祖扩住 p.close() #关闭池子, 不是回城池子中的进程,而是阻止继续向池子中继续提交任务 p.join() #阻塞,直到池子中的任务全部都执行完毕 >>>>>>>> 0 9256 1 11292 2 8212 3 3328 4 9256 5 11292 6 8212 7 3328 8 9256 9 11292
十三:进程池与进程之间的性能测试
import os import time from multiprocessing import Process #导入进程 from multiprocessing import Pool #导入进程池 def fun1(i): print(i,os.getpid()) #打印内容以及当前进程的id if __name__ == '__main__': start_time =time.time() p_lis =[] for i in range(15): p =Process(target=fun1,args=(i,)) p.start() p_lis.append(p) for p in p_lis: p.join() end_time =time.time() pro_time =end_time-start_time start =time.time() pool = Pool(4) for i in range(15): pool.apply_async(fun1,args=(i,)) pool.close() #关闭池子 pool.join() #阻塞直到所有的任务都完成 end =time.time() pool_time =end-start print(pool_time ,pro_time) >>>>>>>>>> 1 10372 4 13412 0 13016 2 10256 6 12348 5 10040 3 4440 8 7064 7 2976 9 860 10 13688 11 8312 12 5984 13 13908 14 2212 0 3956 1 3956 2 3956 3 3956 4 3956 5 3956 6 3956 7 3956 8 3956 9 3956 10 3956 11 3956 12 3956 13 3956 14 3956 2.412966251373291 7.410228252410889
可以出 进程池的时间远远短于 进程 所以推荐使用进程池
十四:进程池的其他机制:
1:map()的用法
import os import time from multiprocessing import Pool def fun1(i): time.sleep(0.5) print(i,os.getpid()) if __name__ == '__main__': p =Pool(4) # for i in range(10): # p.apply_async(fun1,args=(1,)) p.map(fun1,range(10)) #用map 可以表示上面的两个注释的
>>>>>>>>>>>>>
0 13872
1 8412
2 14112
3 10968
4 13872
6 14112
5 8412
7 10968
8 13872
9 8412
2:进程池可以有返回值(在主进程打印)
import os import time from multiprocessing import Pool def fun1(i): time.sleep(0.5) print(i,os.getpid()) # return i*i #返回i*i if __name__ == '__main__': p =Pool(4) ret_lis =[] #用来接收每一个返回值 for i in range(10): ret =p.apply_async(fun1,args=(i,)) #返回值 ret_lis.append(ret) p.close() #关闭池子 p.join() #阻塞,直到子进程全部结束 for rets in ret_lis: print(rets.get()) >>>>>>>>>>>>> 0 8196 1 1212 2 10588 3 14880 4 8196 5 1212 6 10588 7 14880 8 8196 9 1212 0 1 4 9 16 25 36 49 64 81
3:进程池的回调函数:
import time import random from multiprocessing import Process,Pool def get(i): # 进程池的子进程执行的 time.sleep(random.random()) print('从网页获取一个网页的内容', i) return i,'网页的内容'*i def call_back(content): # 主进程执行的,content接受上面的get方法 print(content) if __name__ == '__main__': p = Pool(5) ret_l = [] for i in range(10): p.apply_async(get,args=(i,),callback=call_back) p.close() p.join()
>>>>>
从网页获取一个网页的内容 4
(4, '网页的内容网页的内容网页的内容网页的内容')
从网页获取一个网页的内容 2
(2, '网页的内容网页的内容')
从网页获取一个网页的内容 1
(1, '网页的内容')
从网页获取一个网页的内容 0
(0, '')
从网页获取一个网页的内容 3
(3, '网页的内容网页的内容网页的内容')
从网页获取一个网页的内容 9
(9, '网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容')
从网页获取一个网页的内容 5
(5, '网页的内容网页的内容网页的内容网页的内容网页的内容')
从网页获取一个网页的内容 7
(7, '网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容')
从网页获取一个网页的内容 6
(6, '网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容')
从网页获取一个网页的内容 8
(8, '网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容网页的内容')
---恢复内容结束---