一、 socket并发(进程线程池铺垫)
服务端:
import socket from threading import Thread """ 服务端: 1.固定的ip和port 2.24小时不间断提供服务 3.支持高并发 """ server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) # 半连接池 def communicate(conn): while True: try: data = conn.recv(1024) # 阻塞 if len(data) == 0:break print(data) conn.send(data.upper()) except ConnectionResetError: break conn.close() while True: conn,addr = server.accept() # 阻塞 print(addr) t = Thread(target=communicate,args=(conn,)) t.start()
客户端:
import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while True: info = input('>>>:').encode('utf-8') if len(info) == 0:continue client.send(info) data = client.recv(1024) print(data)
二 、 进程池线程池
如一中的socket并发,假如客户端的数量呈万级甚至百万千万级时,此时cup恐怕要冒烟了,那怎么样能解决同一时间的超大高并发呢?进程池和线程池能够解决
说在前面:无论是开线程还是开进程其实都消耗资源,开线程消耗的资源比开进程的小。
池:
为了减缓计算机硬件的压力,避免计算机硬件设备崩溃
虽然减轻了计算机硬件的压力,但是一定程度上降低了持续的效率
进程池线程池:
为了限制开设的进程数和线程数,从而保证计算机硬件的安全
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time import os # 示例化池对象 # 不知道参数的情况,默认是当前计算机cpu个数乘以5,也可以指定线程个数 pool = ProcessPoolExecutor(5) # 创建了一个池子,池子里面有20个线程 def task(n): print(n,os.getpid()) time.sleep(2) return n**2 def call_back(n): print('我拿到了结果:%s'%n.result()) """ 提交任务的方式 同步:提交任务之后,原地等待任务的返回结果,再继续执行下一步代码 异步:提交任务之后,不等待任务的返回结果(通过回调函数拿到返回结果并处理),直接执行下一步操作 """ # 回调函数:异步提交之后一旦任务有返回结果,自动交给另外一个去执行 if __name__ == '__main__': # pool.submit(task,1) t_list = [] for i in range(20): future = pool.submit(task,i).add_done_callback(call_back) # 异步提交任务 t_list.append(future) # pool.shutdown() # 关闭池子并且等待池子中所有的任务运行完毕 # for p in t_list: # print('>>>:',p.result()) print('主')
三 、 协程
学习协程前的铺垫:
进程:资源单位(车间)
线程:最小执行单位,即CPU的执行单位(流水线)
协程:单线程下实现并发
并发:看上去像同时执行的就可以称之为并发。
多道技术:
空间上的复用
时间上的复用
核心:切换+保存状态
协程:完全就是高技术的人自己意淫出来的,但是没想到还挺好用
通过代码层面自己检测 io 自己实现切换,让操作系统误以为你这个线程没有 io
实现原理就是:通过代码实现切换+保存状态
运用范围:单线程实现高并发
开多进程
多个进程下面再开多线程
多个线程下开协程
实现高并发
gevent 模块的使用(genvet就是用来实现类似切换+保存效果)
from gevent import monkey;monkey.patch_all() # 监测代码中所有io行为 from gevent import spawn # gevent本身识别不了time.sleep等不属于该模块内的io操作 import time def heng(name): print('%s 哼'%name) time.sleep(2) print('%s 哼' % name) def ha(name): print('%s 哈'%name) time.sleep(3) print('%s 哈' % name) start = time.time() s1 = spawn(heng,'egon') s2 = spawn(ha,'echo') s1.join() s2.join() # heng('egon') # ha('kevin') print('主',time.time()-start)
用 gevent 模块实现网络通信的单线程高并发
服务端
from gevent import monkey;monkey.patch_all() from gevent import spawn import socket def communicate(conn): while True: try: data = conn.recv(1024) if len(data) == 0:break print(data.decode('utf-8')) conn.send(data.upper()) except ConnectionResetError: break conn.close() def server(): server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn,addr = server.accept() spawn(communicate,conn) if __name__ == '__main__': s1 = spawn(server) s1.join()
客户端
from threading import Thread,current_thread import socket def client(): client = socket.socket() client.connect(('127.0.0.1',8080)) n = 1 while True: data = '%s %s'%(current_thread().name,n) n += 1 client.send(data.encode('utf-8')) info = client.recv(1024) print(info) if __name__ == '__main__': for i in range(500): t = Thread(target=client) t.start()
四 、IO模型初识
上海张江第一帅元少对于 IO 模块的理解: