簡介
如果一共有 100 個 skynet 節點,在它們啟動完畢後,會建立起 9900條通訊通道。
這個系統是單進程多執行緒模型。
每個內部服務的實現,放在獨立的動態庫中。由動態庫導出的三個接口 create init release 來創建出服務的實例。init 可以傳遞字元串參數來初始化實例。比如用 lua 實現的服務(這裡叫 snlua ),可以在初始化時傳遞啟動代碼的 lua 檔案名稱。
每個服務都是嚴格的被動的訊息驅動的,以一個統一的 callback 函式的形式交給框架。框架從訊息佇列里取到訊息,調度出接收的服務模組,找到 callback 函式入口,調用它。服務本身在沒有被調度時,是不占用任何 CPU 的。
特點
Skynet框架做兩個必要的保證:
一、一個服務的 callback 函式永遠不會被並發。
二、一個服務向另一個服務傳送的訊息的次序是嚴格保證的。
我用多執行緒模型來實現它。底層有一個執行緒訊息佇列,訊息由三部分構成:源地址、目的地址、以及數據塊。框架啟動固定的多條執行緒,每條工作執行緒不斷從訊息佇列取到訊息。根據目的地址獲得服務對象。當服務正在工作(被鎖住)就把訊息放到服務自己的私有佇列中。否則調用服務的 callback 函式。當 callback 函式運行完後,檢查私有佇列,並處理完再解鎖。
執行緒數應該略大於系統的 CPU 核數,以防止系統飢餓。(只要服務不直接給自己不斷發新的訊息,就不會有服務被餓死)
由於我們是在同一個進程內工作的。所以我對訊息傳遞做了一點最佳化。對於目前的點對點訊息,要求傳送者調用 malloc 分配出訊息攜帶數據用到的記憶體;由接受方處理完後調用 free 清理(由框架來做)。這樣數據傳遞就不需要有額外的拷貝了。
做為核心功能,Skynet 僅解決一個問題:
把一個符合規範的 C 模組,從動態庫(so 檔案)中啟動起來,綁定一個永不重複(即使模組退出)的數字 id 做為其 handle 。模組被稱為服務(Service),服務間可以自由傳送訊息。每個模組可以向 Skynet 框架註冊一個 callback 函式,用來接收發給它的訊息。每個服務都是被一個個訊息包驅動,當沒有包到來的時候,它們就會處於掛起狀態,對 CPU 資源零消耗。如果需要自主邏輯,則可以利用 Skynet 系統提供的 timeout 訊息,定期觸發。