Update AsyncSemaphore to accept initial_value parameter #738
Replies: 2 comments 6 replies
-
|
This is also observable with the synchronous API ( |
Beta Was this translation helpful? Give feedback.
-
|
@charxhit you found solution to that? that issue still happens with latest httpcore. I am also trying to customize httpcore/httpcore/_sync/http2.py Lines 115 to 125 in a173552 local_settings_max_streams is 4294967297 because MAX_CONCURRENT_STREAMS was supressed. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I am currently working on an implementation that allows
httpxto expose lower-level connection details in the TLS handshake and initial HTTP/2 settings so that they can be configured by users right from the top-level API. I have most of it down, however, I ran into an issue when changing theMAX_CONCURRENT_STREAMSto different values (or omitting it from the SETTINGS frame altogether, as RFC does not mandate its inclusion) that has to do with howhttpcoreinteracts with this setting and theAsyncSemaphoreit creates to manage and limit maximum streams.Currently,
httpcoreprovides a default value of 100 forMAXIMUM_CONCURRENT_STREAMSinside methodhttpcore._async.http2.AsyncHTTP2Connection._send_connection_init. If you monkey patch it to exclude that setting from being passed, so it isn't included in the initial SETTINGS frame (as clients like Firefox do), then all requests will hang indefinitely.This is because, in the absence of a user-defined value of this setting, the
h2_state.local_settingswill return a value of2**32when asked for themax_concurrent_streamsto denote that the setting is unbounded. This value is passed to theAsyncSemaphoreclass (from insideAsyncHTTP2Connection.handle_async_request) which uses it to denote both, themax_valueand theinitial_valuefor the semaphore. Since the initial value ofmax_streamsis 1, this results in2**32 - 1calls to the semaphore'sacquire()function to synchronize the state of the semaphore with the streams available. This obviously takes quite a while to happen.The fix here is simple, allow
AsyncSemaphoreto accept paraminitial_value, and pass this param with the value ofself.max_streamswhen creating the semaphore, so that no calls toacquireare required at all. Given this, I really don't understand the reasoning behind initializing theAsyncSemaphorewith the same initial and max values. Even with the default value of 100, this logic unnecessarily requires 99 extra calls toacquire()in a frequently accessed method. Am I missing something here or was this a simple oversight? I would be happy to submit a PR to address this.Here is the reproducible example:
Beta Was this translation helpful? Give feedback.
All reactions