Update AsyncSemaphore to accept initial_value parameter #738
Unanswered
charxhit
asked this question in
Potential Issue
Replies: 1 comment 3 replies
-
This is also observable with the synchronous API ( |
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I am currently working on an implementation that allows
httpx
to 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_STREAMS
to different values (or omitting it from the SETTINGS frame altogether, as RFC does not mandate its inclusion) that has to do with howhttpcore
interacts with this setting and theAsyncSemaphore
it creates to manage and limit maximum streams.Currently,
httpcore
provides a default value of 100 forMAXIMUM_CONCURRENT_STREAMS
inside 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_settings
will return a value of2**32
when asked for themax_concurrent_streams
to denote that the setting is unbounded. This value is passed to theAsyncSemaphore
class (from insideAsyncHTTP2Connection.handle_async_request
) which uses it to denote both, themax_value
and theinitial_value
for the semaphore. Since the initial value ofmax_streams
is 1, this results in2**32 - 1
calls 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
AsyncSemaphore
to accept paraminitial_value
, and pass this param with the value ofself.max_streams
when creating the semaphore, so that no calls toacquire
are required at all. Given this, I really don't understand the reasoning behind initializing theAsyncSemaphore
with 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