【问题标题】:using Task for async operation but UI is still unresponsive使用 Task 进行异步操作,但 UI 仍然无响应
【发布时间】:2012-06-14 14:27:51
【问题描述】:

我有一个 WPF 应用程序,我必须在其中执行一项长时间运行的任务(基本上是从网络读取)。只是为了给你一个快照,我在按钮点击上做以下事情

 Dim t As Task(Of String) = Task.Factory.StartNew(Of String)(Function()
                                                                        'Thread.sleep is simulating long running task that will make UI unresponsive
                                                                        Thread.Sleep(10000)
                                                                        Return "Hello world from async task"
                                                                    End Function)

        TextBlock1.Text = t.Result

我不能使用基于事件的异步方法,因为读取 API 实际上存在于我在程序中引用的 dll 中,其中包含函数 Public function ReadFromNetwork() as String。此 API 正在对网络进行异步调用以读取长字符串并返回 UI。所以,简而言之,我正在做TextBlock1.Text = ExternalDll.ReadFromNetwork()

但问题是即使我使用任务异步,UI 仍然没有响应。

您能否检测一下我是否在代码中遗漏了某些内容。

任何帮助/建议将不胜感激 提前感谢

【问题讨论】:

    标签: .net wpf vb.net task-parallel-library


    【解决方案1】:

    您在开始任务后在线使用t.Result。这将使线程阻塞,直到任务完成 - 所以所有的异步都是徒劳的。

    您应该使用Task.ContinueWith 附加一个延续,并将使用任务结果的代码放入该延续。这将允许 UI 在任务执行时返回处理事件,然后在任务完成时触发您的 continuation。传入TaskScheduler.FromCurrentSynchronizationContext 以确保继续在正确的线程上触发。

    请注意,在 VB/C# 的下一个版本中,所有这一切都将更加使用异步方法更容易。如果您能够使用 .NET 4.5 候选版本,您应该考虑立即尝试 - 它会让您的生活变得更加简单。

    【讨论】:

    • 是的,乔恩,我知道... .net 4.5 将 async 和 await 关键字引入语言。但我的应用程序本质上是由 Windows 8 之前的操作系统使用的。
    • @Uday0119:.NET 4.5 不限于 Windows 8。
    • 现在我在通过 ContinueWith 方法访问 TextBlock 时遇到 The calling thread cannot access this object because a different thread owns it. 异常
    • 哎呀,我的错,我没有读到你写的 SynchContext 东西。现在它运行正常。
    • +1。绝对值得考虑 4.5 候选版本。尽管名称 Microsoft support its use in production environments 包括 Windows 7 和 Windows Server 2008
    【解决方案2】:

    您正在调用t.Result,这将强制任务执行。 您应该使用ContinueWith 异步获取结果。

        var action = delegate(Task<string> s)  // to avoid cross thread exception 
            {
                Action ac = delegate() { TextBlock1.Text = s.Result; };
                this.Dispatcher.Invoke(ac);
    
            };
    
          t.ContinueWith(action);
    

    请原谅我使用 c#

    【讨论】:

      【解决方案3】:

      我觉得应该是这样的

      t.ContinueWith((result) => { TextBlock1.Text = result.Result});
      

      或者你只是在发帖时把它弄松了?您可能必须使用正确的调度程序,除了这应该可以解决问题

      【讨论】:

      • 现在我在通过 ContinueWith 方法访问 TextBlock 时遇到 The calling thread cannot access this object because a different thread owns it. 异常
      • 检查重载 Task ContinueWith(Func, TNewResult> continuationFunction, TaskScheduler scheduler);您可以使用 var uithread = TaskScheduler.FromCurrentSynchronizationContext(); 传递可以抓取的 UI 调度程序;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-08
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      • 2011-10-07
      • 1970-01-01
      相关资源
      最近更新 更多