如何直接向接收Action的异步方法传入任意数量的Task或方法
关于任务启动顺序的小问题
你用Task.Run把任务提交给了.NET线程池,线程池的线程调度是系统自动分配的,不会严格按照你调用Task.Run的顺序执行任务。所以哪怕你按a、b、c的顺序调用,线程池也可能先调度Task1,再调度Task3,最后调度Task2,这就导致启动日志的顺序和预期不一样。不过任务的完成顺序还是由Task.Delay的时长决定的,所以最终完成日志是Task1→Task2→Task3,这部分是符合逻辑的。
实现可直接传入方法/任务的异步等待方法
你想要的是不用提前声明Task变量,直接传任意数量的异步方法或已启动Task的方法,以下是具体实现:
方式1:直接接收异步方法(最常用)
这种方式可以直接传入Looping1、Looping2这类异步方法,方法内部会自动启动并等待所有任务完成:
using System; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; public class Task22 : MonoBehaviour { public event Action OnAllTasksCompleted; async void Start() { // 直接传入异步方法,无需提前声明Task变量 await TaskDoneAction(Looping1, Looping2, Looping3); OnAllTasksCompleted?.Invoke(); // 所有任务完成后触发回调 } // 接受任意数量的异步方法(返回Task的方法) async Task TaskDoneAction(params Func<Task>[] taskMethods) { var allTasks = new List<Task>(); foreach (var method in taskMethods) { // 执行异步方法并将返回的Task加入列表 allTasks.Add(method()); } // 等待所有任务完成 await Task.WhenAll(allTasks); Debug.Log("AllTaskDone"); } async Task Looping1() { Debug.Log("StartTask1"); await Task.Delay(1000); Debug.Log("Task1Done"); } async Task Looping2() { Debug.Log("StartTask2"); await Task.Delay(2000); Debug.Log("Task2Done"); } async Task Looping3() { Debug.Log("StartTask3"); await Task.Delay(3000); Debug.Log("Task3Done"); } }
方式2:同时支持已启动Task和异步方法
如果需要兼容已经启动的Task和未执行的异步方法,可以通过类型判断处理:
async Task TaskDoneAction(params object[] tasksOrMethods) { var allTasks = new List<Task>(); foreach (var item in tasksOrMethods) { if (item is Task runningTask) { // 如果是已启动的Task,直接加入列表 allTasks.Add(runningTask); } else if (item is Func<Task> taskMethod) { // 如果是异步方法,执行后加入列表 allTasks.Add(taskMethod()); } else { throw new ArgumentException("参数必须是Task或返回Task的方法"); } } await Task.WhenAll(allTasks); Debug.Log("AllTaskDone"); OnAllTasksCompleted?.Invoke(); } // 使用示例:混合传入已启动Task和异步方法 async void Start() { var preStartedTask = Task.Run(Looping1); await TaskDoneAction(preStartedTask, Looping2, Looping3); }
注意点
- 如果你希望任务在后台线程执行(避免阻塞Unity主线程),可以在异步方法内部用
Task.Run包裹,或者传入时写() => Task.Run(Looping1)。 - Unity中
Start用async void是允许的,但普通异步方法建议用async Task返回值,方便后续等待和错误处理。
内容的提问来源于stack exchange,提问作者aron kan
相关产品推荐
相关产品推荐

