【问题标题】:TPL Data Parallelism IssueTPL 数据并行问题
【发布时间】:2013-01-16 17:38:39
【问题描述】:

我有一个情况是并行处理这组数据,最后我想知道总共有多少个数据处理成功了。我按照http://msdn.microsoft.com/en-us/library/dd460703.aspxhttp://reedcopsey.com/2010/01/22/parallelism-in-net-part-4-imperative-data-parallelism-aggregation/ 的示例提供了以下虚拟代码

    public void DoWork2()
    {
        int sum = 0;
        Parallel.For<int>(0, 10,
            () => 0,
            (i, lockState, localState) =>
            {
                DummyEntity entity = DoWork3(i);
                if (entity != null)
                {
                    Console.WriteLine("Processed {0}, sum need to be increased by 1.", i);
                    return 1;
                }
                else
                {
                    Console.WriteLine("Processed {0}, sum need to be increased by 0.", i);
                    return 0;
                }
            },
            localState =>
            {
                lock (syncRoot)
                {
                    Console.WriteLine("Increase sum {0} by {1}", sum, localState);
                    sum += localState;
                }
            }
            );
        Console.WriteLine("Total items {0}", sum);
    }

    private DummyEntity DoWork3(int i)
    {
        if (i % 2 == 0)
        {
            return new DummyEntity();
        }
        else
        {
            return null;
        }
    }

但是每次我运行时结果都会发生变化。我认为代码有问题。但不知道为什么。

【问题讨论】:

    标签: c# .net-4.0 task-parallel-library


    【解决方案1】:

    您的问题是您对重载的选择。您已存储本地状态信息以尽量减少使用全局状态,但您并未使用本地状态。

    如果您从给出的示例中注意到,他们在循环主体中使用了小计(您称之为 localState):

    subtotal += nums[j];
    return subtotal;
    

    将此与您的代码进行比较(更简洁一些):

    if (entity != null)
    {
        return 1;
    }
    else
    {
        return 0;
    }
    

    那里没有提到localState,所以你实际上已经丢弃了一些答案。如果您将其改为阅读:

    if (entity != null)
    {
        return localState + 1;
    }
    else
    {
        return localState;
    }
    

    您会在命令行上找到以下答案(针对这个给定的问题):

    Total items 5
    

    本地状态的这种用法是为了减少对共享状态的访问。

    这是使用 0..50 作为范围的 sn-p:

    Processed 22, sum need to be increased by 1.
    Processed 23, sum need to be increased by 0.
    Increase sum 0 by 1
    Processed 8, sum need to be increased by 1.
    Processed 9, sum need to be increased by 0.
    Processed 10, sum need to be increased by 1.
    Processed 11, sum need to be increased by 0.
    Increase sum 1 by 2
    Increase sum 3 by 8
    Increase sum 11 by 10
    Processed 16, sum need to be increased by 1.
    Processed 17, sum need to be increased by 0.
    Processed 18, sum need to be increased by 1.
    Increase sum 21 by 4
    Total items 25
    

    【讨论】:

    • 我多次运行更改后的代码,仍然看到相同的行为,最终结果不一致。
    • 我不相信您按照我的建议进行了修改。我每次更改都会得到 5 个。
    • 这是新发现,在我原来的测试代码private DummyEntity DoWork3(int i)函数中,我有一行Thread.Sleep(rnd.Next(200));来模拟延迟处理。如果我有那个线程睡眠,那么我会得到不一致的结果,如果我删除它,那么它会完美运行。所以我认为你的解决方案是正确的。
    • @hardywang:因为localState是一个参数,不会超出方法的范围。
    • @hardywang:localState 在您的情况下是一个 累加器。随着各种任务结果的结合,它提供了临时总和。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    相关资源
    最近更新 更多