一、迭代器(iterator)python
是一個實現了迭代器協議的對象,python的一些內置數據類型(列表,數組,字符串,字典等)均可以經過for語句進行迭代,咱們也能夠本身建立一個容器,實現了迭代器協議,能夠經過for,next方法進行迭代,在迭代的末尾,會引起stopIteration異常。數組
判斷xxx_obj是否能夠迭代 在第1步成立的前提下,調用 iter 函數獲得 xxx_obj 對象的 __iter__ 方法的返回值 __iter__ 方法的返回值是一個迭代器 若是想要一個對象稱爲一個 能夠迭代的對象,便可以使用for,必須實現 __iter__方法 __iter__ 中必須返回對象的引用【要這個對象有__iter__和__next__方法, 實際上取的__next__的返回值】 迭代器結束,須要拋出一個 StopIteration 異常。
二、生成器(generator)【一種特殊迭代器】網絡
1)是經過yield語句快速生成迭代器,能夠不用iter和next方法 ;多線程
2)yield可使一個普通函數變成一個生成器,而且相應的next()方法返回是yield後的值。一種更直觀的解釋是:程序執行到yield時會返回結果並暫停,再次調用next時會從上次暫停的地方繼續開始執行。併發
3)生成器自身有構成一個迭代器,每次迭代時使用一個yield返回 的值,一個生成器中能夠有多個yield的值函數
4)建立生成器的方法:url
a、()spa
b、yield 操作系統
def create_num(all_num): # a = 1 # b = 1 a, b = 0, 1 current_num = 0 while current_num < all_num: yield a # 若是一個函數中有yield語句,那麼這個就不在是函數,而是一個生成器的模板 a, b = b, a + b current_num += 1 if __name__ == '__main__': # 若是在調用create_num的時候,發現這個函數有yield,此時不是調用函數,而是建立一個生成器對象 obj = create_num(10) for num in obj: print(num)
五、send使用--啓動生成器線程
def create_num(all_num): a, b = 0, 1 current_num = 0 while current_num < all_num: res = yield a print(">>>>ret>>>>", res) a, b = b, a + b current_num += 1 if __name__ == '__main__': obj = create_num(4) # obj.send(None) # send通常不會放到第一次啓動生成器,若是非要如此,傳遞None ret = next(obj) print(ret) ret = obj.send("hhhhh") print(ret) # send裏面的數據,會傳遞給第5行,看成yield a的結果,而後res保存這個結果.. # send的結果是下一次調用yield時,yield後面的值 ret = obj.send(None) print(ret) ret = obj.send(None) print(ret)
六、yield和return區別
yield能夠暫停函數執行,且下一次執行時候恢復
三、迭代器和生成器做用
四、多任務-協程(yield執行)
a、生成器函數其實就是實現了協程,即便用yield, send(), next()實現協程
b、進程佔資源最多, 其次線程, 協程佔資源最少!
#!/bin/python3 # -*- coding=utf-8 -*- import time def task_1(): while True: print("------1-------") time.sleep(0.1) yield def task_2(): while True: print("------2------") time.sleep(0.2) yield def main(): t1 = task_1() t2 = task_2() while True: next(t1) next(t2) if __name__ == "__main__": main()
並行: 有兩個任務, 可是有四個CPU的核, 一個任務佔一個核, 每一個都在作
併發: 有不少任務, 可是隻有兩個核, 因此 交替執行
4.一、greenlet實現多任務(核心仍是yield)
#!/bin/python3 # -*- encoding=utf-8 -*- from greenlet import greenlet import time def test1(): while True: print("----A----") gr2.switch() time.sleep(0.5) def test2(): while True: print("----B----") gr1.switch() time.sleep(0.5) gr1 = greenlet(test1) gr2 = greenlet(test2) # 切換到gr1中執行 gr1.switch()
4.二、gevent實現協程(更強大,經常使用)
#!/bin/python3 # -*-encoding=utf-8-*- import gevent import time def f1(n): for i in range(n): print(gevent.getcurrent(), i) gevent.sleep(0.5) def f2(n): for i in range(n): print(gevent.getcurrent(), i) gevent.sleep(0.5) def f3(n): for i in range(n): print(gevent.getcurrent(), i) gevent.sleep(0.5) print("----1-----") g1 = gevent.spawn(f1, 5) print("----2-----") g2 = gevent.spawn(f2, 5) print("----3-----") g3 = gevent.spawn(f3, 5) print("----4-----") g1.join() g2.join() g3.join()
gevent遇到延時操做就切換, 利用了等待耗時的操做, 去作其餘的事情
以下: 加入monkey.patch_all()則無須將 time.sleep()改爲 gevent.sleep()
#!/bin/python3 # -*-encoding=utf-8-*- import gevent from gevent import monkey import time monkey.patch_all() def f1(n): for i in range(n): print(gevent.getcurrent(), i) time.sleep(0.5) # gevent.sleep(0.5) def f2(n): for i in range(n): print(gevent.getcurrent(), i) time.sleep(0.5) # gevent.sleep(0.5) def f3(n): for i in range(n): print(gevent.getcurrent(), i) time.sleep(0.5) # gevent.sleep(0.5) print("----1-----") g1 = gevent.spawn(f1, 5) print("----2-----") g2 = gevent.spawn(f2, 5) print("----3-----") g3 = gevent.spawn(f3, 5) print("----4-----") g1.join() g2.join() g3.join()
以下: 將須要join的代碼, 寫成列表, 簡潔
#!/bin/python3 # -*-encoding=utf-8-*- import gevent from gevent import monkey import time monkey.patch_all() def f1(n): for i in range(n): print(gevent.getcurrent(), i) time.sleep(0.5) # gevent.sleep(0.5) def f2(n): for i in range(n): print(gevent.getcurrent(), i) time.sleep(0.5) # gevent.sleep(0.5) def f3(n): for i in range(n): print(gevent.getcurrent(), i) time.sleep(0.5) # gevent.sleep(0.5) gevent.joinall([ gevent.spawn(f1, 5), gevent.spawn(f2, 5), gevent.spawn(f3, 5) ])
4.3併發下載器
#!/bin/python3 #-*- encoding=utf-8 -*- import gevent import urllib.request from gevent import monkey monkey.patch_all() def downloader(img_name, img_url): req = urllib.request.urlopen(img_url) img_content = req.read() with open("./img/"+ img_name, "wb") as f: f.write(img_content) def main(): gevent.joinall([ gevent.spawn(downloader, "1.jpg", 'https://rpic.douyucdn.cn/asrpic/190417/5440020_3968619_65b10_2_2142.jpg'), gevent.spawn(downloader, '2.png', "https://rpic.douyucdn.cn/asrpic/190417/594613_2143.png") ]) if __name__=="__main__": main()
五、進程/線程/協程對比
進程: 耗費資源最多, 進程裏必定有一個線程, 默認線程稱爲主線程。進程是資源分配的單位。(最穩定, 耗費資源最多)
線程: 線程是操做系統調度的單位. 線程切換須要的資源通常, 效率通常 (不考慮GIL狀況)
協程: 協程切換任務資源很小, 效率高;
特色: 在等待某個資源到來 期間, 去執行其餘代碼....多線程裏有不少網絡堵塞, 推薦先用協程 !