在使用任务并行库时得到奇怪的结果
本文关键字:结果 任务 并行 | 更新日期: 2023-09-27 18:04:07
我正在尝试使用TPL做一些过滤器任务。这里我将代码简化为根据条件过滤数字。下面是代码。
public static void Main (string[] args)
{
IEnumerable<int> allData = getIntData ();
Console.WriteLine ("Complete Data display");
foreach (var item in allData) {
Console.Write(item);
Console.Write(" | ");
}
Console.WriteLine ();
filterAllDatas (ref allData, getConditions ());
foreach (var item in allData) {
Console.Write(item);
Console.Write(" | ");
}
Console.WriteLine ();
}
static void filterAllDatas(ref IEnumerable<int> data, IEnumerable<Func<int,bool>> conditions)
{
List<int> filteredData = data.ToList ();
List<Task> tasks = new List<Task>();
foreach (var item in data.AsParallel()) {
foreach (var condition in conditions.AsParallel()) {
tasks.Add(Task.Factory.StartNew(() => {
if (condition(item)) {
filteredData.Remove(item);
}
}));
}
}
Task.WaitAll(tasks.ToArray());
data = filteredData.AsEnumerable ();
}
static IEnumerable<Func<int,bool>> getConditions()
{
yield return (a) => { Console.WriteLine("modulo by 2"); return a % 2 == 0;};
yield return (a) => { Console.WriteLine("modulo by 3"); Thread.Sleep(3000); return a % 3 == 0;};
}
static IEnumerable<int> getIntData ()
{
for (int i = 0; i < 10; i++) {
yield return i;
}
}
在这里,它是一个简单的代码来过滤掉除以2或3的整数。现在,如果我删除这个线程,睡眠代码工作得很好,但如果我把它不是。
通常表示没有线程。睡眠,两个条件执行10次,例如对每个数字。但是如果我添加线程。睡眠第一种情况执行7次,第二种情况执行13次。因此,很少有人跳过这个条件。我试着调试,但没有得到任何可以指出我的代码问题。
有什么好的方法可以做到这一点吗?如过滤条件下的数据可以异步和并行工作,以提高性能?
代码仅供演示。
仅供参考:目前我在windows机器上使用Xamarine studio的Mono。
如果需要进一步的细节,请告诉我。我猜这与你的任务的lambda在循环变量condition
上关闭的方式有关。试着这样修改:
foreach (var condition in conditions.AsParallel()) {
var tasksCondition = condition
tasks.Add(Task.Factory.StartNew(() => {
if (tasksCondition(item)) {
filteredData.Remove(item);
}
}));
注意,您还关闭了循环变量item
,这可能导致类似的问题。
首先你可以改变getConditions方法,看看里面发生了什么:
static IEnumerable<Func<int, bool>> getConditions()
{
yield return (a) => { Console.WriteLine(a + " modulo by 2"); return a % 2 == 0; };
yield return (a) => { Console.WriteLine(a + " modulo by 3"); Thread.Sleep(3000); return a % 3 == 0; };
}
如果你停止捕获foreach的变量,它将工作:
static void filterAllDatas(ref IEnumerable<int> data, IEnumerable<Func<int, bool>> conditions)
{
List<int> filteredData = data.ToList();
List<Task> tasks = new List<Task>();
foreach (var item in data.AsParallel())
{
var i = item;
foreach (var condition in conditions.AsParallel())
{
var c = condition;
tasks.Add(Task.Factory.StartNew(() =>
{
if (c(i))
{
filteredData.Remove(i);
}
}));
}
}
Task.WaitAll(tasks.ToArray());
data = filteredData.AsEnumerable();
}