Передавать объект в поток в цикле каждый раз, когда в vb.net

#.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 , циклом.