TL;DR;

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

正文

(本文由 GPT 辅助撰写)

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

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

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 的顺序,按序遍历。
  • 最后,这种方法在异步评估谓词时仍然会在遍历每个元素时阻塞,因为我们需要等待每个异步谓词的完成。如果你需要更高效的异步处理,你可能需要考虑使用其他数据结构或并行处理技术。

C# - 能否让 SortedSet.RemoveWhere 内传入的委托异步执行的更多相关文章

  1. 关于Kettle的事务和转换内步骤的顺序执行

    关于Kettle的事务和转换内步骤的顺序执行 近来有项目中遇到Kettle事务处理和转换内步骤顺序执行的问题.为此进行了研究,找到了一个解决办法. 在Kettle中,一个Job内的转换,缺省是顺序执行 ...

  2. [日期工具分享][Shell]为特定命令依次传入顺序日期执行

    [日期工具分享][Shell]为特定命令依次传入顺序日期执行 使用方式: <本脚本文件名(必要时需要全路径)> <要执行的命令所在的文件名> <开始日期> < ...

  3. 一键帮你复制多个文件到多个机器——PowerShell小脚本(内附PS远程执行命令问题解析)

    作为一个后台程序猿,经常需要把一堆程序集(DLL)或者应用程序(EXE)复制到多个服务器上,实现程序的代码逻辑更新,用以测试新的功能或改动逻辑.这里给大家介绍一个自己实现的PowerShell脚本,方 ...

  4. JSP第四篇【EL表达式介绍、获取各类数据、11个内置对象、执行运算、回显数据、自定义函数、fn方法库】

    什么是EL表达式? 表达式语言(Expression Language,EL),EL表达式是用"${}"括起来的脚本,用来更方便的读取对象! EL表达式主要用来读取数据,进行内容的 ...

  5. C#使用进程调用bash,不断往bash内插入命令并执行

    呃呃呃,遇到了一个非常恶心得问题,现在就是,有几十万条数据需要当作参数调用python脚本 一次一次输入命令过去缓慢,经过了多层考虑决定使用进程来解决(不知道线程怎么开启bash得) 原理非常简单,类 ...

  6. C#实现简单的委托异步调用

    delegate void textAsy(); static void Main(string[] args) { textAsy t = texts; AsyncCallback callBack ...

  7. JavaScript使用浏览器内置XMLHttpRequest对象执行Ajax请求

    所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject).XMLHttpRequest 用于在后台与服务器交换数据.这意味着可以在不重新加载整个 ...

  8. 关于always块内for循环的执行方式

    //该模块主要用来说明for结构在时序逻辑中的执行方式 :] eq_dly ); integer i; 'b1; always @(posedge clk_1 or negedge nrst) beg ...

  9. Jquery 循环内间隔执行 异步执行

    <script type="text/javascript"> var arr = new Array(); var arrk = 0; jQuery(function ...

  10. (testng多个class文件执行时混乱,不是等一个class内的所有methods执行完再去执行下一个class内的内容)问题的解决

    问题描述如下: We use TestNG and Selenium WebDriver to test our web application. Now our problem is that we ...

随机推荐

  1. 纯前端实现 JPG 图片压缩 | canvas

    在线 Demo 体验地址 →: https://demos.sugarat.top/pages/jpg-compress/ 前言 在迭代图床应用时,需要用到图片压缩,在之前分享了使用 UPNG.js ...

  2. 【Spring注解驱动开发】你敢信?面试官竟然让我现场搭建一个AOP测试环境!

    写在前面 今天是9月1号,金九银十的跳槽黄金期已拉开序幕,相信很多小伙伴也在摩拳擦掌,想换一个新的工作环境.然而,由于今年疫情的影响,很多企业对于招聘的要求是越来越严格.之前,很多不被问及的知识点,最 ...

  3. zynq之TF卡写入函数f_printf

    zynq之TF卡写入函数f_printf 1.基本原理 前面使用f_write写入了数据到TF(SD)卡中,可以实现较短字符串的写入.当字符增加时,容易出现乱码.而f_printf则是专门用于字符串写 ...

  4. 安卓AlertDialog对话面板的使用---Android开发

    1 AlertDialog.Builder builder=new AlertDialog.Builder(this); 2 builder.setTitle("历史记录").se ...

  5. C++一些例子

    虚析构 #include<iostream> class Base { public: Base() { std::cout << "base 构造" &l ...

  6. OpenHarmony创新赛 | 赛事宣讲会日期重磅官宣!为你带来超详尽的赛事攻略

      最近接到很多小伙伴私信提问,比如如何报名开放原子开源大赛OpenAtom OpenHarmony(简称:"OpenHarmony")创新赛?有哪些赛题可以报名参赛?现在,赛事宣 ...

  7. 玩转OpenHarmony智能家居:如何实现树莓派“碰一碰”设备控制

    一.简介 "碰一碰"设备控制,依托NFC短距通信协议,通过碰一碰的交互方式,将OpenAtom OpenHarmony(简称"OpenHarmony")标准系统 ...

  8. 深究可见性,原子性,有序性的解决方案之volatile源码解析

    上节java内存模型(jmm)概念初探大致了解了由于cpu的快速发展,导致的越来越复杂的内存模型诞生,java内存模型相当于是底层内存模型的映射(实际并不是一一映射,但可以借鉴理解),也是衍生出并发三 ...

  9. 华为运动健康服务Health Kit 6.10.0版本新增功能速览!

    华为运动健康服务(HUAWEI Health Kit)6.10.0 版本新增的能力有哪些? 阅读本文寻找答案,一起加入运动健康服务生态大家庭! 一. 支持三方应用查询用户测量的连续血糖数据 符合申请H ...

  10. MogDB/OpenGauss数据库中通过参数控制抓取慢sql

    MogDB/OpenGauss 数据库中通过参数控制抓取慢 sql 本文出处:https://www.modb.pro/db/221556 mogdb 数据库中可以通过打开相应的参数抓取慢 sql,该 ...