I'm a python beginner and taking from https://www.youtube.com/watch?v=iG6fr81xHKA&t=269s about the power of asyncio, I tried to use this example shown and repurpose it to execute 10 times. Here's a code snippet
def main(x):
print("Hello")
time.sleep(3)
print("World!")
And so I tried to do it in a asyncio fashion however it doesn't execute asynchronously.
Here's so far what I've tried. What am I doing wrong?
import time
import asyncio
async def main(x):
print(f"Starting Task {x}")
await asyncio.sleep(3)
print(f"Finished Task {x}")
async def async_io():
for i in range(10):
await main(i)
if __name__ == "__main__":
start_time = time.perf_counter()
asyncio.run(async_io())
print(f"Took {time.perf_counter() - start_time} secs")
I've also tried to use queue_task in asyncio.
Using await, by definition, waits for the task main to finish. So your code as-is is no different from the synchronous code you posted above. If you want to run them at the same time (asynchronously), while waiting for the results, you should use asyncio.gather or asyncio.wait instead.
async def async_io():
tasks = []
for i in range(10):
tasks += [main(i)]
await asyncio.gather(*tasks)
If you don't care to wait for all of the main() calls to finish, you can also just use asyncio.create_task(main(i)), which creates a Task object and schedule its execution in the background. In this case, def async_io() doesn't need to be async anymore.
Related
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 am trying to do something similar like C# ManualResetEvent but in Python.
I have attempted to do it in python but doesn't seem to work.
import asyncio
cond = asyncio.Condition()
async def main():
some_method()
cond.notify()
async def some_method():
print("Starting...")
await cond.acquire()
await cond.wait()
cond.release()
print("Finshed...")
main()
I want the some_method to start then wait until signaled to start again.
This code is not complete, first of all you need to use asyncio.run() to bootstrap the event loop - this is why your code is not running at all.
Secondly, some_method() never actually starts. You need to asynchronously start some_method() using asyncio.create_task(). When you call an "async def function" (the more correct term is coroutinefunction) it returns a coroutine object, this object needs to be driven by the event loop either by you awaiting it or using the before-mentioned function.
Your code should look more like this:
import asyncio
async def main():
cond = asyncio.Condition()
t = asyncio.create_task(some_method(cond))
# The event loop hasn't had any time to start the task
# until you await again. Sleeping for 0 seconds will let
# the event loop start the task before continuing.
await asyncio.sleep(0)
cond.notify()
# You should never really "fire and forget" tasks,
# the same way you never do with threading. Wait for
# it to complete before returning:
await t
async def some_method(cond):
print("Starting...")
await cond.acquire()
await cond.wait()
cond.release()
print("Finshed...")
asyncio.run(main())
import asyncio
import time
start = time.time()
class DMconvo:
async def feature():
print('hi')
async def two():
await asyncio.sleep(5)
print('hi again')
async def test():
await DMconvo.feature()
await DMconvo.two() # should run in background and wait 5 seconds
time.sleep(10) # should run while the previous script waits 5 seconds
asyncio.run(test())
print("--- %s seconds ---" % (time.time() - start))
I think the code is running synchronously instead of asynchronously, but I'm not sure why.
Asyncio is still synchronous when calling await. This means that the code within test() is running sequentially with DMconvo.two() waiting 5 seconds and time.sleep(10) waiting 10 seconds. Totaling 15 seconds. You could use asyncio.gather to run co-routines concurrently eg.
import asyncio
import time
start = time.time()
class DMconvo:
async def feature():
print('hi')
async def two():
await asyncio.sleep(5)
print('hi again')
async def test():
await asyncio.gather(
DMconvo.feature(),
DMconvo.two(),
asyncio.sleep(10),
)
asyncio.run(test())
print("--- %s seconds ---" % (time.time() - start))
await DMconvo.two()
time.sleep(10) # should run while the previous script waits 5 seconds
The assumption in this comment is incorrect.
time.sleep(10) is not executed until DMconvo.two() is finished.
Compared to synchronous execution, the advantage of using await is that the event loop can do other things while a task is waiting for I/O. But running a task in the background must still be done explicitly, for example by using create_task.
Furthermore, using time.sleep blocks the thread, in which also the asyncio event loop is running. To be able to sleep asynchronously, you need to use asyncio.sleep.
task = asyncio.create_task(DMconvo.two())
await asyncio.sleep(10)
await task
A more abstract and convenient approach to create and run multiple tasks concurrently is to use asyncio.gather, as shown in the answer by ThisIsHowItIs.
Using await means "Program will wait there till this asynchronous function completes"
So,
await DMconvo.two()
Will wait for 5 secs.
Remove await from here and it will run this function in background.
I'm new to Python and have code similar to the following:
import time
import asyncio
async def my_async_function(i):
print("My function {}".format(i))
async def start():
requests = []
# Create multiple requests
for i in range(5):
print("Creating request #{}".format(i))
requests.append(my_async_function(i))
# Do some additional work here
print("Begin sleep")
time.sleep(10)
print("End sleep")
# Wait for all requests to finish
return await asyncio.gather(*requests)
asyncio.run(start())
No matter how long the "additional work" takes, the requests seem to only run after "End sleep". I'm guessing asyncio.gather is what actually begins to execute them. How can I have the requests (aka my_async_function()) start immediately, do additional work, and then wait for all to complete at the end?
Edit:
Per Krumelur's comments and my own findings, the following results in what I'm looking for:
import time
import asyncio
import random
async def my_async_function(i):
print("Begin function {}".format(i))
await asyncio.sleep(int(random.random() * 10))
print("End function {}".format(i))
async def start():
requests = []
# Create multiple requests
for i in range(10):
print("Creating request #{}".format(i))
requests.append(asyncio.create_task(my_async_function(i)))
# Do some additional work here
print("Begin sleep")
await asyncio.sleep(5)
print("End sleep")
# Wait for all requests to finish
return await asyncio.gather(*requests)
asyncio.run(start())
This only works if my_async_function and the "additional work" both are awaitable so that the event loop can give each of them execution time. You need create_task (if you know it's a coroutine) or ensure_future (if it could be a coroutine or future) to allow the requests to run immediately, otherwise they still end up running only when you gather.
time.sleep() is a synchronous operation
You’ll want to use the asynchronous sleep and await it,
E.g.
await asyncio.sleep(10)
Other async code will only run when the current task yields (I.e. typically when “await”ing something).
Using async code means you have to keep using async everywhere. Async operations are meant for I/O-bound applications. If “additional work” is mainly CPU-bound, you are better off using threads (but beware the global interpreter lock!)
I want to use async in python like c# or javascript.For example I want my program not to block next codes or maybe buttons in app while sending a request.I wrote some code about that.However I dont know whether this usage is true or false.I can't understand asyncio
import asyncio
import threading
import time
async def waitForMe(name):
for i in range(5):
await asyncio.sleep(1)
print(name)
async def main():
task1 = asyncio.create_task(waitForMe("task1"))
task2 = asyncio.create_task(waitForMe("task2"))
task3 = asyncio.create_task(waitForMe("task3"))
await task1
await task2
await task3
def mfunction():
asyncio.run(main())
t1=threading.Thread(target=mfunction)
t1.start()
for i in range(3):
time.sleep(1)
print("main")
I'd really recommend this excellent asyncio walkthrough, which should answer most of your questions.
A quote from the mentioned article in the light of your code:
[...] async IO is a single-threaded, single-process design: it uses cooperative multitasking, a term that [...] gives a feeling of concurrency despite using a single thread in a single process.
If you don't want your program to block while processing (IO) requests (as stated in your question), concurrency is sufficient (and you don't need (multi)threading)!
Concurrency [...] suggests that multiple tasks have the ability to run in an overlapping manner.
I'll repeat the exact example from the mentioned article, which has a similar structure as your example:
#!/usr/bin/env python3
# countasync.py
import asyncio
async def count():
print("One")
await asyncio.sleep(1)
print("Two")
async def main():
await asyncio.gather(count(), count(), count())
if __name__ == "__main__":
import time
s = time.perf_counter()
asyncio.run(main())
elapsed = time.perf_counter() - s
print(f"{__file__} executed in {elapsed:0.2f} seconds.")
This runs as follows:
$ python3 countasync.py
One
One
One
Two
Two
Two
countasync.py executed in 1.01 seconds.
Note that this examples uses asyncio.gather to kick-off the three count() processes in a non-blocking manner. Putting three await count() statements after one another won't work.
As far as I can see, this is exactly what you are looking for. As demonstrated, you don't need threading to achieve this.