In asynchronous python coroutine flow analysis process (a)

For better presentation, I prepared three functions, a synchronization function, two asynchronous functions

#Define blocking function 
DEF the ping (url): 
    Print ( "blocking function starts running") 
    the time.sleep (2) 
    os.system ( "the ping% S"% url) 
    Print ( "end of run blocking function") 
    
#define two asynchronous functions 
the async DEF asyncfunc1 (): 
    Print ( "the Suspending func1") 
    the await asyncio.sleep (. 1) 
    Print ( "FUNC func1", threading.current_thread ()) 
    Print ( 'Resuming func1') 
    return "func1" 
    
the async DEF asyncfunc2 (): 
    Print ( "the Suspending func2") 
    the await asyncio.sleep (. 1) 
    Print ( "FUNC func2", threading.current_thread ()) 
    Print ( 'Resuming func2') 
    return "func2"

Control task coroutine

Run a single task coroutine

The above function, for example, I just want to asyncfunc1 () function runs and get the results, you can use the loop.create_task() method to create a task object, task Futures is a subclass when calling loop.run_until_complete() later after coroutine finish, by task.result() acquiring coroutine function return result.

async def asyncfunc1():
    print("Suspending func1")
    await asyncio.sleep(1)
    print("func func1 ", threading.current_thread())
    print('Resuming func1')
    return "func1"

if __name__=="__main__":
    print("In main thread ",threading.current_thread())
    loop = asyncio.get_event_loop()
    task = loop.create_task(asyncfunc1())
    loop.run_until_complete(task)
    print("task result is ",task.result())

The output is

In main thread <_mainthread(mainthread, started="" 6140)=""> Suspending func1 func func1 <_mainthread(mainthread, started="" 6140)=""> Resuming func1 task result is func1

And the main thread is running coroutine function in the same thread.

You can also add a callback method to task objects

#coding:gbk
import asyncio
import time,sys


async def asyncfunc1():
    print("Suspending func1")
    await asyncio.sleep(1)
    print("func func1 ", threading.current_thread())
    print('Resuming func1')
    return "func1"
    
# 定义一个回调函数
def callbackfunc(task):
    print("task 运行结束,它的结果是:",task.result())
    
    
if __name__=="__main__":
    print("In main thread ",threading.current_thread())
    loop = asyncio.get_event_loop()
    task = loop.create_task(asyncfunc1())
    task.add_done_callback(callbackfunc)
    loop.run_until_complete(task)

The output is

In main thread<_mainthread(mainthread, started="" 11248)="">

Suspending func1

func func1<_mainthread(mainthread, started="" 11248)="">

Resuming func1

Run the end of the task, its results are: func1

loop.run_until_complete Is a blocking method, after ending only when it is inside the coroutine runs until the end of this method, the code will run after.

In fact, you can not call loop.run_until_complete after method, create a task, in fact, has been in the running coroutine function, but when the event loop if ready to start running, and this time the task state pending , if not call the event loop, then do not run coroutine function, since the main thread finish, the sub-thread will be destroyed, such as code written as:

if __name__=="__main__":
    print("In main thread ",threading.current_thread())
    loop = asyncio.get_event_loop()
    task = loop.create_task(asyncfunc1())
    time.sleep(3)

The resulting output is

In main thread<_mainthread(mainthread, started="" 6056)="">

Task was destroyed but it is pending!

task:

cb=[callbackfunc() at test.py:39]>

sys:1: RuntimeWarning: coroutine ‘asyncfunc1’ was never awaited

So you want to make coroutine function is implemented, you need to call the event loop to perform tasks above loop.run_until_complete it is to make the cycle began to run, in fact, can also use loop.run_forever() this function as its name suggests, will always run. Only the event loop run up, then use the cycle registered coroutine will be implemented, but if loop.run_forever() it will back up here, there is a event loop stop method, the end of the cycle, we can add a callback method on the object task when after the end of the coroutine execution, calling the event loop stop way to end the whole cycle

#coding:gbk
import asyncio
import time,sys

async def asyncfunc1():
    print("Suspending func1")
    await asyncio.sleep(1)
    print("func func1 ", threading.current_thread())
    print('Resuming func1')
    return "func1"
    
