How do I iterate through a dynamically valued dictionary in parallel?

坚强是说给别人听的谎言 提交于 2020-01-05 04:54:08

问题


I am trying to spawn threads in a for each loop using a copy of the value in a dict.

My initial understanding was that the foreach would create a new scope, and led to:

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));
}

which writes

1
2
2
2

instead of (expected):

1
2
1
2

So I tried cloning the kvp in the foreach:

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

but that renders the same result.

I've also tried it with System.Parallel.ForEach but that seems need values that are not dynamic, which is a bit of a train smash for my dictionary.

How can I iterate through my Dictionary with threads?


回答1:


The problem is closure over your lambda, the way to fix is is to add a local variable inside the for loop

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));
}

What is happening in your version is it captures the variable record not the value of the variable record. So when the timer runs the 2nd time it uses the "current value" of record which is the 2nd element in the array.

Behind the scenes this is what is kinda what is happening in your version of the code.

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);
}

See how when your function ran it for the first itteration had the correct version of _recordStored, but after _recordStored got overwritten it will only show the last set value. By creating a local variable it does not do that overwriting.

A way to imagine it (I am not sure how I could represent it in a code example) is it creates _recordStored1 the first loop, _recordStored2 the 2nd loop, and so on. The function uses the correct version of _recordStored# for when it calls the the function.



来源:https://stackoverflow.com/questions/17658162/how-do-i-iterate-through-a-dynamically-valued-dictionary-in-parallel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!