Skip to content

C# 多线程 07-使用 PLINQ 06-为 PLINQ 查询创建一个自定义的聚合器

🏷️ 《C# 多线程》

示例代码

csharp
/// <summary>
/// 为 PLINQ 查询创建一个自定义的聚合器
/// 统计集合中所有字母出现的频率
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
    var parallelQuery = from t in GetTypes().AsParallel()
                        select t;

    var parallelAggregator = parallelQuery.Aggregate(
        // 一个工厂类
        () => new ConcurrentDictionary<char, int>(),
        // 每个分区的聚合函数
        (taskTotal, item) => AccumulateLettersInformation(taskTotal, item),
        // 高阶聚合函数
        (total, taskTotal) => MergeAccululators(total, taskTotal),
        // 选择器函数(指定全局对象中我们需要的确切数据)
        total => total);

    Console.WriteLine();
    Console.WriteLine("There were the following letters in type names:");
    // 按字符出现的频率排序
    var orderedKeys = from k in parallelAggregator.Keys
                        orderby parallelAggregator[k] descending
                        select k;
    // 打印聚合结果
    foreach (var c in orderedKeys)
    {
        Console.WriteLine($"Letter '{c}' ---- {parallelAggregator[c]} times");
    }

    Console.ReadLine();
}

static ConcurrentDictionary<char, int> AccumulateLettersInformation(ConcurrentDictionary<char, int> taskTotal, string item)
{
    foreach (var c in item)
    {
        if (taskTotal.ContainsKey(c))
        {
            taskTotal[c] += 1;
        }
        else
        {
            taskTotal[c] = 1;
        }
    }

    Console.WriteLine($"{item} type was aggregated on a thread id {Thread.CurrentThread.ManagedThreadId}");

    return taskTotal;
}

static ConcurrentDictionary<char, int> MergeAccululators(ConcurrentDictionary<char, int> total, ConcurrentDictionary<char, int> taskTotal)
{
    foreach (var key in taskTotal.Keys)
    {
        if (total.ContainsKey(key))
        {
            total[key] += taskTotal[key];
        } else
        {
            total[key] = 1;
        }
    }

    Console.WriteLine("---");
    Console.WriteLine($"Total aggregate value was calculated on a thread in {Thread.CurrentThread.ManagedThreadId}");

    return total;
}

static IEnumerable<string> GetTypes()
{
    var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetExportedTypes());
    return from type in types
            where type.Name.StartsWith("Web")
            select type.Name;
}

执行结果

WebClient type was aggregated on a thread id 1
WebHeaderCollection type was aggregated on a thread id 1
WebPermissionAttribute type was aggregated on a thread id 1
WebExceptionStatus type was aggregated on a thread id 3
WebProxy type was aggregated on a thread id 3
WebException type was aggregated on a thread id 4
WebRequestMethods type was aggregated on a thread id 5
WebUtility type was aggregated on a thread id 5
WebSocket type was aggregated on a thread id 5
WebSocketCloseStatus type was aggregated on a thread id 5
WebSocketContext type was aggregated on a thread id 5
WebResponse type was aggregated on a thread id 4
WebSocketException type was aggregated on a thread id 4
WebSocketMessageType type was aggregated on a thread id 4
WebRequest type was aggregated on a thread id 3
WebSocketState type was aggregated on a thread id 3
WebSocketReceiveResult type was aggregated on a thread id 4
WebSocketError type was aggregated on a thread id 5
WebProxyScriptElement type was aggregated on a thread id 3
WebRequestModuleElement type was aggregated on a thread id 3
WebPermission type was aggregated on a thread id 1
WebRequestModuleElementCollection type was aggregated on a thread id 3
WebUtilityElement type was aggregated on a thread id 5
WebRequestModulesSection type was aggregated on a thread id 4
---
Total aggregate value was calculated on a thread in 1
---
Total aggregate value was calculated on a thread in 1
---
Total aggregate value was calculated on a thread in 1

There were the following letters in type names:
Letter 'e' ---- 78 times
Letter 't' ---- 42 times
Letter 'o' ---- 28 times
Letter 'b' ---- 25 times
Letter 'W' ---- 24 times
Letter 's' ---- 19 times
Letter 'i' ---- 18 times
Letter 'c' ---- 16 times
Letter 'l' ---- 16 times
Letter 'n' ---- 15 times
Letter 'S' ---- 13 times
Letter 'u' ---- 12 times
Letter 'r' ---- 10 times
Letter 'E' ---- 8 times
Letter 'R' ---- 8 times
Letter 'k' ---- 8 times
Letter 'p' ---- 6 times
Letter 'x' ---- 6 times
Letter 'm' ---- 6 times
Letter 'C' ---- 5 times
Letter 'd' ---- 5 times
Letter 'q' ---- 5 times
Letter 'M' ---- 5 times
Letter 'y' ---- 5 times
Letter 'a' ---- 5 times
Letter 'P' ---- 4 times
Letter 'h' ---- 1 times
Letter 'v' ---- 1 times
Letter 'A' ---- 1 times
Letter 'T' ---- 1 times
Letter 'H' ---- 1 times
Letter 'g' ---- 1 times
Letter 'U' ---- 1 times