继续代码(ContinueWith)未执行

时间:2020-03-03 14:37:02

标签: c#

我有以下代码,其中延续代码未得到执行。

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Konsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Main starting...");

            Task.Run(async () =>
            {
                await Job1();
            })
            .ContinueWith(async t =>
            {
                await Job2();
            }).Wait();

            Console.WriteLine("Main ending...");
        }

        public static async Task Job1()
        {
            await Task.Run(() =>
            {
                for (int i = 1; i <= 2; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Job1 {i}");
                }
            });
        }

        public static async Task Job2()
        {
            await Task.Run(() =>
            {
                for (int i = 1; i <= 2; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Job2 {i}");
                }
            });
        }
    }
}

控制台输出:

Main starting...
Job1 1
Job1 2
Main ending...

我希望Job2也能在应用程序关闭之前执行。

2 个答案:

答案 0 :(得分:4)

要回答您的问题,您需要从第一个异步调用中“解包”任务,如下所示:

Task.Run(async () =>
         {
           await Job1();
         })
         .ContinueWith(async t =>
         {
           await Job2();
         })
         .Unwrap()
         .Wait();

Unwrap Documentation

不过,这里还有很多其他事情要评论。

如果您正在使用async / await,则应该一直使用它。您的问题没有指定您正在使用哪个版本的C#。如果您使用的是C# 7.1 or above,则应将main方法设为异步方法,如下所示:

public static async Task Main()
{
  Console.WriteLine("Main starting...");
  await Job1();
  await Job2();
  Console.WriteLine("Main ending...");
}

此外,正如@Sean指出的那样,Thread.Sleep在这些情况下不是一个好主意,您应该改用await Task.Delay(1000);Task.Delay Documentation

MSDN上也可以找到一篇不错的文章,其中包含一些异步/等待最佳实践。

答案 1 :(得分:1)

You should not use ContinueWith; it's a dangerous, low-level method。在这种情况下,您会遇到问题,因为ContinueWith无法理解异步委托。

理想情况下,您应将所有对ContinueWith(和Wait)的呼叫替换为await

static async Task Main(string[] args)
{
  Console.WriteLine("Main starting...");

  await Task.Run(async () =>
  {
    await Job1();
  });
  await Job2();

  Console.WriteLine("Main ending...");
}

如果您对变量进行分解以便可以看到类型,则会更加清楚为什么原始代码不起作用:

static async Task Main(string[] args)
{
  Console.WriteLine("Main starting...");

  Task runTask = Task.Run(async () =>
  {
    await Job1();
  });
  Task<Task> continuationTask = runTask.ContinueWith(async t =>
  {
    await Job2();
  });

  // continuationTask is a Task<Task>.
  // This waits for the "outer" task only, not the "inner" task.
  continuationTask.Wait();

  Console.WriteLine("Main ending...");
}