一、协程概念
协程:是单线程下的并发,又称微线程,纤程。英文名Coroutine。协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
大概就是这个样子
协程的运行需要在一个 EventLoop 中进行,由它来控制异步任务的注册、执行、取消等。其大致原理是:
把传入的所有异步对象(准确的说是可等待对象,如 Coroutine
,Task
等,见下文)都注册到这个 EventLoop 上,EventLoop 会循环执行这些异步对象,但同时只执行一个,当执行到某个对象时,如果它正在等待其他对象(I/O 处理) 返回,事件循环会暂停它的执行去执行其他的对象。当某个对象完成 I/O 处理后,下次循环到它的时候会获取其返回值然后继续向下执行。这样以来,所有的异步任务就可以协同运行
EventLoop 接受的对象必须为可等待对象,目前主要有三种类型即 Coroutine
, Task
和 Future。
协程的运行需要在一个 EventLoop 中进行,在 Python 3.7 之前
In [19]: loop = asyncio.get_event_loop()
In [20]: loop.run_until_complete(func())
In [21]: loop.close()
Python 3.7 及以上版本可以直接使用 asyncio.run(func())
import asyncio
from asyncio import get_event_loop, sleep
async def func(num):
print("I'm async func, num ==>", num)
await sleep(1) # 协程里的睡眠等待
return "return from func, num <== [{}]".format(num)
def done_callback(future):
print("async fun done call", future.result())
loop = get_event_loop() # 获取循环事件
coro = func(1) # 生成一个协程对象
future_ = loop.create_task(coro=coro) # 将协程对象传入事件的方法中创建一个task,返回的是一个task对象,Task类是Future的子类
future_.add_done_callback(done_callback) # 添加回调函数
loop.run_until_complete(future_) # 启动事件循环,执行异步任务
# future_.result() # 打印协程结果
loop.close() # 关闭事件循环
res = asyncio.run(func(1)) # Py3.7+
print(res)
执行结果
I'm async func, num ==> 1
async fun done call return from func, num <== [1]
I'm async func, num ==> 1
return from func, num <== [1]
进程已结束,退出代码0
正题:
协程也需要使用到yield关键字,在函数中使用yield关键字,在协程被激活时,在yield处暂停,然后等调用方发送数据,然后再从yield关键字的位置继续往下执行,所以yield是个流程控制的工具,可以实现协作式多任务
简单的协程示例:(需要用next函数进行预激活,然后使用send进行发送值,发送的值会从yield处复制给变量)
def coro_demo(num):
print("enter coroutine ... num ==>", num)
var = yield "yield var"
print("exit coroutine ... var ==> ", var)
coro = coro_demo(111)
next(coro)
coro.send("222")
执行结果
Traceback (most recent call last):
File "C:\Users\guohainan\PycharmProjects\django_study_1\study_1.py", line 8, in <module>
coro.send("222")
StopIteration
enter coroutine ... num ==> 111
exit coroutine ... var ==> 222
进程已结束,退出代码1
在send之前必须先使用next预激活,协程的结束和生成器是一样的通过raise StopIteration给调用方从而达到停止的效果
当结束时抛出的StopIteration异常时,返回值就在异常对象的value属性中
def coro_demo(num):
print("enter coroutine ... num ==>", num)
while 1:
var = yield "yield var"
if var is None:
return "stop var"
print("exit coroutine ... var ==> ", var)
coro = coro_demo(111)
next(coro)
coro.send("222")
coro.send("333")
try:
coro.send(None)
except StopIteration as e:
print("exit value [{}]".format(e.value))
执行结果
enter coroutine ... num ==> 111
exit coroutine ... var ==> 222
exit coroutine ... var ==> 333
exit value [stop var]
进程已结束,退出代码0
yield from:
yield form与for循环相似
def for_():
for i in range(3):
yield i
print(list(for_()))
def yield_from_():
yield from range(3)
print(list(yield_from_()))
执行结果
[0, 1, 2]
[0, 1, 2]
进程已结束,退出代码0
yield from value 运行过程是先调用iter(value) 然后再调用 next(), 所以value可以使任何的iterator,yield from负责打开双向通道,让最外层的调用对象与yield from的对象中的生成器链接起来,通过例子可以看出链接过程:
def coro(val):
print("I'm coroutine, val ==> [{}]".format(val))
val_ = yield val
print("coro val ==> [{}]".format(val_))
return "return from coro"
def inner_func():
res = yield from coro("1111")
print("inner_func res ==> [{}]".format(res))
return res
def outer_func():
res = yield from inner_func()
print("outer_func res ==> [{}]".format(res))
return res
coro_o = outer_func()
coro_o.__next__()
try:
coro_o.send("call from coro_o")
except StopIteration as e:
print("except value == >", e.value)
执行结果
I'm coroutine, val ==> [1111]
coro val ==> [call from coro_o]
inner_func res ==> [return from coro]
outer_func res ==> [return from coro]
except value == > return from coro
进程已结束,退出代码0
可以看的出来在yield from的时候就暂停在了那里,然后进入了yield from后面的函数,知道coro的return再被层层return出来,又因为next预激活了,然后用send的话会抛出StopIteration的异常,值被放在异常的value属性中,如果不用next预激活直接用send的话会抛出“TypeError: can't send non-None value to a just-started generator” 的异常,从上面也可看到yield from起到一个双向通道的作用,同时子生成器也可使用yield from调用另一个子生成器,一直嵌套下去直到遇到yield表达式结束链式。
在Py3.5以前的版本中是用@asyncio.coroutine装饰,使用yield from来驱动,在Py3.5的时候做了改动:
@asyncio.coroutine -> async
yield from -> await
await是用来等待耗时操作并且抛出线程的执行权,等待await结束后会再次获取执行权继续执行后面的代码
asyncio中几个重要概念
1.事件循环
管理所有的事件,在整个程序运行过程中不断循环执行并追踪事件发生的顺序将它们放在队列中,空闲时调用相应的事件处理者来处理这些事件。
2.Future
Future对象:asyncio.futures.Future对象用来链接 底层回调式代码 和高层异步/等待式代码,可以简单理解为future对象是可以使程序hang在某个地方等待有结果了之后再继续执行
import asyncio
async def main():
# 获取当前事件循环
loop = asyncio.get_running_loop()
# 单纯的创建future对象
future = loop.create_future()
# future对象因为什么都没做也就没返回值,所以await会一直等待下去程序就会hang住
print("await future ....")
await future # 一直hang住
asyncio.run(main())
print("over") # 永远不会执行到这一行,因为前面一直hang住了,执行不到后面这一样
执行结果
await future ....
future只是单纯的被创建并且hang住了,没有结果返回来
所以可以调用future对象的set_result()方法进行设置结果
import asyncio
async def func(futurre):
futurre.set_result("set result")
async def main():
# 获取当前事件循环
loop = asyncio.get_running_loop()
# 单纯的创建future对象
future = loop.create_future()
# 创建一个task对象,并且把future对象作为参数传入协程函数func的对象放进task中进行执行
loop.create_task(func(future))
print("await future ....")
print(await future) # 有了结果
# asyncio.run(main()) # Py3.7+
new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)
new_loop.run_until_complete(main())
new_loop.close()
print("over") # 永远不会执行到这一行,因为前面一直hang住了,执行不到后面这一样
执行结果
await future ....
set result
over
进程已结束,退出代码0
3.Task
任务: Task 对象是Future对象的子类,其作用是在运行某个任务的同时可以并发的运行其他任务。
Task 对象可以使用 asyncio.create_task() 函数创建,也可以使用低层级的 loop.create_task()或asnycio.ensure_future()
注意:asyncio.create_task() 是python3.7之后才有的。python3.7之前可以改用asnycio.ensure_future()
asyncio.Task用于实现协作式多任务的库,且Task对象不能用户手动实例化
在Task类中的方法:
取消 Task 对象 cancel()
Task 任务是否被取消 cancelled()
Task 对象是否完成 done()
返回结果 result()
Task 对象被完成,则返回结果
Task 对象被取消,则引发 CancelledError 异常
Task 对象的结果不可用,则引发 InvalidStateError 异常
添加回调,任务完成时触发 add_done_callback(task)
所有任务列表 asyncio.all_tasks()
返回当前任务 asyncio.current_task()
run_until_complete():
run_until_complete 的参数是一个 future,但是我们这里传给它的却是协程对象,之所以能这样,是因为它在内部做了检查,要让这个协程对象转成future
的话,可以通过 asyncio.ensure_future
方法(本质其实是创建了个task对象)。
asyncio.sleep():
模拟IO操作,这样的休眠不会阻塞事件循环,前面加上await后会把控制权交给主事件循环,在休眠(IO操作)结束后恢复这个协程。
提示:若在协程中需要有延时操作,应该使用 await asyncio.sleep(),而不是使用time.sleep(),因为使用time.sleep()后会释放GIL,阻塞整个主线程,从而阻塞整个事件循环
import asyncio
async def do_something():
print("这是一个Task例子....")
# 模拟阻塞1秒
await asyncio.sleep(1)
return "Task任务完成"
# 创建一个事件event_loop
loop = asyncio.get_event_loop()
# 创建一个task
task = loop.create_task(do_something())
# 第一次打印task
print(task)
# 将task加入到event_loop中
loop.run_until_complete(task)
# 再次打印task
print(task)
print(task.result())
""" 运行结果
#1 <Task pending name='Task-1' coro=<do_something() running at /Users/mac/Desktop/userspace/TestDemo/test/async_demo.py:97>>
#2 这是一个Task例子....
#3 <Task finished name='Task-1' coro=<do_something() done, defined at /Users/mac/Desktop/userspace/TestDemo/test/async_demo.py:97> result='Task任务完成'>
#4 Task任务完成
"""
asyncio.wait(list) 和 asyncio.gather(args):
asyncio.wait方法或await关键字只能传可等待 对象
asyncio.wait()里面接受的是一个list对象,gather接受的是多个 Task实例元素,
不同的是,wait是放回一个元组,元组里有两个集合元素,一个是done状态的协程的集合,一个是pending状态的协程的集合而gather直接返回结果
import asyncio
async def coro_ex(num):
print("I'm coro [{}]".format(num))
await asyncio.sleep(1)
return "return from coro_ex: [{}]".format(num)
def call_back(future):
print(future.result())
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
coros = []
for i in range(5):
coros.append(coro_ex(i))
tasks = []
for i in coros:
task = loop.create_task(i)
task.add_done_callback(call_back)
tasks.append(task)
done, pending = loop.run_until_complete(asyncio.wait(tasks))
print("done:", done)
print("pending:", pending)
res = loop.run_until_complete(asyncio.gather(*tasks))
print("res: ", res)
执行结果
I'm coro [0]
I'm coro [1]
I'm coro [2]
I'm coro [3]
I'm coro [4]
return from coro_ex: [0]
return from coro_ex: [2]
return from coro_ex: [4]
return from coro_ex: [1]
return from coro_ex: [3]
done: {<Task finished name='Task-2' coro=<coro_ex() done, defined at .....py:4> result='return from coro_ex: [1]'>, <Task finished name='Task-3' coro=<coro_ex() done, defined at .....py:4> result='return from coro_ex: [2]'>, <Task finished name='Task-1' coro=<coro_ex() done, defined at .....py:4> result='return from coro_ex: [0]'>, <Task finished name='Task-4' coro=<coro_ex() done, defined at .....py:4> result='return from coro_ex: [3]'>, <Task finished name='Task-5' coro=<coro_ex() done, defined at .....py:4> result='return from coro_ex: [4]'>}
pending: set()
res: ['return from coro_ex: [0]', 'return from coro_ex: [1]', 'return from coro_ex: [2]', 'return from coro_ex: [3]', 'return from coro_ex: [4]']
进程已结束,退出代码0
asyncio.wait() 返回一个元组,里面有两个集合,一个集合代表运行结束的协程,一个集合代表等待状态的协程
而asyncio.gather()则直接返回协程函数的return结果
asyncio.run(coro()) 可以直接运行协程对象,因为里面已经封装了run_until_conplete()以及loop,但是显然不支持同时运行多个协程对象
协程函数和普通函数之间可以搭配使用:
async def func3():
print('i`m func3')
await asyncio.sleep(2)
print('func3 finished')
def func4():
print('i`m func4')
asyncio.run(func3())
print('func4 finished')
func4()
"""输出结果:
i`m func4
i`m func3
等待2s
func3 finished
func4 finished
"""
def func5():
print('i`m func5')
time.sleep(2)
print('func5 finished')
async def func6():
print('i`m func6')
func5()
print('func6 finished')
asyncio.run(func6())
print('all finish')
"""
i`m func6
i`m func5
等待2s
func5 finished
func6 finished
all finish
"""
使用线程池、进程池实现异步操作时用到的concurrent.futures.Future对象。它跟asyncio.futures.Future没有关系,但是也是帮助程序hang住直到拿到结果。
多线程的Future:
import time
from concurrent.futures.thread import ThreadPoolExecutor
def func(value):
print("start")
time.sleep(1)
print(value)
# 指定同时可用的线程数量
thread_pool = ThreadPoolExecutor(max_workers=5)
for i in range(10):
# submit(func,*args,**kwargs)方法向线程池提交任务
fut = thread_pool.submit(func, i)
# 返回值为future对象
print(type(fut)) # <class 'concurrent.futures._base.Future'>
执行结果
start
<class 'concurrent.futures._base.Future'>
start<class 'concurrent.futures._base.Future'>
start
<class 'concurrent.futures._base.Future'>
start
<class 'concurrent.futures._base.Future'>
start
<class 'concurrent.futures._base.Future'>
<class 'concurrent.futures._base.Future'>
<class 'concurrent.futures._base.Future'>
<class 'concurrent.futures._base.Future'>
<class 'concurrent.futures._base.Future'>
<class 'concurrent.futures._base.Future'>
0
start
12
start
3
start
start
4
start
75
6
8
9
进程已结束,退出代码0
线程池:用于伪并发执行,由于GIL锁的原因;但是其实遇到IO就切换所以线程启动间隔时间其实很短
上面代码的执行逻辑:先提交一个任务到线程池中 --> 打印 start --> 遇到了IO(此处IO为sleep)后迅速切换任务 --> 打印了future对象的类型 --> 提交第二个任务到线程池中 --> 打印 start --> 遇到了IO(sleep) 迅速切换任务 --> 打印future对象的类型........ --> 任务执行完成
以上任务中如果IO处理完了的话会输出value数字,等前5个执行完了会再来一遍以上流程,因为线程池限制了只维护5个活跃线程,所以一次并发只有5个,而一个任务的完成,线程空闲之后又会迅速获取下一个任务进行执行
多进程的Future:
import time
from concurrent.futures.process import ProcessPoolExecutor
def func(value):
print("start")
time.sleep(1)
print(value)
process_pool = ProcessPoolExecutor(max_workers=5)
if __name__ == '__main__':
for i in range(10):
# 返回值为concurrent.futures._base.Future对象
fut = process_pool.submit(func, i)
进程池的执行步骤以及活跃进程与上面线程池是一致的
在Py3.9当中封装了一个函数
asyncio.to_thread(func, /, *args, **kwargs) #函数直接开线程,传递参数。
Py3.9之前的版本可以用
run_in_executor() 和 run_coroutine_threadsafe()
多线程中执行协程的例子 使用的是run_in_executor(),主线程新开子线程,运行阻塞函数,但是是同步的
import threading
from concurrent.futures import ThreadPoolExecutor
import asyncio, time
def get_thread_ident(): # 查看当前正在运行的thread的ident
import threading
print("running thread ident:", threading.current_thread().ident)
def blockfunc(): # 阻塞运行
print("blocking")
time.sleep(2)
get_thread_ident()
return "after 2s"
async def returnfuture(): # 使用新建的线程进行测试
loop = asyncio.get_event_loop()
newexecutor = ThreadPoolExecutor()
future = await loop.run_in_executor(newexecutor, blockfunc) # 执行阻塞函数
print(future)
print("main thread name: ", threading.get_ident())
asyncio.run(returnfuture())
执行结果
main thread name: 89228
blocking
running thread ident: 81884
after 10s
进程已结束,退出代码0
例子:(也就是动态添加协程的例子)
run_coroutine_threadsafe() 例子:
import asyncio, time, threading
async def block_func(num): # 测试的阻塞函数
print("start block function")
await asyncio.sleep(2)
print(time.time())
get_thread_name()
print("thread ident [{}], ident: [{}]".format(num, threading.get_ident()))
return "return from block_func"
def get_thread_name(): # 查看当前线程名字
print("current thread ident:", threading.current_thread().ident)
def startloop(loop): # 新建event-loop
get_thread_name() # 看一下线程名字
asyncio.set_event_loop(loop)
loop.run_forever()
def call_back(future):
loop = asyncio.get_event_loop()
loop.stop() # 在函数结束后进行关闭事件循环,关闭之后会退出线程
print("loop close status:", loop.is_closed())
print("loop running status:", loop.is_running())
print("result:", future.result())
new_loop = asyncio.new_event_loop()
threading.Thread(target=startloop, args=(new_loop,)).start()
future = asyncio.run_coroutine_threadsafe(block_func(1), new_loop)
future.add_done_callback(call_back)
future2 = asyncio.run_coroutine_threadsafe(block_func(2), new_loop)
future2.add_done_callback(call_back)
print("ovvver")
print("main thread ident: [{}]".format(threading.current_thread().ident))
执行结果
current thread ident: 64076
ovvverstart block function
main thread ident: [88900]
start block function
1672204714.5599377
current thread ident: 64076
thread ident [1], ident: [64076]
1672204714.5599377
current thread ident: 64076
thread ident [2], ident: [64076]
loop close status: False
loop running status: True
result: return from block_func
loop close status: False
loop running status: True
result: return from block_func
进程已结束,退出代码0
以上例子为动态添加协程的方式
动态添加协程: 先创建一个线程,使时间循环 在线程内永久运行
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和一个位置参数
注意:同步方式,回调函数 coro()为普通函数
import asyncio
from threading import Thread
def start_thread_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
def coro(val):
print("I'm coroutine, val ==> [{}]".format(val))
asyncio.sleep(1) # 交出执行权,原地等待IO
return "return from coro < == [{}]".format(val)
new_loop = asyncio.new_event_loop() # 获取一个新的事件循环,区别与主线程中的时间循环,是新建一个循环出来
t = Thread(target=start_thread_loop, args=(new_loop,))
t.start()
handle = new_loop.call_soon_threadsafe(coro, "111")
handle.cancel() # 先取消一个协程
print("main thread continue")
new_loop.call_soon_threadsafe(coro, "2222")
print("---------------")
new_loop.call_soon_threadsafe(coro, "3333")
动态添加协程异步方式
通过调用 asyncio.run_coroutine_threadsafe()函数,传入一个回调函数callback和一个loop对象
注意:异步方式,回调函数 coro()为协程
import asyncio
from asyncio import get_event_loop, set_event_loop
from threading import Thread
def start_thread_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
async def coro(val):
print("I'm coroutine, val ==> [{}]".format(val))
await asyncio.sleep(1) # 交出执行权,原地等待IO
return "return from coro < == [{}]".format(val)
def call_back_(future):
print("call back:", future.result())
new_loop = asyncio.new_event_loop() # 获取一个新的事件循环,区别与主线程中的时间循环,是新建一个循环出来
main_loop = get_event_loop()
t = Thread(target=start_thread_loop, args=(new_loop,))
t.start()
print("thread start")
future = asyncio.run_coroutine_threadsafe(coro=coro("111"), loop=new_loop)
print(future.result())
print("dynamic add coroutine to sub thread")
future_sub = asyncio.run_coroutine_threadsafe(coro("333"), loop=new_loop)
print(future_sub.result())
执行结果
thread start
I'm coroutine, val ==> [111]
return from coro < == [111]
dynamic add coroutine to sub thread
I'm coroutine, val ==> [333]
return from coro < == [333]
然而协程的时间循环并没有结束,因为运行了run_forever()所以只要不执行关闭命令就会一直block住,可以使用线程守护机制 t.daemon = True 来守护主线程
协程中生产-消费模型设计
import asyncio
from threading import Thread
from collections import deque
import random
import time
def start_thread_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
def consumer():
while True:
if dq:
msg = dq.pop()
if msg:
asyncio.run_coroutine_threadsafe(thread_example("msg" + msg), new_loop)
async def thread_example(name):
print('正在执行name:', name)
await asyncio.sleep(2)
return '返回结果:' + name
dq = deque()
new_loop = asyncio.new_event_loop()
loop_thread = Thread(target= start_thread_loop, args=(new_loop,))
loop_thread.setDaemon(True)
loop_thread.start()
consumer_thread = Thread(target= consumer)
consumer_thread.setDaemon(True)
consumer_thread.start()
while True:
i = random.randint(1, 10)
dq.appendleft(str(i))
time.sleep(2)
在asyncio包中有这些方法
['BaseEventLoop', 'Server', 'iscoroutinefunction', 'iscoroutine', 'AbstractEventLoopPolicy', 'AbstractEventLoop', 'AbstractServer', 'Handle', 'TimerHandle', 'get_event_loop_policy', 'set_event_loop_policy', 'get_event_loop', 'set_event_loop', 'new_event_loop', 'get_child_watcher', 'set_child_watcher', 'get_running_loop', 'BrokenBarrierError', 'CancelledError', 'InvalidStateError', 'TimeoutError', 'IncompleteReadError', 'LimitOverrunError', 'SendfileNotAvailableError', 'Future', 'wrap_future', 'isfuture', 'Lock', 'Event', 'Condition', 'Semaphore', 'BoundedSemaphore', 'Barrier', 'BaseProtocol', 'Protocol', 'DatagramProtocol', 'SubprocessProtocol', 'BufferedProtocol', 'Runner', 'run', 'Queue', 'PriorityQueue', 'LifoQueue', 'QueueFull', 'QueueEmpty', 'StreamReader', 'StreamWriter', 'StreamReaderProtocol', 'open_connection', 'start_server', 'create_subprocess_exec', 'create_subprocess_shell', 'Task', 'create_task', 'FIRST_COMPLETED', 'FIRST_EXCEPTION', 'ALL_COMPLETED', 'wait', 'wait_for', 'as_completed', 'sleep', 'gather', 'shield', 'ensure_future', 'run_coroutine_threadsafe', 'current_task', 'all_tasks', 'to_thread', 'Timeout', 'timeout', 'timeout_at', 'BaseTransport', 'ReadTransport', 'WriteTransport', 'Transport', 'DatagramTransport', 'SubprocessTransport', 'SelectorEventLoop', 'ProactorEventLoop', 'IocpProactor', 'DefaultEventLoopPolicy', 'WindowsSelectorEventLoopPolicy', 'WindowsProactorEventLoopPolicy']
as_complete:
# coding=utf-8
import asyncio
import time
async def foo (n):
print('Waiting: ', n)
await asyncio.sleep(n)
return n
async def main ():
# 三个协程
coroutine1 = foo(1)
coroutine2 = foo(2)
coroutine3 = foo(4)
tasks = [
# 安排协程或将来等待的程序。
asyncio.ensure_future(coroutine1),
asyncio.ensure_future(coroutine2),
asyncio.ensure_future(coroutine3)
]
# 返回其值为协程的迭代器。
for task in asyncio.as_completed(tasks):
result = await task # 运行协程对象
print('Task ret: {}'.format(result))
if __name__ == '__main__':
now = time.time()
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
finally:
loop.close()
print("总用时", time.time() - now)
执行结果
Waiting: 1
Waiting: 2
Waiting: 4
Task ret: 1
Task ret: 2
Task ret: 4
总用时 4.005075216293335
get_running_loop(): 是获取当前正在运行的时间循环
# -*- coding: utf-8 -*-
import asyncio
async def main():
await asyncio.sleep(3)
print('Done')
myloop = asyncio.get_running_loop()
print('current loop ')
print(id(myloop))
# loop = asyncio.get_running_loop()
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
print('current loop id')
print(id(loop))
try:
loop.run_until_complete(main())
except KeyboardInterrupt:
print('key board inpterrupt!')
执行结果
current loop id
2591640187664
Done
current loop
2591640187664
进程已结束,退出代码0
验证是否是协程对象(协程函数直接调用执行会返回一个协程对象)
print(asyncio.iscoroutine(func1())) # True
没耐心了,就这样吧
标签:基本,return,携程,python,coro,future,print,loop,asyncio From: https://www.cnblogs.com/hinem/p/17007166.html