python 协程(1)

267 阅读3分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战

先来看一段代码

from selenium import webdriver
#Replace the version to match the Chrome version
import selenium.webdriver.common.devtools.v93 as devtools

async def geoLocationTest():
    chrome_options = webdriver.ChromeOptions()
    driver = webdriver.Remote(
        command_executor='<grid-url>',
        options=chrome_options
    )

    async with driver.bidi_connection() as session:
        cdpSession = session.session
        await cdpSession.execute(devtools.emulation.set_geolocation_override(latitude=41.8781,longitude=-87.6298,accuracy=100))
    driver.get("https://my-location.org/")
    driver.quit()
  

先不管这段代码是要干嘛的,我们先来关注代码中的async关键字,这个关键字是python3.5新增加的特性,用来实现协程,再了解协程之前,我们先简单补充一下进程和线程的相关知识

多进程和多线程

进程和线程的概念都是从操作系统来说,一个任务就是一个进程,例如你打开网易云听歌,就是启动了一个听歌进程,你再打开vscode进行编程,就是打开了一个vscode进程,打开一个浏览器就是启动了一个浏览器进程。

有些进程不止干一件事,比如vscode,可以同时进行编码,语法检查等。在一个进程内部,这些同时运行的多个子任务就是线程。

每个进程至少要干一件事,那就是说一个进程至少有一个线程。

多个线程看起来像是在同时执行,其实是操作系统在线程之间快速切换,让我们感觉像在同时执行一样。

协程

让我们说协程,协程又被称为微线程,和进程和线程的实现区别来看, 进程和线程要靠操作系统, 而协程是程序控制。 正常程序执行,函数调用都是执行顺序明确的,例如一个main主程序,主程序里调用A方法,A方法里又调用B方法, 这样就是执行main,遇到A,A里面遇到B,等B执行完毕返回,然后A执行完毕返回,最后是main执行完

而协程的调用和函数调用不同,协程的执行有点像多线程。例如两个函数A,B, 两者之间是没有相互调用的。


def A():
    print('1')
    print('2')
    print('3')

def B():
    print('x')
    print('y')
    print('z')

协程执行,在执行A的过程中,可以随时中断去执行B,B反过来也可以随时中断,再去执行A, 那既然和线程这么相似,为什么不直接用线程,而是又出来个协程。

最大的优势就是前面所说的,协程是程序控制的,不是操作系统,操作系统切换线程有切换线程的开销,特别是当线程数量特别多的时候,开销就会特别大,这个时候线程的执行效率就比不上协程了。

协程的实现

1.通过yield

在python3.5版本之前,协程是通过python的生成器generator实现的,特别是通过yield关键字 通过一个大家学进程和线程都会遇到的例子生产者-消费者模型。

传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。

如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:

图片.png

2.通过asyncio 标准库

asyncio是Python 3.4版本引入的标准库,这里先不讲篇幅太长,后续补充。

3.async/await

async和await是为了简化asyncio,所以此篇先不讲,下篇和asyncio一起详讲