版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、Stackless Python并發(fā)式編程介紹作者 :Grant Olson電子郵件:日期 :譯者 :2006-07-07劉禹呈電子郵件:日期 :2007-09-19校對 :gashero電子郵件:harry.日期 :2007-09-20原文地址:目錄? 1 介紹o 1.1 為什么要使用 Stackless? 現(xiàn)實世界就是并發(fā)的? 并發(fā)可能是 (僅僅可能是 )下一個重要的編程范式o 1.2 安裝 stackless? 2 stackless 起步o 2.1 微進(jìn)程 (tasklet)o 2.2 調(diào)度器 (scheduler)o 2.3 通道 (channel)o 2.4 總結(jié)? 3 協(xié)程 (c
2、oroutine)o 3.1 子例程的問題? 堆棧? 那么,為什么要使用堆棧?o 3.2 走進(jìn)協(xié)程o 3.3 總結(jié)? 4 輕量級線程o 4.1 hackysack 模擬o 4.2 游戲的傳統(tǒng)線程版本o 4.3 stacklesso 4.4 總結(jié)? 5 數(shù)據(jù)流o 5.1 工廠o 5.2 普“通 ”版本? 分析o 5.3 走進(jìn)數(shù)據(jù)流o 5.4 代碼的 stackless版本? 分析? 休眠功能? 類o 5.5 那我們獲得了什么?o 5.6 推 (push)數(shù)據(jù)? 半加器? 6 角色o 6.1 殺手機器人? 角色基類? 消息的格式? 世界 (world) 類? 一個簡單機器人? 蹊蹺 (Detour
3、) 的 PyGame? 第一輪代碼o 6.2 又一蹊蹺:機理的模擬? 角色屬性? 碰撞檢測? 恒定的時間? 傷害值、生命值和死亡? 第二輪代碼o 6.3 回到角色:一起抓狂? 爆炸? 埋雷機器人? 建造臺? 最終的模擬o 6.4 總結(jié)? 7 完整代碼列表o 7.1 pingpong.py 遞歸的乒乓球示例o 7.2 pingpong_stackless.py 無堆棧的乒乓球示例o7.3 hackysackthreaded.py 基于操作系統(tǒng)線程的hackysack 示例o 7.4 hackysackstackless.py stackless 的 hackysack 示例o 7.5 assem
4、blyline.py 普通的生產(chǎn)線示例o 7.6 assemblyline-stackless.py stackless 的生產(chǎn)線示例o 7.7 digitalCircuit.py stackless 的數(shù)字電路o 7.8 actors.py 第一個角色示例o 7.9 actors2.py 第二個角色示例o 7.10 actors3.py 第三個角色示例? 8 引用鏈接? 9 給 jorge 的 reStructuredText 示例1 介紹1.1 為什么要使用Stackless摘自 stackless網(wǎng)站。NoteStackless Python 是 Python 編程語言的一個增強版本,
5、它使程序員從基于線程的編程方式中獲得好處, 并避免傳統(tǒng)線程所帶來的性能與復(fù)雜度問題。 Stackless為 Python 帶來的微線程擴展,是一種低開銷、輕量級的便利工具,如果使用得當(dāng),可以獲益如下:? 改進(jìn)程序結(jié)構(gòu)? 增進(jìn)代碼可讀性? 提高編程人員生產(chǎn)力以上是Stackless Python很簡明的釋義,但其對我們意義何在?就在于Stackless 提供的并發(fā)建模工具,比目前其它大多數(shù)傳統(tǒng)編程語言所提供的,都更加易用: 不僅是 Python 自身,也包括 Java、C+,以及其它。盡管還有其他一些語言提供并發(fā)特性,可它們要么是主要用于學(xué)術(shù)研究的(如 Mozart/Oz ),要么是罕為使用、
6、或用于特殊目的的專業(yè)語言 (如 Erlang )。而使用 stackless ,你將會在 Python 本身的所有優(yōu)勢之 上,在一個(但愿)你已經(jīng)很熟悉的環(huán)境中,再獲得并發(fā)的特性。這自然引出了個問題:為什么要并發(fā)?現(xiàn)實世界就是并發(fā)的現(xiàn)實世界就是“并發(fā)”的,它是由一群事物(或“演員”)所組成,而這些事物以一種對彼此所知有限的、 松散耦合的方式相互作用。 傳說中面向?qū)ο缶幊逃?一個好處,就是對象能夠?qū)ΜF(xiàn)實的世界進(jìn)行模擬。 這在一定程度上是正確的, 面向?qū)ο缶幊毯芎玫啬M了對象個體, 但對于這些對象個體之間的交互, 卻無法以一種 理想的方式來表現(xiàn)。例如,如下代碼實例,有什么問題?def family
7、TacoNight():husband.eat(dinner)wife.eat(dinner)son.eat(dinner)daughter.eat(dinner)第一印象,沒問題。但是,上例中存在一個微妙的安排:所有事件是次序發(fā)生的,即:直到丈夫吃完飯,妻子才開始吃;兒子則一直等到母親吃完才吃;而女 兒則是最后一個。在現(xiàn)實世界中,哪怕是丈夫還堵車在路上,妻子、兒子和女兒仍然可以該吃就吃, 而要在上例中的話, 他們只能餓死了甚至更糟: 永遠(yuǎn)沒有人 會知道這件事,因為他們永遠(yuǎn)不會有機會拋出一個異常來通知這個世界!并發(fā)可能是 (僅僅可能是 )下一個重要的編程范式我個人相信,并發(fā)將是軟件世界里的下一
8、個重要范式。 隨著程序變得更加復(fù)雜和耗費資源,我們已經(jīng)不能指望摩爾定律來每年給我們提供更快的 CPU了,當(dāng) 前,日常使用的個人計算機的性能提升來自于多核與多 CPU機。一旦單個 CPU的性能達(dá)到極限,軟件開發(fā)者們將不得不轉(zhuǎn)向分布式模型,靠多臺計算機的互相協(xié) 作來建立強大的應(yīng)用(想想 GooglePlex )。為了取得多核機和分布式編程的優(yōu)勢,并發(fā)將很快成為做事情的方式的事實標(biāo)準(zhǔn)。1.2 安裝 stackless安裝 Stackless 的細(xì)節(jié)可以在其網(wǎng)站上找到?,F(xiàn)在 Linux 用戶可以通過 SubVersion 取得源代碼并編譯; 而對于 Windows用戶, 則有一個 .zip 文件供使用
9、,需要將其解壓到現(xiàn)有的 Python 安裝目錄中。接下來,本教程假設(shè) Stackless Python 已經(jīng)安裝好了,可以工作,并且假設(shè)你對 Python 語言本身有基本的了解。2 stackless起步本章簡要介紹了 stackless 的基本概念,后面章節(jié)將基于這些基礎(chǔ),來展示更加實用的功能。2.1 微進(jìn)程 (tasklet)微進(jìn)程是 stackless 的基本構(gòu)成單元,你可以通過提供任一個 Python 可調(diào)用對象(通常為函數(shù)或類的方法) 來建立它,這將建立一個微進(jìn)程并將其添加到調(diào)度器。這是一個快速演示 :bit (Intel) on win32Type help, copyright,
10、 credits or license for more information. import stackless def print_x(x):. print x. stackless.tasklet(print_x)(one) stackless.tasklet(print_x)(two) stackless.tasklet(print_x)(three) stackless.run()one two three注意,微進(jìn)程將排起隊來,并不運行,直到調(diào)用stackless.run()。2.2 調(diào)度器 (scheduler)調(diào)度器控制各個微進(jìn)程運行的順序。 如果剛剛建立了一組微進(jìn)程, 它們
11、將按照建立的順序來執(zhí)行。 在現(xiàn)實中,一般會建立一組可以再次被調(diào)度的微進(jìn)程, 好讓每個都有輪次機會。一個快速演示 :bit (Intel) on win32Type help, copyright, credits or license for more information. import stackless def print_three_times(x):. print 1:, x. stackless.schedule(). print 2:, x. stackless.schedule(). print 3:, x. stackless.schedule(). stackless.t
12、asklet(print_three_times)(first) stackless.tasklet(print_three_times)(second) stackless.tasklet(print_three_times)(third) stackless.run()1: first1: second1: third2: first2: second2: third3: first3: second3: third注意:當(dāng)調(diào)用 stackless.schedule() 的時候,當(dāng)前活動微進(jìn)程將暫停執(zhí)行, 并將自身重新插入到調(diào)度器隊列的末尾, 好讓下一個微進(jìn)程被執(zhí)行。 一旦在它前面的所有其
13、他微進(jìn)程都運行過了,它將從上次 停止的地方繼續(xù)開始運行。這個過程會持續(xù),直到所有的活動微進(jìn)程都完成了運行過程。這就是使用 stackless 達(dá)到合作式多任務(wù)的方式。2.3 通道 (channel)通道使得微進(jìn)程之間的信息傳遞成為可能。它做到了兩件事:1. 能夠在微進(jìn)程之間交換信息。2. 能夠控制運行的流程。又一個快速演示 :C:c:python24pythonbit (Intel) on win32Type help, copyright, credits or license for more information. import stackless channel = stackles
14、s.channel() def receiving_tasklet():.print Recieving tasklet started.print channel.receive().print Receiving tasklet finished. def sending_tasklet():.print Sending tasklet started.channel.send(send from sending_tasklet).print sending tasklet finished. def another_tasklet():.print Just another taskle
15、t in the scheduler. stackless.tasklet(receiving_tasklet)() stackless.tasklet(sending_tasklet)() stackless.tasklet(another_tasklet)() stackless.run()Recieving tasklet startedSending tasklet startedsend from sending_taskletReceiving tasklet finishedJust another tasklet in the schedulersending tasklet
16、finished接收的微進(jìn)程調(diào)用 channel.receive() 的時候,便阻塞住,這意味著該微進(jìn)程暫停執(zhí)行,直到有信息從這個通道送過來。 除了往這個通道發(fā)送信息以外, 沒有其他任何方式可以讓這個微進(jìn)程恢復(fù)運行。若有其他微進(jìn)程向這個通道發(fā)送了信息, 則不管當(dāng)前的調(diào)度到了哪里, 這個接收的微進(jìn)程都立即恢復(fù)執(zhí)行; 而發(fā)送信息的微進(jìn)程則被轉(zhuǎn)移到調(diào)度列表的末尾, 就像調(diào)用了 stackless.schedule()一樣。同樣注意,發(fā)送信息的時候, 若當(dāng)時沒有微進(jìn)程正在這個通道上接收,前微進(jìn)程阻塞 :也會使當(dāng) stackless.tasklet(sending_tasklet)() stackles
17、s.tasklet(another_tasklet)() stackless.run()Sending tasklet startedJust another tasklet in the scheduler stackless.tasklet(another_tasklet)() stackless.run()Just another tasklet in the scheduler #Finally adding the receiving tasklet. stackless.tasklet(receiving_tasklet)() stackless.run() Recieving t
18、asklet started send from sending_tasklet Receiving tasklet finished sending tasklet finished發(fā)送信息的微進(jìn)程, 只有在成功地將數(shù)據(jù)發(fā)送到了另一個微進(jìn)程之后, 才會重新被插入到調(diào)度器中。2.4 總結(jié)以上涵蓋了 stackless 的大部分功能。似乎不多是吧?我們只使用了少許對象,和大約四五個函數(shù)調(diào)用,來進(jìn)行操作。但是,使用這種簡單的 API 作為基本建造單元,我們可以開始做一些真正有趣的事情。3 協(xié)程 (coroutine)3.1 子例程的問題大多數(shù)傳統(tǒng)編程語言具有子例程的概念。 一個子例程被另一個例程
19、(可能還是其它某個例程的子例程)所調(diào)用,或返回一個結(jié)果,或不返回結(jié)果。從定義上說,一個子例程是從屬于其調(diào)用者的。見下例 :def ping():print PINGpong()def pong():print PONGping()ping()有經(jīng)驗的編程者會看到這個程序的問題所在: 它導(dǎo)致了堆棧溢出。 如果運行這個程序,它將顯示一大堆討厭的跟蹤信息,來指出堆??臻g已經(jīng)耗盡。堆棧我仔細(xì)考慮了, 自己對 C 語言堆棧的細(xì)節(jié)究竟了解多少, 最終還是決定完全不去講它。似乎,其他人對其所嘗試的描述,以及圖表,只有本身已經(jīng)理解了的人才能看得懂。我將試著給出一個最簡單的說明, 而對其有更多興趣的讀者可以從網(wǎng)
20、上查找更多信息。每當(dāng)一個子例程被調(diào)用, 都有一個“棧幀”被建立, 這是用來保存變量, 以及其他子例程局部信息的區(qū)域。于是,當(dāng)你調(diào)用 ping() ,則有一個棧幀被建立,來保存這次調(diào)用相關(guān)的信息。簡言之,這個幀記載著 ping 被調(diào)用了。當(dāng)再調(diào)用 pong() ,則又建立了一個棧幀,記載著 pong 也被調(diào)用了。這些棧幀是串聯(lián)在一起的,每個子例程調(diào)用都是其中的一環(huán)。就這樣,堆棧中顯示: ping 被調(diào)用所以 pong 接下來被調(diào)用。顯然,當(dāng) pong() 再調(diào)用 ping() ,則使堆棧再擴展。下面是個直觀的表示:幀 堆棧1 ping 被調(diào)用2 ping 被調(diào)用,所以 pong 被調(diào)用3ping
21、被調(diào)用,所以pong 被調(diào)用,所以ping 被調(diào)用4ping被調(diào)用,所以pong 被調(diào)用,所以ping 被調(diào)用,所以 pong 被調(diào)用5ping被調(diào)用, 所以 pong 被調(diào)用, 所以 ping 被調(diào)用, 所以 pong 被調(diào)用, 所以 ping 被調(diào)用6ping被調(diào)用, 所以 pong 被調(diào)用, 所以 ping 被調(diào)用, 所以 pong 被調(diào)用, 所以 ping 被調(diào)用現(xiàn)在假設(shè),這個頁面的寬度就表示系統(tǒng)為堆棧所分配的全部內(nèi)存空間, 當(dāng)其頂?shù)巾撁娴倪吘壍臅r候,將會發(fā)生溢出,系統(tǒng)內(nèi)存耗盡,即術(shù)語“堆棧溢出”。那么,為什么要使用堆棧?上例是有意設(shè)計的, 用來體現(xiàn)堆棧的問題所在。 在大多數(shù)情況下,
22、當(dāng)每個子例程返回的時候,其棧幀將被清除掉, 就是說堆棧將會自行實現(xiàn)清理過程。 這一般 來說是件好事,在 C 語言中,堆棧就是一個不需要編程者來手動進(jìn)行內(nèi)存管理的區(qū)域。很幸運, Python 程序員也不需要直接來擔(dān)心內(nèi)存管理與堆棧。但是由于 Python 解釋器本身也是用 C實現(xiàn)的,那些實現(xiàn)者們可是需要擔(dān)心這個的。使用堆棧是會使事情方便, 除非我們開始調(diào)用那種從不返回的函數(shù), 如上例中的, 那時候,堆棧的表現(xiàn)就開始和程序員別扭起來,并耗盡可用的內(nèi)存。3.2 走進(jìn)協(xié)程此時,將堆棧弄溢出是有點愚蠢的。 ping() 和 pong() 本不是真正意義的子例程,因為其中哪個也不從屬于另一個,它們是“協(xié)程
23、”,處于同等的地位,并可以彼此間進(jìn)行無縫通信。幀 堆棧1 ping 被調(diào)用2 pong 被調(diào)用3 ping 被調(diào)用4 pong 被調(diào)用5 ping 被調(diào)用6 pong 被調(diào)用在 stackless 中,我們使用通道來建立協(xié)程。 還記得嗎, 通道所帶來的兩個好處中的一個,就是能夠控制微進(jìn)程之間運行的流程。 使用通道,我們可以在 ping 和pong 這兩個協(xié)程之間自由來回,要多少次就多少次,都不會堆棧溢出:# pingpong_stackless.py#import stacklessping_channel = stackless.channel()pong_channel = stackle
24、ss.channel()def ping():while ping_channel.receive(): #在此阻塞print PINGpong_channel.send(from ping)def pong():while pong_channel.receive():print PONGping_channel.send(from pong)stackless.tasklet(ping)()stackless.tasklet(pong)()# 我們需要發(fā)送一個消息來初始化這個游戲的狀態(tài)# 否則,兩個微進(jìn)程都會阻塞 stackless.tasklet(ping_channel.send)(s
25、tartup)stackless.run()你可以運行這個程序要多久有多久, 它都不會崩潰, 且如果你檢查其內(nèi)存使用量(使用 Windows的任務(wù)管理器或 Linux 的 top 命令),將會發(fā)現(xiàn) 使用量是恒定的。這個程序的協(xié)程版本,不管運行一分鐘還是一天,使用的內(nèi)存都是一樣的。而如果你檢查原先那個遞歸版本的內(nèi)存用量,則會發(fā)現(xiàn)其迅速增長, 直 到崩潰。3.3 總結(jié)是否還記得, 先前我提到過, 那個代碼的遞歸版本, 有經(jīng)驗的程序員會一眼看出毛病。但老實說,這里面并沒有什么“計算機科學(xué)”方面的原因在阻礙它的正 常工作,有些讓人堅信的東西, 其實只是個與實現(xiàn)細(xì)節(jié)有關(guān)的小問題只因為大多數(shù)傳統(tǒng)編程語言都
26、使用堆棧。某種意義上說,有經(jīng)驗的程序員都是被洗了腦,從 而相信這是個可以接受的問題。而 stackless ,則真正察覺了這個問題,并除掉了它。4 輕量級線程與當(dāng)今的操作系統(tǒng)中內(nèi)建的、 和標(biāo)準(zhǔn) Python 代碼中所支持的普通線程相比, “微線程”要更為輕量級, 正如其名稱所暗示。 它比傳統(tǒng)線程占用更少的內(nèi)存, 并且微線程之間的切換,要比傳統(tǒng)線程之間的切換更加節(jié)省資源。為了準(zhǔn)確說明微線程的效率究竟比傳統(tǒng)線程高多少,我們用兩者來寫同一個程序。4.1 hackysack模擬Hackysack 是一種游戲,就是一伙臟乎乎的小子圍成一個圈,來回踢一個裝滿了豆粒的沙包,目標(biāo)是不讓這個沙包落地, 當(dāng)傳球給
27、別人的時候, 可以耍各種把戲。踢沙包只可以用腳。在我們的簡易模擬中, 我們假設(shè)一旦游戲開始, 圈里人數(shù)就是恒定的, 并且每個人都是如此厲害,以至于如果允許的話,這個游戲可以永遠(yuǎn)停不下來。4.2 游戲的傳統(tǒng)線程版本import threadimport randomimport sysimport Queueclass hackysacker:counter = 0def _init_(self,name,circle): = nameself.circle = circlecircle.append(self)self.messageQueue = Queue.Queue()
28、thread.start_new_thread(self.messageLoop,()def incrementCounter(self):hackysacker.counter += 1if hackysacker.counter = turns:while self.circle:if hs is not self:sys.exit()def messageLoop(self):while 1:if message = exit:debugPrint(%s is going home % )sys.exit()debugPrint(%s got hackeysack fr
29、om %s % (, )kickTo = self.circlerandom.randint(0,len(self.circle)-1) debugPrint(%s kicking hackeysack to %s % (,kickT)self.incrementCounter()def debugPrint(x):if debug:print xdebug=1hackysackers=5turns = 5def runit(hs=10,ts=10,dbg=1):global hackysackers,turns,debu
30、ghackysackers = hsturns = tsdebug = dbghackysacker.counter= 0circle = one = hackysacker(1,circle)for i in range(hackysackers):hackysacker(i,circle)try:while circle:passexcept:#有時我們在清理過程中會遇到詭異的錯誤。passif _name_ = _main_:runit(dbg=1)一個“玩者”類的初始化用到了其名字,和一個指向包含了所有玩者的全局列表circle的引用,還有一個繼承自Python 標(biāo)準(zhǔn)庫中的 Queue
31、類的消息隊列。Queue這個類的作用,與 stackless 的通道類似。它包含 put() 和 get() 方法,在一個空的 Queue上調(diào)用 put() 會阻塞,直到另一個線程調(diào)用 put() 將數(shù)據(jù)送入 Queue中為止。 Queue這個類被設(shè)計為能與操作系統(tǒng)級的線程高效合作。_init_ 方法接下來使用 Python 標(biāo)準(zhǔn)庫中的 thread 模塊新建一個線程,并在新線程中開始了一個消息循環(huán)。 此消息循環(huán)是個無限循環(huán), 不停地處理隊列中的消息。如果其收到一個特殊的消息 exit ,則結(jié)束這個線程。如果收到了另一個消息指定其收到了沙包, 玩者則從圈中隨機選取一個其他玩者,通過向其發(fā)送一條
32、消息來指定,將沙包再踢給它。由類成員變量 hackysacker.counter 進(jìn)行計數(shù),當(dāng)沙包被踢夠了指定的次數(shù)時,將會向圈中的所有玩者都發(fā)送一條特殊的 exit 消息。注意,當(dāng)全局變量 debug 為非零的時候, 還有個函數(shù) debugPrint可以輸出信息。我們可以使這游戲輸出到標(biāo)準(zhǔn)輸出,但當(dāng)計時的時候,這會影響精確度。我們來運行這個程序,并檢查其是否正常工作:C:Documents andSettingsgrantDesktopwhy_stacklesscodec:python24python.exe hackysackthreaded.py1 got hackeysack from
33、 11 kicking hackeysack to 44 got hackeysack from 14 kicking hackeysack to 00 got hackeysack from 40 kicking hackeysack to 11 got hackeysack from 01 kicking hackeysack to 33 got hackeysack from 13 kicking hackeysack to 34 is going home2 is going home1 is going home0 is going home1 is going homeC:Docu
34、ments and SettingsgrantDesktopwhy_stacklesscode如我們所見,所有玩者到了一起,并很快地進(jìn)行了一場游戲?,F(xiàn)在,我們對若干次實驗運行過程進(jìn)行計時。 Python 標(biāo)準(zhǔn)庫中有一個 timeit.py 程序,可以用作此目的。那么,我們也同時關(guān)掉調(diào)試輸出 :C:Documents andSettingsgrantDesktopwhy_stacklesscodec:python24python.exe c:Python24libtimeit.py -s import hackysackthreaded hackysackthreaded.runit(10,10
35、00,0)10 loops, best of 3: 183 msec per loop在我的機器上,十個玩者共進(jìn)行 1000 次傳球,共使用了 183 毫秒。我們來增加玩者的數(shù)量 :C:Documents andSettingsgrantDesktopwhy_stacklesscodec:python24python.exe c:Python24libtimeit.py -s import hackeysackthreaded hackeysackthreaded.runit(100,1000,0)10 loops, best of 3: 231 msec per loopC:Document
36、s andSettingsgrantDesktopwhy_stacklesscodec:python24python.exec:Python24libtimeit.py -s import hackysackthreadedhackysackthreaded.runit(1000,1000,0)10 loops, best of 3: 681 msec per loopC:Documents andSettingsgrantDesktopwhy_stacklesscodec:python24python.exe c:Python24libtimeit.py -s import hackysac
37、kthreaded hackysackthreaded.runit(10000,1000,0)Traceback (most recent call last):File c:Python24libtimeit.py, line 255, in mainx = t.timeit(number)File c:Python24libtimeit.py, line 161, in timeittiming = self.inner(it, self.timer)File , line 6, in innerFile .hackeysackthreaded.py, line 58, in runith
38、ackysacker(i,circle)File .hackeysackthreaded.py, line 14, in _init_thread.start_new_thread(self.messageLoop,()error: cant start new thread在我的 3GHz、1G內(nèi)存的機器上, 當(dāng)嘗試 10,000 個線程的時候出現(xiàn)了錯誤。就不想拿出這詳細(xì)的輸出內(nèi)容來擾人了,只是通過若干實驗與出錯過程 得出,在我機器上,此程序從 1100 個線程左右開始出錯。另請注意, 1000 個線程時候所耗用的時間,是 10 個線程時候的大約三倍。4.3 stacklessimport
39、stacklessimport randomimport sysclass hackysacker:counter = 0def _init_(self,name,circle): = nameself.circle = circlecircle.append(self)self.channel = stackless.channel()stackless.tasklet(self.messageLoop)()def incrementCounter(self):hackysacker.counter += 1if hackysacker.counter = turns:wh
40、ile self.circle:def messageLoop(self):while 1:if message = exit:returndebugPrint(%s got hackeysack from %s % (, )kickTo = self.circlerandom.randint(0,len(self.circle)-1) while kickTo is self:kickTo =self.circlerandom.randint(0,len(self.circle)-1)debugPrint(%s kicking hackeysack
41、to %s % (, kickT)self.incrementCounter()def debugPrint(x):if debug:print xdebug = 5hackysackers = 5turns = 1def runit(hs=5,ts=5,dbg=1):global hackysackers,turns,debughackysackers = hsturns = tsdebug = dbghackysacker.counter = 0circle = one = hackysacker(1,circle)for i in range(hackysa
42、ckers):hackysacker(i,circle)try:stackless.run()except TaskletExit:passif _name_ = _main_:runit()以上代碼實質(zhì)上與線程版本是等價的, 主要區(qū)別僅在于我們使用微進(jìn)程來代替線程,并且使用通道代替 Queue來進(jìn)行切換。讓我們運行它,并檢查輸出 :C:Documents andSettingsgrantDesktopwhy_stacklesscodec:Python24python.exe hackysackstackless.py1 got hackeysack from 11 kicking hacke
43、ysack to 11 got hackeysack from 11 kicking hackeysack to 44 got hackeysack from 14 kicking hackeysack to 11 got hackeysack from 41 kicking hackeysack to 44 got hackeysack from 14 kicking hackeysack to 0工作情況確如所料?,F(xiàn)在來計時:C:Documents andSettingsgrantDesktopwhy_stacklesscodec:Python24python.exe c:Python24
44、libtimeit.py -simport hackysackstackless hackysackstackless.runit(10,1000,0)100 loops, best of 3: 19.7 msec per loop其僅用了 19.7 毫秒,速度幾乎是線程版本的 10 倍?,F(xiàn)在我們同樣開始增加微線程的數(shù)量 :C:Documents andSettingsgrantDesktopwhy_stacklesscodec:Python24python.exe c:Python24libtimeit.py -simport hackysackstackless hackysackstac
45、kless.runit(100,1000,0)100 loops, best of 3: 19.7 msec per loopC:Documents andSettingsgrantDesktopwhy_stacklesscodec:Python24python.exe c:Python24libtimeit.py -simport hackysackstackless hackysackstackless.runit(1000,1000,0)10 loops, best of 3: 26.9 msec per loopC:Documents andSettingsgrantDesktopwh
46、y_stacklesscodec:Python24python.exe c:Python24libtimeit.py -simport hackysackstackless hackysackstackless.runit(10000,1000,0)10 loops, best of 3: 109 msec per loopC:Documents andSettingsgrantDesktopwhy_stacklesscodec:Python24python.exe c:Python24libtimeit.py -simport hackysackstackless hackysackstac
47、kless.runit(100000,1000,0)10 loops, best of 3: 1.07 sec per loop甚至直到 10,000 個線程的時候,那時線程版本早已不能運行了,而這個仍然可以比線程版本在 10 個線程的時候運行的還快。這里我在盡量保持代碼的簡潔, 因此你可以相信我的話: 計時時間的增長僅僅在于初始化游戲圈子的部分, 而真正進(jìn)行游戲的時間則是一直不變的, 不管使用 10 個微線程,還是 10,000 個。這歸因于通道的工作方式: 當(dāng)它們收到消息的時候,是立即進(jìn)行阻塞和恢復(fù)操作的。另一方面,各個操作系統(tǒng)線程則是輪番檢 查自己的隊列里是否有了東西,這意味著,跑著越多的線程,性能就變得越差。4.4 總結(jié)但愿我已經(jīng)成功地演示了, 微線程的運行至少比操作系統(tǒng)線程快一個數(shù)量級,并具備遠(yuǎn)高于后者的可伸縮性。關(guān)于操作系統(tǒng)線程的一般常識是:( 1)盡量不要使用它,( 2)如果非用不可,就能少用一點就少用一點。而 stackless 的微線程則使我們從這些限制中解放出來。5 數(shù)據(jù)流5.1 工廠假設(shè),我們要寫程序來模擬一個生產(chǎn)玩具娃娃的工廠,具有如下的需求:? 一個倉庫,裝有用來塑造的塑料球。? 一個倉庫,裝有用來連接部件的鉚釘。? 一臺注塑機,可以在 6 秒內(nèi),用 0.2 磅塑料球來制造一雙手臂。? 一臺
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024石材加工行業(yè)標(biāo)準(zhǔn)化及質(zhì)量管理體系合作協(xié)議3篇
- 個人向公司借款詳細(xì)條款合同版B版
- 專業(yè)租車協(xié)議范本:2024年版
- 2025年度地質(zhì)勘查測繪合作協(xié)議書8篇
- 2024版銷售代表獎勵提成協(xié)議樣本一
- 集合2024年度醫(yī)療設(shè)備采購及安裝服務(wù)合同
- 2025年度文化旅游項目合作協(xié)議補充協(xié)議3篇
- 2024精密波紋管訂貨及銷售協(xié)議條款版B版
- 2025年度廠房租賃及品牌授權(quán)使用合同4篇
- 二零二五年度汽車后市場銷售提成及品牌代理協(xié)議
- 礦山隱蔽致災(zāi)普查治理報告
- 2024年事業(yè)單位財務(wù)工作計劃例文(6篇)
- 副總經(jīng)理招聘面試題與參考回答(某大型國企)2024年
- PDCA循環(huán)提高護士培訓(xùn)率
- 2024年工程咨詢服務(wù)承諾書
- 青桔單車保險合同條例
- 車輛使用不過戶免責(zé)協(xié)議書范文范本
- 《獅子王》電影賞析
- 2023-2024學(xué)年天津市部分區(qū)九年級(上)期末物理試卷
- DB13-T 5673-2023 公路自愈合瀝青混合料薄層超薄層罩面施工技術(shù)規(guī)范
- 河北省保定市定州市2025屆高二數(shù)學(xué)第一學(xué)期期末監(jiān)測試題含解析
評論
0/150
提交評論