tarasko · GitHub

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

Read the original on github.com ↗