需要帮助减少多线程VB.net程序的CPU使用率

时间:2017-06-16 04:17:14

标签: vb.net multithreading

我在学习vb.net时一直在研究一个项目:一个多线程代理检查器。我有它工作,并在小测试(1000个代理列表检查)它工作得很好。但是,我想用它来检查500,000或更多代理的列表。当我尝试这样做时,我看到了非常大的CPU使用量。我有一台配备16GB内存的AMD FX-8320,仅供参考。

我的所有代码都可以在我的Github上查看(click this to visit)但是我会在这里复制主要的重要部分。

基本流程:

  1. 用户点击"开始"并且每个线程都已启动 " threadedProxyChecker()"
  2. threadedProxyChecker()遍历包含从文本文件加载的所有代理的List(Of String)的所有成员
  3. 每个线程正在测试的代理被加载到临时List(Of String)中,因此工作没有完成两次,并且此List(Of String)受SyncLock保护。 " checkProxy(代理)"调用,然后从临时List(Of String)中删除代理。
  4. 结果记录为l1表示工作或l2表示失败。 (可能不需要l2,只计算存储在int中的所有失败的数?)
  5. " performStep()"更新UI以在ListBox中显示工作代理,递增ProgressBar,并报告完成百分比以及标签中工作/不响应的计数。
  6. 当每个线程到达列表的末尾时,将工作/无响应代理的总数与列表的大小进行比较,作为程序结束的条件。完成所有工作后调用Thread.Abort()(我知道这很糟糕,但我不知道我还能做到这一点)
  7. 我如何检查每个代理:

    Function checkProxy(proxy As String) As Boolean
        Dim myProxy As WebProxy
        Dim Temp As String
        Try
            myProxy = New WebProxy(proxy)
            Dim r As HttpWebRequest = HttpWebRequest.Create("http://azenv.net")
            r.UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.2 Safari/537.36"
            r.Timeout = 3000
            r.Proxy = myProxy
            Dim re As HttpWebResponse = r.GetResponse()
            Dim rs As Stream = re.GetResponseStream
            Using sr As New StreamReader(rs)
                Temp = sr.ReadToEnd()
            End Using
            Dim Text = Temp
            rs.Dispose()
            rs.Close()
            r.Abort()
            If Text.Contains("HTTP_HOST = azenv.net") Then
                If Text.Contains("REQUEST_TIME =") Then
                    Return True
                End If
            Else
                Return False
            End If
        Catch ex As Exception
            Return False
        End Try
        Return False
    End Function
    

    每个线程执行的主要代码:

    Private Sub threadedProxyChecker()
            Dim counter As Integer = 0
            For Each proxy As String In proxies
                SyncLock curProxLock
                    If tmpProx.Contains(proxy) Then
                        GoTo Skip
                    Else
                        tmpProx.Add(proxy)
                    End If
                End SyncLock
                If Not l2.Contains(proxy) Then
                    If Not l1.Contains(proxy) Then
                        If (checkProxy(proxy)) Then
                            performStep(True, proxy)
                            l1.Add(proxy)
                            SyncLock curProxLock
                                tmpProx.Remove(proxy)
                            End SyncLock
                        Else
                            performStep(False, proxy)
                            l2.Add(proxy)
                            SyncLock curProxLock
                                tmpProx.Remove(proxy)
                            End SyncLock
                        End If
                    End If
                End If
    Skip:
            Next
            If proxies.Count() <= (l1.Count() + l2.Count()) Then
                If Not isBox Then
                    SyncLock indexLock
                        MessageBox.Show("Done checking!" & vbNewLine & l1.Count() & " working proxies")
                        isBox = True
                    End SyncLock
                    Label5.Invoke(Sub()
                                      Label5.Text = "Working: " & l1.Count()
                                      Label5.Update()
                                  End Sub)
                    Label4.Invoke(Sub()
                                      Label4.Text = "Unresponsive: " & l2.Count()
                                      Label4.Update()
                                  End Sub)
                End If
            End If
            Thread.CurrentThread.Abort()
        End Sub
    

    如何启动线程:

     Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        isBox = False
        Dim threadCount As Integer = TrackBar1.Value
    
        For int As Integer = 1 To threadCount Step 1
            d(int.ToString) = New Thread(AddressOf threadedProxyChecker)
            d(int.ToString).IsBackground = True
            d(int.ToString).Start()
        Next
    End Sub
    

    &#34; performStep()&#34; &#34; threadedProxyChecker()&#34;

    调用的方法
    Function performStep(bool As Boolean, proxy As String)
        If bool Then
            ListBox2.Invoke(Sub()
                                ListBox2.Items.Add(proxy)
                                ListBox2.TopIndex = ListBox2.Items.Count - 1
                                ListBox2.Update()
                                Label5.Text = "Working: " & l1.Count()
                                Label5.Update()
                            End Sub)
        Else
            Label4.Invoke(Sub()
                              Label4.Text = "Unresponsive: " & l2.Count()
                              Label4.Update()
                          End Sub)
        End If
    
        count = count + 1
    
        ProgressBar1.Invoke(Sub()
                                ProgressBar1.PerformStep()
                                ProgressBar1.Update()
                            End Sub)
    
        Label1.Invoke(Sub()
                          Dim percent As Double = Math.Round((count / proxies.Count() * 100), 2, MidpointRounding.AwayFromZero)
                          Label1.Text = "Progress: " & count & "/" & proxies.Count() & " checked " & "(" & percent & "%)"
                          Label1.Update()
                      End Sub)
        Return True
    End Function
    

    有关如何使工作更顺利和/或如何降低CPU使用率的任何建议都会很棒!谢谢 :) -Eric

2 个答案:

答案 0 :(得分:1)

执行重复任务的线程应该在其循环中的某个地方Sleep以“处理”到其他线程的处理时间。

在循环中的Sleep(1)语句前加上Next语句。

答案 1 :(得分:0)

线程主要有两种用途。

  1. 在后台工作以保持用户界面响应
  2. 并行工作
  3. 根据您的代码判断,我说您的目标是(2),这意味着您将增加CPU负载(这通常是一件好事,浪费了空闲的CPU)。如果您的代码使用了太多的CPU,那么您可以查看降低可执行文件的优先级。

    'Process Priority
    Dim CurrentProcess As Process = Process.GetCurrentProcess
    CurrentProcess.PriorityClass = ProcessPriorityClass.BelowNormal
    'Thread Priority
    Dim CurrentThread As Thread = Thread.CurrentThread
    CurrentThread.Priority = ThreadPriority.BelowNormal
    

    它仍将使用相同数量的CPU,但它会更好地屈服于其他进程。

    如果你想稍微优化你的代码,我建议你有一个URL列表来检查,并且你的线程在索引上做一个SyncLock来代替选择..类似于:

    Dim ProxyList As New List(Of String) ' The list of URL:s
    Dim Index As Integer = 0 ' The index to use by next thread
    Dim IndexObject As New Object ' The SyncLock object
    
    ' In the thread
    Dim Value As String ' The URL we get
    SyncLock IndexObject
        If Index >= ProxyList.Count Then Return ' We are at the end, we should bail out
        Value = ProxyList(Index) ' Get the value
        Index += 1 ' Increment the counter
    End SyncLock
    

    就像现在一样,每个线程都会执行大量的SyncLock和查找,这可能会减少CPU的负担。