溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python協(xié)程的面試題有哪些

發(fā)布時(shí)間:2021-11-20 16:31:04 來(lái)源:億速云 閱讀:198 作者:iii 欄目:編程語(yǔ)言

這篇文章主要介紹“Python協(xié)程的面試題有哪些”,在日常操作中,相信很多人在Python協(xié)程的面試題有哪些問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Python協(xié)程的面試題有哪些”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

一、什么是協(xié)程

協(xié)程:實(shí)現(xiàn)協(xié)作式多任務(wù),可以在程序執(zhí)行內(nèi)部中斷,轉(zhuǎn)而執(zhí)行其他協(xié)程。

比如我們編寫子程序(或者說(shuō)函數(shù)),通常是利用“調(diào)用”來(lái)實(shí)現(xiàn)從 A 跳去 B,B 跳去 C,如果想回來(lái)調(diào)用方,必須等被調(diào)用方執(zhí)行完才行,整個(gè)調(diào)用過(guò)程是通過(guò)棧實(shí)現(xiàn)的。而協(xié)程是運(yùn)行子程序的過(guò)程中“中斷”,轉(zhuǎn)而執(zhí)行其他子程序,再在適當(dāng)?shù)臅r(shí)候返回來(lái)接著運(yùn)行。

二、協(xié)程與線程的區(qū)別

協(xié)程相比于線程的優(yōu)勢(shì):

1、協(xié)程效率比線程高。線程間切換需要開(kāi)銷,而協(xié)程間切換是由程序自身控制的,不需要開(kāi)銷。

2、協(xié)程不需要多線程的鎖機(jī)制。協(xié)程是在一個(gè)線程內(nèi)進(jìn)行切換,所以不存在同時(shí)寫變量沖突,不需要給共享資源加鎖,只需要判斷狀態(tài)。

PS:如果想使用多CPU的話,可以使用進(jìn)程+協(xié)程。

三、協(xié)程的實(shí)現(xiàn)

協(xié)程是通過(guò)yield實(shí)現(xiàn)的,所以協(xié)程是生成器,可以通過(guò) next 調(diào)用。

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

以上是一個(gè)簡(jiǎn)單的協(xié)程例子,可以看到,my_simple是一個(gè)生成器實(shí)例,需要使用next()方法或send(None)去預(yù)激協(xié)程,協(xié)程運(yùn)行到y(tǒng)ield的時(shí)候停止,當(dāng)使用send()方法給yield賦值時(shí),程序繼續(xù)往下運(yùn)行,并拋出StopIteration異常。

四、協(xié)程返回值

在python3.3版本后,協(xié)程可以有返回值。

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

可以看到,在程序運(yùn)行完后,異常對(duì)象StopIteration的value屬性保存著返回的值。

五、使用yield from獲取協(xié)程返回值

對(duì)于yield from來(lái)說(shuō),解釋器不僅會(huì)捕獲StopIteration異常,還會(huì)把value屬性的值作為yield from表達(dá)式的值。

yield from主要功能是打開(kāi)雙向通道,把最外層的調(diào)用方和最內(nèi)層的子生成器連接起來(lái)。

# 子生成器
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()
# 調(diào)用方
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)

輸出結(jié)果如下:

{'nums1': 231, 'nums2': 199, 'nums3': 294, 'nums4': 422, 'nums5': 447}

委派生成器作為雙向管道把調(diào)用方和子生成器連接起來(lái),委派生成器在yield from表達(dá)式處暫停時(shí),調(diào)用方通過(guò)send()方法把數(shù)據(jù)傳給子生成器,子生成器再把產(chǎn)出值發(fā)送給調(diào)用方,子生成器返回后,會(huì)拋出StopIteration異常,并把返回值添加到異常的value屬性上,此時(shí)你異常生成器會(huì)恢復(fù),并獲取異常的value值作為yield from表達(dá)式的值。

委派生成器相當(dāng)于管道,所以可以把任意個(gè)委派生成器連起來(lái):委派生成器連接的子生成器是一個(gè)委派生成器,以此類推,直到遇到一個(gè)使用yield的生成器或可迭代對(duì)象。

六、總結(jié)

1、協(xié)程是用于控制程序中斷,它與函數(shù)調(diào)用不同

2、協(xié)程是在單線程里可處理多任務(wù),相比多線程節(jié)省了線程切換的開(kāi)銷

