C# 让两个需要循环顺序执行的函数进行异步交叉执行,提高执行速度
有的时候我们需要让2个函数按照顺序循环执行,比如将数据库的数据写到硬盘上,
我们很容易就想到让他们异步执行,避免阻塞,但是为了保证数据的顺序一致,我们又需要整个队列来存放数据,感觉比较麻烦,
今天研究了下,通过异步和信号量控制实现了两个函数异步交叉执行的效果
internal class Tester { int num = 0; readonly int time_getData = 2000; readonly int time_processData = 1000; public async Task Test() { await Task.CompletedTask; Stopwatch sw = new Stopwatch(); sw.Start(); StartCrossLoopTask(GetData, ProcessData); sw.Stop(); var max = (new[] { time_getData, time_processData }).Max(); var r1 = time_getData + time_processData + max * (num - 1); //除了第一包,后面的都是异步交叉的 var r2 = (time_getData + time_processData) * num; //同步执行会阻塞 Console.WriteLine($"实际执行{sw.ElapsedMilliseconds},预估{r1},如果同步执行{r2}"); } string GetData() { if (num > 10) return null; //控制退出 Thread.Sleep(time_getData); //模拟读数据 string data = num.ToString(); Log.Info($"读取数据:{data}"); num++; return data; } void ProcessData(string data) { Thread.Sleep(time_processData); //模拟处理数据 Log.Info($" 处理数据:{data}"); } /// <summary> /// 开启一个交叉循环任务,这是一个循环任务,先getData获取数据,再processData处理数据,直到getData返回null, /// 该函数通过异步和信号量控制,实现了在processData的同时异步getData下一包数据,这样交叉执行,提高了性能 /// </summary> public static void StartCrossLoopTask<T>(Func<T> getData, Action<T> processData) where T : class { Semaphore semaphore1 = new Semaphore(1, 1); //获取数据的信号量 Semaphore semaphore2 = new Semaphore(0, 1); //处理数据的信号量 T data = null; //接收数据的引用 Task.Run(() => { //异步执行,实现非阻塞 while (true) { semaphore1.WaitOne(); //通过信号量控制顺序,保证最多提前获取一包数据,避免不可控的数据堆叠 data = getData(); semaphore2.Release(); //获取到数据后通知处理函数 if (data == null) return; //没有数据时就认为结束了 } }); T temp = null; //处理数据的引用 while (true) { semaphore2.WaitOne(); //阻塞,等待数据 if (data == null) return; //这里也得判断退出,否则会卡死 temp = data; //将数据指向临时引用,避免引用被覆盖 semaphore1.Release(); //释放信号量,处理的同时并行获取下一包数据,实现非阻塞 processData(temp); //处理当前包数据 } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~