-
-
Notifications
You must be signed in to change notification settings - Fork 33.6k
Description
Feature or enhancement
Proposal:
The heapq calls in base_events.py represents quite a bit of asyncio scheduling overhead because they have to run __lt__ quite often in TimerHandle
Line 128 in 0fd97e4
| def __lt__(self, other): |
cpython/Lib/asyncio/base_events.py
Line 1968 in 0fd97e4
| heapq.heapify(new_scheduled) |
cpython/Lib/asyncio/base_events.py
Line 815 in 0fd97e4
| heapq.heappush(self._scheduled, timer) |
cpython/Lib/asyncio/base_events.py
Line 1975 in 0fd97e4
| handle = heapq.heappop(self._scheduled) |
Avoiding running __lt__ can speed up processing call_ats by ~10%
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
Wrapping TimerHandle in a tuple starting with when avoids the __lt__ call. Thank you to whoever wrote the heapq docs for help getting there https://docs.python.org/3/library/heapq.html#basic-examples
6f80b4c
Example benchmark
from asyncio import TimerHandle
import heapq
import timeit
def callback():
"""This is the callback function that will be called when the timer expires."""
class MockLoop:
def get_debug(self):
return False
loop = MockLoop()
def heap_tuple():
scheduled = []
when = 1
for _ in range(100):
when += 1
handle = TimerHandle(when, callback, (), loop)
heapq.heappush(scheduled, (when, handle))
while scheduled:
when, handle = heapq.heappop(scheduled)
def heap_handle():
scheduled = []
when = 1
for _ in range(100):
when += 1
handle = TimerHandle(when, callback, (), loop)
heapq.heappush(scheduled, handle)
while scheduled:
handle = heapq.heappop(scheduled)
print("wrap when, TimerHandle in tuple", timeit.timeit(heap_tuple))
print("bare TimerHandle", timeit.timeit(heap_handle))% python3 bench/timer_handle_heap.py
wrap when, TimerHandle in tuple 34.082984749999014
bare TimerHandle 49.678519583001616
Linked PRs
Metadata
Metadata
Assignees
Labels
Projects
Status