日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Python 使用生成器代替線程的方法

瀏覽:156日期:2022-07-15 09:58:30

問題

你想使用生成器(協(xié)程)替代系統(tǒng)線程來實現(xiàn)并發(fā)。這個有時又被稱為用戶級線程或綠色線程。

解決方案

要使用生成器實現(xiàn)自己的并發(fā),你首先要對生成器函數(shù)和 yield 語句有深刻理解。 yield 語句會讓一個生成器掛起它的執(zhí)行,這樣就可以編寫一個調度器, 將生成器當做某種“任務”并使用任務協(xié)作切換來替換它們的執(zhí)行。 要演示這種思想,考慮下面兩個使用簡單的 yield 語句的生成器函數(shù):

# Two simple generator functionsdef countdown(n): while n > 0: print(’T-minus’, n) yield n -= 1 print(’Blastoff!’)def countup(n): x = 0 while x < n: print(’Counting up’, x) yield x += 1

這些函數(shù)在內部使用yield語句,下面是一個實現(xiàn)了簡單任務調度器的代碼:

from collections import dequeclass TaskScheduler: def __init__(self): self._task_queue = deque() def new_task(self, task): ’’’ Admit a newly started task to the scheduler ’’’ self._task_queue.append(task) def run(self): ’’’ Run until there are no more tasks ’’’ while self._task_queue: task = self._task_queue.popleft() try:# Run until the next yield statementnext(task)self._task_queue.append(task) except StopIteration:# Generator is no longer executingpass# Example usesched = TaskScheduler()sched.new_task(countdown(10))sched.new_task(countdown(5))sched.new_task(countup(15))sched.run()

TaskScheduler 類在一個循環(huán)中運行生成器集合——每個都運行到碰到y(tǒng)ield語句為止。 運行這個例子,輸出如下:

T-minus 10T-minus 5Counting up 0T-minus 9T-minus 4Counting up 1T-minus 8T-minus 3Counting up 2T-minus 7T-minus 2...

到此為止,我們實際上已經(jīng)實現(xiàn)了一個“操作系統(tǒng)”的最小核心部分。 生成器函數(shù)就是任務,而yield語句是任務掛起的信號。 調度器循環(huán)檢查任務列表直到?jīng)]有任務要執(zhí)行為止。

實際上,你可能想要使用生成器來實現(xiàn)簡單的并發(fā)。 那么,在實現(xiàn)actor或網(wǎng)絡服務器的時候你可以使用生成器來替代線程的使用。

下面的代碼演示了使用生成器來實現(xiàn)一個不依賴線程的actor:

from collections import dequeclass ActorScheduler: def __init__(self): self._actors = {} # Mapping of names to actors self._msg_queue = deque() # Message queue def new_actor(self, name, actor): ’’’ Admit a newly started actor to the scheduler and give it a name ’’’ self._msg_queue.append((actor,None)) self._actors[name] = actor def send(self, name, msg): ’’’ Send a message to a named actor ’’’ actor = self._actors.get(name) if actor: self._msg_queue.append((actor,msg)) def run(self): ’’’ Run as long as there are pending messages. ’’’ while self._msg_queue: actor, msg = self._msg_queue.popleft() try: actor.send(msg) except StopIteration: pass# Example useif __name__ == ’__main__’: def printer(): while True: msg = yield print(’Got:’, msg) def counter(sched): while True: # Receive the current count n = yield if n == 0:break # Send to the printer task sched.send(’printer’, n) # Send the next count to the counter task (recursive) sched.send(’counter’, n-1) sched = ActorScheduler() # Create the initial actors sched.new_actor(’printer’, printer()) sched.new_actor(’counter’, counter(sched)) # Send an initial message to the counter to initiate sched.send(’counter’, 10000) sched.run()

完全弄懂這段代碼需要更深入的學習,但是關鍵點在于收集消息的隊列。 本質上,調度器在有需要發(fā)送的消息時會一直運行著。 計數(shù)生成器會給自己發(fā)送消息并在一個遞歸循環(huán)中結束。

下面是一個更加高級的例子,演示了使用生成器來實現(xiàn)一個并發(fā)網(wǎng)絡應用程序:

