協(xié)程

迭代器

迭代是訪問集合元素的一種方式。迭代器是一個可以記住遍歷的位置的對象境析,迭代器對象從集合的第一個元素開始訪問义矛,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會后退缸榛。

可迭代對象

list吝羞,tuple,str内颗,dict等類型的數(shù)據(jù)可以使用for ... in ... 的循環(huán)語法從其中依次拿到數(shù)據(jù)進(jìn)行使用钧排,我們把這樣的過程稱為遍歷,也加迭代均澳。

自己實現(xiàn)一個可以迭代的對象
# coding=utf-8
import time
from collections import Iterable
from collections import Iterator

class Classmate(object):
    def __init__(self):
        self.names = list()
        self.current_num = 0

    def add(self, name):
        self.names.append(name)

    def __iter__(self):
        ''' 如果想要一個對象可以迭代恨溜,那么必須實現(xiàn)__iter__方法 '''
        return self

    def __next__(self):
        if self.current_num < len(self.names):
            ret = self.names[self.current_num]
            self.current_num += 1
            return ret
        else:
            raise StopIteration

classmate = Classmate()
classmate.add("老王")
classmate.add("王二")
classmate.add("張三")

for name in classmate:
    print name
實現(xiàn)斐波拉契數(shù)列
# coding=utf-8

