aio-libs / aio-libs/aiohttp

Streams reorganization

Đang mở
#3,440 2 bình luận 1 reaction 0 người được giao Xem trên GitHub
enhancement need pull request
Ngôn ngữ chính
Python
Star
16.5k
Fork
2.4k
Merge trung bình
17 giờ 22 phút
Pull request đã merge (30 ngày)
212

Mô tả

I'd like to share my thoughts about streams architecture.

Current state
------------------

Now we have a `StreamReader` class.
`ClientSession` has an `auto_compress` parameter for optional disabling a stream compression (gzip, deflate etc.)

WebSockets have own buffer implementation for reading a data from a stream.

Proposal
---------------

Let's use `StreamReader` for everything.
On the bottom, there is a `raw` stream which is a good data source for both zgipped content and websockets data.
Unzipper provides an own class that is a wrapper around a raw stream. Unzipper's `.read()` calls `raw.read()` and pass the given data chunks into decompressor.
Websocket reader does the same.

The raw stream becomes the only TCP flow control aware structure, all descendants just use it.
Raw -> Unzipped
Raw -> WebSocket

The raw stream is accessible from Unzipped stream by it's `.raw` attribute. Something like [`io.BufferedIOBase.raw`](https://docs.python.org/3/library/io.html#io.BufferedIOBase.raw)

I believe the proposal simplifies the design.

Optimizations
-------------------

Since asyncio 3.7 we have an advanced [`BufferedProtocol`](https://docs.python.org/3/library/asyncio-protocol.html#buffered-streaming-protocols) (old good `asyncio.Protocol` for old Python's can be supported easily on top of it, the price is more memory copy operations).

For reducing mem-copy `BufferedProtocol` *should* use mem structures like Linux Kernel [SLAB allocators](https://en.wikibooks.org/wiki/The_Linux_Kernel/Memory#Slab_Allocator), the protocol was *designed* for it.
A simplified idea is:
- Allocate a large memory page (4Kb or more, we can start from a simple scenario but optimize an allocator for 4MB data chunks later)
- Fetch a data chunk into an allocated page
- Free a page when all page's data is consumed by a raw `StreamReader`

P.S.
IIRC `nginx` uses an interesting custom allocator strategy: it has a memory context tightly coupled with HTTP request. The memory is never released until the request is gone, then all memory allocated by the request processing goes away. We cannot steal the NGINX memory strategy as-is: a lot of Python objects are created an released during HTTP request life-cycle but we can optimize at least `StreamReader` implementation for this case.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.