2015-03-05 4 views
1

Этот код работает корректно только в режиме отладки. Я не понимаю, что случилось.Код Parallel.For работает только в режиме отладки

Я попытался изменить код, но без какого-либо прогресса. Я хотел бы добавить результат вызова функции newRow в hashSet, если первый параметр равен true.

foreach (structNumbers sn in numbers) 
//Parallel.ForEach(numbers, new ParallelOptions { MaxDegreeOfParallelism = 1 }, (sn) => 
{ 
    #region       
    //for (Int32 v = 0; v < 16; v++) 
    Parallel.For<Tuple<Boolean, mpz_t, mpz_t>>(0, 16, 
     ()=> { return new Tuple<Boolean, mpz_t, mpz_t>(false, 0, 0); }, 
     (v, pls, state) => 
    { 

     #region 
     Interlocked.Increment(ref countChecked); 

     //if (newRow(i, j, v, t, index, sn.n, sn.m, out nMin, out mMin) == true) 
     //lock(thisLock) 
     Tuple<Boolean, mpz_t, mpz_t> res = newRow(i, j, v/4, v % 4, index, sn.n, sn.m); 
     state = new Tuple<bool, mpz_t, mpz_t>(res.Item1, res.Item2, res.Item3); 


     return state; 

     #endregion 

    }, 
     state => { 
      lock (thisLock) 
      { 
       if (state.Item1 == true) 
       { 
        #region 

        numbersTemp.Add(new structNumbers(state.Item2, state.Item3)); 
        //numbersTemp.Add(new structNumbers(nMin, mMin)); 
        //Console.WriteLine("bla"); 
        #endregion 
       } 

      } 
     } 
    ); 
    #endregion 
} 
//); 
+3

Не могли бы вы объяснить, какую ошибку/неправильное поведение вы получили? –

+0

У меня нет ошибок. numbersTemp не содержит всех элементов. это все –

+0

Утром попробуйте снова использовать debug, но теперь мой код работает неправильно. –

ответ

0

Если вы хотите объединить несколько результатов параллельного цикла, то вы можете сделать это следующим образом:

object lockObject=new object(); 
HashSet<TResult> result=new HashSet<TResult>(); 
Parallel.For(0,16,() => new List<TResult>(),(i,pls,list) => { 
    TResult r; 
    if(TryGetResult(i,out r)) { 
     list.Add(r); 
    } 
    return list; 
},list => { 
    lock(lockObject) { 
     result.UnionWith(list); 
    } 
}); 

Но если TryGetResult представляют собой большую работу (по крайней мере, она должна быть достаточно большой, чтобы оправдать накладные расходы параллельного цикла), вы можете сделать так:

object lockObject=new object(); 
HashSet<TResult> result=new HashSet<TResult>(); 
Parallel.For(0,16,i => { 
    TResult r; 
    if(TryGetResult(i,out r)) { 
     lock(lockObject) { 
      result.Add(r); 
     } 
    } 
}); 

Или это:

ConcurrentBag<TResult> bag=new ConcurrentBag<TResult>(); 
Parallel.For(0,16,i => { 
    TResult r; 
    if(TryGetResult(i,out r)) { 
     bag.Add(r); 
    } 
}); 
HashSet<TResult> result=new HashSet<TResult>(bag); 

На мой взгляд, перегрузка Parallel.For с параметром TLocal типа больше подходит, когда у вас есть скалярный результат, который не может быть обновлен без замка:

object lockObject=new object(); 
BigInteger result=BigInteger.Zero; 
Parallel.For(0,16,i => { 
    BigInteger r=GetBigInteger(i); 
    lock(lockObject) { 
     result+=r; 
    } 
}); 

В этом коде, добавив два BigInteger может быть дорогостоящей операцией и не может быть сделано параллельно, так что вам лучше переписать код так:

object lockObject=new object(); 
BigInteger result=BigInteger.Zero; 
Parallel.For(0,16,() => BigInteger.Zero,(i,pls,subResult) => { 
    return subResult+GetBigInteger(i); 
},subResult => { 
    lock(lockObject) { 
     result+=subResult; 
    } 
}); 
+0

Я хотел бы позвонить в тысячу раз. Функция умножает числа с разными диапазонами чисел. Для них какой метод будет оптимальным для производительности? Задача, Параллельный, BackgroundWork, ожидание/async? Функциональный фактор требует> 10 минут для проверки каждого диапазона. –

+0

@YuriyTigiev Если у вас такая большая работа, вы можете сделать одну единицу работы достаточно большой, чтобы рассматривать накладные расходы при параллельном вызове как пренебрежимое. Поэтому, на мой взгляд, на самом деле не важно, что вы на самом деле выбираете. Но отметить: 'Parallel' основан на' Task'; 'BackgroundWorker' и' await'/'async' больше связаны с асинхронностью, а затем с параллелизмом. – PetSerAl

+0

Я не могу понять, в каком случае я должен использовать параллельный и когда асинхронный метод? Как выбрать правильный метод? Каков критерий? Я прочитал много документов, но это мне не помогает. –

0

путь эта версия Parallel.For() работ является то, что он первым разбивает вход в партии. Затем для каждой партии инициализируйте локальное состояние с помощью делегата localInit, вызовите делегата body для каждого номера в пакете, передав ему последнее состояние и ожидая, что он вернет новое состояние, и, в конце концов, вызвав localFinally на окончательный государство.

Поскольку вы игнорируете состояние ввода вашего body, вы добавляете только последний элемент из каждой партии в результат.

Ответ PetSerAl показывает возможные решения. Вероятно, наиболее разумным для начала является самый простой с lock. Если это окажется слишком медленным, найдите более сложные решения, в том числе те, которые используют локальное состояние.

Смежные вопросы