应用调用GetFilesAsync获取文件夹文件时停止响应是什么原因?
C#调用GetFilesAsync出现挂起无法进入foreach循环的解决方案
问题根因
该问题属于典型的异步上下文同步等待引发的死锁:
- WinUI/UWP等UI框架中,
await异步操作默认会捕获当前同步上下文(即UI线程上下文),异步操作完成后需要回到UI线程执行后续代码 - 调用端使用
AutoResetEvent.WaitOne()直接阻塞了UI线程,导致GetFilesAsync执行完成后无法获得UI线程资源执行后续的foreach逻辑,二者互相等待形成死锁,表现为程序挂起。
错误代码示例
异步方法定义
public async void LoadFiles(AutoResetEvent waitForLoadComplete = null) { var files = await Folder.GetFilesAsync(); foreach (var item in files) { //业务逻辑 } }
调用端代码
AutoResetEvent waitForLoadComplete = new AutoResetEvent(false); LoadFiles(waitForLoadComplete); waitForLoadComplete.WaitOne();
修复方案
优先遵循异步方法最佳实践,全程使用异步等待,不要混合同步阻塞和异步等待:
- 将
async void类型的异步方法改为返回Task,便于外部等待
public async Task LoadFiles() { var files = await Folder.GetFilesAsync(); foreach (var item in files) { //原有业务逻辑 } }
- 调用端使用
await等待异步方法完成,移除AutoResetEvent相关同步阻塞代码
// 调用处所在的方法需要标记为async await LoadFiles(); // 原等待LoadFiles完成后要执行的逻辑,直接写在await之后即可
如果确实存在需要同步调用的场景,可以给await加上ConfigureAwait(false),不捕获原UI上下文,避免死锁:
public async Task LoadFiles() { var files = await Folder.GetFilesAsync().ConfigureAwait(false); foreach (var item in files) { // 注意:此处如果要操作UI控件,需要主动调度回UI线程执行 } }
内容的提问来源于stack exchange,提问作者Vasiliy F
相关产品推荐
相关产品推荐