from collections import dequefrom select import select# This class represents a generic yield event in the schedulerclass YieldEvent: def handle_yield(self, sched, task): pass def handle_resume(self, sched, task): pass# Task Schedulerclass Scheduler: def __init__(self): self._numtasks = 0 # Total num of tasks self._ready = deque() # Tasks ready to run self._read_waiting = {} # Tasks waiting to read self._write_waiting = {} # Tasks waiting to write # Poll for I/O events and restart waiting tasks def _iopoll(self): rset,wset,eset = select(self._read_waiting,self._write_waiting,[]) for r in rset: evt, task = self._read_waiting.pop(r) evt.handle_resume(self, task) for w in wset: evt, task = self._write_waiting.pop(w) evt.handle_resume(self, task) def new(self,task): ’’’ Add a newly started task to the scheduler ’’’ self._ready.append((task, None)) self._numtasks += 1 def add_ready(self, task, msg=None): ’’’ Append an already started task to the ready queue. msg is what to send into the task when it resumes. ’’’ self._ready.append((task, msg)) # Add a task to the reading set def _read_wait(self, fileno, evt, task): self._read_waiting[fileno] = (evt, task) # Add a task to the write set def _write_wait(self, fileno, evt, task): self._write_waiting[fileno] = (evt, task) def run(self): ’’’ Run the task scheduler until there are no tasks ’’’ while self._numtasks: if not self._ready: self._iopoll() task, msg = self._ready.popleft() try: # Run the coroutine to the next yield r = task.send(msg) if isinstance(r, YieldEvent): r.handle_yield(self, task) else: raise RuntimeError(’unrecognized yield event’) except StopIteration: self._numtasks -= 1# Example implementation of coroutine-based socket I/Oclass ReadSocket(YieldEvent): def __init__(self, sock, nbytes): self.sock = sock self.nbytes = nbytes def handle_yield(self, sched, task): sched._read_wait(self.sock.fileno(), self, task) def handle_resume(self, sched, task): data = self.sock.recv(self.nbytes) sched.add_ready(task, data)class WriteSocket(YieldEvent): def __init__(self, sock, data): self.sock = sock self.data = data def handle_yield(self, sched, task): sched._write_wait(self.sock.fileno(), self, task) def handle_resume(self, sched, task): nsent = self.sock.send(self.data) sched.add_ready(task, nsent)class AcceptSocket(YieldEvent): def __init__(self, sock): self.sock = sock def handle_yield(self, sched, task): sched._read_wait(self.sock.fileno(), self, task) def handle_resume(self, sched, task): r = self.sock.accept() sched.add_ready(task, r)# Wrapper around a socket object for use with yieldclass Socket(object): def __init__(self, sock): self._sock = sock def recv(self, maxbytes): return ReadSocket(self._sock, maxbytes) def send(self, data): return WriteSocket(self._sock, data) def accept(self): return AcceptSocket(self._sock) def __getattr__(self, name): return getattr(self._sock, name)if __name__ == ’__main__’: from socket import socket, AF_INET, SOCK_STREAM import time # Example of a function involving generators. This should # be called using line = yield from readline(sock) def readline(sock): chars = [] while True: c = yield sock.recv(1) if not c:break chars.append(c) if c == b’n’:break return b’’.join(chars) # Echo server using generators class EchoServer: def __init__(self,addr,sched): self.sched = sched sched.new(self.server_loop(addr)) def server_loop(self,addr): s = Socket(socket(AF_INET,SOCK_STREAM)) s.bind(addr) s.listen(5) while True:c,a = yield s.accept()print(’Got connection from ’, a)self.sched.new(self.client_handler(Socket(c))) def client_handler(self,client): while True:line = yield from readline(client)if not line: breakline = b’GOT:’ + linewhile line: nsent = yield client.send(line) line = line[nsent:] client.close() print(’Client closed’) sched = Scheduler() EchoServer((’’,16000),sched) sched.run()

這段代碼有點復雜。不過,它實現(xiàn)了一個小型的操作系統(tǒng)。 有一個就緒的任務隊列,并且還有因I/O休眠的任務等待區(qū)域。 還有很多調度器負責在就緒隊列和I/O等待區(qū)域之間移動任務。

討論

在構建基于生成器的并發(fā)框架時,通常會使用更常見的yield形式:

def some_generator(): ... result = yield data ...

使用這種形式的yield語句的函數(shù)通常被稱為“協(xié)程”。 通過調度器,yield語句在一個循環(huán)中被處理,如下:

