IO model
There are two ways to submit tasks:
- Synchronization: The application submits the task, waits for the result, and then executes the next task
- Asynchronous: After the application submits the task, it continues to execute without waiting for the result. After the task is executed, it will automatically start the asynchronous function.
Synchronization does not equal blocking:
- Synchronization: After submitting the task, no matter whether the task is blocked or not, just wait for the received result, and then go down after the task runs.
- Blocking: When IO is encountered when submitting a task, if it is not processed, the operating system will take away the CPU. Solution: use gevent, when IO is detected, switch to other tasks
The main classification of IO model:
- blocking IO blocking IO
- nonblocking IO nonblocking IO
- IO multiplexing IO multiplexing
- Signal driven IO signal driven IO
- Asynchronous IO asynchronous IO
Encountered IO will block: stuck in place; network IO: blocked in place
1. What kind of operation on the server side belongs to IO behavior
- server-side accept, recv, send,
- Among them accept, recv will feel obvious, etc.,
- send doesn't obviously wait, but is also IO behavior
2. Why does IO behavior have the effect of waiting in place
Because the server will have a waiting time when recv, it is waiting for the data in the operating system cache before copying it to the application program
blocking IO
import socket from threading import Thread server = socket.socket (socket.AF_INET, socket.SOCK_STREAM) server.bind(('127.0.0.1',8080)) server.listen(5) def communicate(): while True: try: data = conn.recv(1024 ) print ( ' Received data: ' ,data) conn.send(data.upper()) except ConnectionResetError: break conn.close() print('setting...') while True: print('settings') conn,client_addr = server.accept() # io is blocked, the operating system takes away the cpu print (client_addr) t = Thread(target=communicate,args=(conn,)) t.start() server.close()
import socket client = socket.socket (socket.AF_INET, socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: cmd = input('>>:').strip() if not cmd:continue client.send(cmd.encode('utf-8')) data = client.recv(1024) print(data) phone.close()
non-blocking IO
The application detects io by itself, and when it encounters io, it switches to other tasks, which can greatly improve the efficiency of single thread
Existing problems:
- When the cpu is doing other things, the data is sent, and it will not respond immediately
- There is no blocking on the server side, it is an infinite loop, the cpu will always run, and the process is in a ready state, which takes up a lot of cpu, so that the application program keeps asking the operating system whether the data is good or not, doing useless work
Multiplexed IO
Blocking io: there are wait() waiting process, copy process,
Multiplexing io: There is one more select process than blocking io. This process can be used as an intermediary to ask the operating system for data
- Disadvantages: When there is only one socket, the performance is lower than that of blocking io. When monitoring multiple sockets, the cycle is slow. If there is a lot of list data, the efficiency is low.
- Advantages: When there are multiple sockets, it can be handed over to select for processing, which has higher performance than blocking io
elect : list looping is inefficient
poll : The list data that can be received is not very efficient
epoll: the highest efficiency, bind a callback function to each socket through asynchronous operation, whoever is better will trigger the callback, (there is no need to traverse the inefficiency)
epoll: windows does not have; linux has
The selectors module automatically selects based on the operating system
import socket import select server = socket.socket (socket.AF_INET, socket.SOCK_STREAM) server.bind(('127.0.0.1',8080)) server.listen(5) server.setblocking(False) print('settings') rlist=[server,] #存收的套接字,有两种:conn ,server wlist=[] #存发的套接字 wdata={} while True: rl,wl,xl = select.select(rlist,wlist,[],0.5) #去向操作系统问套接字准备好没有,异常列表[] m每隔0.5秒问一次 print('rl',rl) print('wl',wl) for sock in rl: if sock == server: conn,addr = sock.accept() rlist.append(conn) else: try: #适用于windows系统 data = sock.recv(1024) if not data: #适用于linux系统,会一直收空 sock.close() rlist.remove(sock) continue wlist.append(sock) wdata[sock] = data.upper() except Exception: #客户端连接关闭后走这个异常 sock.close() rlist.remove(sock) for sock in wl: data = wdata[sock] sock.send(data) wlist.remove(sock) #传完数据,就不用监测 wdata.pop(sock) server.close()
import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: cmd = input('>>:').strip() if not cmd:continue client.send(cmd.encode('utf-8')) data = client.recv(1024) print(data.decode('utf-8')) phone.close()