python多任务重点笔记4-3

导读:本篇文章讲解 python多任务重点笔记4-3,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

多任务之协程

协程

  • 1什么是协程?
  • 我们要知道协程需要从头开始
    在这里插入图片描述
    如果你执行用协程,其他得不用了解直接用gevent。但是你要想明白原理,那你要慢慢从头了解

迭代器

  • 1 判断一个变量是不是可以迭代
from collections import Iterable
isinstance([11,22,33], Iterable)判断是不是Itertable的子类
解释一下typeisinstance的区别:
isinstance()type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()

有迭代功能的比如:列表, 元组 ,字典
如果是Iterable()的子类可以迭代的
在这里插入图片描述

  • 2 说一下for 遍历得步骤
    迭代环境会优先使用迭代协议(也就是调用__next__方法),如果对象不支持迭代协议,则使用索引方式进行迭代
    (不知道大家会不会让iter返回一个列表或者字典,元组之类的可迭代得对象,这个是时候程序出现错误,查了一下可能是因为list不是一个迭代器而是一个迭代对象。其他的没在深究)
for i in xxx_obj:
	pass
1 首先for会判断我们的xxx_obj是不是一个可迭代对象
2 如果满足一得话就会调用它的iter()方法,得到其中得返回值
3 然后它会接着调用iter返回值对象得next()方法当遇到StopIterable异常得时候停止遍历
  • 3 如何自己实现一个可迭代的对象
    用__iter__()函数来实现,代码如下(注释往往比代码更重要的奥
from collections import Iterable

class ClassMate(object):
    def __init__(self,name):
        self.name = name
    # 当我们加入函数__iter__()的时候这个时候他产生的对象就是可迭代对象
    def __iter__(self):
        print("this is iterable")


classmate = ClassMate("one")
print(isinstance(classmate, Iterable))

其中对于__iter__()这个函数返回值必须是一个具有itre和next方法得引用,上面这个虽然创建了一个迭代对象,但是不能用for进行遍历。如下代码可以遍历
,我们给类中添加一个next()方法,这个时候iter方法通过返回自己,然后就可调用next然后逐个返回,当有异常StopIteration抛出得时候for停止遍历。

from collections import Iterable

class ClassMate(object):
    def __init__(self):
        self.name = list()
        self.count = 0
    def add(self, name):
        self.name.append(name)
    # 当我们加入函数__iter__()的时候这个时候他产生的对象就是可迭代对象
    def __iter__(self):
        return self
    def __next__(self):
        if self.count < len(self.name):
            data = self.name[self.count]
            self.count += 1
            return data
        else:
            raise StopIteration


classmate = ClassMate()
classmate.add("老王1")
classmate.add("老王2")
classmate.add("老王3")
print(isinstance(classmate, Iterable))
for i in classmate:
    print(i)
  • 3 迭代器的应用
    先说个例子,我们都知道授人以鱼不如授人以渔,就是说我给你鱼吃不如传授给你怎么区捕鱼。为了加强理解我再说一个,就是我们饿的时候才去做饭,有没有这样的,就是我把十天的饭都做好放起来,饿了的时候不用再去做饭了,直接拿着吃就好了。但是如果我们把十年的饭都做好呢,就算做好了放在那里。而且不保鲜。就像是一大批数据,比如列表存数据,数据存放在内存中,如果有一大批数据的话可能就存不了了如果我们能找到一个方法,或者一个函数存放起来,我们通过索引取值,随时要随时生成就好了
    总之:(这句有用)我们为了保护内存,我们不放数据,放的是生成数据的方法。等比数列应该都知道,我们放个公式在里面,需要的时候传个索引就出来了相应的值了。而不需要把每个值都放里面。
例如们进行斐波那契数列,如果我们需要大量的数据,我们用列表存储的话,会用很多内存,但是我存一个方法的话就想用多少,什么时候用,他就会慢慢给我取,随取随用。
from collections import Iterable

class ClassMate(object):
    def __init__(self,num):
        self.name = list()
        self.num = num
        self.count = 0
        self.a = 1
        self.b = 1

    # 当我们加入函数__iter__()的时候这个时候他产生的对象就是可迭代对象
    def __iter__(self):
        return self


    def __next__(self):
        if self.count < self.num:
            data = self.a
            self.a, self.b = self.b, self.a + self.b
            self.count += 1
            return data
        else:
            raise StopIteration


classmate = ClassMate(10)
for i in classmate:
    print(i)

运行结果:
在这里插入图片描述
在这里插入图片描述

生成器

  • 1 生成器是一种特殊的迭代器
    创建上生成器的方式
    • 列表推导式

    nums = [x2 for x in range(10)]这个返回的是一个列表,当我们把中括号变为括号的时候,这个时候Nums = (x2 for i in range(10))这个时候它就是一个可迭代,也就是一个生成器。
    在这里插入图片描述

    • 定一个函数,让其变成生成器,函数中有yield就是一个生成器模板

    加入yield之后,这个函数就是一个可迭代的对象就是一个生成器

def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        yield a
        a, b = b, a+b
        current_num += 1
"""
代码讲解:如果在调用create_ num的时候,发现这个函数中有yield那么此时,
不是调用函数,而是创建一个生成器对象
执行顺序,当执行到yield的时候,这个时候程序会在哪力停下来,然后把a的值返给for循环中的i然后输出。执行完之后,然后程序继续执行,以此循环。
因为生成器是一种特殊的迭代器,也可以通过next进行取值,如果超出取值
范围的时候就会报异常StopIteration
print(create_num(3))
obj = create_num(3)
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
"""
print(create_num(10))
obj = create_num(10)
for i in obj:
    print(i)

在这里插入图片描述
通过next取值:
在这里插入图片描述
如果函数有个返回值怎么接受

def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        yield a
        a, b = b, a+b
        current_num += 1
    """这里有个返回值"""
    return "ok"

print(create_num(3))
obj = create_num(10)
while True:
    try:
        ret = next(obj)
        print(ret)
    except Exception as ex:
        print("return",ex)
        break

异常中有个返回值我们处理异常的时候接受一下就可以了
在这里插入图片描述
与next相对应的是send,它的用法:
send使用时obj.send(发送的数据)

def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        yield a
        a, b = b, a+b
        current_num += 1
    return "ok"


# print(create_num(3))
# obj = create_num(10)
# while True:
#     try:
#         ret = next(obj)
#         print(ret)
#     except Exception as ex:
#         print("return",ex)
#         break


def send_make(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        rep = yield a
        print("这是send发送的数据", rep)
        if rep:
            current_num = int(rep)
        a, b = b, a+b
    return "ok"

obj = send_make(10)
count = 1 
while True:
    try:
        if count == 3:
            obj.send("10")
        num = obj.send(None)
        count += 1
        print(num)
    except Exception as ex:
        print(ex)
        break

运行结果:
提示:如果第一次使用send,需要传送一个空值因为程序从头开始执行,当我们刚开始加载程序的时候,程序没有接受send的值的参数,这个时候就会报错。所以第一次使用需要用None
在这里插入图片描述

协程

  • 1 我们受用yield实现多任务
def task_1():
    while True:
        print("---1-----1-1-1-1-1-1-")
        yield

def task_2():
    while True:
        print("---2-----22222222222")
        # 在着会暂停程序,所以我可以利用它的暂停去执行其他的程序
        yield



def main():
    t1 = task_1()
    t2 = task_2()
    while True:
        time.sleep(1)
        next(t1)
        time.sleep(1)
        next(t2)

main()

运行结果
在这里插入图片描述
这个时候问题来了,如果有好多函数怎么办,我们还要写while循环又要添加函数太麻烦了,有没有好的方法。这个时候greenlet出来了。直接看代码:

这个包greenlet需要安装一下。
from greenlet import greenlet
def task_3():
    while True:
    	开启这个greenlet
        gr4.switch()
        print("---1-----1-1-1-1-1-1-")
        time.sleep(1)

def task_4():
    while True:
        gr3.switch()
        print("---2-----22222222222")
        time.sleep(1)
       
创建这个对象里面填入函数名
gr3 = greenlet(task_3)
gr4 = greenlet(task_4)
gr3.switch()

运行结果:
在这里插入图片描述
这里介绍一下gevent
greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent
其原理是当-个greenlet遇到IO(指的是input output输入输出,比如网络、文件操作等)操作时,
比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行
由于I0操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在
运行,而不是等待I0

import time

import gevent
为了解决用普通time延时可以实现多任务的延时,我们导入此包
from gevent import monkey
然后运行这个方法就可以了
monky.patch_all()
def task_5(i):
    for j in range(6):
        print("1-1-1-1-",i,gevent.getcurrent())
        
        """gevent遇到延时才会运行其他的程序,
        但是对于time,sleep这个延时不起作
        用需要自己的延时gevent.sleep(10)"""
        
        time.sleep(1)

def task_6(i):
    for j in range(6):
        print("2222222",i,gevent.getcurrent())
        time.sleep(1)

ge1 = gevent.spawn(task_5, "this is five")
ge2 = gevent.spawn(task_6, "this is six")
ge1.join()
ge2.join()

用普通延时time.sleep()运行结果:
在这里插入图片描述
用gevent.sleep()延时的结果就有线程的意思了
在这里插入图片描述
参考代码用gevent.sleep:
在这里插入图片描述

放两个彩蛋

1彩蛋

在这里插入图片描述
迭代环境会优先使用迭代协议(也就是调用__next__方法),如果对象不支持迭代协议,则使用索引方式进行迭代
(不知道大家会不会让iter返回一个列表或者字典,元组之类的可迭代得对象,这个是时候程序出现错误,查了一下可能是因为list不是一个迭代器而是一个迭代对象,并且我在在list得源代码中找到了iter但是没找到next方法哦也许就是用的索引进行迭代的吧。其他的没在深究,有知道得大佬可以给解释一下)
如图报错了:TypeError: iter() returned non-iterator of type ‘list’
在这里插入图片描述
list源代码

在这里插入图片描述

2 彩蛋

在这里插入图片描述

进程、线程、协程对比

请仔细理解如下的通俗描述
●有一个老板想要开个工厂进行生产某件商品(例如剪子)
●他需要花一些财力物力制作一 条生产线,这个生产线上有很多的器件以及材料这些所有的为了能够生
产剪子而准备的资源称之为:进程
只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步 步的将剪子做出来,这个来做事情的工人称之为:线程
●这个老板为了提高生产率,想到3种办法:
**1.**在这条生产线上多招些工人,一起来做剪子,这样效率是成倍增长,即单进程多线程方式
**2.**老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老
板又花了些财力物力购置了另外-条生产线,然后再招些工人这样效率又再-步提高了,即多进
程多线程方式
**3.**老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是 多进程
的,每个进程中又有多个线程), 为了再次提高效率,老板想了个损招,规定:如果某个员工在
上班时临时没事或者再等待某些条件(比如等待另一个工人生产完谋道工序之后他才能再次工
作), 那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果-一个线程等待某些条
件,可以充分利用这个时间去做其它事情,其实这就是:协程方式
简单总结
1.进程是资源分配的单位
2.线程是操作系统调度的单位
3.进程切换需要的资源很最大,效率很低,
4.线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
5.协程切换任务资源很小,效率高
6.多进程、多线程根据cpu核数不- -样可能是并行的,但是协程是在一个线程中所以是并发

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/119319.html

(0)
seven_的头像seven_bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!