Python AsyncIO
asyncio is a standard library introduced from Python 3.4 +, which supports async IO and coroutine.
For example: suppose there is a laundry room with 10 washing machines, and a washer is in charge of these 10 washing machines. Then the laundry is equivalent to a process and the laundryman is equivalent to a thread. If there are 10 laundrymen, it is equivalent to 10 threads. One process can open multiple threads. This is multithreading!
What about synergy? Don't worry. As we all know, washing clothes with a washing machine requires waiting time. If there are 10 washing workers and one person is responsible for one washing machine, the efficiency will certainly be improved, but don't you think it's a waste of resources? It takes 10 people to do what one person can do. Just put the clothes in and turn on the switch. There's nothing to do. Just take them out after they're washed. Even if many people come to wash clothes, one person can cope with it. Open the first washing machine, open the second washing machine while waiting, and then open the third one,... Until the clothes are washed, come back and take out the clothes, and then take another one (which one is washed first, so the process is disordered). This is the collaborative process of computer! The washing machine is the method of execution.
When the method in your program needs waiting time, you can use collaborative process, which is efficient and consumes less resources.
okay! To sum up:
Laundry = = > process
Laundryman = = > thread
Washing machine = = > method (function)
1. async await
When + async keyword is used before the function, the wrapper of the function is actually created. When this function is called, a coroutine object will actually be returned
First, use async awit normally
import asyncio async def main(): print("Hello World") print(main())
<coroutine object main at 0x7feada389ec0> RuntimeWarning: coroutine 'main' was never awaited print(main()) RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Coroutine object is different from normal function. If you want to wait for the execution result of coroutine object, you need to use keyword await to wait for the result returned by coroutine. Let's try await:
import asyncio async def main(): print("Hello World") await main()
File "/Users/xx/PycharmProjects/pythonProject/test_ansy.py", line 15 await main() ^ SyntaxError: 'await' outside function
Await can only be used in async functions. However, await needs to be used in async function, and to run async function, await needs to wait for the return result. Event loop is required
2. Event-loop
Event loop is a design pattern that waits for and distributes events or messages in a program
Python coroutine needs to run in event loop
Asyncio this package provides an asyncio The function of run can be used as the entry of coroutine, asyncio Run will create an event loop, and then execute the coroutine object passed to it on this event loop, usually asyncio The run function will only be called once in the program as the entry of coroutine
import asyncio async def main(): print("Hello World") asyncio.run(main())
Hello World
import asyncio async def main(): print("Hello World") await foo("I am foo") print("foo done") async def foo(text): print(text) # Currently, coroutine gives up running and returns after 5 seconds await asyncio.sleep(5) print("wake up") asyncio.run(main())
Hello World I am foo wake up foo done
asyncio.new_event_loop() to create a new event loop, and then through loop run_ until_ Complete () to start a coroutine
import asyncio async def main(): print("Hello World") await foo("I am foo") print("foo done") async def foo(text): print(text) await asyncio.sleep(2) print("wake up foo") loop = asyncio.new_event_loop() loop.run_until_complete(main())
Hello World I am foo wake up foo foo done
3. task
When the foo function sleep, we don't want to wait for it to end. We want to do something else during this period. You can use asyncio create_ task. asyncio. create_ Task will get the currently running event loop, and then schedule a task on this loop. This task will start running as soon as possible. Task is a future like object(Future will be mentioned later). A coroutine runs on this object. The significance of task is to let users run coroutine on event loop. So why as soon as possible? Let's look at the following example first
import asyncio async def main(): print("Hello World") task = asyncio.create_task(foo("I am foo")) print("foo done") await task async def foo(text): print(text) await asyncio.sleep(1) print("wake up") asyncio.run(main())
Hello World foo done I am foo wake up
Surprise! "Foo done" I am foo "It was printed out before. This is because the create_task only schedule d a task on the running event loop and did not start running immediately. Because the main has not suspended the execution, entered the wait, and the execution has not ended, the main will continue to execute. When the main executes the await task, the main suspends the execution, enters the wait, and the next task on the event loop will start to execute, that is It's foo. So we see "foo done" first, then "I am foo". Then foo enters sleep, pauses execution and waits, while main() is waiting for the execution result of foo. There are no other tasks to continue execution on event loop, so the program waits for the end of asyncio.sleep(1) of foo, and finally prints "wake up".
The above scheduling method is called cooperative scheduling. An event loop runs only one Task at a time. When one Task awaits another Task(Future) is completed, the current Task will temporarily stop execution and wait for the results of Future. Then event loop will let other tasks, Future callback (mentioned later), or IO start execution.
Here we will mention asyncio The definition of future.
Future
asyncio. create_ The return of task is task. The definition of task is:
asyncio.tasks class Task(Future[_T], Generic[_T])
future is
asyncio.futures class Future(Awaitable[_T], Iterable[_T])
Task inherits Future, which represents the final result of an async operation in the Future. To wait for the task to complete and return the final result, we can use the await keyword mentioned earlier, because Future is Awaitable.
import asyncio async def main(): print("Hello World") task = asyncio.create_task(foo("I am foo")) await task print("foo done") async def foo(text): print(text) await asyncio.sleep(1) print("wake up") asyncio.run(main())
Hello World I am foo wake up foo done
It can be seen here that the await task in main() makes main wait for foo execution to finish before continuing to print "foo done".
You may also want to ask, how do we get the return result of the task
import asyncio async def main(): task_foo = asyncio.create_task(foo("I am foo")) task_bar = asyncio.create_task(bar()) foo_res = await task_foo await task_bar print(foo_res) async def foo(text): print(text) await asyncio.sleep(4) print("wake up") return "returns " + text async def bar(): for i in range(10): print(i) await asyncio.sleep(1) asyncio.run(main())
I am foo 0 1 2 3 wake up 4 5 6 7 8 9 returns I am foo
res = await task allows the return value of the task to be assigned to res.
When the callback is completed, it can also be used to set the Future
import asyncio async def main(): task_foo = asyncio.create_task(foo("I am foo")) task_foo.add_done_callback(callback) foo_res = await task_foo print(foo_res) async def foo(text): print(text) await asyncio.sleep(1) print("wake up") return "returns " + text def callback(future): print("Future has result:", future.result()) print("I am callback") asyncio.run(main())
I am foo wake up Future has result: returns I am foo I am callback returns I am foo