2013-07-15 5 views
1

Я пытаюсь порождать потоки в каждом цикле, используя копию значения в dict.Как выполнять параллельный параллельный параллельный динамический словарь?

Мое первое понимание было то, что foreach бы создать новую область, и привели к:

Dictionary<string, string> Dict = new Dictionary<string, string>() { { "sr1", "1" }, { "sr2", "2" } }; 
foreach (KeyValuePair<string, string> record in Dict) { 
    new System.Threading.Timer(_ => 
    { 
     Console.WriteLine(record.Value); 
    }, null, TimeSpan.Zero, new TimeSpan(0, 0, 5)); 
} 

, который пишет

1 
2 
2 
2 

вместо (ожидается):

1 
2 
1 
2 

Поэтому я попытался клонировать kvp в foreach:

KeyValuePair<string, string> tmp = new KeyValuePair<string, string>(record.Key, record.Value); 

но это делает тот же результат.

Я также пробовал его с System.Parallel.ForEach, но это кажется необходимым значениям, которые не являются динамическими, что немного напоминает поезд для моего словаря.

Как я могу повторить мой словарь с помощью ниток?

+1

Я не вижу, как код, который вы указали, будет работать вообще, учитывая, что вы не запускаете таймер ... и у вас есть 2 записи в словаре, а не 4, которые вы печатаете вне. Если вы можете создать короткую, но * полную * программу, демонстрирующую проблему, это действительно поможет. –

+1

Во-первых, зачем писать 1/2/1/2, когда все записи dictio имеют значение 1? Затем, почему вы попытались поместить две записи диктофона с тем же ключом «sr»? Он сразу же бросил бы .. – quetzalcoatl

+0

@quetzalcoatl Упс, второй sr должен был быть «2», чтобы продемонстрировать. – Alex

ответ

7

Проблема заключается в том closure over your lambda, способ исправить это, чтобы добавить локальную переменную внутри для цикла

Dictionary<string, string> Dict = new Dictionary<string, string>() { { "sr1", "1" }, { "sr2", "2" } }; 
foreach (KeyValuePair<string, string> record in Dict) { 

    var localRecord = record; 
    new System.Threading.Timer(_ => 
    { 
     Console.WriteLine(localRecord.Value); 
    }, null, TimeSpan.Zero, new TimeSpan(0, 0, 5)); 
} 

Что происходит в вашей версии он захватывает переменную record не значение переменной запись. Поэтому, когда таймер работает во второй раз, он использует «текущее значение» record, который является вторым элементом в массиве.

За кулисами это то, что происходит в вашей версии кода.

public void MainFunc() 
{ 
    Dictionary<string, string> Dict = new Dictionary<string, string>() { { "sr1", "1" }, { "sr2", "2" } }; 
    foreach (KeyValuePair<string, string> record in Dict) { 

     _recordStored = record; 
     new System.Threading.Timer(AnnonFunc, null, TimeSpan.Zero, new TimeSpan(0, 0, 5)); 
    } 
} 

private KeyValuePair<string, string> _recordStored; 

private void AnnonFunc() 
{ 
    Console.WriteLine(_recordStored.Value); 
} 

Посмотрите, как, когда ваша функция побежал в первый itteration имел правильную версию _recordStored, но после того, как _recordStored получил перезаписаны это только покажет последнее установленное значение. Создавая локальную переменную, она не выполняет эту перезапись.

Способ представить это (я не уверен, как я мог бы представить его в примере кода), он создает _recordStored1 первый цикл, _recordStored2 второй цикл и так далее. Функция использует правильную версию _recordStored# для вызова функции.

+1

FYI: [Есть ли причина для повторного использования переменной в foreach] (http: // stackoverflow.com/questions/8898925/is-there-a-reason-for-cs-reuse-of-the-variable-in-a-foreach) описывает все проблемы с autovariable foreach довольно хорошо и подробно, и даже поставляется с EricLippert's комментарии;) – quetzalcoatl

+0

Указатели + ошибки параллелизма - это весело! Почему, черт возьми, мне нужно указать тип foreach, если его просто указатель в любом случае? – Alex

+0

В качестве альтернативы ... можно было просто использовать C# 5, если бы они были изменены IIX, они изменили поведение foreach :) «В C# 5 переменная цикла foreach будет логически внутри цикла, и поэтому закрытие будет закрыто новой копией переменная каждый раз. " http://blogs.msdn.com/b/ericlippert/archive/2009/11/16/closing-over-the-loop-variable-part-two.aspx – NPSF3000

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