Skip to content

Reduce asyncio heapq overhead #122881

Closed as not planned
Closed as not planned
@bdraco

Description

@bdraco

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

def __lt__(self, other):

heapq.heapify(new_scheduled)

heapify

heapq.heappush(self._scheduled, timer)

heappush

handle = heapq.heappop(self._scheduled)

heappop

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

No one assigned

    Labels

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions