并行聚合集合
Parallel Aggregate Collection
我看过基本类型的并行聚合代码,例如
Parallel.For<int>(0, result.Count, () => 0, (i, loop, subtotal) =>
{
subtotal += result[i];
return subtotal;
},
(x) => Interlocked.Add(ref sum, x)
);
我想知道是否有 list/other 集合的等价物,例如:
List<Result> AllResults;
Parallel.ForEach(allIDs, (currentID) =>
{
subList.add(GetResultFor(currentID));
return subList;
},
(x) =>
{
lock(AllResults)
AllResults.AddRange(subList);
};
我猜没有什么比这更漂亮和整洁的了,但我想不出另一种方法,当然不是通过标准 parralel.ForEach 因为我想不出你会怎么说 "this core have this range, this core this range"...
List<Result> AllResults = new List<Result>();
Parallel.ForEach(allIDs, () => new List<Result>(), (id, loopState, subList) =>
{
subList.Add(GetResultFor(id));
return subList;
},
subList =>
{
lock(AllResults)
AllResults.AddRange(subList);
});
我认为在这两个示例中,PLINQ 可以更好地为您服务,并且在使用非线程安全集合时无需手动锁定。
您的求和计算可以转换为:
var sum = result.AsParallel().Sum();
你的第二个例子 List<T>
可以转换为:
List<Result> results = allIDs.AsParallel()
.Select(id => GetResultFor(id))
.ToList();
请注意并行性仅与测试所说的一样好。并行并不总是会加速您的代码,有时它甚至可能会降低顺序循环的性能。
var nums = Enumerable.Range(0, 1000000000);
var parallel = nums.AsParallel();
var mapped = parallel.Select(x => (long) unchecked( x * x));
var sum = mapped.Sum();
Console.WriteLine(sum);
映射 (Select) 总是可以并行发生...reduce (Sum) 也是如此 "sort of"...您可以使用许多工作线程来对所有不同的总和对求和直到剩下 "last" 总和。通常 (90%) 对所有内容进行同步求和会得到最好的结果。
另一个 select 的例子:
IList<IEnumerable<long>> manyNumbers = new List<IEnumerable<long>>();
for (int i = 0; i < 16; i+=2)
{
manyNumbers.Add(Enumerable.Range(2 << i, 2 << (i + 1)).AsParallel().Select(a=> (long)a));
}
var parallel = manyNumbers.AsParallel();
var allPrimes = parallel.SelectMany(sumNums =>
{
IEnumerable<long> somePrimes= sumNums.Where(num =>
{
for (long i = 2; i <= Math.Sqrt(num); i++)
{
if (num % i == 0)
{
return false;
}
}
return true;
}
);
return somePrimes;
}
);
foreach (var number in allPrimes)
{
Console.WriteLine(number);
}
long sumOfPrimes = allPrimes.Sum();
Console.WriteLine(sumOfPrimes);
Console.ReadLine();
这不是一个很好的算法...
我看过基本类型的并行聚合代码,例如
Parallel.For<int>(0, result.Count, () => 0, (i, loop, subtotal) =>
{
subtotal += result[i];
return subtotal;
},
(x) => Interlocked.Add(ref sum, x)
);
我想知道是否有 list/other 集合的等价物,例如:
List<Result> AllResults;
Parallel.ForEach(allIDs, (currentID) =>
{
subList.add(GetResultFor(currentID));
return subList;
},
(x) =>
{
lock(AllResults)
AllResults.AddRange(subList);
};
我猜没有什么比这更漂亮和整洁的了,但我想不出另一种方法,当然不是通过标准 parralel.ForEach 因为我想不出你会怎么说 "this core have this range, this core this range"...
List<Result> AllResults = new List<Result>();
Parallel.ForEach(allIDs, () => new List<Result>(), (id, loopState, subList) =>
{
subList.Add(GetResultFor(id));
return subList;
},
subList =>
{
lock(AllResults)
AllResults.AddRange(subList);
});
我认为在这两个示例中,PLINQ 可以更好地为您服务,并且在使用非线程安全集合时无需手动锁定。
您的求和计算可以转换为:
var sum = result.AsParallel().Sum();
你的第二个例子 List<T>
可以转换为:
List<Result> results = allIDs.AsParallel()
.Select(id => GetResultFor(id))
.ToList();
请注意并行性仅与测试所说的一样好。并行并不总是会加速您的代码,有时它甚至可能会降低顺序循环的性能。
var nums = Enumerable.Range(0, 1000000000);
var parallel = nums.AsParallel();
var mapped = parallel.Select(x => (long) unchecked( x * x));
var sum = mapped.Sum();
Console.WriteLine(sum);
映射 (Select) 总是可以并行发生...reduce (Sum) 也是如此 "sort of"...您可以使用许多工作线程来对所有不同的总和对求和直到剩下 "last" 总和。通常 (90%) 对所有内容进行同步求和会得到最好的结果。
另一个 select 的例子:
IList<IEnumerable<long>> manyNumbers = new List<IEnumerable<long>>();
for (int i = 0; i < 16; i+=2)
{
manyNumbers.Add(Enumerable.Range(2 << i, 2 << (i + 1)).AsParallel().Select(a=> (long)a));
}
var parallel = manyNumbers.AsParallel();
var allPrimes = parallel.SelectMany(sumNums =>
{
IEnumerable<long> somePrimes= sumNums.Where(num =>
{
for (long i = 2; i <= Math.Sqrt(num); i++)
{
if (num % i == 0)
{
return false;
}
}
return true;
}
);
return somePrimes;
}
);
foreach (var number in allPrimes)
{
Console.WriteLine(number);
}
long sumOfPrimes = allPrimes.Sum();
Console.WriteLine(sumOfPrimes);
Console.ReadLine();
这不是一个很好的算法...