f = some_generator()# Initial result. Is None to start since nothing has been computedresult = Nonewhile True: try: data = f.send(result) result = ... do some calculation ... except StopIteration: break

這里的邏輯稍微有點復雜。不過,被傳給 send() 的值定義了在yield語句醒來時的返回值。 因此,如果一個yield準備在對之前yield數(shù)據(jù)的回應中返回結果時,會在下一次 send() 操作返回。 如果一個生成器函數(shù)剛開始運行,發(fā)送一個None值會讓它排在第一個yield語句前面。

除了發(fā)送值外,還可以在一個生成器上面執(zhí)行一個 close() 方法。 它會導致在執(zhí)行yield語句時拋出一個 GeneratorExit 異常,從而終止執(zhí)行。 如果進一步設計,一個生成器可以捕獲這個異常并執(zhí)行清理操作。 同樣還可以使用生成器的 throw() 方法在yield語句執(zhí)行時生成一個任意的執(zhí)行指令。 一個任務調度器可利用它來在運行的生成器中處理錯誤。

最后一個例子中使用的 yield from 語句被用來實現(xiàn)協(xié)程,可以被其它生成器作為子程序或過程來調用。 本質上就是將控制權透明的傳輸給新的函數(shù)。 不像普通的生成器,一個使用 yield from 被調用的函數(shù)可以返回一個作為 yield from 語句結果的值。 關于 yield from 的更多信息可以在 PEP 380 中找到。

最后,如果使用生成器編程,要提醒你的是它還是有很多缺點的。 特別是,你得不到任何線程可以提供的好處。例如,如果你執(zhí)行CPU依賴或I/O阻塞程序, 它會將整個任務掛起直到操作完成。為了解決這個問題, 你只能選擇將操作委派給另外一個可以獨立運行的線程或進程。 另外一個限制是大部分Python庫并不能很好的兼容基于生成器的線程。 如果你選擇這個方案,你會發(fā)現(xiàn)你需要自己改寫很多標準庫函數(shù)。 作為本節(jié)提到的協(xié)程和相關技術的一個基礎背景,可以查看 PEP 342 和 “協(xié)程和并發(fā)的一門有趣課程”

PEP 3156 同樣有一個關于使用協(xié)程的異步I/O模型。 特別的,你不可能自己去實現(xiàn)一個底層的協(xié)程調度器。 不過,關于協(xié)程的思想是很多流行庫的基礎, 包括 gevent, greenlet, Stackless Python 以及其他類似工程。

以上就是Python 使用生成器代替線程的方法的詳細內容,更多關于Python 生成器代替線程的資料請關注好吧啦網(wǎng)其它相關文章!

