首页 > C# > C#同步等待异步操作,为什么 Wait() 会在这里冻结程序

C#同步等待异步操作,为什么 Wait() 会在这里冻结程序

上一篇 下一篇

前言:我在寻找一个解释,而不仅仅是一个解决方案。我已经知道解决方案了。

尽管我花了几天时间研究 MSDN 关于基于任务的异步模式 (TAP)、异步和等待的文章,但我仍然对一些更精细的细节感到有些困惑。

我正在为 Windows 应用商店应用编写记录器,并且希望同时支持异步和同步日志记录。异步方法遵循 TAP,同步方法应该隐藏所有这些,并且外观和工作方式与普通方法相同。

这是异步日志记录的核心方法:

private async Task WriteToLogAsync(string text)
{
    StorageFolder folder = ApplicationData.Current.LocalFolder;
    StorageFile file = await folder.CreateFileAsync("log.log",
        CreationCollisionOption.OpenIfExists);
    await FileIO.AppendTextAsync(file, text,
        Windows.Storage.Streams.UnicodeEncoding.Utf8);
}

现在相应的同步方法…

版本1

private void WriteToLog(string text)
{
    Task task = WriteToLogAsync(text);
    task.Wait();
}

这看起来是正确的,但它不起作用。整个程序永远冻结。

版本2

嗯。。也许任务没有开始?

private void WriteToLog(string text)
{
    Task task = WriteToLogAsync(text);
    task.Start();
    task.Wait();
}

这抛出InvalidOperationException: Start may not be called on a promise-style task.

版本3:

嗯。。 听起来很有希望。Task.RunSynchronously

private void WriteToLog(string text)
{
    Task task = WriteToLogAsync(text);
    task.RunSynchronously();
}

这抛出InvalidOperationException: RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.

版本 4(解决方案):

private void WriteToLog(string text)
{
    var task = Task.Run(async () => { await WriteToLogAsync(text); });
    task.Wait();
}

这行得通。因此,2 和 3 是错误的工具。但是1?1 有什么问题,4 有什么区别?是什么让 1 导致冻结?任务对象有问题吗?是否存在不明显的僵局?

分割线

网友回答:

异步方法内部正在尝试返回到 UI 线程。await

由于 UI 线程正忙于等待整个任务完成,因此会出现死锁。

移动异步调用可解决此问题。
由于异步调用现在在线程池线程上运行,因此它不会尝试返回到 UI 线程,因此一切正常。Task.Run()

或者,您可以在等待内部操作之前调用,使其返回到线程池而不是 UI 线程,从而完全避免死锁。StartAsTask().ConfigureAwait(false)

分割线

网友回答:

从同步代码调用代码可能非常棘手。async

我在我的博客上解释了这种僵局的全部原因。简而言之,有一个“上下文”默认保存在每个方法的开头,并用于恢复该方法。await

因此,如果在 UI 上下文中调用此函数,则在 完成时,该方法会尝试重新进入该上下文以继续执行。遗憾的是,使用 (或) 的代码将阻塞该上下文中的线程,因此该方法无法完成。awaitasyncWaitResultasync

避免这种情况的准则是:

  1. 尽可能多地使用。这使您的方法能够继续执行,而无需重新输入上下文。ConfigureAwait(continueOnCapturedContext: false)async
  2. 一路使用。用代替 或 。asyncawaitResultWait

如果你的方法本质上是异步的,那么你(可能)不应该公开同步包装器。

分割线

网友回答:

这是我所做的

private void myEvent_Handler(object sender, SomeEvent e)
{
  // I dont know how many times this event will fire
  Task t = new Task(() =>
  {
    if (something == true) 
    {
        DoSomething(e);  
    }
  });
  t.RunSynchronously();
}

工作良好且不会阻塞 UI 线程

模板简介:该模板名称为【C#同步等待异步操作,为什么 Wait() 会在这里冻结程序】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【C#】栏目查找您需要的精美模板。

相关搜索
  • 下载密码 lanrenmb
  • 下载次数 406次
  • 使用软件 Sublime/Dreamweaver/HBuilder
  • 文件格式 编程语言
  • 文件大小 暂无信息
  • 上传时间 04-17
  • 作者 网友投稿
  • 肖像权 人物画像及字体仅供参考
栏目分类 更多 >
热门推荐 更多 >
企业网站 html5 微信公众平台 微信文章 自适应 微信素材 单页式简历模板 微信图片 微信模板 响应式
您可能会喜欢的其他模板