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

打印 上一主题 下一主题

主题 1040|帖子 1040|积分 3120

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
TL;DR;

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

(本文由 GPT 辅助撰写)
在.NET中,SortedSet 上的 RemoveWhere 方法本身不支持异步谓词,由于它期望的是一个返回布尔值的同步委托。然而,你可以通过在谓词中使用异步代码来绕过这个限定,使得方法能够在移除元素过程中执行某项异步操作。但在返回结果之前,你需要等待异步操作完成。
下面是一个例子,其中谓词本身是异步的,并在一个同步方法中被等待:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading.Tasks;
  4. class Program
  5. {
  6.     static async Task Main()
  7.     {
  8.         var sortedSet = new SortedSet<int> { 1, 2, 3, 4, 5 };
  9.         Console.WriteLine("RemoveWhere 前: " + string.Join(", ", sortedSet));
  10.         // 异步移除 SortedSet 内的偶数
  11.         int removedCount = await sortedSet.RemoveWhereAsync(IsEvenNumberAsync, CancellationToken.None);
  12.         Console.WriteLine("移除了 " + removedCount + " 个元素");
  13.         Console.WriteLine("RemoveWhere 后: " + string.Join(", ", sortedSet));
  14.     }
  15.     static async ValueTask<bool> IsEvenNumberAsync(int element, CancellationToken token)
  16.     {
  17.         // 模拟一个异步操作,例如网络请求或数据库查询
  18.         await Task.Delay(1000, token);
  19.         return num % 2 == 0; // 返回一个布尔值,表示是否应该移除该元素
  20.     }
  21. }
  22. public static class SortedSetExtension
  23. {
  24.     public static async ValueTask<int> RemoveWhereAsync<T>(this SortedSet<T> sortedSet,
  25.         Func<T, CancellationToken, ValueTask<bool>> asyncPredicate, CancellationToken token)
  26.     {
  27.         ArgumentNullException.ThrowIfNull(asyncPredicate);
  28.         token.ThrowIfCancellationRequested();
  29.         // 由于 SortedSet 不支持遍历过程中移除其中的元素,创建一个等待移除列表来避免 Enumerator 报错
  30.         var elementsToRemove = new List<T>(sortedSet.Count);
  31.         // 异步地评估谓词
  32.         foreach (var element in sortedSet)
  33.         {
  34.             if (await asyncPredicate(element, token)) // 等待异步操作完成
  35.             {
  36.                 elementsToRemove.Add(element); // 如果应该移除,则添加该元素到等待移除中
  37.             }
  38.         }
  39.         // 同步地移除元素
  40.         int actuallyRemoved = 0;
  41.         foreach (var element in elementsToRemove)
  42.         {
  43.             if (sortedSet.Remove(element))
  44.             {
  45.                 actuallyRemoved++;
  46.             }
  47.         }
  48.         return actuallyRemoved;
  49.     }
  50. }
复制代码
在这个例子中:

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

  • 首先,这种方法在异步评估谓词后引入了一个同步阶段(在删除元素时),在数据量较大的环境下不可克制地增加一定的性能开销。
  • 其次,SortedSet 自带的同步方法 RemoveWhere 不在意 Enumerator 的顺序,执行一个广度优先的从左到右的遍历,相较 Enumerator 的遍历效率更高(参考链接),而我们这里的异步方法 RemoveWhereAsync 并没有这类的优化算法,简单地使用 foreach 按照 Enumerator 的顺序,按序遍历。
  • 最后,这种方法在异步评估谓词时仍旧会在遍历每个元素时阻塞,由于我们需要等待每个异步谓词的完成。如果你需要更高效的异步处理,你可能需要考虑使用其他数据结构或并行处理技术。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

络腮胡菲菲

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表