# 定义一个回调函数
def callbackfunc(task):
    print("task 运行结束,它的结果是:",task.result())
    loop.stop()
    
    
if __name__=="__main__":
    print("In main thread ",threading.current_thread())
    loop = asyncio.get_event_loop()
    task = loop.create_task(asyncfunc1())
    task.add_done_callback(callbackfunc)
    loop.run_forever()

In addition to using loop.run_until_complete the method, may also be used asyncio.ensure_future() a method coroutine to run the code above task = loop.create_task(asyncfunc1()) to task = asyncio.ensure_future(asyncfunc1()) get the same result, it is coroutine object or parameter futures, task object may be passed as a futures subclass task, when incoming is a coroutine object, and returns a task object, passing a futures when the futures returns the object directly, that is to say, in the call asyncio.ensure_future() later, will return a task object that it can add a callback method and can be called task.result () method to get the result (note that if the task is not performed end result is called method will throw an exception).

A plurality of tasks in parallel coroutine

I've got the top two asynchronous functions asyncfunc1 and asyncfunc2, if I want to perform these two functions simultaneously and get their return values ​​that how does it work?

With the experience of a single coroutine above, we can also use the event to create two task cycle, then () is executed in run_forever, you can add a callback to the task, and outputs the result.

#coding: GBK 
Import ASYNCIO 

# define two asynchronous functions 
the async DEF asyncfunc1 (): 
    Print ( "the Suspending func1") 
    the await asyncio.sleep (. 1) 
    Print ( "FUNC func1", threading.current_thread ()) 
    Print ( 'Resuming func1 ') 
    return "func1" 
    
the async DEF asyncfunc2 (): 
    Print ( "the Suspending func2") 
    the await asyncio.sleep (. 1) 
    Print ( "FUNC func2", threading.current_thread ()) 
    Print (' Resuming func2 ') 
    return "func2" 

    
# define a callback function 
DEF callbackfunc (task): 
    Print ( "the end of the task run, it is the result:", task.result ()) 
    
    
IF __name__ __ == "__ main__": 
    Print ( "In main thread ",threading.current_thread()) 
    Loop = ASYNCIO.get_event_loop()
    task1 = loop.create_task(asyncfunc1())
    task1.add_done_callback(callbackfunc)
    task2 = loop.create_task(asyncfunc2())
    task2.add_done_callback(callbackfunc)
    loop.run_forever()

The output is

In main thread<_mainthread(mainthread, started="" 8040)="">

Suspending func1

Suspending func2

func func1<_mainthread(mainthread, started="" 8040)="">

Resuming func1

func func2<_mainthread(mainthread, started="" 8040)="">

Resuming func2

Run the end of the task, its results are: func1

Run the end of the task, its results are: func2

This time due to loop called run_forever method, and there is no way to call the stop method, so the program will have the card.

Such a process may be a plurality of co-run, but such a process complicated one, the second is not convenient to recover the result.

asyncio gather there is a method that may be passed multiple task objects, when calling await asyncio.gather (*), it will return all the results

Due to await only write in async def function, so there is also a need to create a new function

async def main():
    task1 = loop.create_task(asyncfunc1())
    task1.add_done_callback(callbackfunc)
    task2 = loop.create_task(asyncfunc2())
    task2.add_done_callback(callbackfunc)
    result = await asyncio.gather(task1,task2)    
    print(result)
    
async def mian2():
    result = await asyncio.gather(asyncfunc1(),asyncfunc2())
    print(result)

Both definitions are ways, one is to gather transfer function is coroutine object is passed to a task object. After calling

if __name__=="__main__":
    print("In main thread ",threading.current_thread())
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main()) # or main2()

The resulting output is

In main thread<_mainthread(mainthread, started="" 7016)="">

Suspending func1

Suspending func2

func func1<_mainthread(mainthread, started="" 7016)="">

Resuming func1

func func2<_mainthread(mainthread, started="" 7016)="">

Resuming func2

Run the end of the task, its results are: func1

Run the end of the task, its results are: func2

[‘func1’, ‘func2’]

This achieves a parallel coroutine recovery and outcome.

This article briefly introduced here, then will continue to analyze the implementation of the synchronization code.

Guess you like

Origin blog.csdn.net/java276582434/article/details/92106788