From aa1cf812b34cb5f30348c257e9e27023979ba20d Mon Sep 17 00:00:00 2001 From: Cyker Way Date: Sun, 25 Sep 2022 23:04:55 +0000 Subject: [PATCH 1/2] Make Semaphore run faster. --- Lib/asyncio/locks.py | 38 +++++++++++++---------------- Lib/test/test_asyncio/test_locks.py | 3 +-- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py index e86d11deb47646..ce5d8d5bfb2e81 100644 --- a/Lib/asyncio/locks.py +++ b/Lib/asyncio/locks.py @@ -356,8 +356,9 @@ def __repr__(self): return f'<{res[1:-1]} [{extra}]>' def locked(self): - """Returns True if semaphore counter is zero.""" - return self._value == 0 + """Returns True if semaphore cannot be acquired immediately.""" + return self._value == 0 or ( + any(not w.cancelled() for w in (self._waiters or ()))) async def acquire(self): """Acquire a semaphore. @@ -368,8 +369,7 @@ async def acquire(self): called release() to make it larger than 0, and then return True. """ - if (not self.locked() and (self._waiters is None or - all(w.cancelled() for w in self._waiters))): + if not self.locked(): self._value -= 1 return True @@ -387,13 +387,13 @@ async def acquire(self): finally: self._waiters.remove(fut) except exceptions.CancelledError: - if not self.locked(): - self._wake_up_first() + if not fut.cancelled(): + self._value += 1 + self._wake_up_next() raise - self._value -= 1 - if not self.locked(): - self._wake_up_first() + if self._value > 0: + self._wake_up_next() return True def release(self): @@ -403,22 +403,18 @@ def release(self): become larger than zero again, wake up that coroutine. """ self._value += 1 - self._wake_up_first() + self._wake_up_next() - def _wake_up_first(self): - """Wake up the first waiter if it isn't done.""" + def _wake_up_next(self): + """Wake up the first waiter that isn't done.""" if not self._waiters: return - try: - fut = next(iter(self._waiters)) - except StopIteration: - return - # .done() necessarily means that a waiter will wake up later on and - # 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(): - fut.set_result(True) + for fut in self._waiters: + if not fut.done(): + self._value -= 1 + fut.set_result(True) + return class BoundedSemaphore(Semaphore): diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py index 1eb25e787576c6..f6c6a282429a21 100644 --- a/Lib/test/test_asyncio/test_locks.py +++ b/Lib/test/test_asyncio/test_locks.py @@ -844,9 +844,8 @@ async def c4(result): sem.release() sem.release() - self.assertEqual(2, sem._value) + self.assertEqual(0, sem._value) - await asyncio.sleep(0) await asyncio.sleep(0) self.assertEqual(0, sem._value) self.assertEqual(3, len(result)) From 6d74cbc5521fb05b0ab01f82a280c727d239fb03 Mon Sep 17 00:00:00 2001 From: Cyker Way Date: Sun, 25 Sep 2022 23:25:18 +0000 Subject: [PATCH 2/2] Add `Misc/NEWS.d`. --- .../next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst diff --git a/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst b/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst new file mode 100644 index 00000000000000..a53902ea670b73 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-25-23-24-52.gh-issue-97545.HZLSNt.rst @@ -0,0 +1 @@ +Make Semaphore run faster.