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 */ );