杰瑞科技汇

Python select 0,select模块如何使用?

Of course. The Python select() function is a powerful tool for monitoring multiple file descriptors (like network sockets, pipes, or files) to see if they are ready for I/O operations (reading, writing, or have an exceptional condition).

Python select 0,select模块如何使用?-图1
(图片来源网络,侵删)

The 0 you're asking about is the timeout value.


The Role of 0 in select.select()

When you call select.select(), it blocks until one of the monitored file descriptors becomes ready, or until a timeout occurs.

The 0 is used as a non-blocking timeout. Here's what it means:

  • timeout = 0: The select() call will not block at all. It will immediately check the status of the file descriptors and return. This is often called "polling" or a "non-blocking" check.
  • timeout = None (or omitting it): The select() call will block indefinitely until at least one file descriptor is ready.
  • timeout = X.X (a positive float, e.g., 0): The select() call will block for up to X.X seconds. If no file descriptors become ready within that time, it will return empty lists.

The select.select() Signature

Let's look at the function signature to be clear:

Python select 0,select模块如何使用?-图2
(图片来源网络,侵删)
select.select(rlist, wlist, xlist[, timeout])
  • rlist: A list of file descriptors to monitor for read readiness.
  • wlist: A list of file descriptors to monitor for write readiness.
  • xlist: A list of file descriptors to monitor for exceptional conditions.
  • timeout: The time in seconds to wait. This is where you put 0.

Return Value

select.select() always returns three lists:

  1. A list of file descriptors from rlist that are ready for reading.
  2. A list of file descriptors from wlist that are ready for writing.
  3. A list of file descriptors from xlist that have an exceptional condition.

If the timeout is reached, all three returned lists will be empty.


Practical Example: Using timeout=0 for Polling

Imagine you have a server that needs to check for incoming data on a socket, but also needs to perform other tasks in a loop (like updating a game state or checking user input). Using timeout=0 is perfect for this.

Let's create a simple server that listens for a connection and then uses select with a timeout of 0 to check for data without getting stuck.

Python select 0,select模块如何使用?-图3
(图片来源网络,侵删)
import select
import socket
import time
# --- 1. Create a listening socket ---
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setblocking(0)  # Set the socket to non-blocking mode
server_socket.bind(('127.0.0.1', 65432))
server_socket.listen(5)
print("Server listening on 127.0.0.1:65432")
# We will monitor this socket for new connections
inputs = [server_socket]
outputs = []
# --- 2. Main loop ---
while inputs:
    print("\n--- Main Loop Tick ---")
    # Use select() with timeout=0 to poll for readiness
    # This returns immediately.
    readable, writable, exceptional = select.select(inputs, outputs, inputs, 0)
    # --- 3. Process readable sockets ---
    for s in readable:
        if s is server_socket:
            # A new connection is ready to be accepted
            try:
                connection, client_address = s.accept()
                print(f"New connection from {client_address}")
                connection.setblocking(0)
                inputs.append(connection) # Add the new connection to our inputs list
            except ConnectionAbortedError:
                pass # Handle rare cases where connection is aborted
        else:
            # Data is ready to be read from an existing connection
            data = s.recv(1024)
            if data:
                print(f"Received from {s.getpeername()}: {data.decode('utf-8')}")
                # Echo the data back by adding the socket to the outputs list
                if s not in outputs:
                    outputs.append(s)
            else:
                # The connection is closed
                print(f"Connection from {s.getpeername()} closed.")
                if s in outputs:
                    outputs.remove(s)
                inputs.remove(s)
                s.close()
    # --- 4. Process writable sockets ---
    for s in writable:
        try:
            # For this example, let's just send a simple acknowledgment
            s.sendall(b"ACK: Message received.\n")
            print(f"Sent ACK to {s.getpeername()}")
        except ConnectionResetError:
            print(f"Connection to {s.getpeername()} lost.")
        # Remove the socket from the outputs list, as we've written to it
        outputs.remove(s)
    # --- 5. Process exceptional conditions ---
    for s in exceptional:
        print(f"Handling exceptional condition for {s.getpeername()}")
        inputs.remove(s)
        if s in outputs:
            outputs.remove(s)
        s.close()
    # Simulate other work in the main application
    print("Doing other application work...")
    time.sleep(2) # Pause for 2 seconds to simulate other tasks

How to Run This Example:

  1. Save the code as a Python file (e.g., server.py).

  2. Run it in your terminal: python server.py

  3. Open a new terminal and connect to it using netcat or telnet:

    # Using netcat (nc)
    nc 127.0.0.1 65432
    # Or using telnet
    telnet 127.0.0.1 65432
  4. Type a message in the netcat/telnet window and press Enter. You will see the server receive it and send an "ACK" back.

What Happens in the Loop:

  1. The select.select(inputs, outputs, inputs, 0) call checks the server_socket.
  2. It returns immediately because the timeout is 0.
  3. If there's no new connection, readable will be empty. The "Doing other application work..." message will print.
  4. The time.sleep(2) pauses the loop for 2 seconds.
  5. Then it checks again. This cycle repeats.
  6. When a client connects, select detects that server_socket is "readable" on the next tick.
  7. The server accepts the connection, adds it to the inputs list, and the loop continues.
  8. Now, select will check both the server_socket and the new client_socket.
  9. When you type in the client terminal, select will detect that the client_socket is "readable". The server will receive the data, add the socket to the outputs list, and on the next loop tick, select will find it in writable, and the server will send the "ACK".

When to Use timeout=0

  • Game Loops: You need to check for network events or user input without freezing the game's rendering or physics.
  • GUI Applications: You need to check for background I/O operations without making the UI unresponsive.
  • Monitoring Multiple Resources: When you need to poll several different sources (sockets, pipes, etc.) in a single, non-blocking loop.
  • Implementing Custom Event Loops: It's the fundamental building block for more complex asynchronous frameworks.

Important Caveat: Portability

The select() module is a thin wrapper around the underlying operating system's select() system call. While timeout=0 works on all major platforms (Linux, macOS, Windows), there are limitations:

  • File Limit: On Unix-like systems, select() is limited to monitoring a number of file descriptors up to FD_SETSIZE (often 1024). For applications that need to handle thousands of connections, select() is not the right tool. Use poll() or epoll (Linux) / kqueue (BSD/macOS) instead.
  • Windows Limitations: Sockets are the only objects that can be used with select() on Windows. You cannot monitor regular files or pipes.
分享:
扫描分享到社交APP
上一篇
下一篇