用python協程設計語音通訊類後端程式

2022-09-23 12:15:12 字數 2897 閱讀 6128

開發中的一些總結,有些亂。

主要描述,如果使用python協程,該如何設計tsapi程式。為最終的排程設計積累一部分的經驗,並且,最終形成乙個框架,在這個框架上,可以方便的新增新的功能,讓其他的員工不再對python協程望而生畏。

1、整個框架主要的部分是call模組,主要負責呼叫流程的控制。它把對asapi的呼叫全部集中到乙個模組中,可以實現對模組的封裝,便於以後的替換。

2、call模組和上層模組的互動物件我本來考慮使用使用者號碼,但是考慮到方便性,以及這樣的話必須基於乙個假設:所有的使用者號碼必須是唯一標識:不利於後期的維護。所以,初步考慮採用asobj模組中的user和meet物件作為互動物件。對user和meet類的使用,建議用組合,然後再考慮繼承。

3、poc server使用的是一種callinfo的機制,即所有處於穩定狀態的使用者都有乙個callinfo來記錄其當前的狀態。本來我不想用這樣的乙個物件來記錄,原因是不同的關係會有不同的callinfo定義,最終callinfo會多起來。不用callinfo就要求協程能夠管理乙個流程的全部生命週期,包括開始和結束,這樣如果兩個流程間有相互關係,將會難於處理。所以,還是要使用callinfo,不過,callinfo只有兩個,p2p和meetcallinfo。

4、考慮一種業務流程:a,b,c三個使用者正在進行乙個呼叫流程,比如轉接,c正在振鈴,還未接通。此時另外乙個更高優先順序流程需要把c拉入新的流程中。要求最好c能夠不用掛機再發起呼叫,並且原有的流程能夠正常處理。實現這個功能需要增加乙個user_man模組,負責使用者管理。所有對使用者的撥出都呼叫此模組的介面進行呼出,每次撥出都申請乙個新的協程,這個協程結束後在返回原先的協程進行處理後續操作。如果呼叫未成功時就有新的流程操作此使用者,則停止原先的協程,makecall協程結束後直接進入新的協程處理。

5、當乙個協程在處理過程中,如何向這個協程傳送乙個訊息,並且讓協程進行不同處理?本來考慮使用類似golang的方法,每個協程對外提供乙個通道,所有的協程對外通訊都使用通道的訊息。可以實現,不過實現後,整個協程機制就會複雜起來。因為每個協程都有乙個棧,每次的訊息處理要停止原先的棧,處理完畢後要返回原先的棧,如果在訊息處理時呼叫了協程介面,則對棧以及訊息的處理會陷入混亂。所以,針對類似的需求,採用如下機制: 1)協程處理過程中發生異常,需要終止協程,可以通過協程的throw介面向協程傳送不同型別的異常。

2)比較難於處理的是,如果乙個使用者在流程過程中被其他的協程拉去處理其他事情,而此使用者離開後,不影響原有的處理流程,所以也無法終止原有流程(如果要能夠終止就好處理了)。當原有流程需要處理此使用者是,可能會和使用者當前處理的協程造成衝突。比如:強插後一使用者保持,強插結束使用者要恢復通話,當此時此使用者已經被其他使用者拉入了其他的處理流程中,如何好好的處理。如下方案: 1、乙個使用者只執行乙個協程進行處理,每次協程開始是,都要設定使用者的鎖(或者標誌),設定鎖後,其他的協程不可以在處理此使用者,除非是被強制解鎖。缺點:提高程式設計複雜度,乙個使用者在被協程使用前,一定要設定過才可以,不使用的時候 要解鎖。容易出錯。確定方案,就用鎖的方案:在協程開始的時候加鎖,協程結束後解鎖。只有對使用者加鎖的協程才可以處理使用者。 2、取消和補償函式也要調整:目前是沒有鎖的方案的,現在要增加鎖,補償是人工不是此協程鎖定此使用者了,那麼也就無法再進行對使用者的操作了。 3、最終解決方案:乙個大的模組,負責維護所有的user,實現user的makecall介面(所有的makecall必須從這裡走)。實現所有的as 呼叫控制介面,對使用者的呼叫控制等操作前,都要判斷使用者是否被當前操作協程控制。所有的補償操作也必須經過協程是否控制使用者的判斷。使用者原先被乙個協程控制,如果要被另外乙個協程控制,則需要清楚使用者相關所有狀態:放音則停止放音,錄音則停止錄音,會場中則離開會場,總之,恢復到呼叫接通原始狀態。如果出於穩定狀態,沒有在攜程中,則另外處理。終極方案:對每呼叫乙個呼叫控制介面則設定一下協程狀態,然後,可以在不同的狀態下受到不同的事件,進行不同的處理,這是最繁瑣的一種方法。不過也是最明顯,最簡單明瞭的一種方法。

