这是异步工作的好习惯吗?

时间:2017-08-26 15:50:15

标签: vb.net

首先,我在这里搜索并看到了许多类似的问题,但没有一个是我想要的。

我的函数需要一些时间来返回一个值 为了简化,我们说它是:

Private Function longProcess() As Boolean
    Threading.Thread.Sleep(10000)
    Return True
End Function

我想运行它并获得它的值,让我们说点击Button1

我尝试了以下代码并且它运行良好

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'some stuff
    Dim output As Boolean = Await Task.Run(Of Boolean)(Function() longProcess())
    'continue another stuff when the longProcess completes
End Sub

如果这种方式足够好?如果没有,它可能有什么问题?

我正在使用另一种方式,但由于 Application.DoEvents()

,它使CPU使用率更高
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'some stuff
    Dim awaiter = Task.Run(Of Boolean)(Function() longProcess()).GetAwaiter()
    Do While Not awaiter.IsCompleted
        Application.DoEvents()
    Loop
    Dim output As Boolean = awaiter.GetResult()
    'continue another stuff when the longProcess completes
End Sub

2 个答案:

答案 0 :(得分:4)

根据评论,您的"长期运行"函数发送http请求,你应该使用"完全" Task.Run

提供的没有额外线程的异步方法
Private Async Function SendRequest() As Task(Of Boolean)
    Using (client As New HttpClient())
        client.BaseAddress = new Uri("http://your:api/")

        Dim response As HttpResponseMessage = Await client.GetAsync(pathToResource)

        Return response.IsSuccessStatusCode
    End Using
End Function

然后点击按钮

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'some stuff
    Dim output As Boolean = Await SendRequest()
    'continue another stuff when the longProcess completes
End Sub

上面的方法比使用Task.Run的方法更好,因为当你从另一个线程发送请求时,该线程什么也不做,只是等待响应。通过使用async-await(或其他类)的异步HttpClient方法,整个工作将在一个线程上完成,而不会阻止应用程序的主UI线程。

关于HttpClient的注意事项:即使在HttpClient块中使用的Using实例上面的示例中,您也应该只为应用程序生命周期使用一个实例。

来自Microsoft文档:

  

HttpClient旨在实例化一次并在整个过程中重复使用   申请的生命。特别是在服务器应用中   为每个请求创建一个新的HttpClient实例将耗尽   重载下可用的插座数量。这将导致   SocketException错误。

答案 1 :(得分:3)

我想说这是一种标准做法。你也可以使长函数同步

Private Async Function longProcessAsync() As Task(Of Boolean)
    Await Task.Delay(10000) ' Simulating web service call
    Return True
End Function

在事件处理程序

中等待它
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'some stuff
    Dim output As Boolean = Await longProcessAsync()
    'continue another stuff when the longProcess completes
End Sub

参考:Async/Await - Best Practices in Asynchronous Programming

  

始终异步

     

...“一直异步”意味着你不应该在不仔细考虑后果的情况下混合同步和异步代码。

     

...

     

允许异步通过代码库增长是最好的解决方案,但这意味着应用程序有很多初始工作要看到异步代码的真正好处。有一些技术可以将大型代码库逐步转换为异步代码,但它们超出了本文的范围。在某些情况下,使用Task.Wait或Task.Result可以帮助进行部分转换,但您需要了解死锁问题以及错误处理问题。