C# - 能否让 SortedSet.RemoveWhere 内传入的委托异步执行

TL;DR;

若想充分利用 RemoveWhere 带来的性能优势,建议传入判断是否删除元素的委托内采取同步操作。若一定要在该委托内使用异步操作,可以采用本文中绕行的方法,但摈弃了 RemoveWhere 所带来的性能优势。

正文

(本文由 GPT 辅助撰写)

在.NET中,SortedSet<T> 上的 RemoveWhere 方法本身不支持异步谓词,因为它期望的是一个返回布尔值的同步委托。然而,你可以通过在谓词中使用异步代码来绕过这个限制,使得方法能够在移除元素过程中执行某项异步操作。但在返回结果之前,你需要等待异步操作完成。

下面是一个例子,其中谓词本身是异步的,并在一个同步方法中被等待:

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var sortedSet = new SortedSet<int> { 1, 2, 3, 4, 5 };

        Console.WriteLine("RemoveWhere 前: " + string.Join(", ", sortedSet));

        // 异步移除 SortedSet 内的偶数
        int removedCount = await sortedSet.RemoveWhereAsync(IsEvenNumberAsync, CancellationToken.None);

        Console.WriteLine("移除了 " + removedCount + " 个元素");
        Console.WriteLine("RemoveWhere 后: " + string.Join(", ", sortedSet));
    }

    static async ValueTask<bool> IsEvenNumberAsync(int element, CancellationToken token)
    {
        // 模拟一个异步操作,例如网络请求或数据库查询
        await Task.Delay(1000, token);
        return num % 2 == 0; // 返回一个布尔值,表示是否应该移除该元素
    }
}

public static class SortedSetExtension
{
    public static async ValueTask<int> RemoveWhereAsync<T>(this SortedSet<T> sortedSet,
        Func<T, CancellationToken, ValueTask<bool>> asyncPredicate, CancellationToken token)
    {
        ArgumentNullException.ThrowIfNull(asyncPredicate);
        token.ThrowIfCancellationRequested();

        // 由于 SortedSet 不支持遍历过程中移除其中的元素,创建一个等待移除列表来避免 Enumerator 报错
        var elementsToRemove = new List<T>(sortedSet.Count);

        // 异步地评估谓词
        foreach (var element in sortedSet)
        {
            if (await asyncPredicate(element, token)) // 等待异步操作完成
            {
                elementsToRemove.Add(element); // 如果应该移除,则添加该元素到等待移除中
            }
        }

        // 同步地移除元素
        int actuallyRemoved = 0;
        foreach (var element in elementsToRemove)
        {
            if (sortedSet.Remove(element))
            {
                actuallyRemoved++;
            }
        }
        return actuallyRemoved;
    }
}

在这个例子中:

  • IsEvenNumberAsync 方法模拟了一个异步操作。
  • RemoveWhereAsync 方法接收一个异步谓词,并对其进行评估,针对 SortedSet 中的每个元素。
  • 在循环内部等待异步谓词的结果。
  • 将要删除的元素收集到一个单独的列表中。
  • 在评估所有元素之后,将从 SortedSet 中删除收集到的元素。

请注意:

  • 首先,这种方法在异步评估谓词后引入了一个同步阶段(在删除元素时),在数据量较大的情况下不可避免地增加一定的性能开销。
  • 其次,SortedSet 自带的同步方法 RemoveWhere 不在意 Enumerator 的顺序,执行一个广度优先的从左到右的遍历,相较 Enumerator 的遍历效率更高(参考链接),而我们这里的异步方法 RemoveWhereAsync 并没有这类的优化算法,简单地使用 foreach 按照 Enumerator 的顺序,按序遍历。
  • 最后,这种方法在异步评估谓词时仍然会在遍历每个元素时阻塞,因为我们需要等待每个异步谓词的完成。如果你需要更高效的异步处理,你可能需要考虑使用其他数据结构或并行处理技术。
相关推荐
大飞pkz24 分钟前
【设计模式】C#反射实现抽象工厂模式
设计模式·c#·抽象工厂模式·c#反射·c#反射实现抽象工厂模式
唐青枫2 小时前
从入门到进阶:C#.NET Stopwatch 计时与性能测量全攻略
c#·.net
私人珍藏库3 小时前
[Windows] 微软 .Net 运行库离线安装包 | Microsoft .Net Packages AIO_v09.09.25
microsoft·.net·运行库
未来之窗软件服务11 小时前
幽冥大陆(二)RDIFSDK 接口文档:布草洗涤厂高效运营的技术桥梁C#—东方仙盟
开发语言·c#·rdif·仙盟创梦ide·东方仙盟
1uther12 小时前
Unity核心概念⑨:Screen
开发语言·游戏·unity·c#·游戏引擎
追逐时光者13 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 54 期(2025年9.8-9.14)
后端·.net
追逐时光者13 小时前
C#/.NET/.NET Core编程技巧练习集,配套详细的文章教程讲解!
后端·.net
阿幸软件杂货间13 小时前
Office转PDF转换器v1.0.py
开发语言·pdf·c#
sali-tec13 小时前
C# 基于halcon的视觉工作流-章34-环状测量
开发语言·图像处理·算法·计算机视觉·c#
Tiger_shl14 小时前
【层面一】C#语言基础和核心语法-02(反射/委托/事件)
开发语言·c#