C# 如何并行运行LINQ“let”语句?
我有这样的代码:C# 如何并行运行LINQ“let”语句?,c#,plinq,let,C#,Plinq,Let,我有这样的代码: var list = new List<int> {1, 2, 3, 4, 5}; var result = from x in list.AsParallel() let a = LongRunningCalc1(x) let b = LongRunningCalc2(x) select new {a, b}; 假设LongRunningCalc方法每个都需要1秒。上面的代码运行大约
var list = new List<int> {1, 2, 3, 4, 5};
var result = from x in list.AsParallel()
let a = LongRunningCalc1(x)
let b = LongRunningCalc2(x)
select new {a, b};
假设LongRunningCalc方法每个都需要1秒。上面的代码运行大约需要2秒钟,因为当5个元素的列表并行运行时,从let语句调用的两个方法被顺序调用
然而,这些方法也可以安全地并行调用。它们显然需要为select重新合并,但在此之前应该并行运行—select应该等待它们
有没有办法做到这一点?您将无法使用查询语法或let操作,但您可以编写一个方法来并行执行每个项的多个操作:
public static ParallelQuery<TFinal> SelectAll<T, TResult1, TResult2, TFinal>(
this ParallelQuery<T> query,
Func<T, TResult1> selector1,
Func<T, TResult2> selector2,
Func<TResult1, TResult2, TFinal> resultAggregator)
{
return query.Select(item =>
{
var result1 = Task.Run(() => selector1(item));
var result2 = Task.Run(() => selector2(item));
return resultAggregator(result1.Result, result2.Result);
});
}
您还可以为其他并行操作添加重载:
public static ParallelQuery<TFinal> SelectAll<T, TResult1, TResult2, TResult3, TFinal>
(this ParallelQuery<T> query,
Func<T, TResult1> selector1,
Func<T, TResult2> selector2,
Func<T, TResult3> selector3,
Func<TResult1, TResult2, TResult3, TFinal> resultAggregator)
{
return query.Select(item =>
{
var result1 = Task.Run(() => selector1(item));
var result2 = Task.Run(() => selector2(item));
var result3 = Task.Run(() => selector3(item));
return resultAggregator(
result1.Result,
result2.Result,
result3.Result);
});
}
可以编写一个版本来处理编译时未知的多个选择器,但要做到这一点,它们都需要计算相同类型的值:
public static ParallelQuery<IEnumerable<TResult>> SelectAll<T, TResult>(
this ParallelQuery<T> query,
IEnumerable<Func<T, TResult>> selectors)
{
return query.Select(item => selectors.AsParallel()
.Select(selector => selector(item))
.AsEnumerable());
}
public static ParallelQuery<IEnumerable<TResult>> SelectAll<T, TResult>(
this ParallelQuery<T> query,
params Func<T, TResult>[] selectors)
{
return SelectAll(query, selectors);
}
我会在NuGet中使用微软的反应式框架Rx Main来实现这一点 这是:
var result =
from x in list.ToObservable()
from a in Observable.Start(() => LongRunningCalc1(x))
from b in Observable.Start(() => LongRunningCalc2(x))
select new {a, b};
很好的一点是,您可以在使用.Subscribe。。。方法:
超级简单 这不是我的专业领域,但你不需要等待任务的结果吗?是的,正在呼叫。结果等待任务执行。我将示例代码简化了一点,但这使我走上了正确的道路,谢谢您的帮助。
var result =
from x in list.ToObservable()
from a in Observable.Start(() => LongRunningCalc1(x))
from b in Observable.Start(() => LongRunningCalc2(x))
select new {a, b};
result.Subscribe(x => /* Do something with x.a and/or x.b */ );