標簽: Python 編程
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧美日本二区| 欧美激情综合| 韩国精品主播一区二区在线观看| 国产精品密蕾丝视频下载| 久久精品72免费观看| 日本午夜精品视频在线观看| 日本免费新一区视频| 欧美片第1页综合| 国产精品一卡| 美女久久久久久| 成人在线观看免费视频| 久久99影视| 久久影院午夜精品| 久久激情一区| 久久www成人_看片免费不卡| 亚洲丝袜啪啪| 日韩av网站免费在线| 久久不见久久见中文字幕免费 | 色爱av综合网| 五月天久久网站| 蜜臀久久99精品久久久久宅男| 日韩精品亚洲aⅴ在线影院| 欧美亚洲免费| 精品一区二区三区免费看| 亚洲精品88| 亚洲主播在线| 国产精品一区二区精品视频观看 | 视频一区日韩精品| 国产精品羞羞答答在线观看| 美女av一区| 91精品一区二区三区综合| 国产模特精品视频久久久久| 91麻豆精品| 日韩综合一区| 欧美日韩国产传媒| 日韩高清一区二区| 97se综合| 亚洲影院天堂中文av色| 国产精品亚洲四区在线观看| 日韩电影在线视频| 在线观看视频免费一区二区三区| 免费一级欧美在线观看视频| 亚洲福利国产| 日韩av中文字幕一区| 精品国产一区二区三区性色av| 欧美aa在线观看| 久久夜色精品| 精品日本视频| 亚洲主播在线| 国内自拍视频一区二区三区| 免费观看不卡av| 欧美日韩在线精品一区二区三区激情综合| 伊人久久在线| 日韩欧美中文在线观看| 中文字幕在线免费观看视频| 日韩制服丝袜av| 国产一区2区| 亚洲无线观看| 亚洲最新无码中文字幕久久 | 一二三区精品| 日韩中文欧美| 日韩av中文在线观看| 91精品国产乱码久久久久久久 | 久久精品国产在热久久| 99国产成+人+综合+亚洲欧美| 国产福利一区二区精品秒拍| 亚洲精品网址| 麻豆精品在线视频| 久久亚洲美女| 日韩和的一区二在线| 久久国产尿小便嘘嘘| 三上悠亚国产精品一区二区三区| 奇米777国产一区国产二区| 神马日本精品| 国产精品99久久免费| 日韩影院在线观看| 精品三级久久| 国产精品久久久久9999高清| 国产亚洲欧洲| se01亚洲视频 | 高清久久精品| 日本免费新一区视频| 黄色在线一区| 亚洲va中文在线播放免费| 国产视频一区二区在线播放| 国产午夜久久| 久久国产精品成人免费观看的软件| 国产精品啊v在线| 天堂成人免费av电影一区| 日韩精品一区二区三区免费观看| 久久免费精品| 国产精品日本一区二区不卡视频| 一区二区三区四区在线观看国产日韩| 欧美aa国产视频| 中文字幕在线免费观看视频| 久久久久黄色| 国产亚洲一区二区三区啪| 老鸭窝亚洲一区二区三区| 久久国产中文字幕| 精品黄色一级片| 国产精品视频一区二区三区 | 亚洲精品1区2区| 成人精品亚洲| 理论片午夜视频在线观看| 精品视频网站| 国产一精品一av一免费爽爽| 亚洲精品成人一区| 在线视频亚洲| 一区在线免费观看| 999久久久91| 亚洲涩涩在线| 国产精品精品| 国产一区2区| 卡一卡二国产精品| 欧美激情视频一区二区三区免费 | 国产精品久久观看| 久久精品九色| 国产一区一一区高清不卡| 国产精品a级| 麻豆精品蜜桃视频网站| 国产精品密蕾丝视频下载| 日韩国产欧美三级| 日韩高清电影免费| 日韩高清电影一区| 欧美日韩1区| 久久爱www成人| 电影91久久久| 日韩一区二区三区免费播放| 久久婷婷av| 九九综合九九| av不卡免费看| 快she精品国产999| 亚洲九九精品| 亚洲精品第一| 国产日韩一区二区三区在线播放| 911精品国产| 欧美视频二区| 国产精品一区毛片| 精品国产乱码久久久| 国产精品毛片久久| 久久久人人人| 91成人超碰| 日韩专区在线视频| 日本aⅴ精品一区二区三区 | 亚洲2区在线| 91成人在线| 精品久久91| 亚洲网站视频| 午夜亚洲福利在线老司机| 蜜臀av在线播放一区二区三区| 中文字幕av亚洲精品一部二部| 欧美日韩精品一区二区三区在线观看| 国产伦乱精品| 中文字幕色婷婷在线视频 | 免费污视频在线一区| 欧美午夜不卡影院在线观看完整版免费| 国产一区成人| 欧美在线看片| 高清久久一区| 国产偷自视频区视频一区二区| 日韩av电影一区| 国产一区二区三区久久久久久久久| 激情自拍一区| 日本亚洲欧美天堂免费| 国产精品久久久久久久久久久久久久久| 国产精品蜜芽在线观看| 亚洲深爱激情| 久久在线91| 在线亚洲免费| 麻豆成人综合网| 激情91久久| 国产精品www994| 1024精品久久久久久久久| 欧美亚洲一区二区三区| 久久精品动漫| 日韩和欧美一区二区| 欧美xxxx中国| 日韩影院精彩在线| 国产精品免费精品自在线观看| 日韩精品欧美| 91欧美极品| 亚洲性图久久| 国产欧美日韩精品一区二区三区| 久久精品免费一区二区三区| 日本不卡一区二区| 日韩一区欧美| 欧美日韩a区| 91精品1区| 麻豆精品蜜桃视频网站| 红桃视频国产精品| 国产一区二区三区四区大秀| 综合激情网站| 亚洲四虎影院| 青草久久视频| 99久久99视频只有精品| 国产精区一区二区| 视频在线观看一区| 日韩国产欧美| 日韩中文av| 国产综合亚洲精品一区二|