4

I am going to create web server which could receive a lot of connections. These 10000 connected users will send to server numbers and server will return these squared numbers to users back. 10000 connections are too many and asynchronous approach is appropriate here. I found two libraries for Python 3.4 which can help:

socketserver & asyncio

With socketserver library we can use ThreadingMixIn and ForkingMixIn classes as async handlers. But this is restricted by number of cores. On the other hand we have asyncio library. And I don't understand how exactly does it works. Which one should I use? And could these two libraries work together?

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
goodgrief
  • 378
  • 1
  • 8
  • 23

1 Answers1

8

There are different approaches to asynchronous programming.

The first approach is to monitor IO operations using threads, and manage those operations in a non-blocking manner. This is what SocketServer does.

The second approach is to monitor IO operations in the main thread using an event loop and a selector. This is usually what people mean when they talk about asynchronous programming, and that's what asyncio, twisted and gevent do.

The single-threaded approach has two advantages:

  • it limits the risk of race condition since the callbacks are running in the same thread
  • it gets rid of the overhead of creating one thread per client (see the 10K problem)

Here is an example of an asyncio TCP server. In your case, simply replace the handle_echo coroutine with your own implementation:

async def handle_client(reader, writer):
    data = await reader.readline()
    result = int(data.decode().strip()) ** 2
    writer.write(str(result)).encode())
    writer.close()

It should easily be able to handle thousands of clients.

Vincent
  • 12,919
  • 1
  • 42
  • 64
  • You mentioned the [selectors](https://docs.python.org/3/library/selectors.html) module. What is the advantage of using selectors directly for the socket server, as in the example they show in the link? – Jay Jun 15 '20 at 06:32
  • 1
    @Jay The [example](https://docs.python.org/3/library/selectors.html#examples) you mentioned is interesting in the sense that it shows how one can write a TCP server that serves multiple clients concurrently in a single thread using a selector and some callbacks. In practice, it's much easier to use asyncio as shown in this [other example of TCP server](https://docs.python.org/3/library/asyncio-stream.html#tcp-echo-server-using-streams). – Vincent Jun 15 '20 at 07:39
  • So asyncio implements something like that under the hood? Does this mean selectors is faster since it's on a lower layer of abstraction? – Jay Jun 15 '20 at 10:33
  • @Jay [Yes it does](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.SelectorEventLoop). But the bare selector approach is not necessarily faster for such programs as most of the time is usually spent waiting for IO. Plus, you could still plug [uvloop](https://github.com/MagicStack/uvloop) into asyncio for better performance. – Vincent Jun 15 '20 at 12:39