0

我有这个 for/next 循环,我在其中下载文件,然后处理并将其 contnets 加载到数据库中:

 For Each f As WinSCP.RemoteFileInfo In remotefilesinf
      If DownloadFile(FTPSession, CacheDirPath, "/mnt/usb", f) Then
           LoadDB(System.IO.Path.Combine(CacheDirPath, f.Name))
      Else
           MsgBox("Download failed.")
      End If
Next

为了加快速度,如何在下载下一个文件时加载数据库?在每个文件下载完成之前,我无法执行 DBLoad,并且由于数据库锁定,我一次只能执行一个 DBLoad 任务。

我尝试使用后台工作程序来执行 LoadDB 任务,但是当 UI 线程忙于下载时,RunWorkerCompleted 事件不会触发,所以我不知道何时可以执行下一个 DBload(数据库未锁定)。

任何建议表示赞赏。

4

4 回答 4

2

这是另一个尝试,因为问题的要求已经改变:

跑步 完成的

Public Class Form1

    Shared rnd As New Random

    Private download_que As New Queue(Of String)
    Private process_que As New Queue(Of String)
    Private download_thread As Thread
    Private process_thread As Thread

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        download_que.Enqueue("File 1.db")
        download_que.Enqueue("File 2.db")
        download_que.Enqueue("File 3.db")
        download_que.Enqueue("File 4.db")
        download_que.Enqueue("File 5.db")
        download_que.Enqueue("File 6.db")

        If download_thread Is Nothing then
            download_thread = New Thread(AddressOf DownloadFiles)
            download_thread.Start()
        End If
    End Sub

    Private AppendTextCaller As New Action(Of TextBox, String)(AddressOf AppendText)

    Public Sub AppendText(ByVal control As TextBox, ByVal text As String)
        control.AppendText(text)            
    End Sub

    Public Sub DownloadFiles()
        Dim file As String
        While download_que.Count > 0
            SyncLock download_que
                file = download_que.Dequeue()
            End SyncLock
            Dim path As String = Download(file)
            SyncLock process_que
                process_que.Enqueue(path)
            End SyncLock

            If process_thread Is Nothing Then
                process_thread = New Thread(AddressOf ProcessFiles)
                process_thread.Start()
            End If
        End While
        download_thread = Nothing
    End Sub

    Public Sub ProcessFiles()
        Dim path As String, ok As Boolean
        ok = True
        While process_que.Count > 0 And ok
            SyncLock process_que
                path = process_que.Dequeue()
            End SyncLock
            ok = LoadDB(path)
        End While
        process_thread = Nothing
    End Sub

    Public Function Download(ByVal filename As String) As String
        Dim sw = Stopwatch.StartNew()        
        Me.Invoke(AppendTextCaller, TextBox1, filename)
        Thread.Sleep(1500 + 500*rnd.Next(15))        
        Dim message As String = String.Format(" ({0:F1} sec)", sw.ElapsedMilliseconds / 1000)
        Me.Invoke(AppendTextCaller, TextBox1, message)
        Me.Invoke(AppendTextCaller, TextBox1, Environment.NewLine)
        Return IO.Path.Combine(IO.Path.GetTempPath(), filename)
    End Function

    Public Function LoadDB(ByVal path As String) As Boolean
        Dim sw = Stopwatch.StartNew()
        Dim filename = IO.Path.GetFileName(path)
        Me.Invoke(AppendTextCaller, TextBox2, filename)
        Thread.Sleep(800 + 500*rnd.Next(6))

        Dim message As String = String.Format(" ({0:F1} sec)", sw.ElapsedMilliseconds / 1000)
        Me.Invoke(AppendTextCaller, TextBox2, message)
        Me.Invoke(AppendTextCaller, TextBox2, Environment.NewLine)
        Return True
    End Function

End Class
于 2013-02-14T20:39:00.307 回答
0

我认为这就是你想要的:

Public Function DownLoadFile(ByVal f As String) As String
    Trace.WriteLine("Start Downloading " & f)
    Dim x As Integer = ProgressBar1.Value
    Threading.Thread.Sleep(2000)        
    Me.Invoke(SetProgressCaller, x + 25)
    Trace.WriteLine("Done Downloading " & f)
    Return IO.Path.Combine(IO.Path.GetTempPath(), f)
End Function

Public Sub LoadDB(ByVal f As String)
    Trace.WriteLine("Start Loading " & f)
    Dim x As Integer = ProgressBar1.Value
    Threading.Thread.Sleep(1000)
    Me.Invoke(SetProgressCaller, x + 25)
    Trace.WriteLine("Done Loading " & f)
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    ProgressBar1.Value = 0
    Dim f_path_1 = DownLoadFile("File 1")
    Dim t1 As New Threading.Thread(AddressOf LoadDB)
    t1.Start(f_path_1)
    ProgressBar1.Value = 50
    Dim f_path_2 = DownLoadFile("File 2")
    Dim t2 As New Threading.Thread(AddressOf LoadDB)
    t2.Start(f_path_2)        
End Sub

' Can be called using Form.Invoke() from any thread
Private SetProgressCaller As New Action(Of Integer)(AddressOf SetProgress)

' Set progress bar in main thread
Public Sub SetProgress(ByVal pct As Integer)
    ProgressBar1.Value = pct
End Sub

结果:

Start Downloading File 1
Done Downloading File 1
Start Downloading File 2
Start Loading C:\Users\#####\AppData\Local\Temp\File 1
Done Loading C:\Users\#####\AppData\Local\Temp\File 1
Done Downloading File 2
Start Loading C:\Users\#####\AppData\Local\Temp\File 2
Done Loading C:\Users\#####\AppData\Local\Temp\File 2

这转化为

  • 下载文件 1(需要 2 秒)
  • 将文件 1 加载到数据库中(需要 1 秒)和
  • 下载文件 2(需要 2 秒)
  • 将文件 2 加载到数据库中(需要 1 秒)
于 2013-02-13T16:22:15.990 回答
0

使用两个后台工作人员怎么样?使用一个下载文件,另一个将它们填充到数据库中。如果下载完成,将文件附加到列表中,每次数据库更新完成时,从 bgw2 中查看该列表...

于 2013-02-13T14:39:13.600 回答
0

您可以DBLoad在一个线程上运行并设置 aManualResetEvent以在启动新线程之前停止执行,DBLoad直到另一个 ona 完成。

Dim locker as New ManualResetEvent(True)

这些locker行为就像一个红绿灯,在被标记时停止执行并等待,否则在被标记时通过。

通过以下方式阻止locker任何地方:

locker.Reset()

通过以下方式解除对locker任何地方的封锁:

locker.Set()

设置停靠点:

locker.WaitOne()

要查看完整功能,请参阅MSDN

于 2013-02-13T14:52:19.210 回答