如何启动多个Async<'T>并行执行并逐个等待结果汇报进度?
F#原生Async实现方案
可以通过递归遍历异步任务列表并逐个等待完成的方式,实现并行执行+实时进度汇报,完全基于F#的Async类型,无需依赖Task。
核心思路
- 将所有计算包装为惰性的
Async<'T>,通过Async.StartChild启动所有任务,让它们并行运行 - 递归处理已启动的任务列表,每完成一个任务就立即输出进度,再继续处理剩余任务
完整实现代码
open System // 模拟耗时纯函数 let expensiveComputation x = let rnd = Random() Threading.Thread.Sleep(rnd.Next(1000, 5000)) x * 2 // 启动所有异步任务,返回正在运行的异步句柄列表 let startAllAsync computations = computations |> List.map (fun comp -> async { let! runningTask = Async.StartChild(comp) return runningTask }) // 递归处理任务,实时汇报进度 let rec processTasksAsync remaining completed total = async { match remaining with | [] -> printfn "\n所有任务完成!总计 %d 个" total return [] | task :: rest -> let! result = task let newCompleted = completed + 1 printfn "任务完成:结果=%d,进度 %d/%d" result newCompleted total let! restResults = processTasksAsync rest newCompleted total return result :: restResults } // 主程序示例 let main () = async { let inputs = [1; 2; 3; 4; 5; 6] let totalTasks = inputs.Length // 包装为异步计算 let asyncComputations = inputs |> List.map (fun x -> async { return expensiveComputation x }) // 启动所有并行任务 let runningTasks = startAllAsync asyncComputations // 处理任务并实时输出进度 let! allResults = processTasksAsync runningTasks 0 totalTasks return allResults } // 运行程序 Async.RunSynchronously(main())
关键细节说明
Async.StartChild的作用:Async本身是惰性的,Async.StartChild会立即启动异步任务并返回一个可等待的句柄,确保所有任务并行执行。- 递归处理的优势:不需要等待全部任务完成,每完成一个就立即更新进度,完全符合实时展示的需求。
- 纯F#风格:全程使用F#原生
Async类型和递归模式,没有引入任何C#风格的TaskAPI,保持函数式编程的简洁性。
典型输出效果
任务完成:结果=4,进度 1/6 任务完成:结果=2,进度 2/6 任务完成:结果=6,进度 3/6 任务完成:结果=8,进度 4/6 任务完成:结果=10,进度 5/6 任务完成:结果=12,进度 6/6 所有任务完成!总计 6 个
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

