#.net #vb.net
#.net #vb.net
Вопрос:
Я не эксперт в vb.net так что это своего рода неприятная проблема для меня. Мне нужно считывать изображения из каталога и обрабатывать их параллельно. ТАК что в идеале мой код должен делать следующее,
Dim Directory As New IO.DirectoryInfo("New Folder\")
Dim allFiles As IO.FileInfo() = Directory.GetFiles("*.bmp")
Dim singleFile As IO.FileInfo
Dim i As Integer = 0
For Each singleFile In allFiles
Console.WriteLine(singleFile.FullName)
If File.Exists(singleFile.FullName) Then
Dim badge As Image(Of Bgr, Byte) = New Image(Of Bgr, Byte) (singleFile.FullName)
i = i 1
Dim checkLabelThread As Thread = New Thread(AddressOf processBadge(badge, i))
End If
Next`
Здесь processBadge — это функция, которая должна обрабатывать значок. Но Vb.net не позволяет мне передавать переменные в эту функцию. Есть ли способ исправить это и выполнить мое требование? Большое спасибо.
Комментарии:
1. Чтобы заставить его скомпилироваться (и предполагая, что ваш
Image(Of T1, T2)
даже реальный тип), вам просто нужно изменитьAddressOf
наSub()
. Однако все это требует переосмысления: запускайте и забывайте потоки внутри цикла? Звучит как плохая идея.
Ответ №1:
Обычно вы можете сделать это:
Dim checkLabelThread As Thread = New Thread(Sub() processBadge(badge, i))
Обратите внимание на замену AddressOf
с Sub()
.
Однако, поскольку вы выполняете поток, значение i
будет обновляться до выполнения потока, поэтому вы никогда не получите фактическое значение i
— цикл завершится, поэтому значением будет количество элементов в allFiles
массиве.
Итак, вот что я бы сделал.
Сначала я бы создал перегрузку processBadge
, чтобы сделать вызывающий код более чистым. Вот так:
Private Sub processBadge(fileInfo As FileInfo, index As Integer)
Console.WriteLine(fileInfo.FullName)
If File.Exists(fileInfo.FullName) Then
Dim badge As Image(Of Bgr, Byte) = _
New Image(Of Bgr, Byte)(singleFile.FullName)
processBadge(badge, index)
End If
End Sub
Тогда я бы назвал это следующим образом Parallel.ForEach
:
Dim source = new System.IO.DirectoryInfo("New Folder\") _
.GetFiles("*.bmp") _
.Select(Function(f, i) New With { .FileInfo = f, .Index = i })
Parallel.ForEach(source, Sub(x) processBadge(x.FileInfo, x.Index))
Это не создаст слишком много потоков и должно максимизировать производительность.
Ответ №2:
Вы можете создать класс для хранения информации о контексте вашего потока (ниже приведен непроверенный код):
Public Class BadgeProcessor
Private ReadOnly _badge As Image
Private ReadOnly _index As Integer
Public Sub New(badge As Image, index As Integer)
_badge = badge
_index = index
End Sub
Public Sub ProcessBadge()
' do what your processBadge method does here
End Sub
End Class
И используйте это в своем цикле:
If File.Exists(singleFile.FullName) Then
Dim badge As Image(Of Bgr, Byte) = New Image(Of Bgr, Byte)(singleFile.FullName)
i = i 1
Dim bp As BadgeProcessor = New BadgeProcessor(badge, i)
Dim checkLabelThread As Thread = New Thread(AddressOf bp.ProcessBadge)
'checkLabelThread.Start() ?
End If
Однако, если у вас есть 1000 изображений в каталоге, вы собираетесь запустить 1000 потоков, что, вероятно, не будет тем, что вы хотите. Вероятно, вам следует изучить библиотеку параллельных задач, которая будет использовать пул потоков для ограничения одновременных потоков чем-то более разумным — возможно Parallel.ForEach
, циклом.