为什么我在下面的代码部分得到不同的结果
代码示例1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ThreadLocalTasks
{
class Program
{
static void Main(string[] args)
{
ThreadLocal<int> aggregrations = new ThreadLocal<int>();
Task<int>[] tasks = new Task<int>[10];
for (int i = 0; i < tasks.Length; i++)
{
aggregrations.Value = 0;
int tempi = i;
tasks[tempi] = new Task<int>(() =>
{
int temp = 0;
for (int j = 1; j <= 3; j++)
{
temp += j;
}
aggregrations.Value = temp;
return aggregrations.Value;
});
}
tasks.ToList().ForEach(x => {
x.Start();
});
Task.WaitAll(tasks);
int sum = 0;
tasks.ToList().ForEach(x =>
{
sum += x.Result;
});
Console.WriteLine("Sum: {0}", sum);
Console.WriteLine("Press any key to quit..");
Console.ReadKey();
}
}
}
样本2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ThreadLocalTasks
{
class Program
{
static void Main(string[] args)
{
ThreadLocal<int> aggregrations = new ThreadLocal<int>();
Task<int>[] tasks = new Task<int>[10];
for (int i = 0; i < tasks.Length; i++)
{
aggregrations.Value = 0;
int tempi = i;
tasks[tempi] = new Task<int>(() =>
{
for (int j = 1; j <= 3; j++)
{
aggregrations.Value += j;
}
return aggregrations.Value;
});
}
tasks.ToList().ForEach(x => {
x.Start();
});
Task.WaitAll(tasks);
int sum = 0;
tasks.ToList().ForEach(x =>
{
sum += x.Result;
});
Console.WriteLine("Sum: {0}", sum);
Console.WriteLine("Press any key to quit..");
Console.ReadKey();
}
}
}
答案 0 :(得分:1)
为什么你甚至试图在这里使用ThreadLocal
存储而不仅仅是在Task中使用局部变量?任务并行库可能会重用一个线程来执行多个任务,并且您的线程本地存储将被覆盖。在第一个例子中,它可能有效,因为每次重用线程时你都没有重置它,但这样会更好:
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = new Task<int>(() =>
{
int sum = 0;
for (int j = 1; j <= 3; j++)
{
sum += j;
}
return sum;
});
}
解释您的代码实际执行的操作:
在第一个示例中,您在启动线程上将单个线程本地值初始化为0,但是您多次执行此操作(显然不是通过将初始化放在for循环中而不是您想要的 - 错误#1)。你积累在一个好的任务局部变量中,然后你用结果覆盖线程局部值,即使该线程局部值可以在顺序执行的多个任务之间共享(例如每个核心一个线程) - bug#2。这将导致某些任务共享相同的线程本地值。错误#3:当你返回线程局部值时,你会很幸运,因为它与temp相同,没有其他线程可以改变它,因此它等同于在任务中使用局部变量。
在您的第二个示例中,您在初始化时犯了同样的错误。但是你继续重复计算值,因为线程本地值没有在每个任务的开始重置,所以如果两个任务在同一个线程上运行,第一个可能返回1 + 2 + 3而第二个可能返回6 + 1 + 2 + 3。