第一次在這裏,所以對我來說很容易。理論上可以同時在單獨的線程上執行兩個OleDBDataAdapter.Fill調用嗎?或者是從根本上有缺陷?在單獨的線程上同時調用OleDbDataAdapter.Fill?
考慮一個包含2個按鈕和2個datagridviews的表單。每個按鈕單擊使用Async \ Await \ Task.Run模式啓動工作線程,該模式調用一個方法來返回填充的數據表並將其分配給其中一個數據網格視圖。第一個線程中的.Fill需要30秒才能完成。第二個線程中的.Fill需要1秒鐘才能完成。當單獨啓動時,兩個按鈕都按預期工作。但是,如果我啓動第一個工作線程(30秒填充),然後啓動第二個線程(1秒填充),第二個DataGridView不會填充,直到第一個.Fill調用完成。我期望第二個datagridview在1秒內填充,第一個datagridview在~30秒後填充。
我在示例代碼中使用OleDBDataAdapter和SqlDataAdapter重複了這個問題。如果我用一個簡單的Thread.Sleep(30000)替換長時間運行的查詢,則第二個datagridview會立即填充。這讓我相信,這不是我的設計模式的問題,而是特定於同時發出.Fill調用的問題。
Private Async Sub UltraButton1_Click(sender As Object, e As EventArgs) Handles UltraButton1.Click
Dim Args As New GetDataArguments
Args.ConnectionString = "some connection string"
Args.Query = "SELECT LongRunningQuery from Table"
Dim DT As DataTable = Await Task.Run(Function() FillDataTable(Args))
If DataGridView1.DataSource Is Nothing Then
DataGridView1.DataSource = DT
Else
CType(DataGridView1.DataSource, DataTable).Merge(DT)
End If
End Sub
Function FillDataTable(Args As GetDataArguments) As DataTable
Dim DS As New DataTable
Using Connection As New OleDbConnection(Args.ConnectionString)
Using DBCommand As New OleDbCommand(Args.Query, Connection)
Using DataAdapter As New OleDbDataAdapter(DBCommand)
DataAdapter.Fill(DS)
End Using
End Using
End Using
Return DS
End Function
Private Async Sub UltraButton2_Click(sender As Object, e As EventArgs) Handles UltraButton2.Click
Dim DS As DataTable = Await Task.Run(Function() LoadSecondDGV("1234"))
DataGridView2.DataSource = DS
End Sub
Function LoadSecondDGV(pnum As String) As DataTable
Dim DX As New DataTable
Using xConn As New OleDbConnection("some connection string")
Using DataAdapter As New OleDbDataAdapter("Select name from products where PNUM = """ & pnum & """", xConn)
DataAdapter.Fill(DX)
End Using
End Using
Return DX
End Function
我實際上使用的是Access數據庫,但是我確實使用完全相同的行爲模擬了針對SQL Server的測試。我在兩種情況下都查詢完全無關的表格,以確保我不會阻止自己。我很欣賞sql注入警告 - 這只是一些快速和骯髒的PoC winforms代碼。任何其他想法?我意識到,鑑於連接字符串等的性質,我沒有執行就緒代碼,但我很想知道是否有人可以重現此問題。 – rSquared
實際上,如果我在每個線程中查詢兩個完全分離的不相關的Access數據庫,問題依然存在。這意味着DataAdapter對象的某些內在特性正在跨線程共享,不是嗎? – rSquared
@rSquared我剛剛意識到你正在使用'async'來做到這一點。理解'async'確實不**使用多線程很重要。它允許事物在同一個線程中按順序運行。它給出了並行的_appearance_,並且它經常使你的cpu或單線程更有效地使用(**很多),但它並不是實際上並行的。如果你有阻塞的東西,比如數據庫調用,你仍然會看到一個調用完成,然後是另一個。 –