Skip to content
Snippets Groups Projects
Unverified Commit 68c46ae6 authored by Cyker Way's avatar Cyker Way Committed by GitHub
Browse files

gh-97545: Make Semaphore run faster. (#97549)

parent d68c37c0
Branches
Tags
No related merge requests found
...@@ -356,8 +356,9 @@ def __repr__(self): ...@@ -356,8 +356,9 @@ def __repr__(self):
return f'<{res[1:-1]} [{extra}]>' return f'<{res[1:-1]} [{extra}]>'
def locked(self): def locked(self):
"""Returns True if semaphore counter is zero.""" """Returns True if semaphore cannot be acquired immediately."""
return self._value == 0 return self._value == 0 or (
any(not w.cancelled() for w in (self._waiters or ())))
async def acquire(self): async def acquire(self):
"""Acquire a semaphore. """Acquire a semaphore.
...@@ -368,8 +369,7 @@ async def acquire(self): ...@@ -368,8 +369,7 @@ async def acquire(self):
called release() to make it larger than 0, and then return called release() to make it larger than 0, and then return
True. True.
""" """
if (not self.locked() and (self._waiters is None or if not self.locked():
all(w.cancelled() for w in self._waiters))):
self._value -= 1 self._value -= 1
return True return True
...@@ -387,13 +387,13 @@ async def acquire(self): ...@@ -387,13 +387,13 @@ async def acquire(self):
finally: finally:
self._waiters.remove(fut) self._waiters.remove(fut)
except exceptions.CancelledError: except exceptions.CancelledError:
if not self.locked(): if not fut.cancelled():
self._wake_up_first() self._value += 1
self._wake_up_next()
raise raise
self._value -= 1 if self._value > 0:
if not self.locked(): self._wake_up_next()
self._wake_up_first()
return True return True
def release(self): def release(self):
...@@ -403,22 +403,18 @@ def release(self): ...@@ -403,22 +403,18 @@ def release(self):
become larger than zero again, wake up that coroutine. become larger than zero again, wake up that coroutine.
""" """
self._value += 1 self._value += 1
self._wake_up_first() self._wake_up_next()
def _wake_up_first(self): def _wake_up_next(self):
"""Wake up the first waiter if it isn't done.""" """Wake up the first waiter that isn't done."""
if not self._waiters: if not self._waiters:
return return
try:
fut = next(iter(self._waiters))
except StopIteration:
return
# .done() necessarily means that a waiter will wake up later on and for fut in self._waiters:
# either take the lock, or, if it was cancelled and lock wasn't
# taken already, will hit this again and wake up a new waiter.
if not fut.done(): if not fut.done():
self._value -= 1
fut.set_result(True) fut.set_result(True)
return
class BoundedSemaphore(Semaphore): class BoundedSemaphore(Semaphore):
......
...@@ -844,9 +844,8 @@ async def c4(result): ...@@ -844,9 +844,8 @@ async def c4(result):
sem.release() sem.release()
sem.release() sem.release()
self.assertEqual(2, sem._value) self.assertEqual(0, sem._value)
await asyncio.sleep(0)
await asyncio.sleep(0) await asyncio.sleep(0)
self.assertEqual(0, sem._value) self.assertEqual(0, sem._value)
self.assertEqual(3, len(result)) self.assertEqual(3, len(result))
......
Make Semaphore run faster.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment