Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > VB .NET > Таймаут между потоками


Автор: RageGod 4.8.2012, 08:54
Столкнулся с проблемой.
У меня берется из ArrayList'а строка, и помешается в определенную строку, и после этого удаляется. Затем берется следующая и так далее.
Но при использование многопоточности, часто программа берет одну и ту же строку, т.к программа не успевает её удалить, а поток уже её берет. 

Как быть?
Может есть какой-то таймаут между потоками ?

Автор: diadiavova 4.8.2012, 11:58
RageGod, не совсем понял, что ты делаешь, но может теб очередь использовать вместо эррэйлист? Да и с джинериками пора бы уже познакомиться. А смысл многпоточности как раз в параллельной работе. Хотя на время обработки объекта одним потоком можно этот объект заблокировать для доступа из других
http://msdn.microsoft.com/ru-ru/library/3a86s51t

Автор: RageGod 4.8.2012, 14:54
Хм.
Посмотрю ваш вариант.

Точнее, работать через аргументы.
Обращаться к процедуре с аргументами, а не удалять во время работы потока из листа.
Поможет, как Вы думаете?

Автор: diadiavova 4.8.2012, 17:03
RageGod, если ты опишешь задачу подробнее, тогда можно будет что-то советовать

Автор: RageGod 6.8.2012, 15:36
Описываю задачу точнее:

Вообщем, список строк загружается в ArrayList.
После этого, берется оттуда первая линия и подставляется в ссылку. Парсятся кое-какие данные с этой ссылки, удаляется данная строка из ArrayList и берется другая.

Проблема такая:
В ArrayList загружено 2-3 строки. Потоков выставляется 5. И тогда потоки берут одно и ту же строку. То есть, она не успевает удалятся, а другой поток уже взял эту строку.

Автор: diadiavova 6.8.2012, 16:12
RageGod, ответ тот же, что и с самого начала. Либо блокируешь доступ к коллекции другим потокам на время, пока с ним уже работает один из потоков, либо сначала извлекаешь строку из коллекции, а потом уже обрабатываешь её (лучше использовать очередь)

Автор: RageGod 6.8.2012, 16:29
Цитата(diadiavova @  6.8.2012,  16:12 Найти цитируемый пост)
либо сначала извлекаешь строку из коллекции, а потом уже обрабатываешь её 

Тогда стоит объявить какую-нибудь переменную, заносить в неё строку, потом удалять из ArrayList данную строку и потом уже подставлять и парсить. Я Вас правильно понял?)

Но тогда как быть, если используется многопоточнсть?
У меня вот такая процедура многопоточности:
Код

    Public Sub pStart(ByVal number As Integer)
        i = -1
        Try
            For a = 0 To number - 1
                Dim bruteThread As New Threading.Thread(New ParameterizedThreadStart(AddressOf Parser))
                Control.CheckForIllegalCrossThreadCalls = False
                bruteThread.IsBackground = True
                bruteThread.Start()
            Next a
        Catch ex As Exception
        End Try
    End Sub

Заносить в строку и удалять из ArrayList'а в этой процедуре или сделать 2 контролирующие процедуры (первая запускает вторую, которая в свою очередь обрабатывает ArrayList, а потом запускает третью, которая уже парсит)?

Автор: diadiavova 6.8.2012, 18:42
RageGod, так, а в чём проблема-то? Метод, обрабатывающий строки и запускаемвй в разных потоках, извлекает строку из коллекции и обрабатывает её.

Автор: RageGod 7.8.2012, 08:38
diadiavova
Немного не понял.
Можно пример какой-нибудь?

Автор: RageGod 8.8.2012, 11:31
Ну так даст может кто-нибудь небольшой пример, как мне помог пользователь diadiavova

Автор: diadiavova 8.8.2012, 12:55
RageGod, честно говоря, мне не очень понятно, что именно непонятно тебе. Исходные строки у тебя есть, код инициализации потоков есть, код обработки строк - тоже. Всё, что нужно сделать - это изменить код обработки так, чтобы строка сначала удалялась из коллекции, а потом только обрабатывалась. Не получится - будем разбираться. Пока просто времени нет на развёрнутый ответ, да и сидеть выдумывать строки и логику их обработки тоже не очень хочетсч, если бы ты хотябы этотвыложил, было бы уже меньше возни.

Автор: diadiavova 8.8.2012, 22:47
RageGod, итак, для начала следует сказать, что для параллельной обработки элементов коллекции в 4-м фреймворке появились новые инструменты, позволяющие избежать непосредственной работы с потоками. Вот пример консольного приложения, выполняющего простую обработку коллекции строк параллельно, если запустить его несколько раз, можно увидеть, что последовательность обработки элементов может меняться.
Код

