Uvicorn: WSGI interface: reading request body is O(n^2) wrt payload size

Created on 30 Jun 2020  路  2Comments  路  Source: encode/uvicorn

Hello!
This is related to https://github.com/encode/uvicorn/issues/371 and potentially a duplicate/complementary information, feel free to close if it is deemed to be the case.

I was fooling around with different WSGI and ASGI servers while hacking on a web framework that would support both in the future.

As noted in https://github.com/encode/uvicorn/issues/371, this is indeed a very inefficient scenario, however, what is worse, I found out the time required to turn around the request is at least O(n^2) or worse wrt the payload size.

POSTing some files and multipart forms with curl:

Payload size: 94171344
real    0m5.763s
user    0m0.033s
sys 0m0.012s

```
Payload size: 186054864
real 0m24.183s
user 0m0.018s
sys 0m0.061s


Payload size: 372178858
real 1m37.760s
user 0m0.044s
sys 0m0.152s

So it is not just inefficient loading everything into memory, but something else is going on.

Test case used:
```python
def app(environ, start_response):
    status = '200 OK'  # HTTP Status
    headers = [('Content-type', 'text/plain')]  # HTTP Headers
    start_response(status, headers)

    stream = environ['wsgi.input']
    length = 0
    while True:
        chunk = stream.read(8192)
        if not chunk:
            break
        length += len(chunk)

    resp = "Payload size: {}".format(length)
    return [resp.encode()]

Running uvicorn==0.11.5 as uvicorn --interface wsgi simple_reader:app.

Most helpful comment

The issue most probably lies in bytestring concatenation: https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/wsgi.py#L85
chunks.append(chunk)... b''.join(chunks), accumulating in a BytesIO, bytearray_var += ... should all work O(n).

All 2 comments

The issue most probably lies in bytestring concatenation: https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/wsgi.py#L85
chunks.append(chunk)... b''.join(chunks), accumulating in a BytesIO, bytearray_var += ... should all work O(n).

Maybe you can try https://github.com/abersheeran/a2wsgi
It works very well on our production program.

Was this page helpful?
0 / 5 - 0 ratings