c# - 在多个 IQueryable 上并行运行相同的 linq 查询?

标签 c# linq parallel-extensions

情况:我有一个 List<IQueryable<MyDataStructure>> .我想对它们中的每一个并行运行一个 linq 查询,然后加入结果。

问题:如何创建可以作为参数传递的 linq 查询?

示例代码:

这是一些简化的代码。首先,我收集了 IQueryable<string> :

    public List<IQueryable<string>> GetQueries()
    {
        var set1 = (new List<string> { "hello", "hey" }).AsQueryable();
        var set2 = (new List<string> { "cat", "dog", "house" }).AsQueryable();
        var set3 = (new List<string> { "cat", "dog", "house" }).AsQueryable();
        var set4 = (new List<string> { "hello", "hey" }).AsQueryable();

        var sets = new List<IQueryable<string>> { set1, set2, set3, set4 };

        return sets;
    }

我想找到所有以字母“h”开头的单词。配单IQueryable<string>这很简单:

query.Where(x => x.StartsWith("h")).ToList()

但我想对所有 IQueryable<string> 运行相同的查询并行对象,然后组合结果。这是一种方法:

        var result = new ConcurrentBag<string>();
        Parallel.ForEach(queries, query =>
        {
            var partOfResult = query.Where(x => x.StartsWith("h")).ToList();

            foreach (var word in partOfResult)
            {
                result.Add(word);
            }
        });

        Console.WriteLine(result.Count);

但我希望这是一个更通用的解决方案。这样我就可以单独定义 linq 操作并将其作为参数传递给方法。像这样:

        var query = Where(x => x.FirstName.StartsWith("d") && x.IsRemoved == false)
            .Select(x => x.FirstName)
            .OrderBy(x => x.FirstName);

        var queries = GetQueries();

        var result = Run(queries, query);

但我不知道该怎么做。有什么想法吗?

最佳答案

因此,您首先需要的是一种获取一系列查询、执行所有查询,然后获得扁平化结果列表的方法。这很简单:

public static IEnumerable<T> Foo<T>(IEnumerable<IQueryable<T>> queries)
{
    return queries.AsParallel()
            .Select(query => query.ToList())
            .SelectMany(results => results);
}

对于每个查询,我们执行它(对其调用 ToList)并且它是并行完成的,这要归功于 AsParallel,然后结果通过SelectMany.

您想要做的另一件事是向查询序列中的每个查询添加一些查询操作。这不需要并行化(由于延迟执行,对 WhereOrderBy 等的调用几乎不需要时间)并且可以通过 选择:

var queries = GetQueries().Select(query =>
    query.Where(x => x.FirstName.StartsWith("d")
        && !x.IsRemoved)
    .Select(x => x.FirstName)
    .OrderBy(x => x.FirstName));

var results = Foo(queries);

我个人认为没有必要将这两种方法结合起来。您可以创建一个同时执行这两种操作的方法,但它们实际上是相当独立的概念,因此我认为没有必要这样做。但是,如果您确实希望将它们组合在一起,那就是:

public static IEnumerable<TResult> Bar<TSource, TResult>(
    IEnumerable<IQueryable<TSource>> queries,
    Func<IQueryable<TSource>, IQueryable<TResult>> selector)
{

    return queries.Select(selector)
        .AsParallel()
        .Select(query => query.ToList())
        .SelectMany(results => results);
}

如果需要,请随意制作 FooBar 扩展方法。此外,如果您要使用它们,您真的最好将它们重命名为更好的名称。

关于c# - 在多个 IQueryable 上并行运行相同的 linq 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14758752/

相关文章:

c# - ASP.NET MVC4 多语言数据注解

linq - 如何使用 LINQ to SQL 预先加载同级数据?

c# - Entity Framework 负载排序

c# - 如何在不加载 .dll 的情况下读取程序集 list

c# - XML 序列化程序可以输出空标签吗?

parallel-processing - 这是 PLINQ 错误吗?

c# - 如何在 parallel.for 上传递不同的范围?

vb.net - 从 linq (vb.net 3.5) 中的数据行中选择两个数据列

c# - 为什么我的结果类型为 List<IEnumerable<T>>

linq - lambda 比 linq 查询快吗?