Python run 2 async infinite loops after the first one already started - python

I want to run 2 infinite async loops that should run simultanoesly.
However though, they are not called together.
The first loop starts running immediately and when it detects something it calls the second loop and they should run independently.
Something like this:
async def test():
while True:
print("test")
time.sleep(7)
async def call_test():
loopd = asyncio.get_running_loop()
task = loopd.create_task(test())
await task
async def print_main():
while True:
print("main")
await call_test()
time.sleep(5)
def main():
loop = asyncio.get_event_loop()
loop.create_task(print_main())
loop.run_forever()
if __name__ == '__main__':
main()
PS:
There are a lot of similar questions, but they all run 2 independent loops from the start.

You should not use time.sleep with asyncio loop in the same thread, otherwise time.sleep will block all other tasks of the asyncio loop.
You need only one asyncio loop in one thread, because only one loop can do work simultaneously in the same thread.
Your code will work with the following changes:
import asyncio
async def test():
while True:
print("test")
await asyncio.sleep(7)
async def print_main():
another_task = None
while True:
print("main")
if another_task is None:
another_task = asyncio.create_task(test())
await asyncio.sleep(5)
def main():
loop = asyncio.get_event_loop()
loop.create_task(print_main())
loop.run_forever()
if __name__ == '__main__':
main()

Related

Python asyncio listener loop doesn't run using idle main loop

I have a "listener" loop that constantly watches for items to process from an asyncio queue. This loop runs in a part of the application that is not using asyncio, so I've been trying to set up a passive asyncio main loop that the listener can be transferred to as needed. The listener is started and stopped as needed per input from the user.
For some reason the code below never results in the listener() actually running (i.e. print("Listener Running") is never printed). start_IOLoop_thread is run at startup of the application.
Can anyone point out what the problem is with this setup? Please let me know if more info is needed.
Edit: replaced code with a runnable example per the comments:
import asyncio
import threading
from asyncio.queues import Queue
import time
class Client:
def __init__(self):
self.streamQ = Queue()
self.loop = None
self.start_IOLoop_thread()
self.stream_listener()
def stream_listener(self):
self.streaming = True
async def listener():
print("Listener Running")
while self.streaming:
data = await self.streamQ.get()
# DEBUG
print(data)
print("Listener Stopped")
print("Starting Listener")
self.listener = asyncio.run_coroutine_threadsafe(listener(), self.loop)
def start_IOLoop_thread(self):
async def inf_loop():
# Keep the main thread alive and doing nothing
# so we can freely give it tasks as needed
while True:
await asyncio.sleep(1)
async def main():
await inf_loop()
def start_IO():
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
asyncio.run(main())
print("Main Exited")
threading.Thread(target=start_IO, daemon=True).start()
# A small delay is needed to give the loop time to initialize,
# otherwise self.loop is passed as "None"
time.sleep(0.1)
if __name__ == "__main__":
C = Client()
input("Enter to exit")
You never start the newly created loop. I adjusted to call main (although here it does nothing I assume the original code is more complex). All changes are in start_IO. Tested with python 3.10 (I think there was some change in the past regarding threads and async)
import asyncio
import threading
from asyncio.queues import Queue
import time
class Client:
def __init__(self):
self.streamQ = Queue()
self.loop = None
self.start_IOLoop_thread()
self.stream_listener()
def stream_listener(self):
self.streaming = True
async def listener():
print("Listener Running")
while self.streaming:
data = await self.streamQ.get()
# DEBUG
print(data)
print("Listener Stopped")
print("Starting Listener")
self.listener = asyncio.run_coroutine_threadsafe(listener(), self.loop)
def start_IOLoop_thread(self):
async def inf_loop():
# Keep the main thread alive and doing nothing
# so we can freely give it tasks as needed
while True:
await asyncio.sleep(1)
async def main():
await inf_loop()
def start_IO():
self.loop = asyncio.new_event_loop()
self.loop.create_task(main())
asyncio.set_event_loop(self.loop)
self.loop.run_forever()
print("Main Exited")
threading.Thread(target=start_IO, daemon=True).start()
# A small delay is needed to give the loop time to initialize,
# otherwise self.loop is passed as "None"
time.sleep(0.1)
if __name__ == "__main__":
C = Client()
input("Enter to exit")

How to make async code run on startup - Python

