vb.net Task.Factory несколько задач, необходимых? - PullRequest
0 голосов
/ 05 ноября 2018

Правильно ли это асинхронное программирование?
Поскольку я использую TAP впервые, я хочу убедиться, что я делаю это правильно с самого начала.

Я хочу заполнить таблицу из базы данных ODBC, а затем прочитать некоторые файлы и извлечь из нее значения, не замораживая свой пользовательский интерфейс.

Зачем мне запускать OdbcDataAdapter и чтение файла как tasks, если я запускаю все Function как task в моем UI Sub? В противном случае он блокирует мой пользовательский интерфейс. нить.

Код интерфейса пользователя

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 голосов
/ 06 ноября 2018

Не следует использовать Task.Factory.StartNew с Async-Await. Вместо этого вы должны использовать Task.Run.

И вам нужно только один раз выйти из потока пользовательского интерфейса для «тяжелой работы» и вернуться, когда закончите.

Попробуйте это:

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 (которое является возвращаемым значением OFS.GetJobList1, завернутый в Task(Of DataTable)), будет развернут и назначен на DataGridView1.DataSource.

...