如何使用TPL同时读取多个文件

时间:2015-02-18 11:58:30

标签: .net vb.net multithreading task-parallel-library

我想创建一个Winforms应用程序来读取48个文本文件,每个文件只有一行逗号分隔值,并使用每个文件的结果填充MySQL数据库和DataGridView。

从Trawling SO和Google以及数月的试验和错误中,我能够提出的最佳结果如下:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    UpdateMcs()
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    Me.MainTableAdapter.Fill(Me.MyDataSet.main)
    If stopPolling = False Then BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub UpdateMcs()
    Dim tasks As New List(Of Task)
    For Each row As DataRow In MyDataSet.main
        If row("model") = "A" Then
            tasks.Add(Task.Factory.StartNew(Sub()
                                                Try
                                                    Dim Path As String = "\\" & row("server_ip") & "\mc_data\mc_" & Format(row("mc_num"), "00") & ".txt"
                                                    Dim lines() As String = File.ReadAllLines(Path)
                                                    Dim data As String = lines(0)
                                                    Dim state As New stateTableAdapter
                                                    Try
                                                        state.UpdateByIP(data, row("ip"))
                                                        Console.WriteLine("{0}: {1}", row("ip"), "Success")
                                                    Catch ex As Exception
                                                        Console.WriteLine("{0}: {1}", row("ip"), ex.Message)
                                                    End Try
                                                Catch ex As Exception
                                                    Console.WriteLine("{0}: {1}", row("ip"), ex.Message)
                                                End Try

                                            End Sub))
        End If
    Next
    Task.WaitAll(tasks.ToArray())
End Sub

我想做的是让每台机器在完成时更新数据库并刷新UI,而不是等待其余部分完成。

我尝试通过为每台机器生成单独的线程来做到这一点,但它导致了非常错误的行为并锁定了UI等。所以不太成功。

我还应该注意到,我还有另外39台机器将使用API​​进行轮询,这些API也需要单独运行。

有没有更有效的方法来解决这个问题?

其中一个主要问题是,如果一台机器(或托管数据文件的服务器)由于某种原因离线,那么确定该事实的时间与轮询在线机器的时间相比可能是500毫秒而不是10秒等待离线的在线机器意味着数据库更新频率受到性能最差的民意调查的严重限制。

对于更好的使用技巧和学习资源的任何建议都非常受欢迎!!

1 个答案:

答案 0 :(得分:1)

这是异步IO的一个很好的例子。同步IO所需的线程数会导致问题,所以让我们使用异步IO来删除它们。

看起来几乎所有的时间花费在ReadAllLines上,所以要让它成为异步。

在C#中看起来大致相同:

tasks.Add(Task.Run(async () => {
 var data = await File.ReadAllLinesAsync(...);
 //rest of code here
});

这几乎是你需要做出的所有改变。

注意,Task.WaitAll将阻止它运行的线程。如果您想避免在此使用awaitawait Task.WhenAll(tasks))。