Task.ContinueWith在任务完成之前触发

时间:2016-08-28 15:28:10

标签: c# async-await .net-4.5

我正在尝试在注册续集后启动任务。但是在调用await Task.Delay()之后会立即触发继续。

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

这里有什么问题?

2 个答案:

答案 0 :(得分:1)

您的问题 - 正如其他人所指出的那样 - 是// should CGContextSetLineCap(context, kCGLineCapRound); // please see the role of line properties why the first should be 0 and the second should be the doulbe of the given line width CGFloat dash[] = {0, lineWidth*2}; // the second value (0) means the span between sets of dot patterns defined by dash array CGContextSetLineDash(context, 0, dash, 2); 无法理解Task.Task代表。正如我在博客中描述的the Task constructor should never be used - 它实际上是用例。

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

另外,你shouldn't use ContinueWith;它是一个极低级别且危险的API(如我的博客所述)。您应该使用Task.Run代替。

await

答案 1 :(得分:0)

使用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

<强>输出:

  

延迟之前
  延迟后   继续与

为什么你的代码不起作用: 看看你的例子(有点修改):

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触发委托的执行并立即继续使用&#34; ContinueWith&#34;代表。 延续连接到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");
}
}