Reputation: 65
I am using Python and PyCharm, I am trying to offload database writing using asyncio
but am having trouble with IDE warnings
In my main.py I start up tasks in this manner
db_logging_monitoring_task = asyncio.create_task(start_logging_jobs_sniffer())
tasks.append(db_logging_monitoring_task)
await gather(*tasks)
where start_logging_jobs_sniffer
is a while loop inside of an async function
# Waits on jobs from a jobs_queue
async def start_logging_jobs_sniffer(self):
while True:
try:
job = await self.logging_jobs_queue.get()
# Adds jobs to a jobs_queue
async def make_logging_job(self, params):
job = self.LoggingJob(params)
await self.logging_jobs_queue.put(job)
similarly in main.py I have another background monitoring task that does polling on a 5 second interval and then logs the polling results
async def poll(self, interval: int):
if self.is_config_applied:
while True:
# ...
asyncio.create_task(make_logging_job(
params={
**self.polling_results
},
))
but pycharm throws a warning at me
Coroutine 'create_task' is not awaited
I specifically want make_logging_job
tasks to work in parallel with other tasks which is why I am not using await
, and this seems to work as expected.
If I run things with the warning present the make_logging_job
seems to be in parallel and is not blocking anything
Pretty much I don't understand why PyCharm is throwing a warning that the create_task
is not awaited, is there some other better way of making the tasks?
Saving the task to a variable suppresses the error and seems to function by running things in the background
test = asyncio.create_task(make_logging_job(
params={
**self.polling_results
},
))
but i have no idea why this helps, saving the task to a variable doesn't wait on the coroutine i assume
Upvotes: 1
Views: 459
Reputation: 110591
When you create an asyncio task, you can´t just "fire and forget" it - you have to keep a reference to it somewhere - and eventually check if it is done, so you can discard your references.
As you found out in the comments, attributing the task to a local variable is needed - but unlike your IDE reports, not enough - as in just attributing a variable and discarding it, you'd have no reference of the task.
Instead, use a container such as a set()
to store the tasks, and spawn another task which checks if they are complete, maybe using an asyncio.wait
call:
import asyncio
all_jobs = set()
async def poll(self, interval: int):
if self.is_config_applied:
while True:
# ...
all_jobs.add(asyncio.create_task(make_logging_job(
params={
**self.polling_results
},
)))
async def task_waiter():
while True:
pending, done = await asyncio.wait(all_jobs, timeout=10) # collect once each 10 seconds - change at your will
all_jobs.clear()
all_jobs.update(pending)
# and wherever in your code, where you call `poll`, instead of
# just `await poll` do:
async def main(...):
...
# await poll(...) #old code, commented out
poll_task = asyncio.create_task(poll(...))
waiter_task = asyncio.create_task(task_waiter())
await asyncio.gather(poll_task, waiter_task)
Upvotes: 1