![]()
1、进程:
几个概念:父进程、子进程、主进程
import os
import time
from multiprocessing import Process
def func():
time.sleep(1)
print('hello',os.getpid(),os.getppid())
def func2():
print('world')
if __name__ == '__main__':
for i in range(3):
p = Process(target=func)
p.start() # 开启了一个新的进程,在这个新的进程里执行func中的代码
for i in range(2):
p = Process(target=func2)
p.start() # 开启了一个新的进程,在这个新的进程里执行func中的代码
time.sleep(1)
print('hello2',os.getpid(),os.getppid())
import time
from multiprocessing import Process
def func(num,name):
print(num,'hello',name)
if __name__ == '__main__':
for i in range(10):
p = Process(target=func,args=(i,'yuan',)) # 传参
p.start() # 非阻塞的
print('主进程')
2、join方法:阻塞,直到子进程执行结束,这样能保证所有的子进程都能执行完毕
from multiprocessing import Process
import time
def send_mail(n):
time.sleep(0.5)
print('发送邮件%s'%n)
if __name__ == '__main__':
l = []
for i in range(10):
p = Process(target=send_mail,args=(i,))
l.append(p)
p.start()
for p in l:
p.join()
print('所有的邮件都已经发出了')
3、进程之间数据隔离,进程之间的数据是隔离独立的
4、开启进程的第二种方式,懂一种就行了
import os
from multiprocessing import Process
class MyProcess(Process):
def __init__(self,arg):
super().__init__()
self.arg = arg
def run(self):
print(os.getpid(),self.arg)
if __name__ == '__main__':
p = MyProcess(123)
p.start()
p.join()
print('主',os.getpid())
5、进程对象的其它方法:判断进程是否活着,消灭进程
import time
from multiprocessing import Process
class MyProcess(Process):
def __init__(self,a,b):
super().__init__()
self.a = a
self.b = b
def run(self):
print('start')
time.sleep(10)
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.1)
print(p.is_alive())
6、守护进程:知道进程是否有在正常运行,保证程序安全运行等
# 1.守护进程 会随着主进程代码的结束而结束
# 2.守护进程不会守护除了主进程代码之外的其他子进程
import time
from multiprocessing import Process
def eye():
while True:
print('告诉server端我很好')
time.sleep(1)
def process2():
print('进程2要做的事情')
time.sleep(8)
print('进程2要做的事情完成')
def main():
print('我想做的事情')
time.sleep(5)
print('done')
if __name__ == '__main__':
p = Process(target=eye)
p2 = Process(target=process2)
p.daemon = True # p进程设置成 守护进程
p.start()
p2.start()
main()
p2.join() # p2结束之后这句代码才会结束,延缓结束达到在全部进程结束再结束
7、socket并发server端:原理,来一个客户端就新开一个进程
# 使用多进程 实现socket tcp协议 server端的并发
import socket
from multiprocessing import Process
def func(conn):
while True:
conn.send(b'hello')
if __name__ == '__main__':
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
while True:
conn,addr = sk.accept()
p = Process(target=func,args = (conn,))
p.start()
8、抢票例子,由于每个购票者都是打开文件并写入新的票数,如果同时打开就会造成票数多卖的情况,解决方法如下
import json
import time
from multiprocessing import Lock
from multiprocessing import Process
def search(name):
with open('ticket') 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') as f:
ticket_count = json.load(f)
time.sleep(0.2)
if ticket_count['count'] >=1:
print('有余票%s张'%ticket_count['count'])
ticket_count['count'] -= 1
print('%s买到票了'%name)
else:
print('%s没买到票' % name)
time.sleep(0.2)
with open('ticket','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,'alex'+str(i),))
p.start()
# 多个进程 抢占同一个数据资源 会造成 数据不安全
# 我们必须要牺牲效率来保证数据的安全性
9、队列,维持数据,先进先出只能一个使用,就是抢票的升级简化版
# 例子
import queue
q = queue.Queue()
print(q)
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())
# 实际应用
from multiprocessing import Queue,Process
def son(q):
msg = q.get()
print(msg)
if __name__ == '__main__':
q = Queue() # pickle + socket + Lock 进程之间数据安全的数据类型
pro = Process(target=son,args = (q,))
pro.start()
q.put('hello')
# 进程之间的通信
# IPC Iter Process Communication
# IPC :管道Pipe(没有锁,数据不安全的),管道 + 锁 == 队列
# 第三方工具(消息中间件) :memcache、redis、kafka、rabbitmq
# 队列的用法 + 模型
10、生产者消费者模型(非常重要):生成和消费之间的传递数据是需要一个盘子,主要用来提高CPU的使用率提高代码速度
import time
from multiprocessing import Queue,Process
def consumer(name,q):
while True:
food = q.get() # get 会阻塞 直到队列里有一个数据,就取出来
if not food:break
time.sleep(1)
print('%s吃了一个%s'%(name,food))
def producer(q,food_name):
for i in range(20):
time.sleep(0.1)
food = '%s%s'%(food_name,i)
print('制造了%s' % food)
q.put(food) # put 如果队列满了 就在这里阻塞 直到队列里有空的位置
if __name__ == '__main__':
q = Queue(5) # qsize 这个队列的容量,否则生产速度过快会导致内存拥挤死机
p1 = Process(target=consumer,args = ('alex',q))
p3 = Process(target=consumer,args = ('wusir',q))
p2 = Process(target=producer,args = (q,'泔水'))
p1.start()
p2.start()
p3.start()
p2.join() # 确认所有的生产者把数据都生产完毕了
q.put(None)
q.put(None)
# ['泔水0'...'泔水9',None,None]
# 吃的人是消费数据的
# 制造吃的的人是生产数据的
# 生产的快 消费的慢 供大于求
# 增加消费者
# 生产的慢 消费的快 供不应求
# 增加生产者
11、数据共享Manager提供很多数据共享的机制,但是对于一些基础数据类型来说,数据是不安全的,可以加锁(少用)
from multiprocessing import Manager,Process,Lock
def work(d,lock):
# lock.acquire()
# d['count']-=1
# lock.release()
with lock: # 上下文管理
d['count'] -= 1 # 这句话之前的上文 lock.acquire(),下文是lock.release()
if __name__ == '__main__':
lock=Lock()
m = Manager()
dic=m.dict({'count':100,'key':99})
p_l=[]
for i in range(100):
p=Process(target=work,args=(dic,lock))
p_l.append(p)
p.start()
for p in p_l:
p.join()
print(dic)
12、进程池:进程不可能无限新建,因为进程含(创建、分配、结束等)会极大占用CPU,使用当有超过CPU个数的任务或数据总是要利用到数据共享应该用进程池来控制数量(CPU+1个)
import os
import time
from multiprocessing import Pool
def func(i):
time.sleep(0.1)
print(i,os.getpid())
if __name__ == '__main__':
p = Pool(4) # cpu个数 + 1/cpu的个数
for i in range(10):
p.apply_async(func,args=(i,)) # async异步的提交任务
p.close() # 关闭池子,不是要回收池子中的进程,而是阻止继续向池子中提交任务
p.join() # 阻塞,直到池子中的任务都执行完毕
# 结果:总是在4个进程以内重复使用
0 4624
1 7640
2 5360
3 1268
4 4624
5 7640
6 5360
7 1268
8 4624
9 7640
# 进程池于多进程的性能测试
import os
import time
from multiprocessing import Pool,Process
def func(i):
print(i,os.getpid())
if __name__ == '__main__':
start = time.time()
p_lst = []
for i in range(100):
p = Process(target=func,args = (i,))
p.start()
p_lst.append(p)
for p in p_lst:
p.join()
end = time.time()
pro_time = end-start
start = time.time()
p = Pool(4)
for i in range(100):
p.apply_async(func,args=(i,)) # async异步的提交任务
p.close() # 关闭池子,不是要回收池子中的进程,而是阻止继续向池子中提交任务
p.join() # 阻塞,直到池子中的任务都执行完毕
end = time.time()
pool_time = end - start
print(pro_time,pool_time)
13、数据池的其它机制:可以利用队列进行进程之间的通信,即子程序往队列放,主程序往队列拿
#普通
import os
import time
from multiprocessing import Pool
def func(i):
time.sleep(1)
print(i,os.getpid())
return i**i
if __name__ == '__main__':
p = Pool(4) # cpu个数 + 1/cpu的个数
ret_lst = []
for i in range(10):
ret = p.apply_async(func,args=(i,)) # async异步的提交任务
ret_lst.append(ret)
p.close() # 关闭池子,不是要回收池子中的进程,而是阻止继续向池子中提交任务
p.join() # 阻塞,直到池子中的任务都执行完毕
for ret in ret_lst:
print(ret.get())
# map版
import os
import time
from multiprocessing import Pool
def func(i):
time.sleep(0.1)
print(i,os.getpid())
return i ** i
if __name__ == '__main__':
p = Pool(4) # cpu个数 + 1/cpu的个数
ret = p.map(func,range(10))
for r in ret:
print(r)
14、进程中的回调函数,执行完毕后返回值给主程序,这样就能发出多个子程序时,将最快返回的子程序值进行数据处理,提高效率
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): # 主进程执行的
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()
# 将n个任务交给n个进程去执行
# 每一个进程在执行完毕之后会有一个返回值,这个返回值会直接交给callback参数指定的那个函数去进行处理
# 这样的话 所有的进程 哪一个执行的最快,哪一个就可以先进性统计工作
# 能在最短的时间内得到结果
15、信号量
import time
from threading import Semaphore,Thread
def func(name,sem):
sem.acquire()
print(name,'start')
time.sleep(1)
print(name,'stop')
sem.release()
sem = Semaphore(5)
for i in range(20):
Thread(target=func,args=(i,sem)).start()
信号量和池的区别:
进程池:有1000个任务,一个进程池中有5个进程,所有的1000个任务多次利用这5个进程来完成任务
信号量:有1000个任务,有1000个进程/线程,所有的1000个任务由信号量的控制,只能5个5个的执行