推迟执行任务

时间:2015-12-08 06:40:54

标签: c# async-await task-parallel-library

我正在玩任务,我想推迟执行任务。

我是这样的示例方法:

private async Task<bool> DoSomething(string name, int delayInSeconds)
{
    Debug.WriteLine($"Inside task named: {name}");
    await Task.Delay(TimeSpan.FromSeconds(delayInSeconds));
    Debug.WriteLine($"Finishing task named: {name}");
    return true;
}

我想首先创建几个任务,然后执行一些工作,然后运行这些任务。当第Task<bool> myTask = DoSomething("Name", 4);行立即触发任务时,我已经想到了这样的事情:

string[] taskNames = new string[2];

Task<Task<bool>>[] myTasks = new Task<Task<bool>>[2];
myTasks[0] =  new Task<Task<bool>>(async () => await DoSomething(taskNames[0], taskNames[0].Length));
myTasks[1] =  new Task<Task<bool>>(async () => await DoSomething(taskNames[1], taskNames[1].Length));

// I think I can declare it also like this, but this will create tasks later
//IEnumerable<Task<Task<bool>>> myTasks = taskNames.Select(x => new Task<Task<bool>>(async () => await DoSomething(x, x.Length)));

taskNames[0] = "First";
taskNames[1] = "Second";

Debug.WriteLine($"Tasks created");

var results = await Task.WhenAll(myTasks.Select(x => { x.Start(); return x.Unwrap(); }));
Debug.WriteLine($"Finishing: {results.Select(x => x.ToString()).Aggregate((a,b) => a + "," + b) }");

这可以以不同的方式完成,而不包装任务吗?

2 个答案:

答案 0 :(得分:2)

你可以使用Task - 生成代理来简化一些事情:

string[] taskNames = new string[2];

Func<Task<bool>>[] myTasks = new Func<Task<bool>>[2];
myTasks[0] = new Func<Task<bool>>(async () => await DoSomething(taskNames[0], taskNames[0].Length));
myTasks[1] = new Func<Task<bool>>(() => DoSomething(taskNames[1], taskNames[1].Length)); // Shorter version, near-identical functionally.

// I think I can declare it also like this, but this will create tasks later
//IEnumerable<Task<Task<bool>>> myTasks = taskNames.Select(x => new Task<Task<bool>>(async () => await DoSomething(x, x.Length)));

taskNames[0] = "First";
taskNames[1] = "Second";

Debug.WriteLine($"Tasks created");

var results = await Task.WhenAll(myTasks.Select(x => x()));
Debug.WriteLine($"Finishing: {results.Select(x => x.ToString()).Aggregate((a, b) => a + "," + b) }");

警告:当您调用这些委托时,DoSomething将同步执行到第一个await,因此行为类似,但不是完全相同。

或者,基于IEnumerable的解决方案也可以正常运行。只需在启动时编写迭代器方法和yield return任务。

就个人而言,我只是这样做:

string[] taskNames = new string[2];

taskNames[0] = "First";
taskNames[1] = "Second";

var results = await Task.WhenAll(taskNames.Select(n => DoSomething(n, n.Length)));
Debug.WriteLine($"Finishing: {results.Select(x => x.ToString()).Aggregate((a, b) => a + "," + b) }");   

答案 1 :(得分:1)

您的示例中不仅仅是“创建Task”。您正在调用方法DoSomething返回一个Task。假设这些是async方法,Task创建和开始发生在编译器生成的代码的幕后。

解决此问题的方法很简单:在您准备好运行方法之前,请不要调用该方法。想象一下,在任何其他情况下,你所要求的行为是多么令人困惑。