1

アプリケーションを開発しています (C# で)。これは基本的にファイルのアップロード/ダウンロード アプリケーションです (filezila と同様)。

しかし、それには(ファイルのダウンロードに関する)特別な機能が1つあります:-

ファイルをさまざまなセグメント (最大 100) に分割できます。そして、このプロセスをさまざまなサイクルで繰り返すことができます (つまり、ファイルをさまざまなセグメントに分割し、このプロセスを複数回 (サイクルごとに) 同時に繰り返すことができます)。

そのためにスレッドの概念を使用しています。アプリケーションには、アップロード/ダウンロードのステータスを示す進行状況バーとラベルがいくつかあります。

私の問題はそれです:-

たとえば、より多くの番号に対してこのプロセス(ダウンロード)を行う場合:-

100 サイクルおよび (サイクルは 100 を超える場合があります)

100セグメント

ファイルを 100 の部分 (セグメント) に分割していることを意味し、同じプロセスが 100 回 (サイクル) 動作します。

100 * 100 = 10,000 個のファイルが同じプロセスで一度にダウンロードされることを意味します。

しかし、このタスクに大きな数を使用すると、より多くのスレッドが開かれるという問題に直面しています。

また、100 個の TCP ポート/スレッドが同時に実行されている場合、アプリケーションはハングします。

私はそのために非常に多くのことを試みましたが、まだ成功していません.Like -

非同期デリゲート、ThreadPool など。

プログレス バーとラベルの更新で大きな問題に直面しています (現在の機能は非同期デリゲートで動作しているため)。

この問題を解決する方法を教えてください。

4

3 に答える 3

2

これらのスレッドはすべて UI スレッドにデータを渡して進行状況を表示する必要があるため、UI スレッドがアプリケーションのボトルネックになっています。

ときどき UI スレッドにジョブの進行状況を検査させるタイマーを追加できます。

このように、UI スレッドは膨大な数のスレッドではなく、時間によって駆動されます。

詳細が必要な場合は、コードを投稿してください。

于 2012-06-18T14:13:23.030 に答える
1

こんにちはエルノ私は理解を深めるためにいくつかのコードを送ります:-

これはダウンロード機能です:

Public Sub FileDownload()

    txtBytesToDownload.Text = totalBytesToDownload.ToString("N", nfi)  'set textbox with total file size

    del = New MyDelegate(AddressOf DownloadDataInRange)

    callback = New AsyncCallback(AddressOf CalcCallback)


    TotalBytesToDownloadForEachCycle = totalBytesToDownload
    downloadedBytes = 0
    dlStopWatch = Stopwatch.StartNew()

    Dim flag As Integer = 0

    Dim segment As Integer = nuSegment.Value          'total segments
    Dim cyl = cycleNumericUpDown.Value                'total cycles

    'ServicePointManager.DefaultConnectionLimit = segment

    If UtilityFunctions.CheckRangeSupported(dlUrlHttpTextBox.Text) Then

        Dim segmentSize As Integer = 0
        segmentSize = TotalBytesToDownloadForEachCycle / segment

        ' For cy As Integer = 0 To (cyl - 1)

        For ctr As Integer = 0 To (segment - 1)        'loop for total Segments

            GC.Collect()
            flag += 1

            Dim fileValues As New FileValues()

            If ctr = 0 Then
                fileValues.StartPoint = 0               'starting point of each segment (in bytes)
            Else
                fileValues.StartPoint = segmentSize * ctr + 1
            End If

            fileValues.EndPoint = fileValues.StartPoint + segmentSize   'end point of each segment (in bytes)

            If (ctr = (segment - 1)) Then
                fileValues.EndPoint += TotalBytesToDownloadForEachCycle Mod segment
            End If

            fileValues.URL = dlUrlHttpTextBox.Text                         'downloading file url
            Dim str As String = ctr.ToString() + "_" + flag.ToString()

            ' del.BeginInvoke(fileValues, callback, Nothing)


            newThread = New System.Threading.Thread(AddressOf DownloadBytes)      'Thread starts here
            newThread.Priority = ThreadPriority.Highest
            newThread.IsBackground = True
            newThread.Start(fileValues)

            'ThreadPool.QueueUserWorkItem(AddressOf DownloadBytes, fileValues)

            fileValues = Nothing

        Next

        ' ProgressBarTotal.Value += 1

        ' Next

    Else
        Dim fileValues As New FileValues()
        fileValues.StartPoint = 0
        fileValues.EndPoint = TotalBytesToDownloadForEachCycle
        fileValues.URL = dlUrlHttpTextBox.Text
        Dim newThread As New System.Threading.Thread(AddressOf DownloadBytes)
        newThread.Name = "Thread1"
        newThread.Start(fileValues)
        'ThreadPool.QueueUserWorkItem(AddressOf DownloadBytes, fileValues)
        fileValues = Nothing

    End If

    Console.WriteLine("Http Downloload End")
    Debug.Print("thread List 1 count =" + _threadsList1.Count.ToString() + ", thread list 2 count =" + _threadsList2.Count.ToString() + ", thread list 3 count =" + _threadsList3.Count.ToString())

    'MessageBox.Show("finished - flag=" + flag.ToString())

    'After all Cycles Complete 
    'startButton.Enabled = True
    'abortButton.Enabled = False
    'skipButton.Enabled = False
    'DataGridViewDLOrPing.Enabled = True
    'DataGridViewUL.Enabled = True

    'protocolComboBox.Enabled = True
    'modelComboBox.Enabled = True
    'testTypeComboBox.Enabled = True
    'measurementComboBox.Enabled = True
    'cycleNumericUpDown.Enabled = True
    'DelayNumericUpDown.Enabled = True
    'InputBoxPrivilege()

End Sub

これは、スレッドがバイトを読み取るために呼び出す関数です。

Public Sub DownloadBytes(ByVal p_fileValues As FileValues)

    Dim httpWebRequest As HttpWebRequest
    Dim httpWebResponse As HttpWebResponse
    Dim responseStream As Stream

    Dim threadName = threadID

    Try
        Console.WriteLine("Start " + Thread.CurrentThread.Name)
        httpWebRequest = DirectCast(WebRequest.Create(p_fileValues.URL), HttpWebRequest)
        'httpWebRequest.ProtocolVersion = HttpVersion.Version11
        httpWebRequest.KeepAlive = False
        httpWebRequest.AddRange(p_fileValues.StartPoint, p_fileValues.EndPoint)
        httpWebRequest.Credentials = CredentialCache.DefaultCredentials
        httpWebRequest.Proxy = WebRequest.DefaultWebProxy
        httpWebResponse = CType(httpWebRequest.GetResponse(), HttpWebResponse)
        responseStream = httpWebResponse.GetResponseStream()

        Dim bytesSize As Integer = 0
        ' A buffer for storing and writing the data retrieved from the server
        Dim downBuffer As Byte() = New Byte(2047) {}
        Dim bytesAlreadyDownloaded As Int64 = p_fileValues.StartPoint

        ' Loop through the buffer until the buffer is empty
        While (True)

            'end while loop if the Abort button is clicked
            If (isActionAborted = True) Then
                Exit While
            End If

            'currentCycle is > total Cycles ,then end while
            If (currentCycleDownload > cycleNumericUpDown.Value) Then
                Exit While
            End If

            bytesSize = responseStream.Read(downBuffer, 0, downBuffer.Length)

            bytesAlreadyDownloaded += bytesSize

            'speedtimer.Start()

            If (bytesSize <= 0) Then
                If (downloadedBytes < totalBytesToDownload) Then
                    Me.Invoke(New UploadProgressCallback(AddressOf Me.UpdateDownloadProgress), New Object() {(totalBytesToDownload - downloadedBytes), totalBytesToDownload})
                End If

                Exit While
            End If

            ' Invoke the method that updates the form's label and progress bar
            Me.Invoke(New DownloadProgressCallback(AddressOf Me.UpdateDownloadProgress), New Object() {bytesSize, TotalBytesToDownloadForEachCycle})

            If (bytesAlreadyDownloaded > p_fileValues.EndPoint) Then
                'Console.WriteLine("Downloading part files Exit " + p_fileValues.StartPoint.ToString() + "," + p_fileValues.EndPoint.ToString())
                Exit While
            End If

        End While

        responseStream.Flush()
        responseStream.Close()
        httpWebResponse.Close()
        responseStream.Dispose()
        responseStream = Nothing
        httpWebResponse = Nothing
        Console.WriteLine("End " + Thread.CurrentThread.Name)

        'ProgressDownload.Value = Convert.ToInt32((downloadedBytes * 100) / totalBytesToDownload)
        ' downloadedBytesTextBox.Text = downloadedBytes.ToString("N", nfi)

    Catch ex As Exception

        Console.WriteLine("Error " + Thread.CurrentThread.Name)
        Console.WriteLine(ex)

    Finally
        Console.WriteLine("Finally " + Thread.CurrentThread.Name)

        GC.Collect()

        ' GC.WaitForPendingFinalizers()
        'newThread.Abort()


        'Try
        'Thread.CurrentThread.Abort()

        'Catch ex1 As Exception

        'End Try
    End Try

    'Return 1

End Sub

この関数は、進行状況バーとフォーム上のその他のラベルを更新します。

Private Sub UpdateDownloadProgress(ByVal BytesRead As Int64, ByVal TotalBytes As Int64)
    If Not swDL Is Nothing AndAlso swDL.IsRunning Then
        swDL.Stop()
        If swDL.ElapsedMilliseconds > 0 Then
            resultGrid.Rows.Item(HandoverGridCounter - 1).Cells(4).Value &= "DL: " & swDL.ElapsedMilliseconds & " ms"
        End If
        swDL = Nothing
    End If


    If (dlCurrentspeed > 0) Then
        'txtCurrentSpeedDL.Text = Math.Round((dlCurrentspeed / 1024), 0) & " KB/s"
    End If


    downloadedBytes += BytesRead
    If downloadedBytes >= totalBytesToDownload Then
        downloadedBytes = totalBytesToDownload
    End If

    ProgressDownload.Value = Convert.ToInt32((downloadedBytes * 100) / TotalBytes)
    downloadedBytesTextBox.Text = downloadedBytes.ToString("N", nfi)  ' & " bytes"

    If totalBytesToDownload = 0 Then
        totalBytesToDownload = TotalBytes
        txtBytesToDownload.Text = totalBytesToDownload.ToString("N", nfi)
    End If

    If downloadedBytes >= totalBytesToDownload Then
        dlCurrentspeed = 0
        dlStopWatch.Stop()

        testEndTickDownload = My.Computer.Clock.TickCount
        testDeltaDownload = (testEndTickDownload - testStartTickDownload) / 1000
        If DLtimedOut = True Then
            DownloadCompleted(TestStatus.Cancelled.ToString(), "")
        Else
            DownloadCompleted(TestStatus.Completed.ToString(), "")
        End If
        If currentCycleDownload <= cycleNumericUpDown.Value Then
            If protocolComboBox.Text = "HTTP" Then
                StartHttpDownload()
            Else
                StartFtpDownload()
            End If
        End If
    End If
End Sub
于 2012-06-19T06:25:19.553 に答える
0

ワーカー スレッドから UI を非同期的に更新するには (明示的に作成されたもの、スレッド プールにキューに入れられた作業項目、または非同期 API からのコールバック) を使用しますControl.BeginInvoke

これにより、UI スレッドがアクションを処理するのを待っている間、ワーカー スレッドはブロックされません。

ただし、UI スレッドは、非同期操作が完了する特定の順序を想定できないことに注意してください (特定の順序で開始された同じ側の 2 つのダウンロードが、その順序で完了する可能性は低いです。外部要因が多すぎると、ダウンロードの速度に影響します)。

最後に、ほとんどのBeginABCメソッドは対応する への呼び出しを必要とEndABCしますが、(便利なことに)Control.BeginInvoke必要ありません。

于 2012-06-19T10:00:35.333 に答える