C#TPL - 隔离?

时间:2012-04-05 13:09:24

标签: c# parallel-processing task-parallel-library

我正在尝试使用TPL。它不应该正常工作,我在动作体内定义的所有东西都是完全分开的吗?似乎并非如此。有人能指出我正确的方向。 基本上我想做的就是多次执行一个方法。此方法始终创建一个对象的实例,该对象具有将要执行的run方法。

1 个答案:

答案 0 :(得分:1)

虽然你没有提供任何代码,但是通灵调试表明你已经找到了lambdas的一个主要特性,即:闭包。 (或根据您的新评论:同步,或者更确切地说是缺乏)

考虑:

int x = 0;
Action y = () => Console.WriteLine("{0}", x++);
Action z = () => Console.WriteLine("{0}", --x);

yz都指的是x的同一个实例。现在,这是一个简单的例子,但考虑for循环或foreach的情况:

for (int i = 0; i < 10; ++i)
{
    Task.Factory.StartNew(() => Console.WriteLine("{0}", i));
}

所有10个任务都将引用相同的变量i!事实上,他们可能也会收到i。这是因为它们都是内存中相同变量周围的闭包。

如果你希望它们是独立的,那么它们的闭包需要独立的变量:

foreach (var datum in data)
{
    // Because myDatum is local to *each* loop iteration,
    // each Task will receive its own variable. The same
    // strategy applies to for-loops.
    var myDatum = datum;
    Task.Factory.StartNew(() => Frob(myDatum));
}

也许您遇到的另一种情况,即无代码,是数据结构的同步。除非你使用concurrent data structure,否则没有开箱即用的同步:

var bad  = new List<int>();          // No implicit thread safety
var good = new ConcurrentBag<int>(); // Thread safe access

Parallel.For(0, 1000, x => bad.Add(x));
Parallel.For(0, 1000, x => good.Add(x));

结合我们讨论过的两个问题,你能看到以下看似正确的代码会遇到的问题吗?

var counts = new Dictionary<int, int>();
for (int i = 0; i < 1000; ++i)
{
    // How many ways can this fail? One should be enough.
    Task.Factory.StartNew(
        () =>
        {
            counts[i] = GetCounts(i);
        });
}