Heyy,
how would I make my asynchronous code run on startup?
So this is the easiest example I could think of to make.
async def mainMenuCLI():
print("This is the CLI")
And I want the asynchronous mainMenuCLI to run on startup but I don't want it to take as many tasks because I'm not sure what is the max :(
I need it to be async because of async_input, discord.py and stuff, just don't tell me to make it sync, thanks!
If I understand your question... Do you need something likethis?
import asyncio
async def async_example():
print("hellooooo, I'm an async function")
async def main():
asyncio.Task(async_example())
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
You can add some tasks outside the async func if you need:
import asyncio
async def async_example():
print("hellooooo, I'm an async function")
await asyncio.sleep(1)
print("async function done")
async def main():
asyncio.Task(async_example())
print('This is before wait')
await asyncio.sleep(1)
print('This is after await')
await asyncio.sleep(1)
print('Ok, goodbye')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
*Note: if your py version is prior to 3.7, change asyncio.Task per asyncio.ensure_future.

How to use python async task without await

I use async create_task to run my task in background, but my_task() method not be executed.
async def my_task():
print("starting my task...")
time.sleep(2)
print("finished my task.")
if __name__ == '__main__':
print("1111")
loop = asyncio.get_event_loop()
loop.create_task(my_task())
print("2222")
the result is
1111
2222
There is a simple fix for this, but you still need to use await which you cannot avoid because create tasks returns a coroutine
import asyncio
async def my_task():
print("starting my task...")
await asyncio.sleep(2)
print("finished my task.")
if __name__ == '__main__':
print("1111")
loop = asyncio.get_event_loop()
loop.run_until_complete(my_task())
# or use can use asyncio.run(my_task())
print("2222")
EDIT: Made changes for pyfile, instead of notebook, thanks user4815162342 for pointing out

python Make an async timer without waiting to finish

I want to make a timer which is started in a normal function, but in the timer function, it should be able to call an async function
I want to do something like this:
startTimer()
while True:
print("e")
def startTimer(waitForSeconds: int):
# Wait for `waitForSeconds`
await myAsyncFunc()
async def myAsyncFunc():
print("in my async func")
Where the while True loop should do its stuff and after waitForSeconds the timer the async function should execute an other async function, but waiting shouldn't block any other actions and doesn't need to be awaited
If something isn't understandable, I'm sorry, I'll try to explain it then
Thanks
If you want to run your synchronous and asynchronous code in parallel, you will need to run one of them in a separate thread. For example:
def sync_code():
while True:
print("e")
async def start_timer(secs):
await asyncio.sleep(secs)
await async_func()
async def main():
asyncio.create_task(start_timer(1))
loop = asyncio.get_event_loop()
# use run_in_executor to run sync code in a separate thread
# while this thread runs the event loop
await loop.run_in_executor(None, sync_code)
asyncio.run(main())
If the above is not acceptable for you (e.g. because it turns the whole program into an asyncio program), you can also run the event loop in a background thread, and submit tasks to it using asyncio.run_coroutine_threadsafe. That approach would allow startTimer to have the signature (and interface) like you wanted it:
def startTimer(waitForSeconds):
loop = asyncio.new_event_loop()
threading.Thread(daemon=True, target=loop.run_forever).start()
async def sleep_and_run():
await asyncio.sleep(waitForSeconds)
await myAsyncFunc()
asyncio.run_coroutine_threadsafe(sleep_and_run(), loop)
async def myAsyncFunc():
print("in my async func")
startTimer(1)
while True:
print("e")
I'm pretty sure that you are familiar with concurent processing, but you didn't show exactly what you want. So if I understand you correctly you want to have 2 processes. First is doing only while True, and the second process is the timer(waits e.g. 5s) and it will call async task. I assume that you are using asyncio according to tags:
import asyncio
async def myAsyncFunc():
print("in my async func")
async def call_after(delay):
await asyncio.sleep(delay)
await myAsyncFunc()
async def while_true():
while True:
await asyncio.sleep(1) # sleep here to avoid to large output
print("e")
async def main():
task1 = asyncio.create_task(
while_true())
task2 = asyncio.create_task(
call_after(5))
# Wait until both tasks are completed (should take
# around 2 seconds.)
await task1
await task2
asyncio.run(main())

How to start coroutines and continue with synchronous tasks?

I am trying to understand asyncio and port my undestanding of threading. I will take the example of two threads running indefinitely and a non-threaded loop (all of them outputting to the console).
The threading version is
import threading
import time
def a():
while True:
time.sleep(1)
print('a')
def b():
while True:
time.sleep(2)
print('b')
threading.Thread(target=a).start()
threading.Thread(target=b).start()
while True:
time.sleep(3)
print('c')
I now tried to port this to asyncio based on the documentation.
Problem 1: I do not understand how to add the non-threaded task as all examples I saw show an ongoing loop at the end of the program which governs the asyncio threads.
I then wanted to have at least the two first threads (a and b) running in parallel (and, worst case, add the third c as a thread as well, abandonning the idea of mixed thread and non-threded operations):
import asyncio
import time
async def a():
while True:
await asyncio.sleep(1)
print('a')
async def b():
while True:
await asyncio.sleep(2)
print('b')
async def mainloop():
await a()
await b()
loop = asyncio.get_event_loop()
loop.run_until_complete(mainloop())
loop.close()
Problem 2: The output is a sequence of a, suggering that the b() coroutine is not called at all. Isn't await supposed to start a() and come back to the execution (and then start b())?
await stops execution at a point, you do await a(), and you have an infinite loop in a(), so it's logical b() doesn't get called. Think about it as if you insert a() in mainloop().
Consider this example:
async def main():
while True:
await asyncio.sleep(1)
print('in')
print('out (never gets printed)')
To achieve what you want you need to create a future which would manage multiple coroutines. asyncio.gather is for that.
import asyncio
async def a():
while True:
await asyncio.sleep(1)
print('a')
async def b():
while True:
await asyncio.sleep(2)
print('b')
async def main():
await asyncio.gather(a(), b())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

Categories