我有一个VB.Net
小项目link to sql
使用网络服务(SOAP
)。
我必须确保所有表格都能完全响应,无论如何,它都能很好地运作。我唯一的问题是加载应用程序!
主要的启动表单只有一行代码:
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Await objWebService.GetCurrentSessionsAsync
End Sub
但是这个"等待"正在执行代码,表单没有响应,冻结并显示等待光标。
关于可能导致此问题的原因以及如何处理它的任何想法?
答案 0 :(得分:1)
关键问题是Async
不会神奇地使你的方法异步。它只允许编译器知道您的方法将包含Await
个关键字,并且代码需要为converted into a state machine。 任何未等待的代码都会同步执行,即使该方法已标记为Async
。请考虑以下示例:
Private Async Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Await LongRunning1() 'opens the form, then asynchronously changes
'Text property after 2 seconds
End Sub
Private Async Function LongRunning1() As Task
Await Task.Factory.StartNew(Sub() Threading.Thread.Sleep(2000))
Me.Text = "Finished LongRunning1"
End Function
这里一个长时间运行的过程Thread.Sleep
作为示例,被包装到一个任务中,并且有一个Await
关键字。它告诉编译器在执行下一行之前等待任务内的语句完成。如果没有Await
,则会立即设置Text
属性。
现在假设您的Async
方法中有一些长时间运行的同步代码:
Private Async Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Await LongRunning2() 'synchronously waits 2 seconds, opens the form,
'then asynchronously changes Text property after 2 seconds
End Sub
Private Async Function LongRunning2() As Task
Threading.Thread.Sleep(2000)
Await LongRunning1()
Me.Text = "Finished LongRunning2"
End Function
请注意,在这种情况下,它会同步等待Thread.Sleep
完成,因此对于最终用户,您的应用程序显示为挂起。底线是 - 你必须知道哪些方法调用可以长时间运行,并将它们包装到基于await模型的任务中。否则你可能会看到你遇到的问题。
如果这听起来太复杂,您可以启动后台工作程序(.NET 2.0+),或使用TPL(.NET 4.0+)来启动任务。如果您希望进入较低级别,则自.NET 1.1起可以使用线程。然后在窗体/控件的顶部显示一些等待/进度窗口/覆盖,其功能尚不可用。看看这些:
感谢@PanagiotisKanavos指出我正确的方向。
答案 1 :(得分:1)
关于你的答案,如果你不结合不同的编程模式,代码可以更清晰,检查一下:
Private Async Sub frmMain_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Dim res = Await GetCurrentSessionsAsync()
End Sub
Private Async Function GetCurrentSessionsAsync() As Task(Of com.services.Server)
Try
Return Await Task.Factory.
StartNew(Function() objWebService.GetCurrentSessions)
Catch ex As Exception
Glob.ErrorLog("GetCurrentSessions", ex, True)
Return New com.services.Server
End Try
End Function
参考文献:
答案 2 :(得分:0)
所以这就是它(我不得不说Neolisk和Panagiotis的答案让我得到了解决方案):
是什么让我的加载形式没有响应是什么似乎是Web服务中的错误,只有我的Web服务的第一次调用会产生这个问题。因此,如果第一次调用是在表单加载后进行的,那么在另一个事件上,我将面临同样的问题。
为了解决这个问题,我改变了使用TaskCompletionSource
变量通过Web服务调用第一个方法的方式,并使用Thread调用了我的第一个方法。我会发布我的前/后代码,以确保我清楚地完成了我的修复。
<强>之前:强>
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim res = Await objWebService.GetCurrentSessionsAsync
End Sub
<强>后:强>
Private Async Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim res = Await GetCurrentSessionsAsync()
End Sub
Dim _tcServer As New TaskCompletionSource(Of MyProject.com.services.Server)
Private Async Function GetCurrentSessionsAsync() As Task(Of com.services.Server)
Try
Dim th As New System.Threading.Thread(AddressOf GetCurrentSessions)
th.Start()
Return Await _tcServer.Task
Catch ex As Exception
Return New MyProject.com.services.Server
End Try
End Function
Private Sub GetCurrentSessions()
Try
Dim res = objWebService.GetCurrentSessions
_tcServer.SetResult(res)
Catch ex As Exception
Glob.ErrorLog("GetCurrentSessions", ex, True)
End Try
End Sub
我希望将来可以帮助别人。 谢谢。