我在学习vb.net时一直在研究一个项目:一个多线程代理检查器。我有它工作,并在小测试(1000个代理列表检查)它工作得很好。但是,我想用它来检查500,000或更多代理的列表。当我尝试这样做时,我看到了非常大的CPU使用量。我有一台配备16GB内存的AMD FX-8320,仅供参考。
我的所有代码都可以在我的Github上查看(click this to visit)但是我会在这里复制主要的重要部分。
基本流程:
我如何检查每个代理:
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
答案 0 :(得分:1)
执行重复任务的线程应该在其循环中的某个地方Sleep
以“处理”到其他线程的处理时间。
在循环中的Sleep(1)
语句前加上Next
语句。
答案 1 :(得分:0)
线程主要有两种用途。
根据您的代码判断,我说您的目标是(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的负担。