多任务——协程

迭代器

可迭代对象:实现迭代器协议的对象,迭代器协议:对象实现了_iter()_和_next()_方法

在python中,可以通过isinstance()判断一个对象是否可以迭代

from collections import Iterable

# 判断列表
print(isinstance([], Iterable))

# 判断元组
print(isinstance((), Iterable))

# 判断字典
print(isinstance({}, Iterable))

# 判断字符串
print(isinstance("", Iterable))

# 判断整数
print(isinstance(100, Iterable))

# 判断boolean
print(isinstance(False, Iterable))

生成器

包含yield关键字的函数,也是一个迭代器,调用next()方法,yield:保持当前程序的执行状态

  • yield关键字有两点作用:
    • 保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
    • 将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用
  • 可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)
  • 也可以使用send()函数来唤醒生成器,使用send()可以在唤醒的同事向断点出传入一个附加数据数据

协程

协程,又称微线程,单线程下的并发,是一种用户态的轻量级线程,由用户之间控制调度的

协程的本质就是在单线程下,由用户之间控制一个任务遇到IO阻塞了就切换另外一个任务去执行,以此来提升效率

在python中使用协程完成多任务,用greenlet模块对其封装,从而使得切换任务变的更加简单

安装方式:

sudo pip3 install greenlet
import greenlet
import time
def wotk():
    while True:
        print("---A---")
        g2.switch()
        time.sleep(1)


def work():
    while True:
        print("---B---")
        g1.switch()
        time.sleep(2)


if __name__ == '__main__':
    # 生成greelent对象
    g1=greenlet.greenlet(run=wotk)
    g2=greenlet.greenlet(run=work)

    g1.switch()
    g2.switch()

gevent

greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent

安装:

pip3 install gevent

代码如下:

import gevent
import time
from gevent import monkey  # 打补丁

def task(index):
    for i in range(3):
        print('任务%d----代码快%d,当前gevent对象名称:%s'%(index,i,str(gevent.getcurrent())))
        time.sleep(1)


if __name__ == '__main__':
    # 打补丁
    monkey.patch_all()
    gevent.joinall([gevent.spawn(task,1),
                    gevent.spawn(task, 2),
                    gevent.spawn(task, 3)])
    print("主线程执行的最后代码")

打印结果如下:

协程之并发下载器实现案例

import urllib.request
from gevent import monkey
import gevent
import time

# 网络数据下载实现
def download(url,file_name):
    # url:要下载数据的网站
    # file_name:存储在本地的文件名
    response=urllib.request.urlopen(url)

    # 保存文件
    write_file=open("文件路径"+file_name,"wb")

    while True:
        content=response.read(4096)
        if content:
            write_file.write(content)
        else:
            break
    write_file.close()

if __name__ == '__main__':
    # 打补丁
    monkey.patch_all()
    start_time=time.time()
    url1="https://desk-fd.zol-img.com.cn/t_s960x600c5/g5/M00/02/00/ChMkJ1bKw0yIXFW5AAbUq3ToEXAAALG0wMHWJsABtTD684.jpg"
    url2="https://desk-fd.zol-img.com.cn/t_s960x600c5/g5/M00/0F/08/ChMkJlauzGuIDo5-AAmEKbHNhzwAAH89wIKvi8ACYRB721.jpg"
    url3="https://desk-fd.zol-img.com.cn/t_s960x600c5/g5/M00/05/0C/ChMkJ1l_JQ6IXG6dAAiAKWFIRycAAfSaADwC8oACIBB894.jpg"
    gevent.joinall([gevent.spawn(download,url1,"1.jpg"),
                    gevent.spawn(download, url2, "2.jpg"),
                    gevent.spawn(download, url3, "3.jpg")])
    end_time=time.time()
    print("下载的时间为:{}".format(end_time-start_time))

打印结果如下:

原文地址:https://www.cnblogs.com/xiaolu915/p/10517386.html