以下代码只检查图像的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
答案 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()
的排队续集将永远无法运行。