2 回答
TA貢獻1848條經驗 獲得超2個贊
這是錯誤/缺失的功能還是有意的設計決定?
這是一個有意的設計決定。具體來說,async狀態機為其邏輯上下文設置“寫時復制”標志。
與此相關的是所有同步方法都屬于它們最近的祖先async方法。
在編寫依賴于 AsyncLocal 的代碼時,我是否需要擔心這種行為?比如說,我想編寫我的 TransactionScope-wannabe,它通過等待點傳輸一些環境數據。這里 AsyncLocal 夠用嗎?
像這樣的大多數系統都AsyncLocal<T>結合了IDisposable清除AsyncLocal<T>值的模式。組合這些模式可確保它適用于同步或異步代碼。AsyncLocal<T>如果消費代碼是一個async方法,它自己會工作得很好;與它一起使用IDisposable確保它可以同時使用async和同步方法。
當涉及到在整個“邏輯代碼流”中保留值時,.NET 中的 AsyncLocal 和 CallContext.LogicalGetData / CallContext.LogicalSetData 是否還有其他替代方案?
不。
TA貢獻1789條經驗 獲得超8個贊
這對我來說似乎是一個有意的決定。
正如您已經知道的那樣,它SetValueInAsyncMethod被編譯成一個隱式捕獲當前 ExecutionContext 的狀態機。當您更改AsyncLocal-variable 時,該更改不會“流”回調用函數。相反,SetValueInNonAsyncMethod它不是異步的,因此沒有編譯成狀態機。因此,不會捕獲 ExecutionContext 并且對AsyncLocal-variables 的任何更改對調用者都是可見的。
如果您出于任何原因需要它,您也可以自己捕獲 ExecutionContext:
private static Task SetValueInNonAsyncMethodWithEC()
{
var ec = ExecutionContext.Capture(); // Capture current context into ec
ExecutionContext.Run(ec, _ => // Use ec to run the lambda
{
asyncLocal.Value = 3;
PrintValue();
});
return Task.CompletedTask;
}
這將輸出值 3,而 Main 將輸出 2。
當然,簡單地轉換SetValueInNonAsyncMethod為異步讓編譯器為您做這件事要容易得多。
關于使用AsyncLocal(或就此而言CallContext.LogicalGetData)的代碼,重要的是要知道更改調用的異步方法(或任何捕獲的 ExecutionContext)中的值不會“回流”。但您當然仍然可以訪問和修改AsyncLocal,只要您不重新分配它即可。
- 2 回答
- 0 關注
- 140 瀏覽
添加回答
舉報
