异步第三方库是否应保证回调在原同步上下文执行?
异步类库回调的同步上下文疑问
我在Windows Forms应用中使用一款提供异步方法的第三方库,该库支持接收异步操作期间执行的回调,但发现用来更新UI状态的回调并非在UI线程中执行。
查看库的实现后发现,内部异步方法调用时使用了ConfigureAwait(false)链式调用——这是类库内部等待任务的推荐写法。
最简复现代码
public class ThirdPartyLibClass { public event EventHandler<EventArgs> StuffDone; public async Task DoStuffAsync() { await Task.Delay(100).ConfigureAwait(false); StuffDone?.Invoke(this, EventArgs.Empty); } } public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void button2_Click(object sender, EventArgs e) { var thirdPartyLibClass = new ThirdPartyLibClass(); thirdPartyLibClass.StuffDone += (s,e2) => this.textBox1.Text = "This will fail because it will be executed in a thread other than the UI's."; await thirdPartyLibClass.DoStuffAsync(); } }
我知道怎么解决这个问题,但让类库使用者默认异步库的回调可能不在原同步上下文执行,感觉有点反直觉。
站在库维护者的角度,我考虑了两种优化方案:
- 移除
ConfigureAwait(false) - 捕获原同步上下文,并在该上下文中触发事件/调用回调
贴合实际的更新示例
基于Stephen的回答,我更新了示例以更贴近实际场景:
public class ThirdPartyLibClass { private Action doSomeMoreStuffForMeAsync; public ThirdPartyLibClass(Action doSomeMoreStuffForMeAsync) { this.doSomeMoreStuffForMeAsync = doSomeMoreStuffForMeAsync; } public async Task DoStuffAsync() { await Task.Delay(100).ConfigureAwait(false); doSomeMoreStuffForMeAsync(); await Task.Delay(100).ConfigureAwait(false); } } public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void button2_Click(object sender, EventArgs e) { var thirdPartyLibClass = new ThirdPartyLibClass( () => this.textBox1.Text = "This will fail because it will be executed in a thread other than the UI's." ); await thirdPartyLibClass.DoStuffAsync(); } }
我实际使用的第三方库是Stateless,在构建状态机时传入了状态转换时执行的委托,但发现无法依赖这些委托在原同步上下文执行,这给我想用状态机组织GUI应用的需求带来了困扰。
核心问题
异步类库是否应确保回调在原同步上下文执行,还是类库使用者需始终默认事件/回调可能来自未知线程?
内容的提问来源于stack exchange,提问作者Arthur Queiroz
相关产品推荐
相关产品推荐

