案例
''' 模拟多个客户端一同去访问服务端,让服务端支持多个客户端访问,从而实现并发效果 不考虑粘包问题 ''' import socket from threading import Thread server=socket.socket() def communicate(conn):#开始通信 while True: try: data=conn.recv(1024)#阻塞 print(data.decode('utf-8')) conn.send(data.upper()) except ConnectionResetError: break conn.close() def servering(ip,port,backlog=5):#建立连接 server.bind((ip,port)) server.listen(backlog) while True: conn,addr=server.accept()#阻塞 print(addr) communicate(conn) #实现并发效果 将建立连接和通信分开,让两个人去做这件事,一个人只负责一件事 if __name__ == '__main__': for i in range(10): t=Thread(target=servering,args=('127.0.0.1',8090)) t.start()
''' 模拟多个客户端一同去访问服务端,让服务端支持多个客户端访问,从而实现并发效果 不考虑粘包问题 ''' import socket from threading import Thread def clients(ip,port): client = socket.socket() # 建立客户端 client.connect((ip,port)) # 客户端与服务端建立连接 while True: info=input('>>:').encode('utf-8').strip() if len(info)==0:continue #判断用户输入是否为空 client.send(info) data=client.recv(1024) #接收来自服务端的回信 print(data.decode('utf-8')) if __name__ == '__main__': for i in range(10): t=Thread(target=clients,args=('127.0.0.1',8090)) t.start()
通过上述的两个例子,我们认识到我们要想实现并发,并不能无限制的开进程或者线程,毕竟计算机硬件资源是有限的,我们如果忽略了计算机硬件的极限,那么迟早计算机会被我们搞破坏,为了在计算机能够承受的情况下,只能加以限制,所以就出现了进程池线程池的概念。
进程池就是一个用来盛放你允许计算机一次可以开启多少个进程的一个容器,里面存放的就是你规定的进程数
线程池是一个用来盛放允许开启的线程数,里面存放的是你规定的线程数
如何实现这个呢?导入模块current.future这个模块,里面有两个类,分别是线程池ThreadPoolExecutor 和进程池ProcessPoolExecutor
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor pool=ThreadPoolExecutor()#里面的参数是你规定的线程数,不写的话默认是CPU*5 # pool=ProcessPoolExecutor()#里面的参数是你规定的进程数,不写的话默认是CPU个数 #提交任务,是异步提交的,他有一个future的返回值,所以可以用future接收一下 future=pool.submit() #提交任务完成计算之后的结果 ,如果直接在这里输入这个结果的话,就会强行将异步提交变成同步,实现的效果是将并发变成串行,效率就会降低,怎么提升? future.result()
本来提交任务的时候是异步,提交完之后就可以去做别的任务了,但是一旦在这里接收的话就会出现同步现象,如何解决,具体实现看代码
#方式一:将提交的任务添加到列表,然后将池子关闭,最后一次性取出,代码如下 pool=ThreadPoolExecutor(20)#你规定的线程数 future_list=[] for i in range(20):#你要开启的线程数(《=规定的线程数) #异步提交 future=pool.submit() #列表添加就会变有序 future_list.append(future) #先关闭池子 pool.shutdown() for future in future_list: #这个时候查看结果的话就会一次性出现,不在那么浪费时间 future.result()
但是基于上面,我们还是发现必须自己手动去处理这件事,那么能不能想到异步提交的点,提交之后就不管了,交给别人去做这件事呢!回调函数可以做到
#方式二:将提交任务的结果交给回调函数去解决 pool=ThreadPoolExecutor(20) def callback('拿到的结果是一个future'): return '拿到的结果'.result for i in range(20): pool.submit('你的任务','任务所需要的参数').add_done_callback('拿到结果之后要做的个人')