协程

一、协程的基本概念:是一个微线程,不会产生cpu的开销,有自己的寄存器。

1、yield

(1)、在自定义函数中使用yield表明自定义函数为生成器

(2)、生成器常用的方法有:

A、generator.__next__():在上一次yield的位置继续执行

B、generator.send():在上一次函数中yield的位置继续执行,并且传递参数给yield

2、yield的例子

def producer():
    print('\033[1;31m[Producer]\033[0m开始生产包子了')
    c1.__next__()
    c2.__next__()
    n = 0
    while n < 5:
        n += 1
        print('\033[1;31m[Producer]\033[0m生产第%s个包子' % n)
        c1.send(n)
        c2.send(n)


def consumer(name):
    print('\033[1;31m%s\033[0m开始吃包子了!' % name)
    while True:
        baozi = yield
        print('%s要吃第%s个包子' % (name, baozi))


c1 = consumer('Treelight')
c2 = consumer('Alex')
p = producer()
yield

3、在协程中手动切换

from greenlet import greenlet


def run1():
    print('First time in run1')
    g2.switch()
    print('Second time in run1')
    g2.switch()


def run2():
    print('First time in run2')
    g1.switch()
    print('Second time in run2')


if __name__ == '__main__':
    g1 = greenlet(run=run1)
    g2 = greenlet(run=run2)
    g1.switch()
在协程中手动切换上下文

(1)、协程中什么时候产生上下文切换:产生IO时

(2)用法:

A、定义实例 g1 = greelet(run=<func_name>)

B、切换到g1:g1.swich()

4、自动切换,例子:

import gevent


def run1():
    print('in the run1')
    gevent.sleep(2)  # 模拟IO
    print('in the run1 again')


def run2():
    print('in the run2')
    gevent.sleep(1)  # 模拟IO
    print('in the run2 again')


def run3():
    print('in the run3')
    gevent.sleep(0)  # 模拟IO
    print('in the run3 again')


if __name__ == '__main__':
    gevent.joinall([  # 需使用列表
        gevent.spawn(run1),  # 生成
        gevent.spawn(run2),
        gevent.spawn(run3)
    ])
    # 在gevent的joinall方法中需使用列表
协程中自动上下文切换

(1)、gevent.sleep():模拟IO

(2)、gevent.joinall([gevent.spawn(<fun_name>)。。。。])  需使用列表,生成。

 

二、协程的基本案例

1、爬虫(注意:需要使用monkey模块,调用monkey.patch_all,使得gevent能识别程序中的IO)

import gevent
from urllib import request
import time
from gevent import monkey
monkey.patch_all()  # 打补丁,使得gevent能识别此程序中产生的IO,从此产生上下文的切换


def get_url_data(url):
    print('获取%s的数据' % url)
    data = request.urlopen(url).read()
    print('网页%s的大小:%s' % (url, len(data)))


start_time = time.time()
url_list = ['https://www.python.org/',
            'https://www.yahoo.com/',
            'https://github.com'
            ]
for url in url_list:
    get_url_data(url)
print('同步获取网页的时间是:', (time.time() - start_time))
print('\n\n')
start_time = time.time()
gevent.joinall([
    gevent.spawn(get_url_data, 'https://www.python.org/'),
    gevent.spawn(get_url_data, 'https://www.yahoo.com/'),
    gevent.spawn(get_url_data, 'https://github.com/')
])
print('异步获取网页的时间是:', (time.time() - start_time))
协程在爬虫中的应用

 2、在socket上实现了并发

import gevent
import socket
from gevent import monkey
monkey.patch_all()


def server(port):
    svr= socket.socket()
    svr.bind(('localhost', port))
    svr.listen()
    while True:
        conn, addr = svr.accept()
        gevent.spawn(handle_request, conn)


def handle_request(conn):
    while True:
        try:
            data = conn.recv(1024)
            conn.send(data)
        except ConnectionResetError:
            print('客户端已断开')
            break


server(9999)
server
import socket
client = socket.socket()
client.connect(('localhost', 9999))
while True:
    msg = input('>>:').strip()
    client.send(msg.encode('utf-8'))
    print(client.recv(1024))
client

 三、协程实现的基本原理

        协程当一遇到IO操作就会切换,IO操作完就会回来。那如何监测IO操作呢?就是通过事件驱动的方式。当一个事件发生时,就会注册一个事件,放到一个队列,然后就产生IO操作,协程就把IO操作交给了操作系统,同时协程还声明了一个回调函数给操作系统,以便通知协程IO已经操作完毕。

转载于:https://www.cnblogs.com/Treelight/p/10958224.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值