class FibIterator(object):
    '''斐波拉契數(shù)列迭代器'''
    def __init__(self, n):
        '''
        :param n: int, 指明生成數(shù)列的前n個數(shù)
        '''
        self.n = n
        # current 保存當(dāng)前生成到數(shù)列中的第幾個數(shù)
        self.current = 0
        # num1 保存前前一個數(shù),初始值為數(shù)列中的第一個數(shù) 0
        self.num1 = 0
        # num2 保存前一個數(shù)找前,初始值是數(shù)列中的第二個數(shù) 1
        self.num2 = 1

    def __next__(self):
        ''' 被next()函數(shù)調(diào)用來獲取下一個數(shù) '''
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, sefl.num1+self.num2
            self.current += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        ''' 迭代器的__iter__返回自身即可 ’‘’
        return self

if __name__ == "__main__":
    fib = FibIterator(10)
    for num in fib:
        print num
生成器

利用迭代器糟袁,我們可以在每次迭代獲取數(shù)據(jù)(通過next()方法)時按照特定的規(guī)律進(jìn)行生成。但是我們在實現(xiàn)一個迭代器時躺盛,關(guān)于當(dāng)前迭代到的狀態(tài)需要自己記錄项戴,進(jìn)而才能根據(jù)當(dāng)前狀態(tài)生成下一個數(shù)據(jù)。為了達(dá)到記錄當(dāng)前狀態(tài)槽惫,并配合next()函數(shù)進(jìn)行迭代使用周叮,我們可以采用更加簡便的方法---生成器辩撑。
生成器是一種特殊的迭代器

創(chuàng)建生成器方法1

要創(chuàng)建一個生成器,有很多方法仿耽。第一種方法合冀,只要把一個列表生成式的[]改為()

L = [x*2 for x in range(5)]
print L
>>> [0, 2, 4, 6, 8]
G = (x*2 for x in range(5))
print G
>>> <generator object <genexpr> at 0x7f626c123db0>
# 創(chuàng)建L和G的區(qū)別僅在于最外層的[]和(),L是一個列表项贺,而G是一個生成器君躺。
# 我們可以直接打印列表L中每一個元素,而對于生成器G敬扛。我們可以按照迭代器的使用方式來使用晰洒。
# 即可以通過next()函數(shù),for循環(huán)啥箭,list()等方法來使用谍珊。
next(G)
>>> 0
next(G)
>>> 2
next(G)
>>> 4  
創(chuàng)建生成器方法2

generator 非常強(qiáng)大。如果推算的算法比較復(fù)雜急侥,用類似列表生成式的for循環(huán)無法實現(xiàn)的時候砌滞,還可以使用函數(shù)來實現(xiàn)。

def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        # print a
        yield a # 如果一個函數(shù)中有yield語句坏怪,那么就不函數(shù)贝润,而是一個生成器模板
        a, b = b,  a + b
        current_num += 1

# 如果在調(diào)用 create_num 的時候,發(fā)現(xiàn)這個函數(shù)中有yield那么此時铝宵,不是調(diào)用函數(shù)打掘,而是創(chuàng)建一個生成器對象。
obj = create_num(10)
print next(obj)
print next(obj)
for num in obj:
    print num
# =====================================================
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...."

obj2 = create_num(10)
while True:
    try:
        ret = next(obj2)
        print ret
    except E  xception as ret:
        print ret.value # 獲取 return 的值
        break
# 使用 send ==================================
def create_num(all_num):
    a, b = 0, 1
    current_num = 0
    while current_num < all_num:
        ret = yield a 
        print ret # 這里會打印 hahahaha
        a, b = b,  a + b
        current_num += 1
    return "ok...."

obj3 = create_num(10)
# obj3.send(None) # send 一般不會放到第一次啟動生成器鹏秋,如果非要這么做尊蚁,那么只能傳遞 None
ret = next(obj)
print ret
# send 里面的數(shù)據(jù)會傳遞給 上面的 ret,當(dāng)做yield的結(jié)果侣夷,然后ret保存這個結(jié)果
# send 的結(jié)果是下一次調(diào)用yield時横朋,yield 左邊的值
ret = obj,send(“hahahaha”)
print ret
yield 實現(xiàn)多任務(wù)
import time

def task_1():
    while True:
        print "11111"
        time.sleep(0.1)
        yield

def task_2():
    while True:
        print "22222"
        time.sleep(0.1)
        yield

def main():
    t1 = task_1()
    t2 = task_2()
    # 先讓t1執(zhí)行一會,當(dāng)遇到y(tǒng)ield的時候百拓,返回回來
    # 再執(zhí)行t2琴锭,當(dāng)t2遇到y(tǒng)ield的時候,再次切換到t1
    # 這樣 t1/t2/t1/t2 交替執(zhí)行衙传,最終實現(xiàn)了多任務(wù)----協(xié)程
    while True:
        next(t1)
        next(t2)

if __nam__ == "__main__":
    main()
使用 greenlet
import time
from greenlet import greenlet

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 中運(yùn)行
gr1.switch()
gevent 使用

greenlet 已經(jīng)實現(xiàn)了協(xié)程决帖,但是這個是人工切換,太麻煩蓖捶。Python還有一個更加強(qiáng)大的模塊 gevent
其原理是當(dāng)一個 greenlet 遇到IO(指的是 input, output, 比如網(wǎng)絡(luò)古瓤,文件操作等)操作時,比如訪問網(wǎng)絡(luò),就自動切換到其他的greenlet落君,等到IO操作完成,再在適當(dāng)?shù)臅r候切換回來繼續(xù)執(zhí)行亭引。
由于IO操作非常耗時绎速,經(jīng)常使程序處于等待狀態(tài),有了gevent為我們自動切換協(xié)程焙蚓,就保證總有 greenlet在運(yùn)行纹冤,而不是等待IO。

import time
import gevent

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)

g1 = gevent.spawn(f1, 5)
g2 = gevent.spawn(f2, 5)
g3 = gevent.spawn(f3, 5)
g1.join()
g2.join()
g3.join()

# ================================================
import time
import gevent
import random
from gevent import monkey

# 有耗時操作時需要
monkey.patch_all() # 將程序中用到的耗時操作代碼购公,換為gevent中自己實現(xiàn)的模塊

def corourine_work(coroutine_name):
    for i in range(10):
        print coroutine_name, i
        time.sleep(random.random())

gevent.joinall([
    gevent.spawn(coroutine_work, "work1"),
    gevent.spawn(coroutine_work, "work2")
])
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萌京,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宏浩,更是在濱河造成了極大的恐慌知残,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件比庄,死亡現(xiàn)場離奇詭異求妹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)佳窑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門制恍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人神凑,你說我怎么就攤上這事净神。” “怎么了溉委?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵鹃唯,是天一觀的道長。 經(jīng)常有香客問我薛躬,道長俯渤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任型宝,我火速辦了婚禮八匠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘趴酣。我一直安慰自己梨树,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布岖寞。 她就那樣靜靜地躺著抡四,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上指巡,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天淑履,我揣著相機(jī)與錄音,去河邊找鬼藻雪。 笑死秘噪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勉耀。 我是一名探鬼主播指煎,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼便斥!你這毒婦竟也來了至壤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枢纠,失蹤者是張志新(化名)和其女友劉穎像街,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體京郑,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宅广,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了些举。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跟狱。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖户魏,靈堂內(nèi)的尸體忽然破棺而出驶臊,到底是詐尸還是另有隱情,我是刑警寧澤叼丑,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布关翎,位于F島的核電站,受9級特大地震影響鸠信,放射性物質(zhì)發(fā)生泄漏纵寝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一星立、第九天 我趴在偏房一處隱蔽的房頂上張望爽茴。 院中可真熱鬧,春花似錦绰垂、人聲如沸室奏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胧沫。三九已至昌简,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绒怨,已是汗流浹背纯赎。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留南蹂,地道東北人址否。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像碎紊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子樊诺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一仗考、總體內(nèi)容 1.1、協(xié)程的介紹 1.2词爬、迭代器以及迭代器的應(yīng)用 1.3秃嗜、生成器(生成器與迭代器保存的都是生成數(shù)據(jù)...
    IIronMan閱讀 861評論 0 1
  • python之進(jìn)程锅锨、線程與協(xié)程 有這么個例子說他們的區(qū)別,幫助理解很有用恋沃。 有一個老板想開一個工廠生產(chǎn)手機(jī)必搞。 他需...
    道無虛閱讀 3,191評論 0 3
  • 目錄:一、基于生成器的協(xié)程二囊咏、協(xié)程狀態(tài)三恕洲、協(xié)程預(yù)激裝飾器四、終止協(xié)程和異常處理五梅割、協(xié)程返回值六霜第、yield fro...
    Recalcitrant閱讀 388評論 0 0
  • 協(xié)程是什么? 協(xié)程是python個中另外一種實現(xiàn)多任務(wù)的方式户辞,只不過比線程更小占用更小執(zhí)行單元(理解為需要的資源)...
    沉吟不語閱讀 373評論 0 0
  • 01182a35a7fc閱讀 113評論 0 0