You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何直接向接收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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 17:31:57