zoukankan      html  css  js  c++  java
  • 多任务--协程

    迭代器:

    常用的可以迭代的类型:

    1 from collections import Iterable
    2 print(issubclass(int,Iterable))    #False
    3 print(issubclass(float,Iterable))  #False
    4 print(issubclass(list,Iterable))   #True
    5 print(issubclass(tuple,Iterable))  #True
    6 print(issubclass(dict,Iterable))   #True
    7 print(issubclass(str,Iterable))    #True
    8 print(issubclass(set,Iterable))    #True

    下面尝试自己写个可以迭代的类出来:

     1 class ClassMate:
     2     def __init__(self):
     3         self.names = list()
     4     
     5     def add(self,name):
     6         self.names.append(name)
     7 
     8 if __name__ == '__main__':
     9     classmate = ClassMate()
    10     classmate.add("tom")
    11     classmate.add("jane")
    12     classmate.add("egon")
    13     
    14     for name in classmate:   #报错,此时是不可以迭代的
    15         print(name)   
    此时的报错: TypeError: 'ClassMate' object is not iterable

    继续

     1 class ClassMate:
     2     def __init__(self):
     3         self.names = list()
     4 
     5     def add(self,name):
     6         self.names.append(name)
     7 
     8     def __iter__(self):
     9         pass
    10 
    11 if __name__ == '__main__':
    12     classmate = ClassMate()
    13     classmate.add("tom")
    14     classmate.add("jane")
    15     classmate.add("egon")
    16 
    17     for name in classmate: #此时是不可以迭代的
    18         print(name)
    19     
    20     #此时的报错是:TypeError: iter() returned non-iterator of type 'NoneType'

    但是,此时它已经是个可迭代的对象了,使用如下代码验证:

    print(issubclass(ClassMate,Iterable))

    所以:

    但是,还是用不了for 循环。

    继续看:

    只要使__iter__() 方法返回一个有iter 和next 方法的对象就行了!

    for 循环的执行过程,

    for 循环得到的是返回的对象里的__next__() 返回的值!

     1 from collections import Iterable,Iterator
     2 
     3 class ClassMate:
     4     def __init__(self):
     5         self.names = list()
     6 
     7     def add(self,name):
     8         self.names.append(name)
     9 
    10     def __iter__(self):
    11         # pass  #必须要返回一个具有 iter 和 next 方法的对象
    12         return MyIterator()
    13 
    14 
    15 class MyIterator:
    16     def __iter__(self):
    17         pass
    18     def __next__(self):
    19         pass
    20 
    21 
    22 if __name__ == '__main__':
    23     classmate = ClassMate()
    24     classmate.add("tom")
    25     classmate.add("jane")
    26     classmate.add("egon")
    27 
    28     #判断 classmate 是否是可迭代对象
    29     # print(isinstance(classmate,Iterable))  #只要是有对象iter() 方法就行,就是可迭代对象
    30 
    31 
    32     myiterator = iter(classmate) #它返回的是MyIterator 的对象 ,它是个迭代器
    33     #判断myiterator 是否是迭代器
    34     # print(isinstance(myiterator,Iterator)) true  #迭代器要满足iter() 和next() 都有

    理论上,此时已经可以运行,但是,迭代器中的next 中还需要一些处理:

     1 from collections import Iterable,Iterator
     2 import time
     3 
     4 class ClassMate:
     5     def __init__(self):
     6         self.names = list()
     7 
     8     def add(self,name):
     9         self.names.append(name)
    10 
    11     def __iter__(self):
    12         # pass  #必须要返回一个具有 iter 和 next 方法的对象
    13         return MyIterator()
    14 
    15 
    16 class MyIterator:
    17     def __iter__(self):
    18         pass
    19     def __next__(self):
    20         return 11
    21 
    22 
    23 
    24 if __name__ == '__main__':
    25     classmate = ClassMate()
    26     classmate.add("tom")
    27     classmate.add("jane")
    28     classmate.add("egon")
    29 
    30     for name in classmate:
    31         print(name)
    32         time.sleep(1)  #这时的输出是 每1s 打印一遍11
    33         

    每秒打印11  ,也验证了上面的说法,for name in classmate 时,

    首先判断classmate 是否可迭代(__iter__())

    继续,判断classmate 中的__iter__() 的返回值是否是个迭代器(对象有 __iter__() __next__())

    最后,得到的name 就是 迭代器对象中的__next__() 方法的返回值 !

    继续改进

     1 from collections import Iterable,Iterator
     2 import time
     3 
     4 class ClassMate:
     5     def __init__(self):
     6         self.names = list()
     7 
     8     def add(self,name):
     9         self.names.append(name)
    10 
    11     def __iter__(self):
    12         # pass  #必须要返回一个具有 iter 和 next 方法的对象
    13         return MyIterator(self.names)
    14 
    15 
    16 class MyIterator:
    17     def __init__(self,args):
    18         self.args = args
    19         self.current_num = 0
    20     def __iter__(self):
    21         pass
    22     def __next__(self):
    23         if self.current_num<len(self.args):
    24             ret = self.args[self.current_num]
    25             self.current_num +=1
    26             return ret
    27         else:
    28             raise StopIteration  #结束for 循环  
    29 
    30 if __name__ == '__main__':
    31     classmate = ClassMate()
    32     classmate.add("tom")
    33     classmate.add("jane")
    34     classmate.add("egon")
    35 
    36     for name in classmate:
    37         print(name)
    38         time.sleep(1)

    不过这时的问题是:有个多余的类,所以我们考虑在一个类里就搞定事情:

    最终如下:

    from collections import Iterable,Iterator
    import time
    
    class ClassMate:
        def __init__(self):
            self.names = list()
            self.current_num = 0
    
        def add(self,name):
            self.names.append(name)
    
        def __iter__(self):
            # pass  #必须要返回一个具有 iter 和 next 方法的对象
            return self   #返回的是个具有 next 和iter 的迭代器
    
        def __next__(self):
            if self.current_num<len(self.names):
                ret = self.names[self.current_num]
                self.current_num +=1
                return ret  #它就是for 循环的name
            else:
                raise StopIteration  #for in  结构会默认处理这个异常
    
    if __name__ == '__main__':
        classmate = ClassMate()
        classmate.add("tom")
        classmate.add("jane")
        classmate.add("egon")
    
        for name in classmate:
            time.sleep(1)
            print(name)
    
    '''
        这也说明了一点:
            一个可以迭代的对象 不一定  是个迭代器
            一个迭代器  一定  是可迭代的对象  
    '''

    迭代器的应用:

    迭代器的优点:

    占用极小的内存空间,它存储的是生成数据的方式,而不是真实的数据本身!

    斐波那契数列案例:

    第一种:用列表放这个数列:

     1 nums = list()
     2 a = 0
     3 b = 1
     4 
     5 for _ in range(10):
     6     nums.append(a)
     7     a,b = b,a+b
     8 
     9 for num in nums:
    10     print(num)

    第二种:用迭代器放这个数列:(占用很小的内存)

     1 class Fib:
     2     def __init__(self,all_num):
     3         self.current_num = 0
     4         self.all_num = all_num
     5         self.a = 0
     6         self.b = 1
     7 
     8     def __iter__(self):
     9         return self
    10 
    11     def __next__(self):
    12         if self.current_num <self.all_num:
    13             ret = self.a
    14 
    15             self.a ,self.b = self.b ,self.a +self.b
    16 
    17             self.current_num +=1
    18             return ret
    19         else:
    20             raise StopIteration
    21 if __name__ == '__main__':
    22     fib =Fib(10)
    23 
    24     for i in fib:
    25         print(i)

    并不是只有for循环能接收可迭代对象

    除了for循环能接收可迭代对象,list、tuple等也能接收。

    它们并不是进行简单的类型转换,

    例如,列表->  tuple   

    它先是创建一个元组,然后利用迭代器取出每个值,然后放入新元组中!

    1 def test():
    2     li = list([1,2,3,4])
    3     tu = tuple(li)
    4     

    生成器:

    利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)。生成器是一类特殊的迭代器

    创建生成器方法1:

    第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )

    创建生成器方法2:

    generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。

    使用函数生成器实现斐波那契数列:

     1 def fib(sum_num):
     2     a,b = 0,1
     3     current_num  = 0
     4     while current_num <sum_num:
     5         yield a   #如果一个函数中有了yield 语句,那么函数就变成了生成器
     6         a,b = b,a+b
     7         current_num += 1
     8 
     9 if __name__ == '__main__':
    10     ret = fib(10)
    11     print(ret) #<generator object fib at 0x0000027E4705E4C0>
    12 
    13     # for i in ret:
    14     #     print(i)
    15 
    16     # print(ret.__next__())  #next(ret)
    17     # print(ret.__next__())  #next(ret)

    生成器扩展:

    此时的函数可以直接当做是个模板(像类一样),

    可以创建多个生成器对象:

     1 def fib(sum_num):
     2     a,b = 0,1
     3     current_num  = 0
     4     while current_num <sum_num:
     5         yield a   #如果一个函数中有了yield 语句,那么函数就变成了生成器
     6         a,b = b,a+b
     7         current_num += 1
     8 
     9 if __name__ == '__main__':
    10     ret = fib(10)
    11     ret2 = fib(10)
    12 
    13     print(ret.__next__())
    14     print(ret2.__next__())

    捕获StopIteration 异常以及获取return 返回的内容:

     1 def fib(sum_num):
     2     a, b = 0, 1
     3     current_num = 0
     4     while current_num < sum_num:
     5         yield a  # 如果一个函数中有了yield 语句,那么函数就变成了生成器
     6         a, b = b, a + b
     7         current_num += 1
     8     return "ok..."
     9 
    10 
    11 if __name__ == '__main__':
    12     obj = fib(10)
    13 
    14     while True:
    15         try:
    16             ret = obj.__next__()
    17             print(ret)
    18         except Exception as e:
    19             print(e.value)  #通过捕获异常来获取迭代器的返回的内容。
    20             break
    21     '''
    22     输出:
    23         0
    24         1
    25         1
    26         2
    27         3
    28         5
    29         8
    30         13
    31         21
    32         34
    33         ok...
    34     '''

    生成器--之send方式:

    上面的是用next/__next__()  来产生下个值,用send也可以 ,send 可以向里面传入参数

     1 def fib(sum_num):
     2     a, b = 0, 1
     3     current_num = 0
     4     while current_num < sum_num:
     5         test = yield a  # 如果一个函数中有了yield 语句,那么函数就变成了生成器
     6         print(test)
     7         a, b = b, a + b
     8         current_num += 1
     9     return "ok..."
    10 
    11 
    12 if __name__ == '__main__':
    13     obj = fib(10)
    14 
    15     ret = obj.__next__()
    16     print(ret)
    17 
    18     ret = obj.send("hahahaha")
    19     print(ret)

    注意:如果生成器  第一次启动时,如果用send() 的话,send 只能传入None 参数,不能传入非None 参数,从第二次开始,就可以随便传入了。

    一般来说第一次都是用next ,需要向里面传值的时候才会使用send  .

    注:c.next()等价c.send(None)

    yield 和return 的区别:

    yield 可以暂停,然后后面继续执行它。 return 是直接结束!

    协程-yield(使用yield 完成多任务):

     1 import time
     2 def task_1():
     3     while True:
     4         print("====1===")
     5         time.sleep(0.1)
     6         yield
     7 
     8 def task_2():
     9     while True:
    10         print("====2===")
    11         time.sleep(0.1)
    12         yield
    13 
    14 if __name__ == '__main__':
    15     t1 = task_1()  #得到是对象
    16     t2 = task_2()
    17     while True:
    18         t1.__next__()
    19         t2.__next__()

    不过,这个多任务是假的多任务,它是并发,而不是真正的并行! 

    它其实是一个进程中的一个线程在工作。

    协程-greenlet 和 gevent :

    greenlet :  

    from greenlet import greenlet  # 使用greenlet 中的switch 就可以完成切换任务。
    import time
    
    def test01():
        while True:
            print("====1====")
            grlet2.switch()
            time.sleep(0.1)
    
    def test02():
        while True:
            print("====2====")
            grlet1.switch()
            time.sleep(0.1)
    
    
    if __name__ == '__main__':
        grlet1 = greenlet(test01)
        grlet2 = greenlet(test02)
    
        grlet1.switch()   
    #它的效果和上面的效果一样!

    gevent:

    greenlet 是对yield 的封装, gevent 是对greenlet 的封装!

    它还是用的最多的,主要是它遇到阻塞(time.sleep())切换!

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

    其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。

    由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO

    没有阻塞的时候(不切换):

     1 import gevent
     2 
     3 
     4 def f1(n):
     5     for i in range(n):
     6         print(gevent.getcurrent(),i)
     7 
     8 def f2(n):
     9     for i in range(n):
    10         print(gevent.getcurrent(),i)
    11 
    12 def f3(n):
    13     for i in range(n):
    14         print(gevent.getcurrent(),i)
    15 
    16 if __name__ == '__main__':
    17     print("=======1=========")
    18     g1 = gevent.spawn(f1,5)    #此时不会执行f1
    19     print("=======2=========")
    20     g2 = gevent.spawn(f2,5)
    21     print("=======3=========")
    22     g3 = gevent.spawn(f3,5)
    23     print("=======4=========")
    24 
    25     g1.join()
    26     g2.join()
    27     g3.join()
    28     '''
    29     输出:
    30         =======1=========
    31         =======2=========
    32         =======3=========
    33         =======4=========
    34         <Greenlet at 0x36f0c90: f1(5)> 0
    35         <Greenlet at 0x36f0c90: f1(5)> 1
    36         <Greenlet at 0x36f0c90: f1(5)> 2
    37         <Greenlet at 0x36f0c90: f1(5)> 3
    38         <Greenlet at 0x36f0c90: f1(5)> 4
    39         <Greenlet at 0x397c270: f2(5)> 0
    40         <Greenlet at 0x397c270: f2(5)> 1
    41         <Greenlet at 0x397c270: f2(5)> 2
    42         <Greenlet at 0x397c270: f2(5)> 3
    43         <Greenlet at 0x397c270: f2(5)> 4
    44         <Greenlet at 0x397c300: f3(5)> 0
    45         <Greenlet at 0x397c300: f3(5)> 1
    46         <Greenlet at 0x397c300: f3(5)> 2
    47         <Greenlet at 0x397c300: f3(5)> 3
    48         <Greenlet at 0x397c300: f3(5)> 4
    49     '''

    有阻塞的时候(切换):

     1 import gevent
     2 import time
     3 
     4 def f1(n):
     5     for i in range(n):
     6         print(gevent.getcurrent(),i)
     7         # time.sleep(0.5) #这种阻塞不行,需要专门的gevent.sleep()
     8         gevent.sleep(0.5)
     9 
    10 def f2(n):
    11     for i in range(n):
    12         print(gevent.getcurrent(),i)
    13         gevent.sleep(0.5)
    14 
    15 def f3(n):
    16     for i in range(n):
    17         print(gevent.getcurrent(),i)
    18         gevent.sleep(0.5)
    19 
    20 if __name__ == '__main__':
    21     print("=======1=========")
    22     g1 = gevent.spawn(f1,5)    #此时不会执行f1
    23     print("=======2=========")
    24     g2 = gevent.spawn(f2,5)
    25     print("=======3=========")
    26     g3 = gevent.spawn(f3,5)
    27     print("=======4=========")
    28 
    29     g1.join()
    30     g2.join()
    31     g3.join()
    32     '''
    33     输出:
    34         =======1=========
    35         =======2=========
    36         =======3=========
    37         =======4=========
    38         <Greenlet at 0x3bafdb0: f1(5)> 0
    39         <Greenlet at 0x3cea270: f2(5)> 0
    40         <Greenlet at 0x3cea300: f3(5)> 0
    41         <Greenlet at 0x3bafdb0: f1(5)> 1
    42         <Greenlet at 0x3cea270: f2(5)> 1
    43         <Greenlet at 0x3cea300: f3(5)> 1
    44         <Greenlet at 0x3bafdb0: f1(5)> 2
    45         <Greenlet at 0x3cea270: f2(5)> 2
    46         <Greenlet at 0x3cea300: f3(5)> 2
    47         <Greenlet at 0x3bafdb0: f1(5)> 3
    48         <Greenlet at 0x3cea270: f2(5)> 3
    49         <Greenlet at 0x3cea300: f3(5)> 3
    50         <Greenlet at 0x3bafdb0: f1(5)> 4
    51         <Greenlet at 0x3cea270: f2(5)> 4
    52         <Greenlet at 0x3cea300: f3(5)> 4
    53     '''

    它主要的思想是利用当一个任务在浪费时间的时候,将这个时间给利用上!

    这就是协程!

    协程依赖线程!协程使用的资源是最小的!

    :不仅仅time.sleep() 阻塞要用gevent 中的专门函数,对于网络编程中的recv   accept 等阻塞也要换!但是如果对于已经有现成项目的代码,已经用了很多的time.sleep() ,如果每个都要改就麻烦,

    下面的方法可以不用改为gevent ():

    打个补丁:

    monkey.patch_all()   # 要导入  from gevent import monkey  

    from gevent import monkey
    import gevent
    import time
    
    monkey.patch_all()
    
    def f1(n):
        for i in range(n):
            print(gevent.getcurrent(),i)
            time.sleep(0.5)
    
    def f2(n):
        for i in range(n):
            print(gevent.getcurrent(),i)
            time.sleep(0.5)
    
    def f3(n):
        for i in range(n):
            print(gevent.getcurrent(),i)
            time.sleep(0.5)
    
    if __name__ == '__main__':
        print("=======1=========")
        g1 = gevent.spawn(f1,5)    #此时不会执行f1
        print("=======2=========")
        g2 = gevent.spawn(f2,5)
        print("=======3=========")
        g3 = gevent.spawn(f3,5)
        print("=======4=========")
    
        g1.join()
        g2.join()
        g3.join()
        '''
        输出:
            =======1=========
            =======2=========
            =======3=========
            =======4=========
            <Greenlet at 0x3bafdb0: f1(5)> 0
            <Greenlet at 0x3cea270: f2(5)> 0
            <Greenlet at 0x3cea300: f3(5)> 0
            <Greenlet at 0x3bafdb0: f1(5)> 1
            <Greenlet at 0x3cea270: f2(5)> 1
            <Greenlet at 0x3cea300: f3(5)> 1
            <Greenlet at 0x3bafdb0: f1(5)> 2
            <Greenlet at 0x3cea270: f2(5)> 2
            <Greenlet at 0x3cea300: f3(5)> 2
            <Greenlet at 0x3bafdb0: f1(5)> 3
            <Greenlet at 0x3cea270: f2(5)> 3
            <Greenlet at 0x3cea300: f3(5)> 3
            <Greenlet at 0x3bafdb0: f1(5)> 4
            <Greenlet at 0x3cea270: f2(5)> 4
            <Greenlet at 0x3cea300: f3(5)> 4
        '''

    gevent.joinall([ ])  的写法:

    gevent 的标准用法模板:

     1 from gevent import monkey
     2 import gevent
     3 import time
     4 
     5 monkey.patch_all()  #  它会自动的将所有代码中的 要阻塞的函数换成gevent 专门的函数
     6 
     7 def f1(n):
     8     for i in range(n):
     9         print(gevent.getcurrent(),i)
    10         time.sleep(0.5)
    11 
    12 def f2(n):
    13     for i in range(n):
    14         print(gevent.getcurrent(),i)
    15         time.sleep(0.5)
    16 
    17 def f3(n):
    18     for i in range(n):
    19         print(gevent.getcurrent(),i)
    20         time.sleep(0.5)
    21 
    22 
    23 if __name__ == '__main__':
    24     gevent.joinall([   #joinall 的写法,将所有的对象放到一个数组中!  方便
    25         gevent.spawn(f1, 5),
    26         gevent.spawn(f2, 5),
    27         gevent.spawn(f3, 5)
    28     ])
    29 
    30     '''
    31     输出:
    32         <Greenlet at 0x3bafdb0: f1(5)> 0
    33         <Greenlet at 0x3cea270: f2(5)> 0
    34         <Greenlet at 0x3cea300: f3(5)> 0
    35         <Greenlet at 0x3bafdb0: f1(5)> 1
    36         <Greenlet at 0x3cea270: f2(5)> 1
    37         <Greenlet at 0x3cea300: f3(5)> 1
    38         <Greenlet at 0x3bafdb0: f1(5)> 2
    39         <Greenlet at 0x3cea270: f2(5)> 2
    40         <Greenlet at 0x3cea300: f3(5)> 2
    41         <Greenlet at 0x3bafdb0: f1(5)> 3
    42         <Greenlet at 0x3cea270: f2(5)> 3
    43         <Greenlet at 0x3cea300: f3(5)> 3
    44         <Greenlet at 0x3bafdb0: f1(5)> 4
    45         <Greenlet at 0x3cea270: f2(5)> 4
    46         <Greenlet at 0x3cea300: f3(5)> 4
    47     '''

    进程,线程,协程区别:

    通俗描述

    • 有一个老板想要开个工厂进行生产某件商品(例如剪子)
    • 他需要花一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的 为了能够生产剪子而准备的资源称之为:进程
    • 只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程
    • 这个老板为了提高生产率,想到3种办法:
      1. 在这条生产线上多招些工人,一起来做剪子,这样效率是成倍増长,即单进程 多线程方式
      2. 老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了些财力物力购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程 多线程方式
      3. 老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时临时没事或者再等待某些条件(比如等待另一个工人生产完谋道工序 之后他才能再次工作) ,那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,其实这就是:协程方式

    简单总结

    1. 进程是资源分配的单位
    2. 线程是操作系统调度的单位
    3. 进程切换需要的资源很最大,效率很低
    4. 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
    5. 协程切换任务资源很小,效率高
    6. 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发

    效率最高的是协程!

    案例:并发下载器:

    通过程序上网,可以通过 import  urllib.request ,使用里面的urlopen() 来打开url 并获取结果! 

    一次爬取一张图片

     1 import urllib.request
     2 
     3 def main():
     4     req = urllib.request.urlopen("https://img02.sogoucdn.com/v2/thumb/resize/w/120/h/135/zi/on/iw/90.0/ih/101.0?t=2&url=http%3A%2F%2Fpic.baike.soso.com%2Fugc%2Fbaikepic2%2F19951%2Fcut-20190523135122-1670915825_jpg_298_373_11703.jpg%2F300&appid=200524&referer=http%3A%2F%2Fbaike.sogou.com%2Fv6234.htm%3FfromTitle%3D%25E7%2599%25BE%25E5%25BA%25A6")
     5 
     6     img_content = req.read()
     7     with open("e:/1.jpg","wb") as f:
     8         f.write(img_content)
     9 
    10 if __name__ == '__main__':
    11     main()

    因为网络下载是个阻塞的过程,所以可以使用gevent 利用协程来下载!

     1 import urllib.request
     2 import gevent
     3 from gevent import monkey
     4 import time
     5 
     6 monkey.patch_all()
     7 
     8 
     9 
    10 def downloader(img_url):
    11     req = urllib.request.urlopen(img_url)
    12 
    13     img_content = req.read()
    14     timestamp =time.time()   #时间戳 
    15     with open("e:/{}.jpg".format(timestamp),"wb") as f:
    16         f.write(img_content)
    17 
    18 def main():
    19     gevent.joinall([
    20         gevent.spawn(downloader,"http://img0.dili360.com//ga/M02/49/A2/wKgBy1nPDXGAWgvpAADIK-c2-PQ056.jpg"),
    21         gevent.spawn(downloader, "http://img0.dili360.com/ga/M01/02/64/wKgBy1Q22liAYjlPAA0ov-3Wnvs953.jpg@!rw9")
    22     ])
    23 
    24 
    25 if __name__ == '__main__':
    26     main()

    补:

    这上面说的是迭代器,生成器,以后还会说装饰器,先看一个装饰器的小例子:

    import time
    def decorator(func):
        def wrapper(name):
            t1=time.perf_counter()
            func(name)
            time.sleep(1)
            print("总时间为:",time.perf_counter() - t1)
    
        return wrapper
    
    
    @decorator
    def test(name):
        print("Hello World!",name)
    
    if __name__ == '__main__':
        test("tom")
    View Code

    它们三个(迭代器,生成器和装饰器)是Python 高级语法中重要的内容!

  • 相关阅读:
    多态
    SSM前后端分离 ssm+html+js(ajax) 这种controll层的返回值是结合或者网址
    Eclipse创建ssm项目
    在idea中创建Maven项目
    Maven的安装和配置
    IDEA修改快捷键!和一些常用的快捷键
    mysql数据库的安装和连接测试并给root用户赋密码
    ssm动态sql语句
    Java基础--JDBC
    Java基础--注解、反射
  • 原文地址:https://www.cnblogs.com/zach0812/p/11443985.html
Copyright © 2011-2022 走看看