Python 3.7: Asynchronous Server Objects

Have you heard of asynchronous programming? Are you curious to know more about it and how you can use it in your work? Perhaps you’ve even tried to write threaded programs and run into some issues. If you’re looking to understand how to use async features in Python 3.7, then you’ve come to the right place.
All of the example code in this article have been tested with Python 3.7.2. You can grab a copy to follow along by clicking the link below:
Understanding Asynchronous Programming
A synchronous program is executed one step at a time. Even with conditional branching, loops and function calls, you can still think about the code in terms of taking one execution step at a time. When each step is complete, the program moves on to the next one.
Here are two examples of programs that work this way:

Batch processing programs are often created as synchronous programs. You get some input, process it, and create some output. Steps follow one after the other until the program reaches the desired output. The program only needs to pay attention to the steps and their order.

Command-line programs are small, quick processes that run in a terminal. These scripts are used to create something, transform one thing into something else, generate a report, or perhaps list out some data. This can be expressed as a series of program steps that are executed sequentially until the program is done.

An asynchronous program behaves differently. It still takes one execution step at a time. The difference is that the system may not wait for an execution step to be completed before moving on to the next one.
This means that the program will move on to future execution steps even though a previous step hasn’t yet finished and is still running elsewhere. This also means that the program knows what to do when a previous step does finish running.
Why would you want to write a program in this manner? The rest of this article will help you answer that question and give you the tools you need to elegantly solve interesting asynchronous problems.
Building a Synchronous Web Server
A web server’s basic unit of work is, more or less, the same as batch processing. The server will get some input, process it, and create the output. Written as a synchronous program, this would create a working web server.
It would also be an absolutely terrible web server.
Why? In this case, one unit of work (input, process, output) is not the only purpose. The real purpose is to handle hundreds or even thousands of units of work as quickly as possible. This can happen over long periods of time, and several work coming in all at once.

Can a synchronous web server be made better? Sure, you could optimize the execution steps so that all the work coming in is handled as quickly as possible. Unfortunately, there are limitations to this approach. The result could be a web server that doesn’t respond fast enough or can’t handle many requests at once.

 

In contrast, an asynchronous web server is designed to handle multiple requests simultaneously by executing them in parallel without blocking resources. This allows for faster response times and better resource utilization. Asynchronous programming can be used to create a non-blocking I/O system that enables the server to process incoming requests quickly and efficiently, even when there are many concurrent connections.

To illustrate this concept, let’s compare two web servers: one synchronous and one asynchronous. The synchronous server executes each request sequentially, waiting for input from the client before moving on to the next step in the process. This can result in long wait times for clients and slow response times overall.
The asynchronous server, on the other hand, uses a non-blocking I/O system that allows it to handle multiple requests simultaneously without blocking resources. When a request is received, the server creates a new task or thread to process it independently of any other tasks currently running. This enables faster response times and better resource utilization overall.
In terms of code implementation, an asynchronous web server can be built using Python’s asyncio library. The following example demonstrates how to create a simple HTTP server that handles multiple requests simultaneously:

# This script creates a simple HTTP server that handles multiple requests simultaneously using Python's asyncio library.

# Import necessary libraries
import http.server # Importing the http.server module to create a HTTP server
from urllib.parse import urlparse # Importing the urlparse function from the urllib.parse module to parse the request path
import asyncio # Importing the asyncio library to enable asynchronous operations

# Define a class for handling HTTP requests
class MyHandler(http.server.BaseHTTPRequestHandler):
    # Define a method for handling GET requests
    def do_GET(self):
        # Parse the request path
        parsed = urlparse(self.path)
        # Check if the path is '/'
        if parsed.path == '/':
            # Send a successful response with a status code of 200
            self.send_response(200)
            # Set the content type header to 'text/plain'
            self.send_header('Content-type', 'text/plain')
            # End the headers
            self.end_headers()
            # Write the response body
            self.wfile.write(b'Hello, world!\n')
        # If the path is not '/', send a 404 error
        else:
            # Send a 404 error response
            self.send_error(404)
            # End the headers
            self.end_headers()
            # Write the response body
            self.wfile.write(b'Not Found\n')

# Create an instance of the MyHandler class
handler = MyHandler
# Set the server address to listen on all available interfaces on port 8000
address = ('', 8000)
# Create an instance of the HTTPServer class with the specified address and handler
server = http.server.HTTPServer(address, handler)
# Get the event loop for the current thread
loop = asyncio.get_event_loop()
# Run the server indefinitely using the event loop
loop.run_until_complete(server.serve_forever())

In this example, the server uses Python’s built-in HTTP server as a base class for handling requests. The `do_GET` method is overridden to handle GET requests and return a simple response. When the server starts running, it creates an event loop using asyncio and runs until the server is stopped (using `server.serve_forever()`)

In terms of performance, asynchronous programming can significantly improve web server response times by handling multiple requests simultaneously without blocking resources. This is particularly useful for high-traffic websites or applications that require fast and efficient processing of incoming data. Asynchronous frameworks like AIOHTTP are designed to handle large sets of concurrent connections using Python’s asyncio library, which allows for faster execution speeds and better resource utilization overall.

In addition to improved performance, asynchronous programming can also provide other benefits such as increased scalability, reduced memory usage, and simplified code structure. By handling multiple requests simultaneously without blocking resources, asynchronous frameworks like AIOHTTP can handle a larger number of concurrent connections with fewer system resources than traditional synchronous web servers. This is particularly useful for resource-constrained environments or applications that require high levels of scalability and performance.

Overall, the use of asynchronous programming in Python 3.7 provides developers with powerful tools to create efficient and scalable web server solutions that can handle large sets of concurrent connections without sacrificing performance or resource utilization. By leveraging frameworks like AIOHTTP, developers can build high-performance web servers that are capable of handling thousands of requests simultaneously while maintaining fast response times and low memory usage.

SICORPS