Imports System.Threading.Tasks
Module Module1

    Sub Main()
        Parallel.ForEach(_stringCollection,
                         Sub(item As String)
                             Console.WriteLine(item.Substring(6))
                         End Sub)
        Console.ReadKey()
    End Sub

    Dim _stringCollection As List(Of String) = New List(Of String) From {
        "строка1", "строка2", "строка3", "строка4", "строка5", "строка6",
        "строка7", "строка8", "строка9", "строка10", "строка11", "строка12"}

End Module

Здесь я вместо ArrayList использовал List(Of T), в силу того, что АррэйЛист морально устарел и его использовать нецелесообразно вообще.

Далее привожу пример того, о чем я говорил. Здесь у меня и первый пример и второй в одном приложении, просто вызов параллельной обработки закоментирован
Код

Imports System.Threading.Tasks
Imports System.Threading
Module Module1

    Sub Main()
        'ProcessParallel()
        ProcessMultyThread()
        Console.ReadKey()
    End Sub

    Sub ProcessParallel()
        Parallel.ForEach(_stringCollection,
                               Sub(item As String)
                                   Console.WriteLine(item.Substring(6))
                               End Sub)
    End Sub

    Sub ProcessMultyThread()
        For i = 0 To _stringCollection.Count - 1
            Dim th As New Thread(AddressOf ProcessSingleString)
            th.Start()
        Next
    End Sub

    Sub ProcessSingleString()
        Dim str = _stringCollection(0)
        _stringCollection.RemoveAt(0)
        Console.WriteLine(str.Substring(6))
    End Sub

    Dim _stringCollection As List(Of String) = New List(Of String) From {
        "строка1", "строка2", "строка3", "строка4", "строка5", "строка6",
        "строка7", "строка8", "строка9", "строка10", "строка11", "строка12"}

End Module



Автор: RageGod 9.8.2012, 09:19
Так, что адаптировать ваш пример под мой, следует сделать так:
заместо 
Код

Console.WriteLine(str.Substring(6))
 вставить процедуру парсинга. И уже в процедуре парсинга использовать значение переменную str, как значение, которое надо будет подставить в ссылку. Я правильно понял?

Автор: diadiavova 9.8.2012, 12:40
RageGod, ты понял правильно, вот только я не понял, зачем тебе это надо. Если ради производительности, то лучше использовать инструменты параллельных вычислений, как показано в первом примере или ещё лучше написать параллельный линк-запрос. А если цели другие, то интересно какие.

Автор: RageGod 9.8.2012, 18:25
diadiavova, На самом деле все проще, чем вы думаете.
Просто хочется более высокой скорости работы.
Точнее, чтобы парсинг был быстрее.

Другого метода наладить скорость я не знаю. (кроме оптимизации кода еще, но там и так наладил все, что знаю).

Автор: diadiavova 9.8.2012, 19:44
Цитата(RageGod @ 9.8.2012,  19:25)
diadiavova, На самом деле все проще, чем вы думаете.
Просто хочется более высокой скорости работы.
Точнее, чтобы парсинг был быстрее.

Другого метода наладить скорость я не знаю. (кроме оптимизации кода еще, но там и так наладил все, что знаю).

Ну почему же проще?  Я так и предположил. Я написал о том, что для этого надо использовать инструменты параллельных вычислений. Почему-то некоторые думают, что чем больше потоков, тем быстрее всё работает, хотя это далеко не так, даже напротив - иногда избыток потоков может только замедлить обработку. Видимо есть смысл в создании потоков, количество которых не превышает количества ядер процессора, но ещё раз повторюсь, что использование параллельных вычислений предпочтительнее иуж точно проще и  надёжнее в использовании. Например плинк-запрос, решающий твою задачу будет выглядеть примерно так
Код

From item As String In stringCollection.AsParallel() Select ParseString( item)
 этот запрос возвратит коллекцию обработанных строк, причём при обработке элементы коллекции будут равномерно распределены между доступными ядрами процессора.

Автор: RageGod 10.8.2012, 12:30
В принципе, вы правы.
Где-нибудь прочитать про такие параллельные вычисления можно?)

И как я понял, как они работают (судя по коду, которые вы предоставили мне):
По нажатию на кнопку (допустим так) запускается ProcessMultyThread, которые в свою очередь запускает начинает выполнение ProcessSingleString, до тех пор, пока количество строк в нашей коллекции не будет равно -1. Следовательно, здесь используется тоже что-то похожее на потоки, и это и называется параллельным вычислением, так?
Тогда, это своего рода потоки, только более надежно, да?

Автор: diadiavova 10.8.2012, 12:36
Ну естественно за кулисами используются потоки, только учитывается множество нюансов и вся рутинная работа уже сделана, а разработчику только сливки smile 
http://msdn.microsoft.com/ru-ru/library/dd460693.aspx

Автор: RageGod 10.8.2012, 13:46
Спасибо.

Я правильно понял работу параллельных вычислений? 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)