Improve FileResponse performance by always using aiohttp's sendfile fallback if native sendfile is not available#12945
Conversation
…ble for transport
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #12945 +/- ##
=======================================
Coverage 98.95% 98.95%
=======================================
Files 131 131
Lines 47998 48002 +4
Branches 2494 2495 +1
=======================================
+ Hits 47498 47502 +4
Misses 376 376
Partials 124 124
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Merging this PR will improve performance by ×2.1
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | test_simple_web_file_sendfile_fallback_response[tcp-large] |
128.5 ms | 38.8 ms | ×3.3 |
| ⚡ | test_simple_web_file_response[ssl-large] |
243.8 ms | 149.7 ms | +62.85% |
| ⚡ | test_simple_web_file_sendfile_fallback_response[ssl-large] |
243 ms | 149.9 ms | +62.15% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing tarasko:feature/sendfile_fallback_opt (1804c99) with master (db5c238)
Footnotes
-
83 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
for more information, see https://pre-commit.ci
Is it possible that the aiohttp version can be upstreamed into asyncio? |
It is all about chunk size, not the implementation itself. I'll open an issue there. I guess they would need to add a new argument The change is rather trivial, but probably, wouldn't be available before 3.16, The thing is, even with 3.16 this wouldn't let to remove |
I made a curious finding while looking at
sendfilebenchmarks.aiohttp's
_sendfile_fallbackis much more efficient than asyncio'sloop.sendfilefallback mode for large files.Unfortunately, I had to use a non-public asyncio API to reliably detect when loop provides native sendfile.
Just reject this PR if you are not comfortable with it.
What do these changes do?
Make aiohttp to use its own sendfile fallback instead of loop fallback when native sendfile is not available for the transport.
aiohttp version of
_sendfile_fallbackis much more efficient and agile than asyncio's fallback.Both implementations use another thread to read chunks:
Because of the GIL and time it takes to transfer task to/from another thread it is much more efficient to do it with bigger chunk size.
asyncio has hardcoded chunk size of 16 Kb
aiohttp chunk size is 256 Kb by default and can be adjusted.
Are there changes in behavior for the user?
No
Is it a substantial burden for the maintainers to support this?
No, aiohttp _sendfile_fallback is currently used anyway if compression is enabled, or with uvloop SSL transports.
Related issue number
Checklist
CONTRIBUTORS.txtCHANGES/folder