SoFunction
Updated on 2024-12-17

Deeper understanding of the select module in python

summary

The select module in Python focuses on I/O multiplexing, providing three methods, select poll epoll (the last two of which are available in Linux, windows only supports select), and kqueue (freeBSD system).

select method

The process specifies which events for which file descriptors (up to 1024 fd's) the kernel listens to. When no file descriptor events occur, the process is blocked; when one or more file descriptor events occur, the process is woken up.

When we call select():

1. Context switching converts to kernel state

2. Copy fd from user space to kernel space

3. The kernel iterates through all fd's to see if their corresponding events occur

4, if it did not happen, the process will be blocked, when the device driver generates an interrupt or timeout time, the process will wake up, traversal again

5. Return the traversed fd

6. Copy fd from kernel space to user space

fd:file descriptor file descriptor

fd_r_list, fd_w_list, fd_e_list = (rlist, wlist, xlist, [timeout])

Parameters: Four parameters are accepted (the first three are mandatory).

  • rlist: wait until ready for reading
  • wlist: wait until ready for writing
  • xlist: wait for an “exceptional condition”
  • timeout: timeout time

return value:Three lists

The select method is used to monitor file descriptors (select blocks when the file descriptor condition is not met), and when the state of a file descriptor changes, three lists are returned

1、When the fd in the parameter 1 sequence meets the condition of "readable", then get the changed fd and add it to fd_r_list.

2, when the parameter 2 sequence contains fd, then all the fd in the sequence will be added to fd_w_list

3. When an error occurs in the fd in the parameter 3 sequence, add the fd in which the error occurred to the fd_e_list

4. When the timeout is empty, select will keep blocking until the handle of the listener changes.

When timeout = n (positive integer), then if none of the listening handles have changed, select will block for n seconds, and then return three empty lists, which will be executed directly if the listening handles have changed.

Example: Using select to implement a concurrent server side

import socket
import select

s = ()
(('127.0.0.1',8888))
(5)
r_list = [s,]
num = 0
while True:
 rl, wl, error = (r_list,[],[],10)
 num+=1
 print('counts is %s'%num)
 print("rl's length is %s"%len(rl))
 for fd in rl:
  if fd == s:
   conn, addr = ()
   r_list.append(conn)
   msg = (200)
   (('first----%s'%()).encode())
  else:
   try:
    msg = (200)
    ('second'.encode())
   except ConnectionAbortedError:
    r_list.remove(fd)


()
import socket

flag = 1
s = ()
(('127.0.0.1',8888))
while flag:
 input_msg = input('input>>>')
 if input_msg == '0':
  break
 (input_msg.encode())
 msg = (1024)
 print(())

()

On the server side we can see that we need to keep calling select, which means:

1 When there are too many file descriptors, it can be time-consuming to copy file descriptors between user space and kernel space

2 When there are too many file descriptors, kernel traversal of file descriptors is also a waste of time

3 select only supports a maximum of 1024 file descriptors.

The difference between poll and select is not significant and will not be covered in this article.

The epoll method:

epoll is a nice improvement on select:

1. The epoll solution is in the epoll_ctl function. Each time a new event is registered into the epoll handle, all the fd's are copied into the kernel instead of being copied repeatedly during epoll_wait. epoll ensures that each fd is copied only once throughout the process.

2, epoll will be in epoll_ctl when the specified fd traversal once (this time is essential) and for each fd to specify a callback function, when the device is ready to wake up the wait queue on the waiter, will call this callback function, and this callback function will be ready fd to join a ready chain table. epoll_wait work is actually in this ready queue. The job of epoll_wait is actually to look through this ready list to see if there are any ready fd's.

3. epoll has no additional restrictions on file descriptors

(sizehint=-1, flags=0) establishepollboyfriend


()
Close the control file descriptor of the epoll object.clotureepollboyfriend的文件描述符


True if the epoll object is closed.sensingepollboyfriend是否cloture

()
Return the file descriptor number of the control fd.come (or go) backepollboyfriend的文件描述符

(fd)
Create an epoll object from a given file descriptor.Based on the specifiedfdestablishepollboyfriend

(fd[, eventmask])
Register a fd descriptor with the epoll object.towardepollboyfriend中注册fdand the corresponding event

(fd, eventmask)
Modify a registered file descriptor.modificationsfdincidents

(fd)
Remove a registered file descriptor from the epoll object.unregister

(timeout=-1, maxevents=-1)
Wait for events. timeout in seconds (float)blockage,Until the registeredfdoccurrence,会come (or go) back一个dict,format:{(fd1,event1),(fd2,event2),……(fdn,eventn)}

Events:

EPOLLIN Available for read readable The status character is1
EPOLLOUT Available for write writable The status character is4
EPOLLPRI Urgent data for read
EPOLLERR Error condition happened on the assoc. fd error occurs The status character is8
EPOLLHUP Hang up happened on the assoc. fd pending
EPOLLET Set Edge Trigger behavior, the default is Level Trigger behavior Defaults to horizontal triggering,Setting this event triggers the edge
EPOLLONESHOT Set one-shot behavior. After one event is pulled out, the fd is internally disabled
EPOLLRDNORM Equivalent to EPOLLIN
EPOLLRDBAND Priority data band can be read.
EPOLLWRNORM Equivalent to EPOLLOUT
EPOLLWRBAND Priority data may be written.
EPOLLMSG Ignored.

Horizontal triggering and edge triggering:

Level_triggered (level triggered, sometimes called conditionally triggered): when a readable/writable event occurs on the file descriptor being monitored, the()will notify the handler to read or write. If the data is not read or written all at once this time (e.g., the read/write buffer is too small), then the next call to the()When it does, it will also notify you to continue reading and writing on the file descriptors that you didn't finish reading and writing on, and of course if you never go to read or write, it will keep notifying you!!!! If there are a lot of ready file descriptors in the system that you don't need to read or write, and they return every time, this will greatly reduce the efficiency of the handler to retrieve the ready file descriptors that it cares about!!!! The advantages are obvious: stability and reliability

Edge_triggered (edge-triggered, sometimes called state-triggered): when a readable or writeable event occurs on the file descriptor being monitored, the()will notify the handler to read or write. If it doesn't read or write all the data this time (e.g., the read/write buffer is too small), then the next call to the()When it does, it will not notify you, i.e. it will only notify you once, and not until a second readable/writable event occurs on that file descriptor!!!! This mode is more efficient than horizontal triggering, and the system won't be flooded with tons of ready file descriptors that you don't care about!!! Cons: Unreliable under certain conditions

epoll instance:

import socket
import select

s = ()
(('127.0.0.1',8888))
(5)
epoll_obj = ()
epoll_obj.register(s,)
connections = {}
while True:
 events = epoll_obj.poll()
 for fd, event in events:
  print(fd,event)
  if fd == ():
   conn, addr = ()
   connections[()] = conn
   epoll_obj.register(conn,)
   msg = (200)
   ('ok'.encode())
  else:
   try:
    fd_obj = connections[fd]
    msg = fd_obj.recv(200)
    fd_obj.sendall('ok'.encode())
   except BrokenPipeError:
    epoll_obj.unregister(fd)
    connections[fd].close()
    del connections[fd]

()
epoll_obj.close()
import socket

flag = 1
s = ()
(('127.0.0.1',8888))
while flag:
 input_msg = input('input>>>')
 if input_msg == '0':
  break
 (input_msg.encode())
 msg = (1024)
 print(())

()

summarize

The above is the entire content of this article, I hope that the content of this article on your learning or work can bring some help, if there are questions you can leave a message to exchange, thank you for my support.