3、協(xié)程通過(guò) yield 關(guān)鍵字實(shí)現(xiàn),它也是一種生成器

4、協(xié)程調(diào)用方可通過(guò) send() 方法給被調(diào)用方發(fā)送值。協(xié)程的開(kāi)啟需要預(yù)激,預(yù)激方法是:send(None)或者next()

5、協(xié)程在 python3.3 之后是有返回值的,返回值會(huì)放在 StopIteration 異常的 value 里

6、yield from 的作用是在生成器里調(diào)用子生成器,可以優(yōu)化一個(gè)嵌套 for 循環(huán)等復(fù)雜代碼

7、協(xié)程有四種狀態(tài):GEN_CREATED(等待開(kāi)始執(zhí)行)、GEN_RUNNING(解釋器正在執(zhí)行)、GEN_SUSPENDED(在yield表達(dá)式處停止)、GEN_CLOSED(執(zhí)行結(jié)束)。通過(guò) inspect.getgeneratorstate(…) 函數(shù)可獲取

8、結(jié)束協(xié)程的兩種方式:generator.throw 或 generator.close

七、相關(guān)面試題

上面介紹了關(guān)于Python學(xué)習(xí)協(xié)程的概念,相對(duì)應(yīng)的這里提供幾個(gè)關(guān)于協(xié)程的面試題目。

理論結(jié)合“面試”

1、什么是進(jìn)程、線程、協(xié)程?

答案要點(diǎn):

a、進(jìn)程是資源分配,每個(gè)進(jìn)程擁有獨(dú)立的資源空間,因?yàn)檫M(jìn)程不共享資源,所以就涉及到進(jìn)程間通信的方式,常見(jiàn)的方式有:消息隊(duì)列、管道、信號(hào)量、socket套接字等。(這里會(huì)引申出幾個(gè)面試題:進(jìn)程間有通信方式有哪些?-> 使用過(guò)哪些消息隊(duì)列?)

b、線程(英語(yǔ):thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。線程是在進(jìn)程下,所以同一進(jìn)程下的多個(gè)線程是能共享資源的。線程能共享的資源有:堆、全局變量、文件描述符和信號(hào)處理等,不共享的資源:棧、寄存器等(這里會(huì)引申出的面試題:多線程怎么實(shí)現(xiàn)?-> 多線程并發(fā)問(wèn)題 -> 多線程共享哪些資源)

c、協(xié)程是單線程下實(shí)現(xiàn)多任務(wù),它通過(guò) yield 關(guān)鍵字來(lái)實(shí)現(xiàn),能有效地減少多線程之間切換的開(kāi)銷。它是一種比線程更加輕量級(jí)的存在。正如一個(gè)進(jìn)程可以擁有多個(gè)線程一樣,一個(gè)線程也可以擁有多個(gè)協(xié)程。

2、協(xié)程有什么優(yōu)缺點(diǎn)?

答案要點(diǎn)

a、協(xié)程不是被操作系統(tǒng)內(nèi)核所管理,而完全是由程序所控制(也就是在用戶態(tài)執(zhí)行),性能得到了很大的提升,不會(huì)像線程切換那樣消耗資源。

b、缺點(diǎn):異步代碼,可能不那么容易理解和調(diào)度

3、下面代碼輸出結(jié)果是什么?

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

答案要點(diǎn):

這其實(shí)是屬于生成器的一個(gè)題目,輸出如下:

1:沒(méi)有任何輸出,它不會(huì)執(zhí)行 print(“1”*30),只會(huì)返回一個(gè)生成器

2:輸出 “111…111”(30個(gè)),同時(shí)打印返回值"A"

3:輸出 “111…111”(30個(gè)),同時(shí)打印返回值"B"

4:異常、StopIteration

4、請(qǐng)寫一個(gè)簡(jiǎn)單的協(xié)程示例 或 利用協(xié)程實(shí)現(xiàn)一個(gè) 生產(chǎn)者消費(fèi)者 模式

面試一般其實(shí)比較少說(shuō)讓面試者手寫一個(gè)協(xié)程代碼,不過(guò)之前確實(shí)有遇到過(guò)讓手寫一個(gè)利用協(xié)程實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式的。

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)
 # 終止協(xié)程
 # 終止協(xié)程的方式:generator.throw 或者 generator.close
 c.close()
if __name__=='__main__':
 c = consumer()
 produce(c)

到此,關(guān)于“Python協(xié)程的面試題有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI