這是一個記錄問題+求助的文章。
關于 waker 與運行時的合作方式
我膚淺地學習了 Rust 異步底層實現原理,關于 Future、waker 和運行時等。關于 waker 我有三點猜測:
- waker 是由實現執行器的人提供的
- 在執行器中會調用 epoll_wait,epoll 返回 fd,執行器找到對應的 waker,調用 wake() 通知任務繼續
- 最底層的 future 是人工實現的,而不是編譯器生成的,future 內部調用 cx.waker() 獲取 waker,在任務無法繼續執行時,把 waker 注冊到特定運行時的注冊表中,與 fd 關聯。調用 epoll_ctl 注冊 fd。
我想知道既然 Future 要把 waker 注冊給運行時,使得運行時知道這個 waker 是與某個 fd 關聯的。那么實現這個 Future 的 poll 方法時,就應該知道這個 Future 將來會被哪個運行時調用,從而知道怎么給這個運行時注冊 waker。但真的是這樣嗎,這樣豈不就決定了這個 Future 不能被其他運行時調用了?或者說 Rust 生態中,你要實現一個異步庫,就必須得選定一個運行時,干脆用運行時提供的底層 Future,自己只是實現一些上層的應用邏輯?
關于無棧協程的傳染性
這種說法的來源是哪里?網上有人說無棧協程以“函數返回”的方式完成從協程到主協程(或者說正常線程執行流)的切換,所以協程執行過程中創造的棧沒有被保存,最終導致傳染性。而傳染性是指調用 await 的地方,必須在 async,而 async 又必須以 await 的形式調用,這樣傳入到最外層也都是 async/await 了。
但是“必須在 async 里調用 await”不只是一個編譯器規定嗎,如果編譯器沒這么規定就沒有傳染性了?一定有人說,編譯器之所以這么規定是因為“無棧”的設計,這么規定是必然的。但 async 函數實際上是 impl Future 類型,對 Future 的 poll 是沒有傳染性的(可以在一般的非 async 函數中 poll),而 Future poll 的過程也會在不同的地方中斷,其局部變量等上下文不也保存的好好的?無棧只是指局部變量不以棧的形式保存,也不以切換上下文的形式切換。
我沒用過太多 Rust 異步特性,用的也都是在很高層次上使用。我覺得為了理解上述問題可能需要閱讀一些異步庫,甚至自己寫一個小的 tokio。(閱讀 tokio 的源碼是不是太難了,有沒有 mini-tokio 啊)
BTW,我是不是不應該指望?csdn 的環境能有人回答我的問題呀hh,希望有大佬能參與討論