协程笔记

概念

并发与并行

  • 并发:指一个时间段内,有几个程序在同一个cpu上运行,但是任意时刻只有一个程序在cpu上运行。
  • 并行:指任意时刻,有多个程序同时在多个cpu上运行。

同步与异步

  • 同步:指代码调用IO操作时,必须等待IO操作完成才返回的调用方式。
  • 异步:指代码调用IO操作时,不必等IO操作完成就返回的调用方式。

协程解决的问题

  • 一、采用同步的方式去编写异步的代码。
  • 二、使用单线程去切换任务:
    1、线程是由操作系统切换的,单线程切换意味着需要程序员自己去调度任务。2、不需要锁,并发性高,如果单线程内切换函数,性能远高于线程切换,并发性更高。

协程的定义

协程指可以暂停的函数,可以向暂停的地方传入值。

生成器的高级方法

send用法

启动生成器的方式有两种,分别是next和send,其中next可以获取生成器yield后面的值,send则可以向生成器内部传值。

1、send在向生成器内部传值的同时,也可以接受生成器返回的值,同时将生成器的代码执行到下一个yield。

def gen_func():
    html = yield "http://www.baidu.com"
    print(html)
    yield 2

if __name__ == "__main__":
    #生成器初始化
    gen = gen_func()
    url = next(gen)
    html = "hello world !"
    res = gen.send(html)
    print(res)

打印结果如下:

hello world !
2

Process finished with exit code 0

2、在调用send发送非none信息时,必须启动生成器,将生成器指针移动到第一个yield的位置。

def gen_func():
    html = yield "http://www.baidu.com"
    print(html)
    yield 2

if __name__ == "__main__":
    #生成器初始化
    gen = gen_func()
    #url = next(gen)
    html = "hello world !"
    res = gen.send(html)
    print(res)

上述未启动生成器,直接传非None值,直接报以下错误:

TypeError: can't send non-None value to a just-started generator

Process finished with exit code 1

以下代码先传None值,在传非None值则没有问题:

def gen_func():
    html = yield "http://www.baidu.com"
    print(html)
    yield 2

if __name__ == "__main__":
    #生成器初始化
    gen = gen_func()
    gen.send(None)
    html = "hello world !"
    res = gen.send(html)
    print(res)

除了传None,也可以通过调用一次next方法来启动生成器。

close方法

close方法可以用来关闭生成器

def gen_func():
    html = yield "http://www.baidu.com"
    print(html)
    yield 2
    yield 3
    return "ccc"

if __name__ == "__main__":
    #生成器初始化
    gen = gen_func()
    print(next(gen))
    gen.close()
    next(gen)

上述代码在执行close关闭生成器后,继续执行next,结果报错:

StopIteration

Process finished with exit code 1

throw方法

throw方法可以向生成器中传入异常。

yield from 方法

1、yield from后面可以接一个可迭代对象:

my_list = [1,2,3,4,5,6,7]
def gen_func():
    yield from my_list


if __name__ == "__main__":
    gen = gen_func()
    print(next(gen))
    print(next(gen))
    print(next(gen))

执行结果如下:

1
2
3

Process finished with exit code 0

由于生成器也是可迭代对象,yield from可以在调用方与子生成器之间建立一个双向通道,以下代码为例:

def g1(gen):
    yield from gen

def main():
    g = g1()
    g.send(None)

其中函数main调用方,g1是委托生成器,gen是子生成器。

async和await

python3.5以后,为了将语义变得更加明确,就引入了async和await关键词用于定义原生的协程。
async和await可以替换yield from的语法:

def downloader(url):
    return "xxx"

def download_url(url):
    html = yield from downloader(url)
    return html

可以写成:

async def downloader(url):
    return "xxx"

async def download_url(url):
    html = await downloader(url)
    return html

你可能感兴趣的:(协程笔记)