2013-08-10 3 views
0

В настоящее время я пытаюсь улучшить проект C#, над которым я работаю. В частности, моя цель - распараллелить некоторые операции, чтобы сократить время обработки. Я начинаю с небольших фрагментов, чтобы получить его. Следующий код (не параллельно) работает правильно (как и ожидалось)Parallel.for вызывает разные результаты

for (int i = 0; i < M; i++) 
{ 
    double d; 
    try 
    { 
      d = Double.Parse(lData[i]); 
    } 
    catch (Exception) 
    { 
     throw new Exception("Wrong formatting on data number " + (i + 1) + " on line " + (lCount + 1)); 
    } 
    sg[lCount % N][i] = d; 
} 

Используя следующее (параллельный) код, который я бы ожидать, чтобы получить те же результаты, но это не так.

Parallel.For(0, M, i => 
{ 
    double d; 
    try 
    { 
     d = Double.Parse(lData[i]); 
    } 
    catch (Exception) 
    { 
     throw new Exception("Wrong formatting on data number " + (i + 1) + " on line " + (lCount + 1)); 
    } 
    sg[lCount % N][i] = d; 
}); 

Часть программы, от которой эти фрагменты считываются из файла, по одной строке за раз. Каждая строка представляет собой последовательность чисел двойной точности, разделенных запятыми, которые я вставляю в вектор lData [], используя String.Split(). Каждые M строк последовательность данных начинается с нового кадра данных (следовательно, % M в индексе элемента, когда я присваиваю значения).

Это мое понимание (явно неправильное), что, поместив код из (последовательного) цикла в третий параметр Parallel.For, я распараллеливаю его выполнение. Это не должно изменить результаты. Проблема в том, что все потоки доступны для lCount и M? Должен ли я делать потоковые локальные копии?

Спасибо.

(так как я новый, я не позволил создать Parallel.For тег)

EDIT: я провел еще несколько тестов. В основном я смотрел на результат ранее в коде, чем то, что я делал раньше. Похоже, что параллельная версия моего кода не заполняет массив sg[][] полностью. Скорее, некоторые значения оставлены по умолчанию (0, в моем случае).

EDIT 2 (ответить на некоторые из комментариев): lData[] является string[], полученный с помощью string.Split(). Исходная строка, которую я разделяю, считывается из моих файлов данных. Я написал код, который их генерирует, поэтому они обычно хорошо отформатированы (я по-прежнему использовал конструкцию try-catch по привычке). Как раз перед циклом for (петля параллельна или последовательна) я проверяю, что lData[] имеет правильное количество значений (M). Если это не так, я выдаю исключение, которое мешает программе достичь заданного цикла. sg[][] представляет собой массив N по M типа double (в отпечатках была опечатка, теперь исправлена; в моем исходном коде эта ошибка отсутствовала). После того, как я прочитал N строк из файла, массив sg[][] содержит целый набор данных. После цикла for (loop) (параллельного или последовательного) есть часть прихода, которая выглядит так: lCount ++; // считая строки, я уже читал если ((LCOUNT% N) == 0) { // делать вещи с Sg [] [] // сброс к.с. [] [] } Итак, я специально переписывая все строки sg[][]. Общая цель for-loop - обновить значения в sg[][].

+0

Кроме того, вы можете увеличить производительность с помощью 'Double.TryParse' вместо обработки исключений. – James

+0

Спасибо @ Джеймс, я этого не знал. – Bovaz

+0

Для отсутствующих значений вы получили исключение? Также, если ваша обработка зависит от порядка, Parallel.For не выполняется в определенном порядке. – seshuk

ответ

3

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

В принципе, без ведома, потоки, созданные parallel.for, не наследовали CultureInfo (это нормальное поведение потоков, и я этого не знал). То, что происходило тогда, было то, что строки, такие как 3.256, обрабатывались до 3256.0. Это вызвало проблемы, которые я нашел с выходом. (Примечание: языковой стандарт по умолчанию на моем компьютере настроен на использование запятой в качестве десятичного разделителя, но я установил полную остановку в program.cs для всего моего кода. Я неправильно предположил, что это будет унаследовано новыми потоками)

правильный параллельный фрагмент выглядит следующим образом:

CultureInfo newCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone(); 
newCulture.NumberFormat.NumberDecimalSeparator = "."; 
Parallel.For(0, M, i => 
{ 
    Thread.CurrentThread.CurrentCulture = newCulture; 
    double d; 
    try 
    { 
     d = Double.Parse(lData[i]); 
    } 
    catch (Exception) 
    { 
     throw new Exception("Wrong formatting on data number " + (i + 1) + " on line " + (lCount + 1)); 
    } 
    GlobalVar.sgData[lCount % N][i] = d; 
}); 

Спасибо всем, кто стан с комментариями и мнениями. Хорошая информация для улучшения моего программирования.

Я обновил теги вопросов, чтобы отразить, где проблема действительно была.

+0

Вы можете использовать свойство [CultureInfo.DefaultThreadCurrentCulture] (http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.defaultthreadcurrentculture.aspx) вместо того, чтобы устанавливать его явно, чтобы оно получило унаследованный новыми потоками. –

2

Ничто в коде по существу неправильный, насколько я могу видеть. Я предполагаю, что у вас есть условие гонки или проблема закрытия в функции, содержащей фрагменты, возможно, на переменной N.

Если вы вложили этот фрагмент внутри другого вызова Parallel.For(), возможно, вам не хватает того факта, что N закрыт в выражении лямбда и может обновляться.Поэтому, пока вы не обновляете «N», вы ожидаете, что он останется постоянным внутри лямбда. Для того, чтобы решить, что, попробуйте следующее:

// Create a local copy of N and M, so that if we update 
// it elsewhere it doesn't affect the closure 
var n = N; 
var m = M; 
Parallel.For(0, m, i => 
{ 
    double d; 
    try 
    { 
     d = Double.Parse(lData[i]); 
    } 
    catch (Exception) 
    { 
     throw new Exception("Wrong formatting on data number " + (i + 1) + " on line " + (lCount + 1)); 
    } 
    sg[lCount % n][i] = d; 
}); 
+0

Здравствуйте. Я попробовал это решение. Он не изменил результат параллельного цикла. – Bovaz

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