A callback function is called multiple times in event loop

Question:

I am trying to understand the behavior of the code below. I tried to register a callback function trampoline to be called in an event loop using asyncio module. The trampoline got itself is called multiple times, which I am sure why that happened please. My expectation was the callback trampoline will call itself only once later after 0.5 seconds?

import asyncio
import datetime

loop = asyncio.get_event_loop()

def print_date():
    print(datetime.datetime.now())

def trampoline(name: str = "") -> None:
    print("name:", end=" ")
    print_date()
    loop.call_later(0.5, trampoline, name)

loop.call_soon(trampoline())
loop.call_later(8, loop.stop)
loop.run_forever()

Output: I also have an exception, which also I am not sure about:

name: 2022-11-11 16:29:04.335313
Exception in callback None()
handle: <Handle>
Traceback (most recent call last):
  File "C:Anaconda3libasyncioevents.py", line 81, in _run
    self._context.run(self._callback, *self._args)
TypeError: 'NoneType' object is not callable
name: 2022-11-11 16:29:04.850481
name: 2022-11-11 16:29:05.363303
name: 2022-11-11 16:29:05.872649
name: 2022-11-11 16:29:06.383004
name: 2022-11-11 16:29:06.898766
name: 2022-11-11 16:29:07.413907
name: 2022-11-11 16:29:07.915795
name: 2022-11-11 16:29:08.428609
name: 2022-11-11 16:29:08.939604
name: 2022-11-11 16:29:09.454111
name: 2022-11-11 16:29:09.966438
name: 2022-11-11 16:29:10.470832
name: 2022-11-11 16:29:10.981675
name: 2022-11-11 16:29:11.496746
name: 2022-11-11 16:29:12.011841

Process finished with exit code 0
Asked By: Avv

||

Answers:

The issue is that trampoline schedules a callback to itself when called.

That means that trampoline will be called after 0.5 seconds, rescheduling again a callback to itself for 0.5 seconds later

To have it only called once, you should remove .call_later from inside trampoline and move it outside:

...
def trampoline(name: str = "") -> None:
    print("name:", end=" ")
    print_date()

loop.call_later(0.5, trampoline)
...

The exception is due to calling .call_soon with trampoline() (the return value: None) instead of trampoline (the function itself)

Answered By: Pignotto
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.