2015-03-02 2 views
0

на C# Net 2.0Многопоточный заполняющий массив

Код работает немного медленнее, чем однопоточная версия. xDiff = 2100, yDiff = 2000; Почти 14 секунд в однопоточной, 16 сек в многопоточном (этот код). Что-то должно быть неправильно. Мне нужно заполнить массив результатов. Только один раз записывает данные на узле массива, не читает, поэтому он должен быть подходящим для многопоточности.

double[,] result = new double[xDiff, yDiff]; 
int threadCount = Environment.ProcessorCount; 
ManualResetEvent finished = new ManualResetEvent(false); 
int perthread = xDiff/threadCount; 
int left = xDiff % threadCount; 
int toProcess = threadCount; 
int s = 0; 
int e = left; 
for (int ii = 0; ii < threadCount; ii++) 
{ 
    ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state) 
    { 
     for (int x = s; x < e; x++) 
     for (int y = 0; y < yDiff; y++) 
     { 
      result[x, y] = DoWork((xStart + x), (yStart + y), p) 
     } 
     if (System.Threading.Interlocked.Decrement(ref toProcess) == 0) finished.Set(); 
    }), null); 
    s = e; 
    e += perthread; 
} 
finished.WaitOne(); 
return result; 

xStart, yStart double и p - большой класс. Функция DoWork Только вызывает некоторые функции p, но не записывает/не изменяет данные в классе.

Кратко результат [x, y] = DoWork ((xStart + x), (yStart + y), p); Мне нужно заполнить массив так быстро, как я могу. Как мне это сделать?

+0

ли DoWork делать какую-то операцию блокировки? Если это так, вы лучше ставите в очередь новый рабочий элемент за звонок DoWork. Обратите внимание, что QueueUserWorkItem фактически не создает новые потоки –

+0

Рассмотрите возможность использования одной из готовых циклов в классе Parallel. Ваше дело не выглядит особенным. – usr

+0

@usr Я забыл, что сначала, но OP использует .NET 2.0. – CodesInChaos

ответ

2

Я думаю, что проблема здесь в том, что переменные s и e являются замыканиями, которые изменяются за пределами потоков, поэтому потоки получают неправильные значения и используют неправильные диапазоны.

Чтобы увидеть, если это так, то попробуйте добавить Console.WriteLine() или Trace.WriteLine() для распечатки значений s и e внутри потока (после вызова QueueUserWorkItem()), чтобы увидеть, если это то, что происходит.

Чтобы исправить это, скопируйте измененные замыкания во временные переменные и использовать их в потоке, например, так:

for (int ii = 0; ii < threadCount; ii++) 
{ 
    int ts = s; // Copy them outside the loop. 
    int te = e; 
    ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state) 
    { 
     for (int x = ts; x < te; x++) // Use the copy here. 

Также см Access to Modified Closure

+0

Худший случай: все работники заполняют весь массив –

+0

Спасибо, я пропустил его. Когда я проверяю s и e, все потоки пытаются заполнить весь массив. – user1708062

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