WinForm中Async/Await代码阻塞UI,控制台模式正常问题求助
Fixing UI Blocking in WinForms with Bandwidth 3.1.5 Async Implementation
我明白你现在遇到的麻烦——明明把同步代码改成了异步,WinForms的UI还是会卡住。咱们来拆解下问题出在哪,以及怎么彻底解决它。
首先看你的代码:你用Task.Run把Bandwidth的同步List方法包起来,但这其实不是最优的异步实现方式,甚至可能是导致UI阻塞的潜在原因之一。另外,大概率你调用这个异步方法的时候,没有正确使用Await(比如误用了.Result或.Wait()),这会直接把异步操作又拉回同步阻塞的状态。
修正后的代码方案
首先,Bandwidth 3.1.5的SDK应该提供了原生的异步方法(比如ListAsync),这才是真正的非阻塞实现,不需要用Task.Run来包装同步方法。同时,注意复用Client实例(每次创建新实例会浪费资源),调用时必须用Await。
''' <summary> ''' Gets a list of your numbers. ''' </summary> ''' <param name="size">Optional: Used for pagination to indicate the size of each page requested for querying a ''' list of phone numbers. If no value is specified the default value is 25. (Maximum value 1000)</param> ''' <param name="name">Optional: Used to filter the retrieved list of numbers allocated for the authenticated user by it’s name.</param> ''' <param name="applicationId">Optional: Used to filter the retrieved list of numbers by an associated application ID.</param> ''' <param name="state">Optional: Used to filter the retrieved list of numbers allocated for the authenticated user by a US state.</param> ''' <param name="city">Optional: Used to filter the retrieved list of numbers allocated for the authenticated user by it’s city.</param> ''' <param name="numberState">Optional: Used to filter the retrieved list of numbers allocated for ''' the authenticated user by the number state. <seealso cref="Bandwidth.Net.Api.PhoneNumberState"/></param> ''' <returns></returns> ' 建议把Client实例做成全局复用的,不用每次创建 Private Shared ReadOnly _bandwidthClient As New Client( CommonApplication.BandWidth_USER_ID, CommonApplication.Bandwidth_API_TOKEN, CommonApplication.Bandwidth_API_SECRET) Public Shared Async Function GetListOfPhoneNumbers( ByVal size As Integer?, ByVal name As String, ByVal applicationId As String, ByVal state As String, ByVal city As String, ByVal numberState As Api.PhoneNumberState?) As Threading.Tasks.Task(Of List(Of Api.PhoneNumber)) Dim objQuery As New Api.PhoneNumberQuery With { .Size = size, .Name = name, .ApplicationId = applicationId, .State = state, .City = city, .NumberState = numberState } ' 使用SDK原生异步方法,无需Task.Run包装 Dim response = Await _bandwidthClient.PhoneNumber.ListAsync(objQuery) Return response.ToList() End Function
正确的WinForms调用方式
关键!在UI事件里调用这个方法时,必须用Await,绝对不能用.Result或.Wait(),否则会直接阻塞UI线程:
Private Async Sub btnFetchNumbers_Click(sender As Object, e As EventArgs) Handles btnFetchNumbers.Click ' 先禁用按钮防止重复操作 btnFetchNumbers.Enabled = False Try Dim phoneNumbers = Await GetListOfPhoneNumbers(25, Nothing, Nothing, Nothing, Nothing, Nothing) ' 把结果绑定到UI控件,比如DataGridView dgvPhoneNumbers.DataSource = phoneNumbers Catch ex As Exception MessageBox.Show($"获取号码失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error) Finally ' 恢复按钮状态 btnFetchNumbers.Enabled = True End Try End Sub
为什么原来的代码会阻塞?
- 错误的异步包装:用
Task.Run把同步方法扔去后台线程,本质上还是占用了一个线程,而且如果调用时没正确Await,UI线程还是会等着它完成。原生异步方法是基于IOCP的,不会占用额外线程,才是真正的非阻塞。 - 调用方式错误:如果你的代码里用了
GetListOfPhoneNumbers(...).Result,会强制UI线程等待异步任务完成,直接导致卡顿。
内容的提问来源于stack exchange,提问作者DsscSystems
相关产品推荐
相关产品推荐

