的任务.ContinueWith在任务完成前触发

本文关键字:任务 ContinueWith | 更新日期: 2023-09-27 18:04:19

我试图在注册延续后启动任务。但是在调用await Task.Delay()之后立即触发continuation。

using System;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApplication30
{
    class Program
    {
        static void Main(string[] args)
        {
            var task = new Task(async delegate {
                Console.WriteLine("Before delay");
                await Task.Delay(1000);
                Console.WriteLine("After delay");
            });
            task.ContinueWith(t => {
                Console.WriteLine("ContinueWith");
            });
            task.Start();
            Console.ReadLine();
        }
    }
}
输出:

Before delay
ContinueWith
After delay

怎么了?

的任务.ContinueWith在任务完成前触发

你的问题-正如其他人所指出的-是Task.Task不理解async代表。正如我在我的博客中所描述的,Task构造函数永远不应该被使用——它实际上有用例。

如果要在线程池线程上运行代码,请使用Task.Run

同样,你不应该使用ContinueWith;它是一个非常低级和危险的API(如我的博客所述)。您应该使用await

class Program
{
    static void Main(string[] args)
    {
        MainAsync().Wait();
    }
    static async Task MainAsync()
    {
        var task = Task.Run(async delegate {
            Console.WriteLine("Before delay");
            await Task.Delay(1000);
            Console.WriteLine("After delay");
        });
        await task;
        Console.WriteLine("await");
        Console.ReadLine();
    }
}

使用Task.Run

void Main()
{
    Task.Run(async()=>{
                Console.WriteLine("Before delay");
                await Task.Delay(1000);
                Console.WriteLine("After delay");
            }).ContinueWith(t => {
                // do somthing with your Task t here
                Console.WriteLine("ContinueWith");
            });
           // task.Start();
            Console.ReadLine();
}
// Define other methods and classes here
输出:

延迟前
延误后
ContinueWith

为什么你的代码不工作:看一下您的示例(稍作修改):

static void Main(string[] args)
{
    var outerTask = new Task(async delegate {
        Console.WriteLine("Before delay");
         await Task.Delay(1000); // inner task
        Console.WriteLine("After delay");
    },"Outertask");
    outerTask.ContinueWith(t => {
        Console.WriteLine("ContinueWith");
    });
    outerTask.Start();
    outerTask.Wait(); // wait for outerTask to finish
    var breakHere = 0; // set a brakpoint here
}

得到一个对outerTask的引用。outerTask和innerTask没有连接。在调用start之后,outerTasks触发委托的执行,并立即继续执行"ContinueWith"委托。延续连接到outerTask!

OP的评论:

我正在尝试创建一个任务,当它从任务列表中删除自己完成。为了安全起见,我需要确保它被添加到列表。我正在尝试做以下事情:创建一个任务,将其添加到列表中,注册删除它的延续,开始这个任务。有没有更好的办法?

虽然下面的代码可以工作,但您必须首先证明其用法!代码没有优化或者其他什么。肯定有更好的模式。做你的调查。

ConcurrentBag<AsyncLazy<Task>> taskList = new ConcurrentBag<AsyncLazy<Task>>();
void Main()
{
    int v = 3242;
    AsyncLazy<Task> objAsyncLazy = null;
    objAsyncLazy = new AsyncLazy<Task>(new Func<Task<Task>>(async () =>
   {
       return await Task.FromResult<Task>(doLongRunningAsync(v).
                    ContinueWith<Task>(async (doLongRunningAsyncCompletedTask) =>
                   {
                       Console.WriteLine(doLongRunningAsyncCompletedTask.IsCompleted); // 
                       await removeMeFromListAsync(objAsyncLazy);
                   }));
   }));
    taskList.Add(objAsyncLazy);
    Console.WriteLine("al added");
    Console.WriteLine("ConcurrentBag.Count: " + taskList.Count);
    // execute the task
    var t = objAsyncLazy.GetValueAsync(System.Threading.CancellationToken.None);
    // wait for the first task "t" to finish or not, 
    // ContinueWith will execute after first task "t" has finished anyways. 
    t.Wait(); 
    // ContinueWith is executing now
    Console.ReadLine();
}
public async Task doLongRunningAsync(int val)
{
    Console.WriteLine("Before delay" + val);
    await Task.Delay(1000);
    Console.WriteLine("After delay");
}
public async Task removeMeFromListAsync(AsyncLazy<Task> al) //(AsyncLazy<Task> t)
{
    Console.WriteLine("continue start");
    taskList.TryTake(out al);
    Console.WriteLine("al removed");
    Console.WriteLine("ConcurrentBag.Count: " + taskList.Count);
    await Task.Delay(1000);
    Console.WriteLine("continue end");
}
}