Python 学习笔记: 多进程
多进程
1 , windows 平台上开启多进程, 使用multiprocessing 时, 要注意主进程的文件中需要使用
if __name__ == '__main__' : 语句
import socket from multiprocessing import Process def serv(conn): while True: conn.send('你好'.encode('utf-8')) msg = conn.recv(1024).decode('utf-8') print(msg) if msg == 'bye': break info = input('>>>').encode('utf-8') conn.send(info) conn.close() if __name__ == '__main__': sk = socket.socket() sk.bind(('127.0.0.1', 8080)) sk.listen() while True: conn,addr = sk.accept() p = Process(target=serv, args=(conn,)) p.start() sk.close()
2 利用“锁”来控制数据的安全, 买票程序示例:
from multiprocessing import Process from multiprocessing import Lock import time import json def show(i): with open('ticket.txt','r') as f: dic = json.load(f) time.sleep(0.1) if dic['tickets'] > 0: print('用户No. %d 查询到票有%d张'%(i,dic['tickets'])) else: print('用户No. %d 查询到无票' %i) def buy_ticket(i,lock): lock.acquire() #取得锁 with open('ticket.txt', 'r') as f: dic = json.load(f) time.sleep(0.1) if dic['tickets'] >0: dic['tickets'] -=1 print('%d 买到票'%i) else: print('%d没有买到票'%i) with open('ticket.txt','w') as f: json.dump(dic,f) time.sleep(0.1) lock.release() #归还锁 if __name__ == '__main__': for i in range(10): p = Process(target=show,args=(i,)) p.start() time.sleep(1) lock = Lock() p_list=[] for i in range(10): p = Process(target=buy_ticket,args=(i,lock)) p.start() p_list.append(p) #等待所有子进程执行完 for i in p_list: i.join()
票的文件ticket.txt
{"tickets": 2}
10个人去抢2张票:
执行结果:(买到票的人是不确定的)
用户No. 2 查询到票有2张 用户No. 3 查询到票有2张 用户No. 0 查询到票有2张 用户No. 1 查询到票有2张 用户No. 5 查询到票有2张 用户No. 6 查询到票有2张 用户No. 7 查询到票有2张 用户No. 4 查询到票有2张 用户No. 9 查询到票有2张 1 买到票 用户No. 8 查询到票有2张 0 买到票 2没有买到票 4没有买到票 7没有买到票 6没有买到票 3没有买到票 9没有买到票 8没有买到票 5没有买到票
3 事件。 Event 类, 红绿灯课题举例, 车辆通过红绿灯。
from multiprocessing import Process,Event import time import random def cars(i, e): if not e.is_set(): print('\033[31m汽车%i等待\033[0m'%i) e.wait() print('\033[32m汽车%i通过\033[0m'%i) def light(e): while True: if e.is_set(): e.clear() print('\033[31m红灯亮了 \033[0m\n') else: e.set() print('\033[32m绿灯亮了\033[0m\n') time.sleep(3) if __name__ == '__main__': e = Event() traffic = Process(target=light, args=(e,)) traffic.start() for i in range(20): car = Process(target=cars, args=(i, e)) time.sleep(random.random()) car.start()
本例子中, e.wait() 根据e.is_set() 的值决定是否阻塞。 True 时不阻塞, False时阻塞。
知识点:
from multiprocessing import Event e = Event() print(e.is_set()) # 缺省是 False , 阻塞 print('hello') e.set() # 设置为 True , 非阻塞 print(e.is_set()) e.wait() e.clear() # 设置为 False , 阻塞 print(e.is_set()) # False , 阻塞 e.wait() print('world')
4 通过队列实现进程间通信
from multiprocessing import Process,Queue def produce(q): q.put('hello') def consume(q): print(q.get()) if __name__ =='__main__': q = Queue() p = Process(target=produce,args=(q,)) p.start() c = Process(target=consume,args=(q,)) c.start()
5 生产者与消费者例子
from multiprocessing import Process from multiprocessing import JoinableQueue import time def procedure(q, name ,product): for i in range(20): info = '%s 生产了 第 %d个 %s'%(name,i,product) print(info) q.put('第%i个--%s'%(i,product)) time.sleep(0.1) q.join() def consume(q,name): while True: print('%s 消费了 %s'%(name,q.get())) time.sleep(0.1) q.task_done() if __name__ =='__main__': q = JoinableQueue() p1 = Process(target=procedure,args=(q, 'Jinboss','包子')) p2 = Process(target=procedure,args=(q, 'Alex','馒头')) p1.start() p2.start() c1 = Process(target=consume, args=(q,'消费者1')) # c2 = Process(target=consume,args=(q,'消费者2')) c1.daemon = True # c2.daemon = True c1.start() # c2.start() p1.join() p2.join()
6 pipe 管道
from multiprocessing import Pipe, Process def func(conn1,conn2): conn1.close() while True: try: print(conn2.recv()) except EOFError: conn2.close() break if __name__ == '__main__': conn1,conn2 = Pipe() p1 = Process(target=func, args=(conn1,conn2)) p1.start() conn2.close() for i in range(10): conn1.send('吃了么') conn1.close()
7 进程池 Pool
from multiprocessing import Pool,Process import time def fun(n): for i in range(10): print(n+i) if __name__ == '__main__': start = time.time() pool = Pool(5) pool.map(fun,range(100)) t1 = time.time() - start # p_list = [] # start = time.time() # for i in range(100): # p = Process(target=fun, args=(i,)) # p_list.append(p) # p.start() # # for i in p_list: # i.join() # # t2 = time.time() - start print(t1)
进程池的异步提交任务方式:
import os import time import random from multiprocessing import Pool def func(n): print('%s begin ...%s'%(n, os.getpid())) time.sleep(random.randint(1,3)) print('%s end %s'%(n, os.getpid())) if __name__ == '__main__': pool = Pool(5) for i in range(10): pool.apply_async(func, args=(i,)) pool.close() pool.join()
pool.close() 指进程池不再接收新任务了。
pool.join() 指感知进程池中执行任务的结束。
输出如下: (注意观察进程的开启, 及进程ID始终只有5个进程)
0 begin ...11800 1 begin ...11520 2 begin ...11016 3 begin ...9188 4 begin ...5864 0 end 11800 5 begin ...11800 3 end 9188 6 begin ...9188 1 end 11520 7 begin ...11520 5 end 11800 8 begin ...11800 2 end 11016 9 begin ...11016 6 end 9188 4 end 5864 7 end 11520 9 end 11016 8 end 11800 Process finished with exit code 0
8 回调函数
from multiprocessing import Pool import os def func1(n): print('in func1 %s'%os.getpid()) return n*n def func2(m): print('in func2 %s'%os.getpid()) print(m*m) if __name__ =='__main__': p = Pool(5) print('main process %s'%os.getpid()) p.apply_async(func1, args=(10,), callback=func2) p.close() p.join()
执行结果:回调函数是在主进程中执行的。
main process 272 in func1 12716 in func2 272 10000