我想同时启动Task
对象的集合,并等待所有步骤完成。以下代码显示了我想要的行为。
public class Program
{
class TaskTest
{
private Task createPauseTask(int ms)
{
// works well
return Task.Run(async () =>
// subsitution: return new Task(async () =>
{
Console.WriteLine($"Start {ms} ms pause");
await Task.Delay(ms);
Console.WriteLine($"{ms} ms are elapsed");
});
}
public async Task Start()
{
var taskList= new List<Task>(new[]
{
createPauseTask(1000),
createPauseTask(2000)
});
// taskList.ForEach(x => x.Start());
await Task.WhenAll(taskList);
Console.WriteLine("------------");
}
}
public static void Main()
{
var t = new TaskTest();
Task.Run(() => t.Start());
Console.ReadKey();
}
}
输出为:
Start 1000 ms pause
Start 2000 ms pause
1000 ms are elapsed
2000 ms are elapsed
------------
现在,我想知道是否可以准备我的任务并分别启动它们。为此,我将createPauseTask(int ms)
方法中的第一行从return Task.Run(async () =>
更改为return new Task(async () =>
,在Start()
方法中,我在taskList.ForEach(x => x.Start());
之前加入了WhenAll
。但是随后发生了可怕的事情。 WhenAll
调用立即完成,输出为:
Start 2000 ms pause
Start 1000 ms pause
------------
1000 ms are elapsed
2000 ms are elapsed
有人可以告诉我我的错误是什么以及如何解决吗?
答案 0 :(得分:6)
问题是您使用的<div>
<h1 id="test-h1">Line height 0, reported height 0:</h1>
<pre id="bounding-rect"></pre>
</div>
构造函数接受p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell = True)
while p.poll() is None:
line = p.stdout.readline()
if "somestring" in line:
functionCall()
委托。当你说
Task
您不是要创建“做事”的任务;相反,您创建了一个任务,该任务执行返回任务的操作,并且那个(内部)任务就是“做事”。创建此(内部)任务非常快,因为委托人在第一个Action
处返回var task = new Task(async () => { /* Do things */ });
,几乎立即完成。由于委托是Task
,因此有效的await
被丢弃,现在不再可以等待。
当您对外部任务调用Action
时,您仅在等待内部任务的创建(几乎立即)。内部任务随后将继续运行。
有一些构造函数重写,可以让您做自己想做的事情,但是语法会像Paulo的回答那样麻烦一些:
Task
您现在有一个执行相同任务的任务,但是这次返回内部await Task.WhenAll(tasks)
。要等待内部任务,您可以执行以下操作:
public static Task<Task> CreatePauseTask(int ms)
{
return new Task<Task>(async () =>
{
Console.WriteLine($"Start {ms} ms pause");
await Task.Delay(ms);
Console.WriteLine($"{ms} ms are elapsed");
});
}
内部等待将返回内部任务的列表,外部等待将等待它们的任务。
但是,也已经提到-使用构造函数创建未启动的任务是您真正应该进入的领域,如果您有一个高度特定的要求,即使用Task
或只是调用任务返回的更标准的做法方法不符合要求(它将在99.99%的时间内完成)。
这些await Task.WhenAll(await Task.WhenAll(taskList));
构造函数中的大多数是在异步等待之前就创建的,并且可能由于传统原因仍然存在。
编辑:这可能还有助于查看2个委托的签名,C#lambda表示法使我们可以(通常很方便)忽略它们。
对于Task.Run()
,我们有
Task
(此处的主要问题是new Task(async () => { /* Do things */ })
。
对于async void Action() { }
,我们有
void
两个lambda在语法上是相同的,但在语义上是不同的。
答案 1 :(得分:2)
我不知道为什么找到Sub
。只是不需要在代码中进行任何使用。
我还想知道您在哪里读到推荐使用void
构造函数。
无论如何,不使用Task.Run
构造函数,将是这样的:
Task
然后输出:
Task
使用class TaskTest
{
private async Task CreatePauseTask(int ms)
{
Console.WriteLine($"Start {ms} ms pause");
await Task.Delay(ms);
Console.WriteLine($"{ms} ms are elapsed");
}
public async Task Start()
{
var taskList = new List<Task>(new[]
{
CreatePauseTask(1000),
CreatePauseTask(2000)
});
await Task.WhenAll(taskList);
Console.WriteLine("------------");
}
}
static void Main()
{
var t = new TaskTest();
t.Start();
Console.ReadKey();
}
构造函数将是:
Start 1000 ms pause
Start 2000 ms pause
1000 ms are elapsed
2000 ms are elapsed
------------
然后输出:
Task
这里的问题是class TaskTest
{
private Task CreatePauseTask(int ms)
{
return new Task<Task>(async () =>
{
Console.WriteLine($"Start {ms} ms pause");
await Task.Delay(ms);
Console.WriteLine($"{ms} ms are elapsed");
}, TaskCreationOptions.DenyChildAttach);
}
public async Task Start()
{
var taskList = new List<Task>(new[]
{
CreatePauseTask(1000),
CreatePauseTask(2000)
});
taskList.ForEach(t => t.Start(TaskScheduler.Default));
await Task.WhenAll(taskList);
Console.WriteLine("------------");
}
}
static void Main()
{
var t = new TaskTest();
t.Start();
Console.ReadKey();
}
理解Start 1000 ms pause
Start 2000 ms pause
------------
1000 ms are elapsed
2000 ms are elapsed
返回的函数,而Task.Run
构造函数却不知道。因此,使用Task
构造函数将调用该函数,该函数将在第一次阻塞等待(Task
)时返回。
这是预期的行为。