c# - 如何等待稍后开始的任务

标签 c# asynchronous async-await

在我的代码示例中,task2 完成时主线程不会等待。

public async Task Run()
{
    Console.WriteLine("Main start");
    await getTask1();
    Console.WriteLine("Main 2");
    var task2 = getTask2();
    await Task.Delay(1);
    Console.WriteLine("Main 3");
    task2.Start();
    await task2;
    Console.WriteLine("Main end");
}

private async Task getTask1()
{
    Console.WriteLine("task1 start");
    await Task.Delay(100);
    Console.WriteLine("task1 end");
}

private Task getTask2()
{
    return new Task(async () =>
    {
        Console.WriteLine("task2 start");
        await Task.Delay(100);
        Console.WriteLine("task2 end");
    });
}

这段代码的执行结果是

Main start
task1 start
task1 end
Main 2
Main 3
task2 start
Main end
task2 end

如何更改“Main end”位于列表末尾的代码。

最佳答案

getTask2 中,您正在启动一个Task,而该任务又启动另一个Task。因此,当您等待任务时,它会在完成启动内部任务后立即继续执行,而不是当该内部任务启动时>完成。

在这种情况下,您根本没有理由创建一个新任务只是为了首先开始一个新任务;您应该只使用第一种方法中使用的方法。

当然,如果由于某种原因,您确实需要创建一个新的Task只是为了开始一个新任务,那么您需要获取内部任务 并确保 main 方法仅在内部 任务 完成后继续执行。有一个 Unwrap 方法来创建一个 Task,该任务在逻辑上等同于一个 Task,而该 Task 是另一个任务的 Result 任务:

private Task getTask2()
{
    Task<Task> task = new Task<Task>(async () =>
    {
        Console.WriteLine("task2 start");
        await Task.Delay(100);
        Console.WriteLine("task2 end");
    });
    task.Start();
    return task.Unwrap();
}

但你甚至不需要这样做。如果给定一个生成 Task 的 lambda,Task.Run 将自动为您解包该值:

private Task getTask2()
{
    return Task.Run(async () =>
    {
        Console.WriteLine("task2 start");
        await Task.Delay(100);
        Console.WriteLine("task2 end");
    });
}

再次强调,这一切都假设只是启动异步操作就需要卸载到另一个线程,这种情况应该非常罕见。通常这意味着该异步方法存在一个错误,因为在首先向您提供其 Task 之前,它不应该执行长时间运行的同步工作,但有时该方法来自外部您无法控制的库,因此这将是您唯一的选择。

关于c# - 如何等待稍后开始的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39415527/

相关文章:

node.js - 为什么这个 Node 片段没有捕捉到被拒绝的 Promise?

c# - 对象实例内部运行的 main 与纯静态有什么区别?

qt - 如何在 Qt 对话框关闭时终止异步函数

c# - 将 IP 字符串列表排序为具有空白条目的数字

iphone - 对将 Class 方法与具有委托(delegate)的对象一起使用感到困惑

node.js - 为什么等待不适用于 Node 请求模块?

c# - 在异步/等待中取消线程

c# - 异步事件处理程序和并发

c# - DateTime.TryParseExact 将我日期中的月份错误地解析为一月

c# - Azure 表存储位数据类型