Python select Module

📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.

✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.

🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.

▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube

The select module in Python provides tools to efficiently manage multiple I/O operations. It allows you to monitor multiple file descriptors to see if they have any I/O events (like readability or writability) ready. This is particularly useful in network programming where you need to handle multiple connections simultaneously.

Table of Contents

  1. Introduction
  2. Key Functions
    • select.select
    • select.poll
    • select.epoll
    • select.kqueue
  3. Examples
    • Using select for I/O Multiplexing
    • Using poll for I/O Multiplexing
    • Using epoll for I/O Multiplexing
    • Using kqueue for I/O Multiplexing
  4. Real-World Use Case
  5. Conclusion
  6. References

Introduction

The select module provides mechanisms to efficiently manage multiple I/O streams, such as sockets or files. It helps in determining which file descriptors are ready for reading, writing, or have encountered an exceptional condition. This is crucial for implementing high-performance network servers and clients.

Key Functions

select.select

Monitors multiple file descriptors to see if they are ready for some kind of I/O operation.

import select

readable, writable, exceptional = select.select(inputs, outputs, errors, timeout)

select.poll

Provides a more scalable way to monitor file descriptors compared to select.

import select

poller = select.poll()
poller.register(fd, select.POLLIN | select.POLLOUT)
events = poller.poll(timeout)

select.epoll

Provides an interface to the Linux epoll system call, which is more efficient for a large number of file descriptors.

import select

epoll = select.epoll()
epoll.register(fd, select.EPOLLIN | select.EPOLLOUT)
events = epoll.poll(timeout)

select.kqueue

Provides an interface to the BSD kqueue system call, which is efficient for managing many file descriptors.

import select

kq = select.kqueue()
kevent = select.kevent(fd, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)
kq.control([kevent], 0)
events = kq.control(None, 1, timeout)

Examples

Using select for I/O Multiplexing

import socket
import select

# Create two non-blocking sockets
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.setblocking(0)
s1.bind(('localhost', 9001))
s1.listen(5)

s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.setblocking(0)
s2.bind(('localhost', 9002))
s2.listen(5)

inputs = [s1, s2]
outputs = []
errors = []

while inputs:
    readable, writable, exceptional = select.select(inputs, outputs, errors)
    
    for s in readable:
        if s is s1:
            conn, addr = s.accept()
            print(f'Connection from {addr} on socket 1')
        elif s is s2:
            conn, addr = s.accept()
            print(f'Connection from {addr} on socket 2')

    for s in exceptional:
        inputs.remove(s)
        s.close()

Using poll for I/O Multiplexing

import socket
import select

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)
server.bind(('localhost', 9000))
server.listen(5)

poller = select.poll()
poller.register(server, select.POLLIN)

connections = {}

while True:
    events = poller.poll()
    for fd, flag in events:
        if fd == server.fileno():
            conn, addr = server.accept()
            conn.setblocking(0)
            poller.register(conn, select.POLLIN)
            connections[conn.fileno()] = conn
        elif flag & select.POLLIN:
            conn = connections[fd]
            data = conn.recv(1024)
            if data:
                print(f'Received data: {data}')
            else:
                poller.unregister(fd)
                conn.close()
                del connections[fd]

Using epoll for I/O Multiplexing

import socket
import select

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)
server.bind(('localhost', 9000))
server.listen(5)

epoll = select.epoll()
epoll.register(server.fileno(), select.EPOLLIN)

connections = {}

while True:
    events = epoll.poll()
    for fd, event in events:
        if fd == server.fileno():
            conn, addr = server.accept()
            conn.setblocking(0)
            epoll.register(conn.fileno(), select.EPOLLIN)
            connections[conn.fileno()] = conn
        elif event & select.EPOLLIN:
            conn = connections[fd]
            data = conn.recv(1024)
            if data:
                print(f'Received data: {data}')
            else:
                epoll.unregister(fd)
                conn.close()
                del connections[fd]

Using kqueue for I/O Multiplexing

import socket
import select

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)
server.bind(('localhost', 9000))
server.listen(5)

kq = select.kqueue()
kevent = select.kevent(server.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)
kq.control([kevent], 0)

connections = {}

while True:
    events = kq.control(None, 1)
    for event in events:
        if event.ident == server.fileno():
            conn, addr = server.accept()
            conn.setblocking(0)
            kevent = select.kevent(conn.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)
            kq.control([kevent], 0)
            connections[conn.fileno()] = conn
        elif event.filter == select.KQ_FILTER_READ:
            conn = connections[event.ident]
            data = conn.recv(1024)
            if data:
                print(f'Received data: {data}')
            else:
                kevent = select.kevent(conn.fileno(), filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)
                kq.control([kevent], 0)
                conn.close()
                del connections[event.ident]

Real-World Use Case

Chat Server

import socket
import select

def chat_server():
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setblocking(0)
    server.bind(('localhost', 9000))
    server.listen(5)

    inputs = [server]
    outputs = []
    message_queues = {}

    while inputs:
        readable, writable, exceptional = select.select(inputs, outputs, inputs)

        for s in readable:
            if s is server:
                conn, addr = s.accept()
                print(f'New connection from {addr}')
                conn.setblocking(0)
                inputs.append(conn)
                message_queues[conn] = []
            else:
                data = s.recv(1024)
                if data:
                    message_queues[s].append(data)
                    if s not in outputs:
                        outputs.append(s)
                else:
                    if s in outputs:
                        outputs.remove(s)
                    inputs.remove(s)
                    s.close()
                    del message_queues[s]

        for s in writable:
            try:
                next_msg = message_queues[s].pop(0)
            except IndexError:
                outputs.remove(s)
            else:
                s.send(next_msg)

        for s in exceptional:
            inputs.remove(s)
            if s in outputs:
                outputs.remove(s)
            s.close()
            del message_queues[s]

if __name__ == '__main__':
    chat_server()

Conclusion

The select module in Python is used for managing multiple I/O operations. It provides several mechanisms (select, poll, epoll, kqueue) to efficiently monitor file descriptors for I/O events, making it essential for building high-performance networked applications.

References

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare