线程进程池,协程,IO模型
1. 线程进程池
1.池: 在保证计算机硬件安全的情况下最大限度的使用计算机硬件,池其实是降低了程序的运行效率,但是保证了计算机硬件的安全(硬件的发展跟不上软件发展的速度)
2: 线程池与进程池: 开线程和进程都需要消耗资源,只不过两者比较情况下线程消耗的资源比较少,使用进程池与线程池能在计算机能承受的范围内最大限度的使用计算机
3: 在python中开线程池与进程池需要导入concurrent.futurs 标准模块
#1 介绍 concurrent.futures模块提供了高度封装的异步调用接口 ThreadPoolExecutor:线程池,提供异步调用 ProcessPoolExecutor: 进程池,提供异步调用 Both implement the same interface, which is defined by the abstract Executor class. #2 基本方法 #submit(fn, *args, **kwargs) 异步提交任务 #map(func, *iterables, timeout=None, chunksize=1) 取代for循环submit的操作 #shutdown(wait=True) 相当于进程池的pool.close()+pool.join()操作 wait=True,等待池内所有任务执行完毕回收完资源后才继续 wait=False,立即返回,并不会等待池内的任务执行完毕 但不管wait参数为何值,整个程序都会等到所有任务执行完毕 submit和map必须在shutdown之前 #result(timeout=None) 取得结果 #add_done_callback(fn) 回调函数 # done() 判断某一个线程是否完成 # cancle() 取消某个任务
4.实例:
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import os import time # pool = ThreadPoolExecutor(5) # 指定线程池内线程个数,默认为cpu个数 * 5 pool = ProcessPoolExecutor(5) # 指定进程池内进程个数,默认为cpu个数 def func(n): print(n,os.getpid()) time.sleep(2) return n*n def call_back(n): # 回调函数 print(f'异步回调结果为{n.result()}') if __name__ == '__main__': t_list = [] for i in range(20): t = pool.submit(func,i) # 异步向进程池中提交任务 t.add_done_callback(call_back) # 绑定一个回调函数,一旦有结果,立即执行回调函数,把任务的返回值作为参数传给回调函数 # t_list.append(t) # # pool.shutdown() # 关闭池子,等待池子中所有任务执行完毕后执行下面的代码想当与join # for i in t_list: # print(i.result()) # 获取返回值通过result方法获取,否则拿到的是一个对象 #
2. 协程: 是程序员自己定义的名词,通过代码来检测程序中的IO,一旦遇到IO自己通过代码切换并保存当前状态,让操作系统误认为这个程序没有IO操作,从而保证程序在运行态和就绪态来回切换,从而提升代码的运行效率
1. 在程序中使用协程需要第三方模块 gevent ,gevent模块介绍:
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的 g2=gevent.spawn(func2) g1.join() #等待g1结束 g2.join() #等待g2结束 #或者上述两步合作一步:gevent.joinall([g1,g2]) g1.value#拿到func1的返回值
注意 gevent模块没办法自动识别time.sleep等IO去情况.需要手动再配置一个参数
from gevent import monkey;monkey.patch_all( )
2. 实例:
from gevent import monkey;monkey.patch_all() import time import gevent def eat(): print('正在吃') time.sleep(2) print('吃完了') def play(): print('正在玩') time.sleep(3) print('玩完了') g1 = gevent.spawn(eat) # spawn 来检测当前函数中的IO操作,遇到则切换 g2 = gevent.spawn(play) g1.join() g2.join()
3: 使用协程来实现socket服务端的并发
客户端:
from threading import Thread,current_thread import socket sk = socket.socket() sk.connect(('127.0.0.1',8080)) def func(): while 1: res = f'{current_thread().name}' sk.send(res.encode('utf-8')) ret = sk.recv(1024) print(ret) for i in range(400): t = Thread(target=func,) t.start()
服务端:
from gevent import monkey;monkey.patch_all() import gevent import socket sk = socket.socket() sk.bind(('127.0.0.1', 8080)) sk.listen() def func(conn): while 1: try: ret = conn.recv(1024) if len(ret) == 0:break print(ret) conn.send(ret.upper()) except ConnectionResetError: break conn.close() def func1(): while 1: conn,addr = sk.accept() gevent.spawn(func,conn) if __name__ == '__main__': g1 = gevent.spawn(func1) g1.join()
3 IO模型
1: 阻塞IO(blocking IO)
2: 非阻塞IO(non-blocking IO)
3.多路复用IO(IO multiplexing)
4. 异步IO(Asynchronous I/O)