Python--Demo18--异步IO之协程

协程:

使用一个线程来实现异步操作的。它相对于多线程执行效率高,不存在线程切换;此外协程不牵扯多线程中锁的机制,所以不必考虑加锁这些复杂操作。

协程是通过generator来实现的,就是yield关键字和send()函数的使用。

生成器的yield关键字:

yield关键字可以将值(信息)返回,同时在信息返回后使程序停留在当前行。

>>> def test():
...     number=1
...     while True:
...             number*=2
...             yield number
...             print(‘yield下面的代码‘)
...
>>> t=test()
>>> t
<generator object test at 0x000001E372BDA5F0>
>>> type(t)
<class ‘generator‘>
>>> next(t)
2
>>>
>>> next(t)
yield下面的代码
4
>>> next(t)
yield下面的代码
8
>>> next(t)
yield下面的代码
16

生成器的send()函数:

yield还可以接收调用者传递过来的信息:通过sned()函数,将值(消息)传递给生成器。生成器通过yield前面的变量来接收传递过来的值。

>>> def tst():
...     number=1
...     while True:
...             pam=yield number
...             print(‘yield下面代码‘)
...             print(‘调用者传递过来的值:‘,pam)
...
>>> tt=tst()
>>> tt.send(None)
1
>>> tt.send(None)
yield下面代码
调用者传递过来的值: None
1
>>> tt.send(111)
yield下面代码
调用者传递过来的值: 111
1

说明:send()函数和next()函数都推动生成器向下执行,next()函数仅仅是接收了yield右边的返回值;而send()函数则可以使调用者给生成器发消息。

生成器的close()函数:

调用close()函数就可以关闭生成器,接下来next()函数再应用于生成器就会提示生成器已停止的信息

>>> def test():
...     number=1
...     while True:
...             number*=2
...             yield number
...             print(‘yield下面的代码...‘)
...
>>> gen=test()
>>> next(gen)
2
>>> next(gen)
yield下面的代码...
4
>>> next(gen)
yield下面的代码...
8
>>> gen.close()
>>> next(gen)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

协程:

通过下面一个消费者和生产者的例子,我们实现一下,生产者生产之后消费者立马消费掉,来进一步了解协程。

注意:必须在调用send()前,启动生成器。启动生成器可以是next(生成器)或者生成器.send(None),让生成器执行到第一个yield处。之后就可以不断使用send()传入值了。

def consumer():
    r = ‘‘
    while True:
        n = yield r  # yield 后面的r是返回给调用者的值,yield前面的 n 用来接收调用者通过send函数传过来的值
        if not n:  # 如果n是None,就结束该函数,因为None代表还没有生产出来产品
            print(‘consumer即将结束‘)
            return
        print(‘消费者正在消费%s...‘ % n)
        r = ‘200 OK‘

def produce(c):
    print(‘send返回值为: ‘, c.send(None))
    n = 0
    while n < 5:
        n = n + 1
        print(‘生产者生产了%s...‘ % n)
        r = c.send(n)  # 生产出来就去给消费者
        print(‘生产者接收消费者返回的信息:%s‘ % r)
    c.close()

c = consumer()
produce(c)

结果:

send返回值为:
生产者生产了1...
消费者正在消费1...
生产者接收消费者返回的信息:200 OK
生产者生产了2...
消费者正在消费2...
生产者接收消费者返回的信息:200 OK
生产者生产了3...
消费者正在消费3...
生产者接收消费者返回的信息:200 OK
生产者生产了4...
消费者正在消费4...
生产者接收消费者返回的信息:200 OK
生产者生产了5...
消费者正在消费5...
生产者接收消费者返回的信息:200 OK

说明:整个过程无锁,一个线程使produce()和consumer()完成协作。

原文地址:https://www.cnblogs.com/bigbosscyb/p/12394744.html

时间: 2024-10-07 18:32:35

Python--Demo18--异步IO之协程的相关文章

Python异步IO之协程(一):从yield from到async的使用

引言:协程(coroutine)是Python中一直较为难理解的知识,但其在多任务协作中体现的效率又极为的突出.众所周知,Python中执行多任务还可以通过多进程或一个进程中的多线程来执行,但两者之中均存在一些缺点.因此,我们引出了协程. Tips 欲看完整代码请见:我的GitHub 为什么需要协程?首先,我们需要知道同步和异步是什么东东,不知道的看详解.简单来说:[同步]:就是发出一个“调用”时,在没有得到结果之前,该“调用”就不返回,“调用者”需要一直等待该“调用”结束,才能进行下一步工作.

Python异步IO之协程(二):使用asyncio的不同方法实现协程

引言:在上一章中我们介绍了从yield from的来源到async的使用,并在最后以asyncio.wait()方法实现协程,下面我们通过不同控制结构来实现协程,让我们一起来看看他们的不同作用吧- 在多个协程中的线性控制流很容易通过内置的关键词await来管理.使用asyncio模块中的方法可以实现更多复杂的结构,它可以并发地完成多个协程. 一.asyncio.wait() 你可以将一个操作分成多个部分并分开执行,而wait(tasks)可以被用于中断任务集合(tasks)中的某个被事件循环轮询

