async await永远不会结束,但同步会立即运行

时间:2015-01-07 11:04:07

标签: vb.net async-await

以下代码只检查图像的URL是否有效。当我按照下面的方式运行时,它会立即检查并返回

 Function testUrl(ByVal myImage As String) As Boolean

    myHttpClient.BaseAddress = New Uri(imageUrl)
    myHttpResponse = myHttpClient.GetAsync(myImage).result

    success= myHttpResponse.IsSuccessStatusCode

End Function

但是当我用async-await运行它时,我不知道会发生什么。因为我在等待线上设置我的断点并按f10,我没有进展,我不确定是不是因为异步,它运行但我没看到下一行有任何中断,如果我的断点成功= myhttpresponse.issucessstatuscode线。

Url是一个有效的网址,第一个代码立即返回true。我可以告诉你发生了什么吗?

 Async Function testUrl_async(ByVal myImage As String) As Task(Of Boolean)

    myHttpClient.BaseAddress = New Uri(imageUrl)
    myHttpResponse = Await myHttpClient.GetAsync(myImage)

    success= myHttpResponse.IsSuccessStatusCode

End Function

编辑: 当我甚至尝试下面的代码时,它没有做任何事情。但没有异步等待工作

 Async Function testUrl_async() As Task(Of Boolean)

         myHttpClient.BaseAddress = New Uri("http://www.logoeps.net/")
                myImage = "wp-content/uploads/2013/06/stackoverflow_logo.jpg"
         Try
           myHttpResponse = Await myHttpClient.GetAsync(myImage)

         Catch ex As Exception

End Function

        End Try

2 个答案:

答案 0 :(得分:3)

听起来你遇到了我在博客上描述的common deadlock issue。进一步调整您的调用堆栈,您可能会调用Task.Wait()Task<T>.Result。这可能会导致死锁。

Await暂停其方法时,它首先捕获“上下文”。这个“上下文”是SynchronizationContext.Current(除非它是null,在这种情况下它是TaskScheduler.Current)。如果您不熟悉SynchronizationContext,这只是意味着如果在UI线程上运行它会捕获UI上下文,如果它在ASP.NET请求线程上运行则是ASP.NET请求上下文,或线程池上下文(除非您使用其他一些上下文)。此捕获的上下文用于恢复Async方法。

稍后,当等待完成时(在本例中为HTTP Get),Async方法尝试继续执行。但是,如果调用代码阻止 UI线程/ ASP.NET请求线程,则该方法无法在该上下文中执行。因此,上下文线程被阻塞,等待Async方法完成,Async方法被阻止,等待上下文空闲。死锁。

避免这种僵局的最佳方法是我在MSDN article on async best practices中描述的: 一直使用Async。换句话说,将Task.Wait()Task<T>.Result的所有来电替换为Await

答案 1 :(得分:0)

您的第一个示例有效,因为访问Result的{​​{1}}将阻止当前线程,直到设置Task为止。幸运的是,Result似乎使用不同的线程(或更可能的I / O完成端口)来完成其工作,否则您的应用程序将会死锁。由于这个原因,阻止异步方法通常是一个坏主意。

在第二个示例中更改为HttpClient.GetAsync()表示当前线程将阻止结果。相反,它会在设置结果时排队运行的其余函数。此时,将运行对await的调用之后的代码。如果您只是在此时退出,testUrl_async()的排队续集将永远无法运行。