我需要处理数百万个文件。目前,我使用自定义线程管理器来完成工作,使用 DataGridView 来跟踪线程和计时器来检查是否可以启动更多线程;有点像(sudo):
Private Sub ThreadManager()
If AVailableThreads > 0 then
Dim t as Threading.Thread = New Thread(AddressOf MyThread)
t.Start()
AvailableThreads = AvailableThreads - 1
ThreadManager()
End If
End Sub
这有很多缺点,主要是 CPU 和内存使用率很高,因为上述每个线程都处理一个完整的目录,而不是独立地处理每个文件。
所以我重写了这个过程。现在我有一个类将在文件级别执行该过程并将结果报告回主线程;像这样:
Imports System.IO
Public Class ImportFile
Public Class ImportFile_state
Public ID as Long = Nothing
Public FilePath as String = Nothing
Public Result as Boolean = False
End Class
Public Event ReportState(ByVal state as ImportFile_state)
Dim _state as ImportFile_state = New ImportFile_State
Public Sub New(ByVal ID as Long, ByVal FilePath as String)
MyBase.New()
_state.ID = ID
_state.FilePath = FilePath
End Sub
Public Sub GetInfo()
'Do the work here, but just return the result for this demonstration
Try
_state.Result = True
Catch ex As Exception
_state.Result = False
Finally
RaiseEvent ReportState(_state)
End Try
End Sub
End Class
上面的类就像一个魅力,非常快,几乎不使用内存,几乎没有 CPU。尽管我只能使用 Threading.Thread 进程用几百个线程对此进行测试。
现在我想使用 ThreadPool.QueueUserWorkItem 为每个文件执行上述类,从而允许系统控制在任何给定时间运行的线程数。但是,我知道我不能在不锁定服务器的情况下将数百万个线程转储到 ThreadPool 中。我对此做了很多研究,我只能找到关于将 ThreadPool.QueueUserWorkItem 用于几个线程的示例/讨论。我需要的是触发数百万个这些线程。
所以,我有两个问题:1)我是否应该尝试使用 ThreadPool.QueueUserWorkItem 来运行这么多线程,以及 2)下面的代码是否足以在不锁定服务器的情况下执行此过程?
到目前为止,这是我的代码:
For Each subdir As String In Directory.GetDirectories(DirPath)
For Each fl In Directory.GetFiles(subdir)
'MsgBox(fl)
Dim f As ImportFile = New ImportFile(0, fl)
AddHandler f.ReportState, AddressOf GetResult
ThreadPool.QueueUserWorkItem(New Threading.WaitCallback(AddressOf f.GetInfo))
ThreadPool.GetAvailableThreads(worker, io)
Do While (worker) <= 0
Thread.Sleep(5000)
ThreadPool.GetAvailableThreads(worker, io)
Loop
Next
Next