网络编程服务端要知足一下三点要求:python
- 1. 固定的ip和port程序员
- 2. 24小时不间断提供服务编程
- 3. 可以实现并发安全
#服务端 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)
- 不管开线程仍是开进程其实都消耗资源,开线程消耗的资源比开进程小服务器
- 池: 为了减缓计算机硬件的压力,避免计算机硬件设备奔溃网络
虽然减轻了计算机硬件的压力,可是必定程度上下降了持续的效率多线程
- 进程池/线程池:并发
为了限制开设的进程数和线程数,从而保证计算机硬件的安全app
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('主')
- 进程:资源单位(车间)异步
- 线程:最小执行单位(流水线)
- 协程:单线程下实现并发
1.协程彻底是程序员本身想出来的的东西,经过代码层面本身检测io本身实现切换,
让操做系统误认为这个线程没有io
2.切换+保存状态必定能够提高程序效率吗?
按状况考虑:1.当任务是计算密集型的任务时,反而会下降效率
2.当任务是IO密集型任务是,能够提升运行效率
3.实现高并发:将单线程的效率提高到最高,多进程先开多线程,多线程下使用协程
一个spawn就是一个管理任务的对象
gevent模块不能识别它自己以外的IO行为
因此必须导入它内部封装的模块,能够帮助咱们识别全部io行为
from gevent import monkey;monkey.patch_all() # 检测全部的IO行为 from gevent import spawn,joinall # joinall列表里面放多个对象,实现join效果 import time def play(name): print('%s play 1' %name) time.sleep(5) print('%s play 2' %name) def eat(name): print('%s eat 1' %name) time.sleep(3) print('%s eat 2' %name) start=time.time() g1=spawn(play,'刘清正') g2=spawn(eat,'刘清正') # g1.join() # g2.join() joinall([g1,g2]) print('主',time.time()-start) # 单线程下实现并发,提高效率
连接和通讯都是io密集型操做,咱们要在这二者之间来回切换,就能实现并发效果
服务端检测链接和通讯任务,客户端起多线程同时连接服务器
# 服务端 from gevent import monkey;monkey.patch_all() from socket import * from gevent import spawn def communicate(conn): while True: try: data = conn.recv(1024) if len(data) == 0: break conn.send(data.upper()) except ConnectionResetError: break conn.close() def server(ip, port, backlog=5): server = socket(AF_INET, SOCK_STREAM) server.bind((ip, port)) server.listen(backlog) while True: # 连接循环 conn, client_addr = server.accept() print(client_addr) # 通讯 spawn(comunicate,conn) if __name__ == '__main__': g1=spawn(server,'127.0.0.1',8080) g1.join() # 客户端 from threading import Thread, current_thread from socket import * def client(): client = socket(AF_INET, SOCK_STREAM) client.connect(('127.0.0.1', 8080)) n = 0 while True: msg = '%s say hello %s' % (current_thread().name, n) n += 1 client.send(msg.encode('utf-8')) data = client.recv(1024) print(data.decode('utf-8')) if __name__ == '__main__': for i in range(500): t = Thread(target=client) t.start() # 本来服务端须要开启500个线程才能跟500个客户端通讯,如今只须要一个线程就能够扛住500客户端 # 进程下面开多个线程,线程下面再开多个协程,最大化提高软件运行效率
阻塞IO
非阻塞IO(服务端通讯针对accept用s.setblocking(False)加异常捕获,cpu占用率太高)
IO多路复用
在只检测一个套接字的状况下,他的效率连阻塞IO都比不上。由于select这个中间人增长了环节。
可是在检测多个套接字的状况下,就能省去wait for data过程
异步IO