2121
2222# TODO: pick what public namespace to re-export this from.
2323
24+ # This is one of the few things that should unreservedly be reimplemented natively.
25+ # Atomic ops allow the design here to be lockfree.
26+ # Actually using a futex here might improve performance further, though I doubt it.
27+
28+ # We can also do a little bit better prior to making it native by only locking
29+ # if we observe multiple threads. The gain for this is minor, but not insignificant.
30+
31+ # This particular lock implementation optimizes for the uncontested lock case.
32+ # This is the most important optimization for well-designed parallel code
33+ # with fine-grained lock use. It's also barging, which is known to be better
34+ # than FIFO in the case of highly contested locks.
35+
2436
2537class AsyncLock :
2638 """An async lock that doesn't bind to an event loop."""
@@ -36,36 +48,26 @@ def __init__(self) -> None:
3648 self ._lockv : bool = False
3749 self ._internal_lock : threading .RLock = threading .RLock ()
3850
39- def __locked (self ) -> bool :
40- with self ._internal_lock :
41- return self ._lockv or (any (not w .cancelled () for w in (self ._waiters )))
42-
4351 async def __aenter__ (self ) -> None :
44- # placing the body of acquire here
45- # causes problems with eager tasks factories.
46- await self .__acquire ()
47-
48- async def __acquire (self ) -> None :
4952 with self ._internal_lock :
50- if not self .__locked () :
53+ if not self ._lockv :
5154 self ._lockv = True
5255 return
5356
5457 fut : cf .Future [None ] = cf .Future ()
5558
56- with self ._internal_lock :
57- self ._waiters .append (fut )
59+ self ._waiters .append (fut )
5860
5961 try :
6062 await asyncio .wrap_future (fut )
6163 except asyncio .CancelledError :
62- if fut .done () and not fut .cancelled ():
63- self ._lockv = False
64+ with self ._internal_lock :
65+ if not self ._lockv :
66+ self ._maybe_wake ()
6467 raise
6568
66- finally :
67- self ._maybe_wake ()
68- return
69+ with self ._internal_lock :
70+ self ._lockv = True
6971
7072 def _maybe_wake (self ) -> None :
7173 with self ._internal_lock :
0 commit comments