6、如何對使用者進行掛機或呼叫結束操作?使用者分兩種,主動呼入與撥出,這些使用者應該如何掛機那?還是根據業務的需要,由上層業務自己選擇,或者在協程的補償中掛機,或者等待操作員的操作下掛機,或者使用類似垃圾**機制,如果沒有呼叫或者協程在使用者上,則自動垃圾**掉。——根據業務再看看。

拆線操作,第一步流程搶占:把使用者從原有流程中拉出,原有流程進行使用者拉出操作。第二步,判斷使用者狀態,如果已經通話,則掛機,如果處在新呼叫的協程中,則停止新的協程。

每個流程根據不同的情況,選擇對使用者的不同處理。同時,考慮增加垃圾**保護。

7、編碼的過程中,發現greenlet原有的模式:父協程呼叫子協程,子協程處理完成後,switch到父協程來處理。這種模式非常容易出錯,原因是他們在協程互動過程中,如果涉及到互動,很容易出錯:父協程想等待,卻等不到子協程的執行結果。所以,考慮按照go協程的處理方法來處理協程。

8、重新考慮乙個模組管理所有的使用者:呼叫,掛機,搶占。

協程的kill有問題:kill時,協程可能已經結束,但是還在協程任務列表中未被處理。

9、使用者搶占時要在統一入口中考慮,記錄當前正在搶的使用者。如果有新的流程對同乙個使用者搶占,則停止之前的搶占。使用者搶占成功後給新的流程。 搶占就是clear user的所有呼叫操作:(錄音,放音,連線,會議等),直到剛呼通,沒有任何操作的狀態。 有乙個問題是搶占時如果使用者正在進行操作,比如connect,不能做到很好的取消。這是需要取消協程才能夠取消的。 協程間傳送訊息如果要等待響應要能夠進行coro操作。呼叫的搶占:一定要先停止協程,再情況使用者操作。因為協程取消是可能會影響新的操作。所有流程的session在流程建立的時候申請,用於儲存流程的相關資訊,報個各個使用者的搶占處理函式。

總結:使用python協程簡化流程開發,比較難以搞定的是狀態和資料的同步問題。如果協程間關聯不大,則相對比較簡單,但是我們公司面臨的挑戰往往不是效能,而是業務邏輯複雜度,特別是流程間無時無刻都存在的流程互動。這是我用python協程解決類似問題的第二次嘗試,目前已經基本解決,不過仍有優化空間,部分模組複雜度還是有些高。

python協程與非同步協程

在前面幾個部落格中我們一一對應解決了消費者消費的速度跟不上生產者,浪費我們大量的時間去等待的問題,在這裡,針對業務邏輯比較耗時間的問題,我們還有除了多程序之外更優的解決方式,那就是協程和非同步協程。在引入這個概念之前我們先看 看這個圖 從這個我們可以看出來,假如來了9個任務,即使我們開了多程序,在業...

golang 協程通訊總結

select 配合 case default 使用,case 條件必須是乙個 chan chan1 make chan int t time.ticker time.second 3 select t.stop 共享資源 通過加鎖的方式 實現共享記憶體通訊模型我們所說的同步其實就是在控制多個執行緒對...

python協程使用 協程的案例

概念 使用者層面在乙個執行緒中進行多工切換的機制,比執行緒更加輕量級 實現併發量更大 協程的使用 使用第三方庫 gevent gevent 是乙個基於協程的 python 網路庫,在遇到 io 阻塞時,程式會自動進行切換,可以讓我們用同步的放肆寫非同步 io 協程的使用 from gevent im...