【python技能】掌握这3点,轻松搞定python协程
自从python3开始普及之后,那么协程就成为了很多应用的性能首选,于是很多从python2转过来的小伙伴们就纷纷的投入它的怀抱。不管是做web开发还是爬虫开发,要想做到更高的并发和更好的系统资源的利用都离不开它。
在python3.7之前,学习这个玩意还是有些伤脑筋的,为什么呢?因为它的语法对于很多人来讲不是很友好,而且用到的方法太多了,导致很多人学的时候都是晕乎乎的完全不明所以。因此很多的小伙伴也就退而求其次的选择用多线程解决,毕竟多线程写起来还是那么的熟练和简单嘛。
掌握Python3的协程只要记住以下几个重要概念和注意事项就OK。非常好入门,我们这里用的是python3.8,如果是你,那么请使用python3.7以上的版本。
-
协程函数 -
可等待对象 -
任务
什么是协程?
在python里面,协程的概念很简单,python的协程就是用async def
定义的函数,这个函数也叫协程函数。
看起来大概是这样的:
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
那么如何运行一个协程函数呢?记住这三点就可以了:
-
使用 await
关键字,就好比上面的例子那样,在await
右边放上你的协程函数 -
使用 asyncio.create_task
函数并发的执行,这个后面会讲 -
使用 asyncio.run
函数执行,这个主要就是用来运行主入口协程函数的
上面的例子我们就可以这么执行:
asyncio.run(main())
我们还可以看到,这个函数里面还有一个新奇的关键字await
,这个是干嘛的呢?
从字面上理解就是异步的等待,它会等待它右边的函数执行完成,但是这个它是异步的。什么意思呢?也就是一旦遇到这个await
那么这个函数就暂时在这里暂停了,然后程序可以去执行其他的一些操作,当它右边的函数执行完成之后,才会继续往下执行。
能放在await
右边的对象叫做「可等待对象」
可等待对象
python里面的可等待对象说的是可以放在await
关键字右边的对象(python里面一切皆对象)。可等待对象有哪些?
-
协程函数,前面说到的 -
任务(Task)后面会讲 -
Future对象,这个大部分情况下用不到,不用理会
那么关于await
除了知道只有上面的三种对象可以进行await
之外,就是要记住,这个await
只能出现在协程函数里面,别的地方是不能出现的哦,普通函数里面也没有的。所以这样就知道如何使用它啦。
import asyncio async def nested(): return 42 async def main(): # 像这样子是不会被执行的 nested() # 可以通过await来执行它 print(await nested()) # 打印输出 "42". asyncio.run(main())
最后来看看这个任务对象
任务对象
协程函数本身是不会进行并发的,要想并发的执行协程函数,那么就得通过创建任务的方式来进行,所以这个任务对象的主要目的就是让协程函数可以并发的执行。
「如何创建一个任务呢?」使用asyncio.create_task
函数就可以创建一个任务啦。只需要传入要被执行的协程函数就可以并发的进行运行了。
import asyncio async def say_after(delay, what): await asyncio.sleep(delay) print(what) async def main(): task1 = asyncio.create_task( say_after(1, 'hello')) task2 = asyncio.create_task( say_after(2, 'world')) print(f"started at {time.strftime('%X')}") # 使用await等待任务结束 await task1 await task2 print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
任务有什么特点呢?
任务创建函数只是将协程函数并发的执行,所以它的参数里面只能传入协程函数,而不能是其它东西。
当然,要实现并发的执行协程函数还有另外的一个方法
asyncio.gather
函数,它可以并发执行N个可等待对象,注意是可等待对象。
import asyncio async def factorial(name, number): f = 1 for i in range(2, number + 1): print(f"Task {name}: Compute factorial({i})...") await asyncio.sleep(1) f *= i print(f"Task {name}: factorial({number}) = {f}") async def main(): # 这里会并发的执行三个协程函数 await asyncio.gather( factorial("A", 2), factorial("B", 3), factorial("C", 4), ) asyncio.run(main())
但是这个本质上也会转换为任务对象然后再执行。
最后还要说一点就是这个asyncio.run()
函数,这个函数正常情况下,在一个python程序里面只调用一次,如果需要调用多次的话,只能是等待上一个函数执行完成之后再调用,否则就会抛出RuntimeError
的错误。
总结
基本上写python的协程脚本,只需要记住上面提到的几点就OK,这里总结一下。
-
协程函数是由 async def
来进行声明和定义的,想要执行协程函数必须使用await
或创建任务或者是通过asyncio.run
方法执行 -
await 是用于等待可等待对象的完成,可等待对象有三种,协程函数、Task任务和Future对象, await
只能出现在协程函数里面。 -
协程函数本身不会并发执行,它必须的通过创建任务来并发执行,所以任务的主要目的就是并发的执行协程函数。 -
任务只能是在协程函数里面创建和运行哦,普通函数里面创建任务是会失败的。 -
asyncio.run
函数一般在一个脚本里面只建议出现一次,多次出现的话得有执行顺序,一般不建议多次出现。它的目的就是用来执行程序主入口协程函数。
今天就到这里吧。其实很多东西没你想的那么难哈!
关注我,学习更多的SEO相关技术