2 回答

TA貢獻(xiàn)1848條經(jīng)驗(yàn) 獲得超2個(gè)贊
這是錯(cuò)誤/缺失的功能還是有意的設(shè)計(jì)決定?
這是一個(gè)有意的設(shè)計(jì)決定。具體來說,async
狀態(tài)機(jī)為其邏輯上下文設(shè)置“寫時(shí)復(fù)制”標(biāo)志。
與此相關(guān)的是所有同步方法都屬于它們最近的祖先async
方法。
在編寫依賴于 AsyncLocal 的代碼時(shí),我是否需要擔(dān)心這種行為?比如說,我想編寫我的 TransactionScope-wannabe,它通過等待點(diǎn)傳輸一些環(huán)境數(shù)據(jù)。這里 AsyncLocal 夠用嗎?
像這樣的大多數(shù)系統(tǒng)都AsyncLocal<T>
結(jié)合了IDisposable
清除AsyncLocal<T>
值的模式。組合這些模式可確保它適用于同步或異步代碼。AsyncLocal<T>
如果消費(fèi)代碼是一個(gè)async
方法,它自己會(huì)工作得很好;與它一起使用IDisposable
確保它可以同時(shí)使用async
和同步方法。
當(dāng)涉及到在整個(gè)“邏輯代碼流”中保留值時(shí),.NET 中的 AsyncLocal 和 CallContext.LogicalGetData / CallContext.LogicalSetData 是否還有其他替代方案?
不。

TA貢獻(xiàn)1789條經(jīng)驗(yàn) 獲得超8個(gè)贊
這對(duì)我來說似乎是一個(gè)有意的決定。
正如您已經(jīng)知道的那樣,它SetValueInAsyncMethod被編譯成一個(gè)隱式捕獲當(dāng)前 ExecutionContext 的狀態(tài)機(jī)。當(dāng)您更改AsyncLocal-variable 時(shí),該更改不會(huì)“流”回調(diào)用函數(shù)。相反,SetValueInNonAsyncMethod它不是異步的,因此沒有編譯成狀態(tài)機(jī)。因此,不會(huì)捕獲 ExecutionContext 并且對(duì)AsyncLocal-variables 的任何更改對(duì)調(diào)用者都是可見的。
如果您出于任何原因需要它,您也可以自己捕獲 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。
當(dāng)然,簡(jiǎn)單地轉(zhuǎn)換SetValueInNonAsyncMethod為異步讓編譯器為您做這件事要容易得多。
關(guān)于使用AsyncLocal(或就此而言CallContext.LogicalGetData)的代碼,重要的是要知道更改調(diào)用的異步方法(或任何捕獲的 ExecutionContext)中的值不會(huì)“回流”。但您當(dāng)然仍然可以訪問和修改AsyncLocal,只要您不重新分配它即可。
- 2 回答
- 0 關(guān)注
- 110 瀏覽
添加回答
舉報(bào)