Использование ThreadPool.QueueUserWorkItem для миллионов потоков
У меня есть необходимость обрабатывать миллионы файлов. В настоящее время я использую собственный менеджер потоков, чтобы выполнить работу, используя 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
Это имеет много недостатков, основные из которых заключаются в том, что загрузка ЦП и памяти высока, поскольку каждый из указанных выше потоков обрабатывает полный каталог, а не каждый файл независимо.
Итак, я переписал процесс. Теперь у меня есть класс, который будет выполнять процесс на уровне файлов и сообщать основному потоку результаты; вот так:
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
Вышеупомянутый класс работает как чудо и очень быстро, почти не использует памяти и почти ничего от процессора. Хотя я смог проверить это только с несколькими сотнями потоков, используя процесс 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