none
Параллельные вычисления RRS feed

  • Вопрос

  • Всем привет!

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

    public void SequentProcess()
    {   string[] FileNameArr=File.ReadAllLines("с:FileName.Lst");
         for (int i=0;i<FileNameLst.Length;i++)
         {   Prepare("c:"+FileNameArr[i]);
    }   }
    public void ParallelProcess()
    {    string []FileNameArr=File.ReadAllLines("с:FileName.Lst");
           ThreadPool.QueueUserWorkItem
            (   delegate
                 {   FileNameArr.AsParallel().Select((Item)=>
                      Path.Combine("c:", Item)).ForAll(Prepare);
                  }
            );
    }
    public void Prepare ( string S ) { prepareClass sP=new prepareClass(S); }
    public class prepareClass 
    {   public prepareClass(string fileName)
         {   ToDo(fileName);
    }   }

    11 марта 2012 г. 17:25

Ответы

  • 1) лучше весь код переписать и задокументировать, иначе через пару месяцев вы сами в нем ничего не будите понимать

    2) можно написать свою реализацию потокобезопасного листа или воспользоваться существующими решениями, как например - C# - Fast Parallel ConcurrentList<t>Implementation</t>


    Для связи [mail]

    • Помечено в качестве ответа QazRdx 23 марта 2012 г. 22:47
    20 марта 2012 г. 11:09

Все ответы

  • Здравствуйте.

    Вроде бы не должно быть ни каких пересечений. Вот Select можно опустить, он изменяет начальный массив FileNameArr, возможно в этом какая-то проблема.

    Path.Combine можно вынестив фунция Prerape, т.к. она также получает элемент массива FileNameArr.


    Для связи [mail]

    12 марта 2012 г. 13:10
  • Спасибо, Дмитрий! Без Select-а действительно изящней, но проблема пока не решена. Вполне возможно, что это мой баг в обрабатывающем классе, но где пока не вижу, на тестах работает нормально, а на реальных данных нет. Причем ошибки возникают в разных местах, а при последовательной обработке этого нет. Как еще тестировать пока не знаю.
    13 марта 2012 г. 0:09
  • > данные, после обработки одним и тем же классом при последовательном процессе отличаются от
    тех же данных, обработанных при параллельном процессе 
        
       
    попробуйте следующий код.

     

    public void ParallelProcess(string fname, string disk = "c:\\")
    {
        WaitCallback run = state =>
        {
            var lines = state as string[];
            lines.AsParallel().Select(line => Path.Combine(disk, line)).ForAll(Prepare);
        };
        ThreadPool.QueueUserWorkItem(run, File.ReadAllLines(fname));
    }
    public void SequentProcess(string fname, string disk = "c:\\")
    {
        foreach (var line in File.ReadAllLines(fname))
            Prepare(Path.Combine(disk, line));
    }
    void Prepare(string line)
    {
    }
      
        
    13 марта 2012 г. 3:44
  • Спасибо, Malobukv!
    Попробовал - то же самое.
    Думаю, проблема в обрабатывающем классе,
    в потоко не безопасных операциях.
    Разберусь - сообщу.

    13 марта 2012 г. 5:33
  • Да, видимо не по зубам мне эти многопоточные операции.

    Все вроде работает, но глюки,

    о которых я уже говорил, встречаются довольно часто.

    Отлавливать их сложно, они ассинхронные,

    т.е. не привязаны к коду, ни к данным.

    Программирование осложнено тем,

    что класс List<string>, который у меня повсеместно используется,

    и операции с объектами которого и глючат,

    не имеет полноценного аналога в System.Collection.Concurrent.

    ConcurrentBag - это далеко не то, что надо.

    Подожду, когда появится что-нибудь более устойчивое.

    Какие будут мнения?

    16 марта 2012 г. 14:25
  • > Все вроде работает, но глюки, о которых я уже говорил, встречаются довольно часто. [...] Какие будут мнения?


    если возможно, приведите компилируемый код, воспроизводящий проблему.
     
     

    16 марта 2012 г. 14:58
  • Показать весь код не представляется возможным - он достаточно велик и неуклюж - многоярусные вложенные классы, куча переменных, перегрузок... По хорошему его бы переписать, а перед тем красиво спроектировать... Но это сложно - алгоритм слишком витиеват. Все разрабатывалось в процессе... Пусть уж остается как есть... Всем спасибо!
    16 марта 2012 г. 16:32
  • 1) лучше весь код переписать и задокументировать, иначе через пару месяцев вы сами в нем ничего не будите понимать

    2) можно написать свою реализацию потокобезопасного листа или воспользоваться существующими решениями, как например - C# - Fast Parallel ConcurrentList<t>Implementation</t>


    Для связи [mail]

    • Помечено в качестве ответа QazRdx 23 марта 2012 г. 22:47
    20 марта 2012 г. 11:09
  • Дмитрий, большое спасибо!

    1.Так и есть.
    По этому поводу у меня большой опыт,
    Смысл которого состоит в том,
    что никакая документация не в состоянии
    облегчить мне сопровождение моего ПО.
    Бывает, через пару дней, а не месяцев,
    я смотрю на свою программу, как ... на новые ворота,
    а комментарии, которыми я старательно описывал процесс,
    только усложняют разбирательство. ;-E)

    2.Кажется, это то, что нужно! 
    Разбираюсь!
    Большое спасибо!
    Я уже было успокоился...


    • Изменено QazRdx 20 марта 2012 г. 13:31
    20 марта 2012 г. 13:29
  • Не понимаю, к чему следующие 2 фрагмента из предложенного Вами примера.
    Без них, видимо, никак, но и с ними - тоже. Оба дают ошибки.

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        object IList.this[int index]
        {
            get { return ((IList<T>)this)[index]; }
            set { ((IList<T>)this)[index] = (T)value; }
        }
    

    20 марта 2012 г. 15:28
  • С первым понятно - нужно прописать 
    using System.Collections;
    А со вторым - по-прежнему туман.
    20 марта 2012 г. 15:46
  • Второй закоментировал - и все Ок!

    К этому примеру нужны 

    using System; using System.Collections; using System.Collections.Generic; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks;

    Буду теперь пытаться все это пользовать в своей многострадальной проге.

    Дмитрий, большое спасибо!

    • Изменено QazRdx 20 марта 2012 г. 16:36
    20 марта 2012 г. 16:34