loop.create_task without saving a reference to the result
Hi! Thank you for your library :smiley:
I have a question about this line of code:
loop.create_task(new_coro())
I am confused that the link to the result is not saved here. Because there is a warning about this in the documentation.
Thank you in advance for your response.
Yes it's odd isn't it? I already noticed this quite a while ago. Check this out:
import gc
import asyncio
async def blah():
for i in range(20):
print(i)
await asyncio.sleep(1)
async def main():
loop = asyncio.get_running_loop()
loop.create_task(blah())
gc.collect()
await asyncio.sleep(20)
print('main done')
if __name__ == '__main__':
asyncio.run(main())
Even immediately calling gc.collect() doesn't make the referenceless task disappear. I don't know why, but if you find out I would love to know :)
Yeah, you are right - it works :) Because the ref count of the newly created task is 1.
And I think I found the reason.
- loop.create_task
- _asyncio_Task___init___impl
- task_call_step_soon
- TaskStepMethWrapper_new
- Py_INCREF
Ah interesting.
I should probably make the change to assign the result to something anyway, because you never know if a future version of python becomes more aggressive to remove garbage earlier. It just seems silly to assign to a var that isn't used.
It just seems silly to assign to a var that isn't used.
Yeah.
Maybe, we can use a dummy variable here:
_ = loop.create_task(new_coro())
Yes ofc, but I hate needing to do that 😄
Also, it's plausible in the general case that _ might get used for something else in the same scope. Maybe not this project, but as a general solution. So _ on it's own is probably not a good idea. Perhaps just background_tasks like the docs suggested.
Yes, this looks like the best solution.
P.S. I was worried about deleting the task after it's done, but it turns out there is already a solution based on add_done_callback in the documentation :smile: .