python中协程异步IO(asyncio)详解(二)

接着python中协程异步IO(asyncio)详解(一)的内容

继续讲讲asyncio的控制任务和添加协程的操作

控制任务

通过asyncio.wait()可以控制多任务

asyncio.wait()是一个协程,不会阻塞,立即返回,返回的是协程对象。传入的参数是future或协程构成的可迭代对象。

最后将返回值传给run_until_complete()加入事件循环

最简单控制多任务

下面代码asyncio.wait()中,参数传入的是由协程构成的可迭代对象

示例代码

import asyncio
async def coroutine_example(name):
    print('正在执行name:', name)
    await asyncio.sleep(1)
    print('执行完毕name:', name)
loop = asyncio.get_event_loop()
tasks = [coroutine_example('mtck_' + str(i)) for i in range(3)]
wait_coro = asyncio.wait(tasks)
loop.run_until_complete(wait_coro)
loop.close()

运行结果

正在执行name: mtck_2

正在执行name: mtck_1

正在执行name: mtck_0

执行完毕name: mtck_2

执行完毕name: mtck_1

执行完毕name: mtck_0

多任务中获取返回值

方案1:需要通过loop.create_task()创建task对象,以便后面来获取返回值

下面代码asyncio.wait()中,参数传入的是由future(task)对象构成的可迭代对象

示例代码

import asyncio
async def coroutine_example(name):
    print('正在执行name:', name)
    await asyncio.sleep(1)
    print('执行完毕name:', name)
    return '返回值:' + name
loop = asyncio.get_event_loop()
tasks = [loop.create_task(coroutine_example('mtck_' + str(i))) for i in range(3)]
wait_coro = asyncio.wait(tasks)
loop.run_until_complete(wait_coro)
for task in tasks:
    print(task.result())
loop.close()

运行结果

正在执行name: mtck_0

正在执行name: mtck_1

正在执行name: mtck_2

执行完毕name: mtck_0

执行完毕name: mtck_1

执行完毕name: mtck_2

返回值:mtck_0

返回值:mtck_1

返回值:mtck_2

方案2:通过回调add_done_callback()来获取返回值

示例代码

import asyncio
def my_callback(future):
    print('返回值:', future.result())
async def coroutine_example(name):
    print('正在执行name:', name)
    await asyncio.sleep(1)
    print('执行完毕name:', name)
    return '返回值:' + name
loop = asyncio.get_event_loop()
tasks = []
for i in range(3):
    task = loop.create_task(coroutine_example('mtck_' + str(i)))
    task.add_done_callback(my_callback)
    tasks.append(task)
wait_coro = asyncio.wait(tasks)
loop.run_until_complete(wait_coro)
loop.close()

运行结果

正在执行name: mtck_0

正在执行name: mtck_1

正在执行name: mtck_2

执行完毕name: mtck_0

执行完毕name: mtck_1

执行完毕name: mtck_2

返回值: 返回值:mtck_0

返回值: 返回值:mtck_1

返回值: 返回值:mtck_2

动态添加协程

方案是创建一个线程,使事件循环在线程内永久运行

相关函数介绍:

loop.call_soon_threadsafe() :与 call_soon()类似,等待此函数返回后马上调用回调函数,返回值是一个 asyncio.Handle 对象,

此对象内只有一个方法为 cancel()方法,用来取消回调函数。

loop.call_soon() : 与call_soon_threadsafe()类似,call_soon_threadsafe() 是线程安全的

loop.call_later():延迟多少秒后执行回调函数

loop.call_at():在指定时间执行回调函数,这里的时间统一使用 loop.time() 来替代 time.sleep()

asyncio.run_coroutine_threadsafe(): 动态的加入协程,参数为一个回调函数和一个loop对象,返回值为future对象,通过future.result()获取回调函数返回值

动态添加协程同步方式

通过调用 call_soon_threadsafe()函数,传入一个回调函数callback和一个位置参数

注意:同步方式,回调函数 thread_example()为普通函数

示例代码

import asyncio
from threading import Thread
def start_thread_loop(loop):
    asyncio.set_event_loop(loop)
    loop.run_forever()
def thread_example(name):
    print('正在执行name:', name)
    return '返回结果:' + name
new_loop = asyncio.new_event_loop()
t = Thread(target= start_thread_loop, args=(new_loop,))
t.start()
handle = new_loop.call_soon_threadsafe(thread_example, 'mtck1')
handle.cancel()
new_loop.call_soon_threadsafe(thread_example, 'mtck2')
print('主线程不会阻塞')
new_loop.call_soon_threadsafe(thread_example, 'mtck3')
print('继续运行中... ')

运行结果

正在执行name: mtck1

正在执行name: mtck2

主线程不会阻塞

继续运行中...

正在执行name: mtck3

动态添加协程异步方式

通过调用 asyncio.run_coroutine_threadsafe()函数,传入一个回调函数callback和一个loop对象

注意:异步方式,回调函数 thread_example()为协程

示例代码

import asyncio
from threading import Thread
def start_thread_loop(loop):
    asyncio.set_event_loop(loop)
    loop.run_forever()
async def thread_example(name):
    print('正在执行name:', name)
    await asyncio.sleep(1)
    return '返回结果:' + name
new_loop = asyncio.new_event_loop()
t = Thread(target= start_thread_loop, args=(new_loop,))
t.start()
future = asyncio.run_coroutine_threadsafe(thread_example('mtck1'), new_loop)
print(future.result())
asyncio.run_coroutine_threadsafe(thread_example('mtck2'), new_loop)
print('主线程不会阻塞')
asyncio.run_coroutine_threadsafe(thread_example('mtck3'), new_loop)
print('继续运行中...')

运行结果

正在执行name: mtck1

返回结果:mtck1

正在执行name: mtck2

主线程不会阻塞

正在执行name: mtck3

继续运行中...

从上面2个例子中,当主线程运行完成后,由于子线程还没有退出,故主线程还没退出,等待子线程退出中。

若要主线程退出时子线程也退出,可以设置子线程为守护线程 t.setDaemon(True)

你可能感兴趣的:(python,python)