tokio task的通信和同步(1): 簡介

通常來說,對於允許併發多執行分支的內核或引擎來說,都需要提供對應的通信機制和同步機制。

例如,多進程之間,有進程間通信方式,比如管道、套接字、共享內存、消息隊列等,還有進程間的同步機制,例如信號量、文件鎖、條件變量等。多線程之間,也有線程間通信方式,簡單粗暴的是直接共享同進程內存,同步機制則有互斥鎖、條件變量等。

tokio提供了異步多任務的併發能力,它也需要提供異步任務之間的通信方式和同步機制。

在介紹它們之前,需要先開啟tokio的同步功能。

tokio = {version = "1.13", features = ["rt", "sync", "rt-multi-thread"]}

sync模塊功能簡介

sync模塊主要包含兩部分功能:異步任務之間的通信模塊以及異步任務之間的狀態同步模塊。

任務間通信

tokio的異步任務之間主要採用消息傳遞(message passing)的通信方式,即某個異步任務負責發消息,另一個異步任務收消息。這種通信方式的最大優點是避免併發任務之間的數據共享,消滅數據競爭,使得代碼更加安全,更加容易維護。

消息傳遞通常使用通道(channel)來進行通信。tokio提供幾種不同功能的通道:

  • oneshot通道: 一對一發送的一次性通道,即該通道只能由一個發送者(Sender)發送最多一個數據,且只有一個接收者(Receiver)接收數據
  • mpsc通道: 多對一發送,即該通道可以同時有多個發送者向該通道發數據,但只有一個接收者接收數據
  • broadcast通道: 多對多發送,即該通道可以同時有多個發送者向該通道發送數據,也可以有多個接收者接收數據
  • watch通道: 一對多發送,即該通道只能有一個發送者向該通道發送數據,但可以有多個接收者接收數據

不同類型的通道,用於解決不同場景的需求。通常來說,最常用的是mpsc類型的通道。

任務間狀態同步

在編寫異步任務的併發代碼時,很多時候需要去檢測任務之間的狀態。比如任務A需要等待異步任務B執行完某個操作後才允許向下執行。

比較原始的解決方式是直接用代碼去輪詢判斷狀態是否達成。但在異步編程過程中,這類狀態檢測的需求非常普遍,因此異步框架會提供一些內置在框架中的同步原語。同步原語封裝了各種狀態判斷、狀態等待的輪詢操作,這使得編寫任務狀態同步的代碼變得更加簡單直接。

通常來說,有以下幾種基本的同步原語,這些也是tokio所提供的:

  • Mutex: 互斥鎖,任務要執行某些操作時,必須先申請鎖,只有申請到鎖之後才能執行操作,否則就等待
  • RwLock: 讀寫鎖,類似於互斥鎖,但粒度更細,區分讀操作和寫操作,可以同時存在多個讀操作,但寫操作必須獨佔鎖資源
  • Notify: 任務通知,用於喚醒正在等待的任務,使其進入就緒態等待調度
  • Barrier: 屏障,多個任務在某個屏障處互相等待,只有這些任務都達到了那個屏障點,這些任務才都繼續向下執行
  • Semaphore: 信號量(信號燈),限制同時執行的任務數量,例如限制最多隻有20個線程(或tokio的異步任務)同時執行