Vb.net wait是阻塞线程还是传递给调用者,还是两者都传递?

Vb.net wait是阻塞线程还是传递给调用者,还是两者都传递?,vb.net,asynchronous,async-await,Vb.net,Asynchronous,Async Await,有两种观点,我的实验表明两者都发生了 不,等待只需将控件移动到调用方 对。要执行的下一条语句是wait之后的下一条语句 考虑一下这段代码 Public Shared Async Function getMarketDetailFromAllExchangesAsync() As Task For Each account In uniqueAccounts() Await account.Value.getMarketInfoAsync() Next End Fu

有两种观点,我的实验表明两者都发生了

  • 不,等待只需将控件移动到调用方
  • 对。要执行的下一条语句是wait之后的下一条语句
  • 考虑一下这段代码

    Public Shared Async Function getMarketDetailFromAllExchangesAsync() As Task
        For Each account In uniqueAccounts()
            Await account.Value.getMarketInfoAsync()
        Next
    End Function
    
    代码调用

    Public Overrides Async Function getMarketInfoAsync() As Task
        'readbalances()
        Dim json = Await CookieAwareWebClient.downloadString1Async("https://api.lbkex.com/v1/ticker.do?symbol=all")
    
        Dim ja = JArray.Parse(json)
    
        For Each jo In ja
            Dim symbol = jo("symbol").ToString
            Dim base1 = ""
    ...
            Dim bidaskTuple = Await getBidAskFromDepthArrayWithURLAsync("https://api.lbkex.com/v1/depth.do?symbol=" + symbol + "&size=1", "bids", "asks", CDbl(jo(LOW)), CDbl(jo(HIGH)))
            jo(BID) = bidaskTuple.Item1
            jo(ASK) = bidaskTuple.Item2
        Next
    
        typicalGetMarketInfoWithJsonStringAlreadyReady(ja.ToString, "", BID, ASK, HIGH, LOW, VOLUME, LAST, "https://www.lbank.info/exchange.html?asset={quote}&post={base}", "", BASE, QUOTE, "", 0, "")
        'getOrders()
    End Function
    
    之后

            Dim bidaskTuple = Await getBidAskFromDepthArrayWithURLAsync("https://api.lbkex.com/v1/depth.do?symbol=" + symbol + "&size=1", "bids", "asks", CDbl(jo(LOW)), CDbl(jo(HIGH)))
    
    下一个调用的代码是

            jo(BID) = bidaskTuple.Item1
    
    这是下一句话

    但是,在本规范中

    Public Async Sub finRepeatOrderingSync()
        Dim i = Await finRepeatOrderingAsync()
        Dim b = i 'can't get it till we got i
    End Sub
    
    同样的事情。等待finRepeatOrderingAsync后,尚未调用dim b=i

    但是,运行finRepeatOrderingSync的代码将完成

    此代码

    Private Sub Button2_Click_1(sender As Object, e As EventArgs) Handles cmdGroupRepeat.Click
        startAndStopClickingButton(sender, Sub()
                                               finRepeatOrderingSync() ' this one never end
                                               Dim b = 1
                                           End Sub)
    End Sub
    
    完成了

    实际上我想要的是相反的结果。uniqueAccounts中的每个帐户都应该有自己的任务(或者线程,但等待和同步实际上是单线程的,对吗?)

    另一方面,我希望在finRepeatOrderingSync完成后重新启用控件中的所有按钮


    我如何才能做到这一点?

    wait不会阻塞线程,总是将控制权传递给调用者,这就是它的目的

    此代码

    Private Sub Button2_Click_1(sender As Object, e As EventArgs) Handles cmdGroupRepeat.Click
        startAndStopClickingButton(sender, Sub()
                                               finRepeatOrderingSync() ' this one never end
                                               Dim b = 1
                                           End Sub)
    End Sub
    
    完成了

    事件处理程序是同步运行的,因为它从不等待任何东西,异步代码应该始终由异步代码调用。看看

    实际上我想要的是相反的结果。uniqueAccounts中的每个帐户都应该有自己的任务(或者线程,但等待和同步实际上是单线程的,对吗?)

    对于要在单独线程上完成的CPU绑定工作,应使用Task.Run(),文档可在此处找到:

    另一方面,我希望在finRepeatOrderingSync完成后重新启用控件中的所有按钮

    我该怎么做

    您可以通过禁用按钮,然后等待您想要完成的CPU限制工作的结果,然后重新启用按钮来完成此操作:

    Private Async Sub Button2_click(sender As Object, e As EventArgs) Handles Button2.click
        DisableButtons()
        Dim Result As Object = Await Task.Run(Function() SomeFunction)
        EnableButtons()
    
    End Sub
    

    在您的问题中,您有很多代码和很多讨论,这些似乎可以归结为此代码是如何执行的:

    Public Async Function Foo() As Task
        Dim i = Await GetValueAsync()
        Dim b = i
    End Function
    
    Foo
    的调用将调用
    GetValueAsync
    ,然后在
    GetValueAsync
    运行时返回到
    Foo
    的调用者,并且只有在有结果时才在
    Foo
    方法中继续

    从逐步的角度来看,它与以下代码相同:

    Public Sub Foo()
        Dim i = GetValue()
        Dim b = i
    End Sub
    
    我从您的最后三段(这似乎是您问题中最重要的部分)中了解到,您希望同时执行所有
    getMarketinfoancy
    调用,但仍要等待对所有调用的调用。这很容易做到

    不过,首先,您的代码结构和命名约定不是您在.NET项目中通常看到的。我已经编写了一个更典型的场景,我将把它留给您来翻译回您正在做的事情

    首先,我定义了以下简单类:

    Public Class MarketInfo
        Public Account As Account
    End Class
    
    Public Class Account
    End Class
    
    现在,我假设您有这两种方法可用并且工作正常:

    Private Shared Function UniqueAccounts() As List(Of Account)
    Public Shared Async Function GetMarketInfoAsync(account As Account) As Task(Of MarketInfo)
    
    现在,为适应这些更改而更新的原始方法如下所示:

    Public Shared Async Function GetMarketDetailFromAllExchangesAsync() As Task
        For Each account In UniqueAccounts()
            Await GetMarketInfoAsync(account)
        Next
    End Function
    
    Dim info As MarketInfo() = Await GetMarketDetailFromAllExchangesAsync()
    
    根据我所说的操作发生方式,您可以在某处使用
    wait GetMarketDetailFromAllExchangesAsync()
    调用它,代码将针对每个
    帐户执行,而不会阻塞调用线程

    您希望能够一次调用所有这些函数并返回所有结果。以下是方法:

    Public Shared Async Function GetMarketDetailFromAllExchangesAsync() As Task(Of MarketInfo())
        Return Await Task.WhenAll(UniqueAccounts().Select(Function (account) GetMarketInfoAsync(account)).ToArray())
    End Function
    
    现在你可以这样称呼它:

    Public Shared Async Function GetMarketDetailFromAllExchangesAsync() As Task
        For Each account In UniqueAccounts()
            Await GetMarketInfoAsync(account)
        Next
    End Function
    
    Dim info As MarketInfo() = Await GetMarketDetailFromAllExchangesAsync()
    

    我在总结这两个答案。这就是我所做的,使启用按钮在等待之后发生

    Private Async Sub RepeatTheWholeThing_Click_1(sender As Object, e As EventArgs) Handles cmdGroupRepeat.Click
        Await startAndStopClickingButton2(sender, Async Function() As Task
                                                      Await finRepeatOrderingAsync() ' this one never end
                                                      Dim b = 1
                                                  End Function)
    End Sub
    
    Public Async Function startAndStopClickingButton2(ByVal sender As Object, ByVal SomeSub As System.Func(Of Task)) As Task
        startClickingButton(sender)
        Await SomeSub.Invoke()
        stopClickingButton(sender)
    End Function
    
    这就是我所做的,使帐户几乎同时加载

    Public Shared Async Function getMarketDetailFromAllExchangesAsync() As Task
        Dim taskList = New List(Of Task)
        For Each account In uniqueAccounts()
            Dim newtask = account.Value.getMarketInfoAsync()
            taskList.Add(newtask)
        Next
        Await Task.WhenAll(taskList.ToArray)
    
        Dim b = 1
    End Function
    

    这个想法和“神秘性”的想法是一样的。但是,我使用for next而不是select。因此更容易调试。

    那么事件处理程序必须是异步的?如果事件处理程序不是异步的,是否可以执行此操作?如果事件处理程序调用异步代码,则处理程序本身应该是异步的。如果不希望处理程序是异步的,那么就不应该异步调用“SomeFunction”(在上面的示例中)。在这种情况下,您只需在没有任务的情况下调用“SomeFunction”。运行此命令可获得相同的结果(在执行工作时禁用按钮),但区别在于所有工作都是在主线程上完成的(因此会阻止它)您不希望eventHandler是异步的,有什么具体原因吗?请注意,“SomeFunction”本身不需要是异步函数。Run负责在后台线程上异步运行它。它创建了一个可以等待的taskobject。因此,事件处理程序将控制权返回到主线程,直到CPU绑定的工作完成,因此UI在工作时保持响应。我不是按你的方式做的。我做的不同,但概念是一样的。我用的是when all。谢谢你选择了什么?是linq吗?两个答案回答了问题的两个不同方面。我选择了@Aconfusedsimpleton答案,因为他只有82分。我想知道这是否合适?你不需要点数,对吗?@user4951-小心按你的方式做-有龙。是,
    选择
    为LINQ。无论哪种方式,积分都没有戏剧性。您应该只选择您认为未来读者应该看到的答案。@user4951您应该选择您认为回答问题更好的答案,而不管相应的回答者有多少分。