异步IO(协程,消息循环队列)

同步是CPU自己主动查看IO操作是否完成,异步是IO操作完成后发出信号通知CPU(CPU是被通知的) 阻塞与非阻塞的区别在于发起IO操作之后,CPU是等待IO操作完成再进行下一步操作,还是不等待去做其他的事直到IO操作完 成了再回来进行. 消息模型:当遇到IO操作时,代码只负责发出IO请求,不等待IO结果,然后直接结束本轮消息处理,进入下一轮 消息处理过程.当IO操作完成后,将收到一条"IO完成"的消息,处理该消息时就可以直接获取IO操作结果. 子程序调用总是一个入口,一次返回,调用顺

Python的异步编程[0] -&gt; 协程[1] -&gt; 使用协程建立自己的异步非阻塞模型

使用协程建立自己的异步非阻塞模型 接下来例子中,将使用纯粹的Python编码搭建一个异步模型,相当于自己构建的一个asyncio模块,这也许能对asyncio模块底层实现的理解有更大的帮助.主要参考为文末的链接,以及自己的补充理解. 完整代码 1 #!/usr/bin/python 2 # ============================================================= 3 # File Name: async_base.py 4 # Author: L

异步io和协程

常见的异步io模块asyncio.gevent.twisted.tornado 核心技术为select()和协程 异步io请求的本质则是[非阻塞Socket]+[IO多路复用] 协程在这里不是一个必须使用的技术,在使用select()事件驱动循环本身就可以达到单线程异步的效果 io协程在遇到阻塞时进行切换,其实现需要依赖select()事件循环进行切换 协程本质是一种上下文切换技术,通过生成器yield记录状态的特性来实现 r,w,e = select.select([rlist],[wlist

Python爬虫案例演示:Python多线程、多进程、协程

很多时候我们写了一个爬虫,实现了需求后会发现了很多值得改进的地方,其中很重要的一点就是爬取速度.本文 就通过代码讲解如何使用 多进程.多线程.协程 来提升爬取速度.注意:我们不深入介绍理论和原理,一切都在代码中. 二.同步 首先我们写一个简化的爬虫,对各个功能细分,有意识进行函数式编程.下面代码的目的是访问300次百度页面并返回状态码,其中 parse_1 函数可以设定循环次数,每次循环将当前循环数(从0开始)和url传入 parse_2 函数. import requests def pars

关于C10K、异步回调、协程、同步阻塞

最近到处在争论这些话题,发现很多人对一些基础的常识并不了解,在此发表一文做一下解释.此文未必能解答所有问题,各位能有一个大致的了解就好. C10K的由来 大家都知道互联网的基础就是网络通信,早期的互联网可以说是一个小群体的集合.互联网还不够普及,用户也不多.一台服务器同时在线100个用户估计 在当时已经算是大型应用了.所以并不存在什么C10K的难题.互联网的爆发期应该是在www网站,浏览器,雅虎出现后.最早的互联网称之为Web1.0, 互联网大部分的使用场景是下载一个Html页面,用户在浏览器中

python并发编程(二):协程

'''协程: 1. 协程的定义: 1) 是一种用户态的轻量级线程, 即协程是由用户程序自己控制调度的 2) 是一种协作而非抢占式的处理并发方式, A --> B ---> A --> C 3) 协程的切换属于程序级别的, 操作系统不需要切换 2. 协程的特点: 1) 协程本身是一个线程, 是用户态的切换 2) 相比线程优点: 1> 切换没有消耗 2> 修改共享程序不需要加锁 3) 相比线程缺点: 一旦引入协程,就需要检测单线程下所有的IO行为, 实现遇到IO就切换,少一个都不

Python黑魔法 --- 异步IO( asyncio) 协程

https://www.jianshu.com/p/b5e347b3a17c python asyncio 网络模型有很多中,为了实现高并发也有很多方案,多线程,多进程.无论多线程和多进程,IO的调度更多取决于系统,而协程的方式,调度来自用户,用户可以在函数中yield一个状态.使用协程可以实现高效的并发任务.Python的在3.4中引入了协程的概念,可是这个还是以生成器对象为基础,3.5则确定了协程的语法.下面将简单介绍asyncio的使用.实现协程的不仅仅是asyncio,tornado和g

python进程、线程、协程、IO多路复用

线程进程介绍 工作最小单元是线程 应用程序 -> 至少有一个进程 -> 至少有一个线程 应用场景: IO密集型:线程 计算密集型:进程 4. GIL,全局解释器锁. 保证同一个进程中只有一个线程同时被调度 线程 1. 基本使用 def task(arg): time.sleep(arg) print(arg) for i in range(5): t = threading.Thread(target=task,args=[i,]) # t.setDaemon(True) # 主线程终止,不等