vb.net Task.Factory需要多个任务吗?

时间:2018-11-05 15:35:24

标签: vb.net asynchronous async-await task

此异步编程是否正确?
由于这是我第一次使用TAP,因此我要确保从一开始就正确执行操作。

我想从ODBC数据库中填充一个表,然后读取一些文件并从中提取值,而不会冻结UI。

如果我在UI Sub中将整个OdbcDataAdapter作为tasks运行,为什么我需要运行Function并将文件读取为task?否则,它将阻止我的UI。线程。

UI代码

Private Async Sub frmOfsList_Shown(sender As Object, e As EventArgs) Handles MyBase.Show
    Dim sw As New Stopwatch 'query time
    sw.Start()

    DataGridView1.Visible = False
    Label2.Visible = False

    DataGridView1.DataSource = Await OFS.GetJobList 'async method

    sw.Stop()
    Label2.Text = "Query time: " & sw.Elapsed.TotalSeconds & "s"

    For i As Integer = 0 To DataGridView1.Rows.Count - 1    'color days until prodution date
        If DataGridView1.Rows(i).Cells(3).Value < 0 Then
            DataGridView1.Rows(i).Cells(3).Style.ForeColor = Color.Red
        Else
            DataGridView1.Rows(i).Cells(3).Style.ForeColor = Color.Green
        End If
    Next

    DataGridView1.Visible = True    'show grid
    DataGridView1.ClearSelection()
    Label2.Visible = True
End Sub

异步功能

Public Shared Async Function GetJobList() As Task(Of DataTable)

    Dim dq As Char = """"
    Dim con As OdbcConnection = New OdbcConnection(constr)
    con.Open()

    'get data from OFS 
    Dim cmd As String = "SELECT p1.ProductionOrder, p1.Project, p1.ProductionDate, p1.Item, p1.Revision, p1.PlannedQty FROM " &
                            dq & "OFS460" & dq & "." & dq & "dbo" & dq & "." & dq & "tblProductionOrders" & dq & " p INNER JOIN " & dq & "OFS460" & dq & "." & dq & "dbo" &
                                   dq & "." & dq & "tblProductionOrders" & dq & " p1 ON p.ProductionOrder = p1.ProductionOrder WHERE (p.Task=2820 AND p.StatusID=4) AND (p1.Task=2830 AND (p1.StatusID=1 OR p1.StatusID=2 OR p1.StatusID=3)) ORDER BY p1.ProductionDate"

    Dim adapter As OdbcDataAdapter = New OdbcDataAdapter(cmd, con)
    Dim datatable As New DataTable("JobList")

    'fil table with job data async
    Await Task.Factory.StartNew(Sub()
                                    adapter.Fill(datatable)
                                End Sub)

    'add columns to table
    datatable.Columns.Add("Length", GetType(Double))
    datatable.Columns.Add("Outside Dia", GetType(Double))
    Dim proddate As DateTime
    datatable.Columns.Add("Days until").SetOrdinal(3)

    'calculate days
    For j As Integer = 0 To datatable.Rows.Count - 1
        proddate = datatable(j)(2)
        datatable.Rows(j)(3) = proddate.Subtract(DateTime.Now).Days
    Next

    'Get length and diameter for each part
    Dim searchpath As String = My.Settings.g250path
    Await Task.Factory.StartNew(Sub()

                                    Dim files As String()
                                    Dim filetext As String
                                    For i As Integer = 0 To datatable.Rows.Count - 1

                                        files = System.IO.Directory.GetFiles(searchpath, "*" & datatable.Rows(i)("Item") & "*") 'get file by item#
                                        If files.Length > 0 Then
                                            filetext = System.IO.File.ReadAllText(files(0)) 'read file

                                            datatable.Rows(i)("Length") = ProgramManager.GetValue(filetext, "I_R872", 7).ToString   'extract values
                                            datatable.Rows(i)("Outside Dia") = ProgramManager.GetValue(filetext, "I_R877", 7).ToString
                                        End If

                                    Next i
                                End Sub)

    Return datatable

End Function

1 个答案:

答案 0 :(得分:0)

您不应将Task.Factory.StartNewAsync-Await一起使用。您应该改用Task.Run

您只需退出UI线程一次即可完成“繁重的工作”,并在完成后返回。

尝试一下:

Public Shared Function GetJobList() As DataTable

    Dim dq As Char = """"
    Dim con As OdbcConnection = New OdbcConnection(constr)
    con.Open()

    'get data from OFS 
    Dim cmd As String = "SELECT p1.ProductionOrder, p1.Project, p1.ProductionDate, p1.Item, p1.Revision, p1.PlannedQty FROM ""OFS460"".""dbo"".""tblProductionOrders"" p INNER JOIN ""OFS460"".""dbo"".""tblProductionOrders"" p1 ON p.ProductionOrder = p1.ProductionOrder WHERE (p.Task=2820 AND p.StatusID=4) AND (p1.Task=2830 AND (p1.StatusID=1 OR p1.StatusID=2 OR p1.StatusID=3)) ORDER BY p1.ProductionDate"

    Dim adapter As OdbcDataAdapter = New OdbcDataAdapter(cmd, con)
    Dim datatable As New DataTable("JobList")

    'fil table with job data async
    adapter.Fill(datatable)

    'add columns to table
    datatable.Columns.Add("Length", GetType(Double))
    datatable.Columns.Add("Outside Dia", GetType(Double))
    Dim proddate As DateTime
    datatable.Columns.Add("Days until").SetOrdinal(3)

    'calculate days
    For j As Integer = 0 To datatable.Rows.Count - 1
        proddate = datatable(j)(2)
        datatable.Rows(j)(3) = proddate.Subtract(DateTime.Now).Days
    Next

    'Get length and diameter for each part
    Dim searchpath As String = My.Settings.g250path

    Dim files As String()
    Dim filetext As String
    For i As Integer = 0 To datatable.Rows.Count - 1
        files = System.IO.Directory.GetFiles(searchpath, "*" & datatable.Rows(i)("Item") & "*") 'get file by item#
        If files.Length > 0 Then
            filetext = System.IO.File.ReadAllText(files(0)) 'read file
            datatable.Rows(i)("Length") = ProgramManager.GetValue(filetext, "I_R872", 7).ToString   'extract values
            datatable.Rows(i)("Outside Dia") = ProgramManager.GetValue(filetext, "I_R877", 7).ToString
        End If
    Next i

    Return datatable

End Function

并像这样调用它:

DataGridView1.DataSource = Await Task.Run(AddressOf OFS.GetJobList1)

这样,将OFS.GetJobList1函数安排在线程池线程上执行,完成后,将在调用者子函数/函数和Task.Run的返回值(其中是用{{1}包裹的OFS.GetJobList1的返回值)将被解包并分配给Task(Of DataTable)