Skip to content

Bad performance of asyncio.loop.sendfile() fallback #152074

Description

@tarasko

Bug report

Bug description:

loop.sock_sendfile() fallback uses constants.SENDFILE_FALLBACK_READBUFFER_SIZE and reads 256 KiB chunks.

But loop.sendfile() fallback still reads 16 KiB chunks, because this value is just hard-coded inplace.

blocksize = min(count, 16384) if count else 16384

Since both paths offload file reads through loop.run_in_executor(), the transport fallback pays 16x more executor round trips per MiB. Reading such chunk requires transferring tasks to/from another thread and more importantly releasing GIL and reacquiring it from another thread on a non freethreaded python.

Which is quite expensive.

I stumbled upon it, while looking at codspeed fileresponse benchmarks in aiohttp.
aio-libs/aiohttp#12945

Changing asyncios fallback to aiohttps improves this particular functional test performance by

  • 62% for TLS
  • 330% for TCP

This performance improvement is only because aiohttp`s fallback uses 256 KB chunk size.

Suggestion

  • Use constants.SENDFILE_FALLBACK_READBUFFER_SIZE in _sendfile_fallback
  • Consider adding fallback_chunk_size keyword only argument to both loop.sendfile and loop.sock_sendfile, which allows to override the default value

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    performancePerformance or resource usagestdlibStandard Library Python modules in the Lib/ directorytopic-asynciotype-bugAn unexpected behavior, bug, or error
    No fields configured for issues without a type.

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions