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

処理を高速化するために、次のファイルのダウンロード中にDBの読み込みを行うにはどうすればよいですか?各ファイルのダウンロードが完了するまでDBLoadを実行できません。また、データベースがロックされているため、一度に1つのDBLoadタスクしか実行できません。

LoadDBタスクにバックグラウンドワーカーを使用しようとしましたが、UIスレッドがダウンロードでビジー状態のときにRunWorkerCompletedイベントが発生しないため、次のDBloadをいつ実行できるかわかりません(DBはロックされていません)。

アドバイスをいただければ幸いです。

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をDBにロードする(1秒かかります)AND
  • ファイル2のダウンロード(2秒かかります)
  • ファイル2のDBへのロード(1秒かかります)
于 2013-02-13T16:22:15.990 に答える
0

2人のバックグラウンドワーカーを使用するのはどうですか?1つを使用してファイルをダウンロードし、もう1つを使用してファイルをデータベースに詰め込みます。ダウンロードが完了したら、ファイルをリストに追加し、データベースの更新が完了するたびに、bgw2からそのリストを確認します...

于 2013-02-13T14:39:13.600 に答える
0

スレッドでを実行し、他のオナが終了するまで新しいスレッドを起動する前に実行を停止するようにDBLoad設定できます。ManualResetEventDBLoad

Dim locker as New ManualResetEvent(True)

信号機のlockerように機能し、実行を停止し、マークが付けられたときに待機し、そうでない場合は通過します。

locker次のコマンドでどこでもブロックします。

locker.Reset()

locker次のコマンドでどこでもブロックを解除します。

locker.Set()

停止場所を設定します。

locker.WaitOne()

全機能を確認するには、 MSDNを参照してください。

于 2013-02-13T14:52:19.210 に答える