# VB.NET中async函数调用时使用await与.result的区别

By [Nbrave51](https://paragraph.com/@nbrave51) · 2024-06-27

---

最近写的一个async函数：

        Public Async Function AfterFirstChat(ByVal strSendMessage As String) As Task(Of String)
          
            Try
                If strSendMessage = "" Then
                    strModOllAmaErrString = STRcurErrHead & "没有提供要发送的message。"
                    Return ""
                End If
                Dim builder As New StringBuilder
    
                ' Create a new PromptExecutionSettings object
                Dim executionSettings As New OpenAIPromptExecutionSettings()
    
                ' User question & answer loop
                Chat.AddUserMessage(strSendMessage)
    
                builder.Clear()
    
                ' Get the AI response streamed back to the console
                Dim asyncEnumerator As IAsyncEnumerator(Of StreamingChatMessageContent) = Ai.GetStreamingChatMessageContentsAsync(Chat, executionSettings, kKernel).GetAsyncEnumerator()
                Try
                    While Await asyncEnumerator.MoveNextAsync()
    
                        Try
                            Dim message As StreamingChatMessageContent = asyncEnumerator.Current
                            builder.Append(message.Content)
    
                        Catch ex As Exception
    
                        End Try
                    End While
    
                Catch ex As Exception
    
                End Try
    
                Chat.AddAssistantMessage(builder.ToString())
                Return builder.ToString()
            Catch ex As Exception
    
                Return ""
            End Try
        End Function
    

然后调用时：

如果使用：

Return ModOllAmaAfterFirstChat(strFirstChat).result

在执行到函数的：

    While Await asyncEnumerator.MoveNextAsync()
    

语句时，就会死锁，始终得不到回应。

而使用：

Return Await ModOllAmaAfterFirstChat(strFirstChat)

就一切正常。

唯一的区别就是调用async函数的方式不同。

* * *

然后大量查询资料，终于发现了秘密。

如以下例子：

    static void Main(string[] args)
            {
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:start");
    
                Test(); //不等待
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:end");
                Console.Read();
            }
    
            static Task<int> Sleep()
            {
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:Sleep start");
                Thread.Sleep(1000);
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:Sleep end");
                return Task.FromResult(100);
            }
            
            static Task<int> Test()
            {
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:Test start");
                var a=Task.Run(Sleep).Result;//由上一篇文章可知Run将会在线程池内调度执行
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:Test end");
                return Task.FromResult(a);
            }
    

运行结果：

1:start

1:Test start

4:Sleep start

4:Sleep end

1:Test end

1:end

由此可以看出Task.Result会阻塞主线程（Main函数），主线程必须等待被调用的子函数（最终被调用的子函数时是一个async函数：Sleep）执行完成后才能继续执行。

而如果是这样写：

    static void Main(string[] args)
            {
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:start");
    
                TestAsync();//不等待
    
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:end");
                Console.Read();
            }
    
            static Task<int> Sleep()
            {
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:Sleep start");
                Thread.Sleep(1000);
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:Sleep end");
                return Task.FromResult(100);
            }
            
            static async Task<int> TestAsync()
            {
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:Test start");
                var a = await Task.Run(Sleep);
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}:Test end");
                return a;
            }
    

则运行结果是：

1:start

1:Test start

4:Sleep start

1:end

4:Sleep end

4:Test end

应当注意到，这儿没有等待Test函数执行完成，主函数main就执行完成了，同样主函数更没有等待Sleep函数执行完成就执行完成了。

* * *

在看到这个例子之前，我看到的文章都说，一般情况下使用.result的写法多数会造成主线程阻塞，推荐使用await的写法，我还在想，是不是把之前的那些 函数调用写法都修改成await写法。

现在一看，其实是各有千秋，各有特色，我想这也是两种调用方法都存在的原因。

作此笔记的目的就是防止自己今后又记混。

---

*Originally published on [Nbrave51](https://paragraph.com/@nbrave51/vb-net-async-await-result)*
