【问题标题】:vb.net Task.Factory multiple tasks needed?vb.net Task.Factory 需要多个任务吗?
【发布时间】:2019-04-08 23:50:08
【问题描述】:

这种异步编程正确吗?
由于这是我第一次使用 TAP,因此我想确保从一开始就正确使用。

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

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

界面代码

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

【问题讨论】:

    标签: vb.net asynchronous async-await task


    【解决方案1】:

    您不应将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 的返回值(即返回值)上继续执行用Task(Of DataTable) 包裹的OFS.GetJobList1 将被解包并分配给DataGridView1.DataSource

    【讨论】:

    • 试试修改后的答案。
    • 我像DataGridView1.DataSource = Await Task.Run(Of DataTable)(Function() Return OFS.GetJobList1 End Function) 一样做到了,它确实有效。但是,如果您能快速向我解释一下,这比我的解决方案更好吗?
    • 我选择了DataGridView1.DataSource = Await Task.Run(AddressOf OFS.GetJobList1),并在答案中添加了简要说明。
    猜你喜欢
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-25
    • 2016-08-12
    • 1970-01-01
    相关资源
    最近更新 更多