I want to execute multiple async functions at the same time, here is an example
import asyncio
async def sayhello():
await asyncio.sleep(5)
print("hello")
async def saybye():
print("Bye")
async def execute():
await sayhello()
await saybye()
asyncio.run(execute())
Like, i want to execute "sayhello" and "saybye" at the same time, so first is gonna say bye, wait 5 seconds, and say hello, Not wait 5 seconds and say "hello, bye"
Related
Is there a way to create a secondary asyncio loop(or prioritize an await) that when awaited does not pass control back to the main event loop buts awaits for those 'sub' functions? IE
import asyncio
async def priority1():
print("p1 before sleep")
await asyncio.sleep(11)
print("p1 after sleep")
async def priority2():
print("p2 before sleep")
await asyncio.sleep(11)
print("p2 after sleep")
async def foo():
while True:
print("foo before sleep")
#do not pass control back to main event loop here but run these 2 async
await asyncio.gather(priority1(),priority2())
print("foo after sleep")
async def bar():
while True:
print("bar before sleep")
await asyncio.sleep(5)
print("bar after sleep")
async def main():
await asyncio.gather(foo(),bar())
asyncio.run(main())
I would like foo to wait for priority1/2 to finish before passing control back to the main event loop.
Right now it would go:
foo before sleep
bar before sleep
p1 before sleep
p2 before sleep
bar after sleep
I would like to see:
foo before sleep
bar before sleep
p1 before sleep
p2 before sleep
p1 after sleep
p2 after sleep
bar after sleep
Is this possible?
thanks
It is not possible to run two event loops on the same thread. The code in asyncio and specs even look like they were thought in a way to permit that - but afterwards the API bent in a way it is no longer possible (for example, the explicit loop parameter for several of the relevant calls has been deprecated and removed)
In the same line, there is no way to prioritize a subset of tasks in the running loop. I answered a question on this line a couple weeks ago, and managed to get to a synchronization primitive to be used in place of asyncio.sleep which could take priority into account - but it requires all participating tasks to call it, so it would not be much different of a lock or something (I will link to it bellow - the idea is: your code call await custom.sleep() at certain points: it will only return when there are no other higher-prioritized tasks also calling that custom.sleep() ) -check it here: Execute asyncio task as soon as possible
When wrtting that code, I realized that it is possible to write an event loop which could take into account a "priority" attribute on tasks. But having a production-grade for this requires some non-hobby work: by using that loop, you could get what you are asking for, with no changes needed in the tasks code.
However, I think running a secondary loop in another thread, and then waiting synchronously on that thread to complete is a way to get your things accomplished.
import asyncio
import threading
def priority(func):
async def wrapper(*args, **kwargs):
result = None
def runner(*args, **kw):
nonlocal result
result = asyncio.run(func(*args, **kw))
t = threading.Thread(target=runner, args=args, kwargs=kwargs)
await asyncio.sleep(0)
t.start()
# if one wants to perform limited yields to the main loop, it should be done here
t.join()
return result
return wrapper
async def priority1():
print("p1 before sleep")
await asyncio.sleep(.11)
print("p1 after sleep")
async def priority2():
print("p2 before sleep")
await asyncio.sleep(.11)
print("p2 after sleep")
#priority
async def foo():
print("foo before sleep")
#do not pass control back to main event loop here but run these 2 async
await asyncio.gather(priority1(),priority2())
print("foo after sleep")
async def bar():
print("bar before sleep")
await asyncio.sleep(.05)
print("bar after sleep")
async def main():
await asyncio.gather(foo(),bar())
asyncio.run(main())
I'm trying to run some code asynchronously. My expectation is that the test coroutine should not block the print(running first) statement. This is because I've dispatched it to the event loop, and should be seeing the output of this command logged first.
import asyncio
async def test():
await asyncio.sleep(5)
print("I should run second")
asyncio.run(test())
print('running first')
Does anyone have any tips on how to how this code run so that print('running first') is ran before print("I should run second")? I believe this code should be non-blocking, so I'm confused as to why the order of print messages isn't matching my expectation.
I believe this is what you want:
import asyncio
async def test():
await asyncio.sleep(5)
print("I should run second")
async def main():
task1 = asyncio.create_task(test())
print('running first')
await task1
asyncio.run(main())
A more detail explaination:
asyncio.run() will try to wait all of the task inside it to finish before it continues.
In your code, you are running asyncio.run(test()) first and it will continue ONLY IF test() IS ENDED and you awaited the sleep. so test() will end after the sleep and run the print then the main print.
This is why your code delay so long before running. The solution to it is simple. Fire the task without waiting, which is what asyncio.create_task() is doing, I created a task, fire it but wait it at the end.
btw normally when you are using async, you will have a ton of task in a list. If you want to wait it as a list you should use gather():
import asyncio
async def test():
await asyncio.sleep(5)
print("I should run second")
async def main():
task_list = []
for _ in range(100):
task_list.append(asyncio.create_task(test()))
print('running first')
await asyncio.gather(*task_list)
asyncio.run(main())
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())
I was testing Python3.7 async/await functions and written simple code like this:
import asyncio
import time
async def first():
print('FIRST')
async def second():
time.sleep(2)
print('SECOND')
async def main():
asyncio.create_task(second())
asyncio.create_task(second())
asyncio.create_task(second())
asyncio.create_task(first())
asyncio.create_task(first())
asyncio.create_task(first())
asyncio.run(main())
When I run this code, it prints this:
SECOND
SECOND
SECOND
FIRST
FIRST
FIRST
Which is not what I expected. I thought FIRSTs should be printed first because they don't have delay. However, create_task waits until second() is finished before proceeding to text async task.
Is it possible to execute async tasks without making them to wait each other?
You have to use the gather() function and modify a bit your code. You also have to use the await keyword.
import asyncio
import time
async def first():
print('FIRST')
await asyncio.sleep(1)
print('SECOND')
async def main():
await asyncio.gather(first(), first(), first())
asyncio.run(main())
You can't use the time.sleep() function since it is not asynchronous, resulting in an actual sleep for the entire program. use the asyncio.sleep() function and await it so it runs asynchronously:
import asyncio
async def first():
print('FIRST')
async def second():
# The Fix:
await asyncio.sleep(2)
print('SECOND')
async def main():
await asyncio.gather(
second(),
second(),
second(),
first(),
first(),
first()
)
if __name__ == '__main__':
asyncio.run(main())
The result should be:
FIRST
FIRST
FIRST
SECOND
SECOND
SECOND
Assume the following code:
import asyncio
import time
async def say_after():
for i in range(10):
await asyncio.sleep(1)
print("first function")
async def say_after2():
for i in range(10):
await asyncio.sleep(1)
print("second function")
async def main():
await say_after()
await say_after2()
asyncio.run(main())
It would first print "first function" 10 times and after function say_after is finished then it would print "second function" 10 times. now i want to run both functions at the same time like 2 threads (like parallel) with asycio not sequential executing. how do i do it?