【问题标题】:Task's ConfigureAwait(False) not working任务的 ConfigureAwait(False) 不起作用
【发布时间】:2016-10-20 00:20:53
【问题描述】:

我已经阅读了很多关于 await/async 的教程,并且我明白当涉及到 await 关键字时,它会回到 main context 然后回到 await(当它是完成),然后如果在 away 之后在 async 方法中有某些内容,则继续。我还读到有类似ConfigureAwait(False) 之类的东西,这只是意味着与我之前写过的await 相反,此时它不会回到main context,而是会留在这里等待await 完成,然后在 async 方法中继续,之后将返回到 main cotext。所以不同之处在于它不会回到main context,而是等待await。如果我错了,请纠正。基于第一个示例中的知识,我应该看到以下结果:

After DoStafAsync
Done running the long operation asynchronously.

但是当我只是简单地添加 ConfigureAwait(False) 时,它应该是:

Done running the long operation asynchronously.
After DoStafAsync

因为它不会返回上下文,而是会等待,在异步方法完成后会返回。不知何故,我看到了第一个输出中的结果。我错过了什么?

Public Class Form1

    Sub LongOperation()
        Threading.Thread.Sleep(5000)
    End Sub

    Private Async Function DoStafAsync() As Task
        lblStatus.Text = "Running a long operation asynchronously... (UI thread should be fully responsive)"
        Await Task.Run(Sub()
                           LongOperation()
                       End Sub).ConfigureAwait(False)

        lblStatus.Text = "Done running the long operation asynchronously."
    End Function

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load    
        dfg
        lblStatus.Text = "After DoStafAsync"
    End Sub

    Async Sub Dfg
        Await DoStafAsync
    End Sub

End Class

附加问题:有些人声称任务不是在创造 线程,但在同一个 ui 线程上工作。但也有一些人 声称他们是,也有人声称 有时任务创建线程,有时不。什么是真的?

【问题讨论】:

  • Eric Lippert 在这方面写了一些很棒的帖子Like this one这个is epic
  • @Plutonix 好的,但我仍然没有在我的代码中看到问题,那么对于第二种情况,任务没有创建踏板?

标签: vb.net


【解决方案1】:

我知道,当涉及到 await 关键字时,它会返回到主上下文,然后返回到 await(当它完成时),然后如果在 async 方法中之后有什么东西,则继续。

我认为您使用术语“上下文”的方式与解释异步代码时通常使用的方式不同。查看我的async intro blog post,它准确地解释了上下文是什么以及await 如何使用它。

特别是,“上下文”不是意味着“方法或功能”。它不能确定代码如何或何时返回到代码的另一部分。

您可能还想阅读我的MSDN article on async best practices,它解释了为什么您应该避免使用 async void(事件处理程序除外)。如果您将 Form1_Load 设为 async void 并删除 dfg,那么它会按您的预期工作:

Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load    
  Await DoStafAsync
  lblStatus.Text = "After DoStafAsync"
End Sub

它之前不起作用的原因是因为Form1_Load 没有等待dfg(或DoStafAsync)完成 - 它只是将它们关闭,然后立即继续设置标签文本。正如我在最佳实践文章中指出的那样,async void (async sub) 的主要问题之一是调用代码无法确定它何时完成(至少,不容易)。

【讨论】:

  • 嗨,我收到错误或等待 DoStafAsync:无效操作异常:附加信息:跨线程操作无效:控件“lblStatus”从创建它的线程以外的线程访问.
  • 这样做是因为如果我标记为 .ConfigureAwait(False) 那么这一行: lblStatus.Text = "完成异步运行长操作。"正在尝试从线程池中调用吗?
  • 所以当我想使用 .ConfigureAwait(False) \?
  • @JimmyJimm:正如我解释我的MSDN article on async best practices,当你的方法不需要需要在上下文中恢复时,你应该使用ConfigureAwait(false)(在这种情况下,在UI线程)。由于您的方法更新了 UI 元素,它确实需要在 UI 线程上恢复,因此不能使用 ConfigureAwait(false)
  • Clear 所以这只是意味着 await 之后的代码将通常在 UI 上下文中完成,除非我将其标记为 ConfigureAwait(false) 然后等待之后的代码将在线程池上运行?因此,如果它在线程池上运行,我不能像控件一样引用 UI 上下文,对吗?我写的都是正确的吗?
猜你喜欢
  • 2019-11-14
  • 1970-01-01
  • 2015-08-20
  • 2014-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
相关资源
最近更新 更多