如何改写方法使字典支持await foreach异步枚举?
问题:将字典返回方法改写为支持await foreach的异步枚举形式
我需要把一个返回字典的方法改成可以用await foreach枚举的形式,当前尝试没有成功,请求帮助。
原方法代码:
public IDictionary<long, long> TransformListInDictionary(IList<string> list) { var result = new Dictionary<long, long>(); foreach (var member in list) { var idx = member.IndexOf(':'); var key = member.Substring(0, idx); var value = member.Substring(idx + 1); result.Add(Convert.ToInt64(key), Convert.ToInt64(value)); } return result; }
目标是让这个方法返回IAsyncEnumerable<KeyValuePair<long,long>>,这样就能用await foreach循环遍历。
需求背景:
我有一段代码,希望foreach循环在后台执行,主流程直接进入for循环的下一次迭代,我理解需要把foreach替换成await foreach,原代码如下:
var logic = new AllLogic(); var variable = Convert.ToInt32(Console.ReadLine()); var randomSecundForPause = new Random(); for (int i = 0; i < variable; i++) { var list = new List<string>(); var dict = logic.TransformListInDictionary(list); //some code foreach (var item in dict) { try { //some code Thread.Sleep(randomSecundForPause.Next(100000, 150000)); } catch (Exception e) { //some code Thread.Sleep(randomSecundForPause.Next(100000, 150000)); } } }
解决方案
1. 改写原方法为异步枚举方法
把原来同步生成字典的逻辑改成逐个返回键值对的异步枚举方法,代码如下:
public async IAsyncEnumerable<KeyValuePair<long, long>> TransformListInDictionaryAsync(IList<string> list) { foreach (var member in list) { var idx = member.IndexOf(':'); var key = member.Substring(0, idx); var value = member.Substring(idx + 1); // 释放当前线程,让后续处理在后台执行(可选,适合耗时的转换操作) await Task.Yield(); yield return new KeyValuePair<long, long>(Convert.ToInt64(key), Convert.ToInt64(value)); } }
- 方法标记为
async,返回IAsyncEnumerable<KeyValuePair<long, long>> - 使用
yield return逐个返回处理后的键值对,避免一次性生成整个字典 await Task.Yield()可以让方法立即返回,后续元素的处理在后台线程进行,适合转换操作较耗时的场景
2. 修改循环逻辑实现后台执行
原代码中的foreach需要改成await foreach,同时把阻塞线程的Thread.Sleep换成异步的Task.Delay,并将整个循环逻辑包装成后台任务,让主流程无需等待即可进入下一次for迭代:
var logic = new AllLogic(); var variable = Convert.ToInt32(Console.ReadLine()); var randomSecundForPause = new Random(); for (int i = 0; i < variable; i++) { var list = new List<string>(); // 调用改写后的异步枚举方法 var asyncItems = logic.TransformListInDictionaryAsync(list); //some code // 将循环逻辑包装成后台任务,主流程不等待其完成 _ = Task.Run(async () => { await foreach (var item in asyncItems) { try { //some code // 异步等待,不阻塞线程 await Task.Delay(randomSecundForPause.Next(100000, 150000)); } catch (Exception e) { //some code await Task.Delay(randomSecundForPause.Next(100000, 150000)); } } }); }
- 使用
await foreach遍历异步枚举的元素 - 用
Task.Delay替代Thread.Sleep,避免阻塞线程,提升并发效率 Task.Run将循环逻辑放到后台线程执行,_ =表示主流程不等待该任务完成,直接进入下一次for迭代
内容的提问来源于stack exchange,提问作者itehnoviking
相关产品推荐
相关产品推荐

