day 31
day 31 Event、进or线程池、协程、IO模型
01.Event
-
调用该类实例化一个对象 e = Event()
-
若该方法出现在任务中会进入阻塞态
-
用一些线程控制其他线程的状态
-
from threading import Event from threading import Thread import time e = Event() # 创建一个Event对象,初始值为Fales,可通过e.is_set()查看 def func1(): print('func1运行') time.sleep(5) e.set() # 将对象e的值设置为True print('func1结束') def func2(name): print(f'{name}正在等待') e.wait() # 当对象e的值为True时往下执行 print(f'{name}等待结束') t=Thread(target=func1) t.start() for i in range(10): t=Thread(target=func2,args=(i,)) t.start()
02.线程池与进程池
-
进程池与线程池是用来控制当前程序允许进程/线程的数量
-
保证在硬件允许的范围内创建(进程/线程)的数量
-
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor ProcessPoolExecutor(5) # 表示只能同时开启5个进程,默认以CPU核心个数 ThreadPoolExecutor(5) # 表示只能同时开启5个线程,默认以CPU数*5
-
from concurrent.futures import ThreadPoolExecutor import time pool = ThreadPoolExecutor(3) # 实例化对象以调用 def func1(res): print(f'{res}开始') time.sleep(1) print('结束') return 123 def func2(res): print(type(res)) # 传入的res为一个对象 res2=res.result() # 通过result()的方法将上一线程的值取出 print(res2) for i in range(5): pool.submit(func1,1).add_done_callback(func2) # 调用对象自动创建线程,将函数对象和参数传入。设置接收函数 pool.shutdown() # 如同join()保证子线程结束后在往下运行主线程 print('主')
-
pass
03.协程
-
单线程下通过手动模拟操作系统的多道技术实现并发(切换+保存状态)
-
优点;在IO密集型下,会提高效率
-
缺点;在计算密集型下,会降低效率
-
# 使用gevent实现单线程下遇到IO操作自动切换状态 from gevent import monkey import time from gevent import spawn,joinall monkey.patch_all() # 监听该程序下的所有IO操作 def func1(): print(1) time.sleep(1) print('1over') def func2(): print(2) time.sleep(3) print('2over') def func3(): print(3) time.sleep(2) print('3over') start_time=time.time() s1 = spawn(func1) # 模拟并发,spawn内的函数在遇到IO时就会(保存状态+切换)向下运行 s2 = spawn(func2) s3 = spawn(func3) joinall([s1,s2,s3]) # 相当于s1.join(),s2.join(),s3.join() end_time=time.time() print(end_time-start_time)
-
pass
04.IO模型
- blocking IO;阻塞IO
- nonblocking IO;非阻塞IO
- multiplexing IO;多路复用IO
- Asynchronous IO;异步IO
05.单线程下模拟并发TCP服务端
# server
import socket
import json
import struct
from gevent import monkey,spawn
monkey.patch_all()
server = socket.socket()
server.bind(('127.0.0.1',9608))
server.listen(5)
print('启动服务器')
def working(conn):
unm=1
while True:
try:
headers=conn.recv(4)
if not headers:
continue
data_len=struct.unpack('i',headers)[0]
bytes_data=conn.recv(data_len)
back_dic=json.loads(bytes_data.decode('utf-8'))
print(unm)
unm+=1
msg={'msg':back_dic['msg'].upper()}
bytes_msg=json.dumps(msg)
msg_len=struct.pack('i',len(bytes_msg))
conn.send(msg_len)
conn.send(bytes_msg.encode('utf-8'))
except Exception as e:
print(e)
break
def server2():
while True:
conn,addr = server.accept()
spawn(working,conn)
if __name__ == '__main__':
s1=spawn(server2)
s1.join()
# client
import socket
import json
import struct
from concurrent.futures import ThreadPoolExecutor
pool=ThreadPoolExecutor(60)
def client(i):
c1=socket.socket()
c1.connect(('127.0.0.1',9608))
print('启动客户端')
num=1
while True:
try:
send_dic={'msg':f'{i}hello{num}'}
bytes_send=json.dumps(send_dic)
num+=1
send_len=struct.pack('i',len(bytes_send))
c1.send(send_len)
c1.send(bytes_send.encode('utf-8'))
data_len=c1.recv(4)
if not data_len:
continue
dic_len=struct.unpack('i',data_len)[0]
data_dic=c1.recv(dic_len)
msg_dic=json.loads(data_dic.decode('utf-8'))
print(msg_dic['msg'])
except Exception as e:
print(e)
break
c1.close()
for i in range(60):
pool.submit(client,i)
pool.shutdown()
print('主')