python3协程实操备忘

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
'''
协程:又称微线程,纤程,只有一个线程。但由程序根据需要自己调度,协同运行!
1.生成器yield实现协程功能:yield控制生成器执行的中断,并记录执行的位置;next()函数和send()方法控制程序继续执行
2.greenlet模块实现程序间切换执行:
    gevent安装需要依赖greenlet,以下为gevent的安装方法,同时会安装greenlet
    pip3 install --user gevent
    先创建greenlet对象,再使用switch()方法进行跳转
3.gevent模块实现程序间切换执行:----推荐使用,特别是爬虫
    第三方库,gevent会主动识别程序内部的IO操作,当子程序遇到IO后,切换到别的子程序。如果所有的子程序都进入IO,则阻塞。
    gevent.joinall([gevent.spawn(f,args),gevent.spawn(f,args),.....]),创建线程并行执行程序,碰到IO就切换
    显著提高程序运行速度

    from gevent import monkey
    monkey.patch_all()       #将程序中所有IO操作做上标记使程序非阻塞状态,速度更快

'''
#************gevent爬虫异步IO阻塞切换:实现协程功能**************
import gevent
from gevent import monkey
monkey.patch_all()       #将程序中所有IO操作做上标记使程序非阻塞状态,速度更快!
from urllib.request import urlopen
import random
import os

def func(url):
    print("获得url:%s"%url)
    resp = urlopen(url)     # 对象 http.client.HTTPResponse
#    print(type(resp))
    data = resp.read()    # bytes类型的数据
#    print(type(data))
    filename = ""
    for i in range(10):     # 获得一个由字母和数据随机生成的10位数
        a = str(random.choice([random.randrange(10),chr(random.randrange(65,91))]))
        filename += a
    filename = filename + ".html"   # 把10位的随机数作为文件名
    filename = os.path.join(os.path.dirname(os.path.abspath(__file__)),"html",filename)  # 获得是保存文件的绝对路径
    with open(filename,"wb") as f:
        f.write(data)

if __name__ == "__main__":
    gevent.joinall([                        
        gevent.spawn(func, "http://www.mmjpg.com/"),   #创建线程并行执行程序,碰到IO就切换
        gevent.spawn(func, "http://www.xiaohuar.com/"),
        gevent.spawn(func, "http://www.zol.com.cn"),   
    ])
'''
#************greenlet实现协程功能**************
from greenlet import greenlet

def A(n):
    print("A....1.....%s"%n)
    b.switch()  # 启动greenlet对象b,并运行
    print("A.....2.。。。。%s"%n)
    b.switch()
    
def B():
    print("B.....3")
    a.switch()  # 启动greenlet对象a(函数内无法再传参数)
    print("B......4")

if __name__ == "__main__":
    a = greenlet(A)     # 获得一个greenlet对象,但没有启动,<greenlet.greenlet object at 0x7f6a98756cc0>
    b = greenlet(B)     # 相当于把函数变成了greenlet对象
    a.switch(5)  # 启动a函数,并传参数给到函数---
'''

'''
#************生成器yield实现协程功能**************
import time

def producer(name):
    print("%s我要开始做包子了。。。"%name)
    next(conn1)     # 启动消费者生成器。碰到yield停止,第一次启动必须用next方法。或者是send(None)
    next(conn2)
    i = 0
    j = 1
    while True:
        i += 2
        j += 2
        print("%s生产了一个包子%s"%(name,i))
        print("%s生产了一个包子%s"%(name,j))
        conn1.send(i)   # 继续启动消费者生成器。继续执行。碰到yield停止。并把包子名称发送给到yield前面的变量接收
        conn2.send(j)
        time.sleep(2)
                   
def consumer(name):
    print("%s我要开始吃包子了。。。"%name)
    while True:
        bz_name = yield
        print("%s正吃包子%s。。。"%(name,bz_name))

if __name__ == "__main__":
    conn1 = consumer("c1")      # 创建一个生产器对象
    conn2 = consumer("c2")
    producer("scz")     # 调用生产者函数。启动生产包子
'''    
    
    


posted @ 2019-01-11 13:30  挖坑达人  阅读(6)  评论(0编辑  收藏  举报