# VB.NET中async函数调用时使用await与.result的区别 **Published by:** [Nbrave51](https://paragraph.com/@nbrave51/) **Published on:** 2024-06-27 **URL:** https://paragraph.com/@nbrave51/vb-net-async-await-result ## Content 最近写的一个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写法。 现在一看,其实是各有千秋,各有特色,我想这也是两种调用方法都存在的原因。 作此笔记的目的就是防止自己今后又记混。 ## Publication Information - [Nbrave51](https://paragraph.com/@nbrave51/): Publication homepage - [All Posts](https://paragraph.com/@nbrave51/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@nbrave51): Subscribe to updates