社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

[python技能]掌握这3点,轻松搞定python协程

brooks的技术小屋 • 4 年前 • 835 次点击  

自从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,这里总结一下。

  1. 协程函数是由async def来进行声明和定义的,想要执行协程函数必须使用await或创建任务或者是通过asyncio.run方法执行
  2. await 是用于等待可等待对象的完成,可等待对象有三种,协程函数、Task任务和Future对象,await只能出现在协程函数里面。
  3. 协程函数本身不会并发执行,它必须的通过创建任务来并发执行,所以任务的主要目的就是并发的执行协程函数。
  4. 任务只能是在协程函数里面创建和运行哦,普通函数里面创建任务是会失败的。
  5. asyncio.run函数一般在一个脚本里面只建议出现一次,多次出现的话得有执行顺序,一般不建议多次出现。它的目的就是用来执行程序主入口协程函数。

今天就到这里吧。其实很多东西没你想的那么难哈!

关注我,学习更多的SEO相关技术

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/103865
 
835 次点击