asynchronous-python

Explore async Python concepts with code examples and tutorials. Covers asyncio and Python features. Let's learn together!

Web Applications

ASGI vs. WSGI: Understanding the differences and benefits

WSGI and Gunicorn

WSGI stands for web server gateway interface. As the official documentation of WSGI indicates, it has created standard interface between web servers and python applications (or frameworks). By web server, we mean software and its underlying hardware that accepts requests via HTTP/HTTPS protocol, e.g. Nginx and Apache.

Gunicorn is a Python WSGI HTTP server which is known for running Python applications synchronously by default. Let’s see an example of Gunicorn from its official document.

# ex_7_1
def app(environ, start_response):
    """Simplest possible application object"""
    data = b'Hello, World!\n'
    status = '200 OK'
    response_headers = [
        ('Content-type', 'text/plain'),
        ('Content-Length', str(len(data)))
    ]
    start_response(status, response_headers)
    return iter([data])

In order to run this app, this command can be used:

$ gunicorn --workers=2 --worker_class='sync' ex_7_1:app

workers is an important parameter in gunicorn, which is the number of worker processes for handling requests. 2-4 times the number of cores is doc’s suggestion.

worker_class parameter determines different modes of workers, which is sync by default. There are other modes e.g. gevent and eventlet are asynchronous workers.

Moreover, you’ve to consider that Gunicorn only supports HTTP/1.1.

ASGI and Uvicorn

ASGI (Asynchronous Server Gateway Interface) is a spiritual successor to WSGI, intended to provide a standard interface between async-capable Python applications and web server. It also supports HTTP/1.1, HTTP/2 and websocket connection.

Uvicorn is an ASGI web server implementation for Python. Uvicorn uses the ASGI specification for interacting with an application.

Let’s see an example of python application which runs with uvicorn from official document:

# ex_7_2
async def app(scope, receive, send):
    assert scope['type'] == 'http'

    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [
            [b'content-type', b'text/plain'],
        ],
    })
    await send({
        'type': 'http.response.body',
        'body': b'Hello, world!',
    })

You can find the meaning of each scope, receive and send here.

In order to run this app, use the command below:

uvicorn ex_7_2:app

To know about additional parameters to pass, this link is helpful.

Building RESTful APIs with async Python: Introduction to Starlette microframework

As described here, a RESTful API is an Application Programming Interface (API) that uses the Representational State Transfer (REST) architectural style for its implementation. Statelessness is one of its main characteristics.

Well-known FastAPI is an API microframework and uses Starlette internally. FastAPI has more features built on top of Starlette for creating APIs e.g. data validation and serialization, swagger documentation, …

Let’s see an example from Starlette documentation:

# ex_7_3
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route


async def homepage(request):
    return JSONResponse({'hello': 'world'})


app = Starlette(debug=True, routes=[
    Route('/', homepage),
])

And then run application with Uvicorn with 4 workers. Consider that ex_7_3 is our python file name.

uvicorn ex_7_3:app --workers 4