您好,登錄后才能下訂單哦!
這篇文章主要介紹“Python協程的面試題有哪些”,在日常操作中,相信很多人在Python協程的面試題有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Python協程的面試題有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
一、什么是協程
協程:實現協作式多任務,可以在程序執行內部中斷,轉而執行其他協程。
比如我們編寫子程序(或者說函數),通常是利用“調用”來實現從 A 跳去 B,B 跳去 C,如果想回來調用方,必須等被調用方執行完才行,整個調用過程是通過棧實現的。而協程是運行子程序的過程中“中斷”,轉而執行其他子程序,再在適當的時候返回來接著運行。
二、協程與線程的區別
協程相比于線程的優勢:
1、協程效率比線程高。線程間切換需要開銷,而協程間切換是由程序自身控制的,不需要開銷。
2、協程不需要多線程的鎖機制。協程是在一個線程內進行切換,所以不存在同時寫變量沖突,不需要給共享資源加鎖,只需要判斷狀態。
PS:如果想使用多CPU的話,可以使用進程+協程。
三、協程的實現
協程是通過yield實現的,所以協程是生成器,可以通過 next 調用。
def simple(a): print("----start----") r = yield a print('----r------' + str(r)) >>> my_simple = simple(5) >>> my_simple <generator object simple at 0x10f9242b0> >>> next(my_simple) ----start---- 5 >>> my_simple.send(8) ----r------8 Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
以上是一個簡單的協程例子,可以看到,my_simple是一個生成器實例,需要使用next()方法或send(None)去預激協程,協程運行到yield的時候停止,當使用send()方法給yield賦值時,程序繼續往下運行,并拋出StopIteration異常。
四、協程返回值
在python3.3版本后,協程可以有返回值。
def simple(a): print("----start----") r = yield a print('----r------' + str(r)) return r >>> my_simple = simple(5) >>> next(my_simple) ----start---- 5 >>> my_simple.send(8) ----r------8 Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration: 8
可以看到,在程序運行完后,異常對象StopIteration的value屬性保存著返回的值。
五、使用yield from獲取協程返回值
對于yield from來說,解釋器不僅會捕獲StopIteration異常,還會把value屬性的值作為yield from表達式的值。
yield from主要功能是打開雙向通道,把最外層的調用方和最內層的子生成器連接起來。
# 子生成器 def total_num(): total = 0 while True: num = yield if num == None: break total += num return total # 委派生成器 def send_num(result, key): while True: result[key] = yield from total_num() # 調用方 def main(data): result = {} for key, nums in data.items(): group = send_num(result, key) next(group) for num in nums: group.send(num) group.send(None) print(result) data = { 'nums1': [12, 34, 23, 4, 35, 34, 34, 55], 'nums2': [22, 44, 33, 24, 33, 24, 4, 15], 'nums3': [32, 54, 43, 41, 31, 44, 24, 25], 'nums4': [42, 64, 53, 43, 37, 74, 74, 35], 'nums5': [52, 74, 63, 46, 39, 84, 44, 45] } if __name__ == "__main__": main(data)
輸出結果如下:
{'nums1': 231, 'nums2': 199, 'nums3': 294, 'nums4': 422, 'nums5': 447}
委派生成器作為雙向管道把調用方和子生成器連接起來,委派生成器在yield from表達式處暫停時,調用方通過send()方法把數據傳給子生成器,子生成器再把產出值發送給調用方,子生成器返回后,會拋出StopIteration異常,并把返回值添加到異常的value屬性上,此時你異常生成器會恢復,并獲取異常的value值作為yield from表達式的值。
委派生成器相當于管道,所以可以把任意個委派生成器連起來:委派生成器連接的子生成器是一個委派生成器,以此類推,直到遇到一個使用yield的生成器或可迭代對象。
六、總結
1、協程是用于控制程序中斷,它與函數調用不同
2、協程是在單線程里可處理多任務,相比多線程節省了線程切換的開銷
3、協程通過 yield 關鍵字實現,它也是一種生成器
4、協程調用方可通過 send() 方法給被調用方發送值。協程的開啟需要預激,預激方法是:send(None)或者next()
5、協程在 python3.3 之后是有返回值的,返回值會放在 StopIteration 異常的 value 里
6、yield from 的作用是在生成器里調用子生成器,可以優化一個嵌套 for 循環等復雜代碼
7、協程有四種狀態:GEN_CREATED(等待開始執行)、GEN_RUNNING(解釋器正在執行)、GEN_SUSPENDED(在yield表達式處停止)、GEN_CLOSED(執行結束)。通過 inspect.getgeneratorstate(…) 函數可獲取
8、結束協程的兩種方式:generator.throw 或 generator.close
七、相關面試題
上面介紹了關于Python學習協程的概念,相對應的這里提供幾個關于協程的面試題目。
理論結合“面試”
1、什么是進程、線程、協程?
答案要點:
a、進程是資源分配,每個進程擁有獨立的資源空間,因為進程不共享資源,所以就涉及到進程間通信的方式,常見的方式有:消息隊列、管道、信號量、socket套接字等。(這里會引申出幾個面試題:進程間有通信方式有哪些?-> 使用過哪些消息隊列?)
b、線程(英語:thread)是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。線程是在進程下,所以同一進程下的多個線程是能共享資源的。線程能共享的資源有:堆、全局變量、文件描述符和信號處理等,不共享的資源:棧、寄存器等(這里會引申出的面試題:多線程怎么實現?-> 多線程并發問題 -> 多線程共享哪些資源)
c、協程是單線程下實現多任務,它通過 yield 關鍵字來實現,能有效地減少多線程之間切換的開銷。它是一種比線程更加輕量級的存在。正如一個進程可以擁有多個線程一樣,一個線程也可以擁有多個協程。
2、協程有什么優缺點?
答案要點
a、協程不是被操作系統內核所管理,而完全是由程序所控制(也就是在用戶態執行),性能得到了很大的提升,不會像線程切換那樣消耗資源。
b、缺點:異步代碼,可能不那么容易理解和調度
3、下面代碼輸出結果是什么?
def test(): print("1"*30) yield "A" print("A"*30) yield "B" print("B"*30) t = test() # 1 print(next(t)) # 2 print(next(t)) # 3 print(next(t)) # 4
答案要點:
這其實是屬于生成器的一個題目,輸出如下:
1:沒有任何輸出,它不會執行 print(“1”*30),只會返回一個生成器
2:輸出 “111…111”(30個),同時打印返回值"A"
3:輸出 “111…111”(30個),同時打印返回值"B"
4:異常、StopIteration
4、請寫一個簡單的協程示例 或 利用協程實現一個 生產者消費者 模式
面試一般其實比較少說讓面試者手寫一個協程代碼,不過之前確實有遇到過讓手寫一個利用協程實現生產者消費者模式的。
import time def consumer(): r = '' while True: n = yield r if not n: return print('[CONSUMER] Consuming %s...' % n) time.sleep(1) r = '200 OK' def produce(c): c.next() n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) print('[PRODUCER] Consumer return: %s' % r) # 終止協程 # 終止協程的方式:generator.throw 或者 generator.close c.close() if __name__=='__main__': c = consumer() produce(c)
到此,關于“Python協程的面試題有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。