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