我是多线程的新手,所以我需要一般指导如何继续。
简而言之,我需要每秒拨打一次外部网络服务数千次。每条记录的响应大约为1秒,如果我有一百万条记录要发送,则效果不佳。所以,我的任务是使用多线程来打开多个线程(数字是动态控制的)来同时调用WS。所以,如果我可以打开100个同时调用WS的线程,那么任务应该在理论上完成得更快......
代码位于底部,我已经删除了很多不必要的部分,所以如果有什么不合理的话请告诉我
这段代码背后的想法是你要调用Threads.Process
,传递DataTable
需要通过WS发送的数据。此过程将一直运行,直到我们处理数据表中的所有记录,而_threads(其中包含当前正在工作的背景对象列表)中的项目为零。
StartThreads
将实例化新的后台对象。当后台对象完成其任务时,为了将数据传递回静态对象以记录其数据,它调用Threads.ThreadFinished
并将其自身作为参数传递,此时将记录日志信息并从{{中删除backgroundobject 1}}。
然而,在我测试期间,我注意到调用_threads
时线程重叠,我试图用SyncLock来抵消它以保持线程安全,但它仍然不能100%傻瓜证明(可能是因为有其他共享功能仍然没有受到保护)。由于我不太了解这种线程,我觉得有一种更简单的方法可以做到这一点。那么,我是在正确的轨道上吗?我应该继续前进还是改用其他方法?我研究了其他多线程方法,比如ThreadPool,但我最终得到了这种方法。
Threads.ThreadFinished
编辑1:
我认为我已经解决了线程被“丢失”的问题 - 基本上我必须在所有Public Class Threads
Public Shared Sub ProcessRecords(ByVal dt As DataTable)
_threads.Clear()
_startTime = Now
_dt = dt
While Working()
StartThreads()
Thread.Sleep(100)
End While
End Sub
Private Shared Sub StartThreads()
While _threads.Count < Settings.NumberOfThreads AndAlso _rowCounter < _dt.Rows.Count
Dim id As String = GetRandomChar(, 20) ' Generate a random ID for logging purposes
Dim tw As New ThreadWorker(_dt.Rows(_rowCounter), _rowCounter, id, _dt.Rows(_rowCounter)("id").ToString())
_rowCounter += 1
_threads.Add(tw)
End While
End Sub
Public Shared Sub ThreadFinished(ByVal tw As ThreadWorker)
SyncLock tw
Log(tw.Log)
_threads.Remove(tw)
End SyncLock
StartThreads()
End Sub
Private Shared Function Working() As Boolean
Return _rowCounter < _dt.Rows.Count OrElse _threads.Count > 0
End Function
End Class
Public Class ThreadWorker
Private _bw As System.ComponentModel.BackgroundWorker
Private _logDebug As New StringBuilder
Sub New(ByVal dr As DataRow)
_bw = New System.ComponentModel.BackgroundWorker
_bw.WorkerReportsProgress = True
_bw.WorkerSupportsCancellation = True
AddHandler _bw.DoWork, AddressOf bw_Working
AddHandler _bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
_bw.RunWorkerAsync()
End Sub
Private Sub bw_Working(ByVal Sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
' Call webservice ...
_logDebug.AppendLine("Response from WS")
End Sub
Public Sub bw_RunWorkerCompleted(ByVal Sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)
_logDebug.AppendLine("Job completed")
Threads.ThreadFinished(Me)
End Sub
End Class
函数中SyncLock _threads
(Shared
似乎没有做到这一点)。尽管如此,这充其量只是肮脏和骇人听闻。我觉得有更好的办法。我目前正在研究ThreadPool方法,但我有点因为它的线程限制而被推迟。我可能需要打开数千个线程。
我注意到的是,我打开的并发线程越多,从WS获得初始响应所需的时间就越长。例如,如果我一次只处理1个记录/线程,则需要1秒钟才能从WS获得响应。如果我打开100个线程,则需要一分钟才能得到响应。我怀疑网络在这里屈服,或者它的窗口限制?