将循环转换为任务
Converting loop to tasks
我有以下同步代码:
foreach ( var step in result ) {
step.Run();
}
我试图将其转换为任务,但没有成功。我尝试像这样使用 Task.WhenAll
转换它(并且我确实将异步附加到方法签名):
var tasks = new List<Task>();
foreach ( var step in result ) {
tasks.Add( new Task( () => step.Run() ) );
}
await Task.WhenAll( tasks );
此 returns 立即执行并且不执行 Run()
方法。然后我尝试将其转换为以下代码:
var tasks = new List<Task>();
foreach ( var step in result ) {
tasks.Add( new Task( () => step.Run() ) );
}
var task = Task.WhenAll( tasks );
task.Wait();
这将永远阻塞。但是,当我在循环中创建它时,它起作用了:
foreach ( var step in result ) {
var t = Task.Run( () => step.Run() );
t.Wait();
}
如果我改用 await Task.Run( () => step.Run() );
它只等待第一个并恢复主线程。
运行 方法如下所示:
public async void Run() {
var result = Work();
if ( null != result && result.Count > 0 ) {
var tasks = new List<Task>();
foreach ( var step in result ) {
await Task.Run( () => step.Run() );
}
}
}
所有步骤都实现一个 Work() 方法(在基础 class 中是抽象的)。我的第一步是这样的:
class NoWorkStep : WorkerStep {
protected override IList<WorkerStep> Work() {
Console.WriteLine( "HERE" );
List<WorkerStep> newList = new List<WorkerStep>();
for ( int i = 0; i < 10; i++ ) {
newList.Add( new NoWorkStep2() );
}
return newList;
}
}
我的第二步是这样的:
class NoWorkStep2 : WorkerStep {
protected override IList<WorkerStep> Work() {
Console.WriteLine( "HERE-2" );
return new List<WorkerStep>();
}
}
我简单地创建了一个 NoWorkStep 实例并调用 instance.Run()
。
使用 Task.WhenAll
执行步骤时我在哪里遇到问题?
编辑: 将 运行 方法更改为 async Task RunAsync
后调用代码:
private static async void doIt() {
var step = new NoWorkStep();
await step.RunAsync();
}
让我们找出代码中的问题:
new Task(() => step.Run())
这 returns 很冷 Task
,这意味着 Task
并未真正启动。为了启动它,您需要调用:
new Task(() => step.Run()).Start)
但是,无论如何你不应该使用 new Task
,你应该使用 Task.Run
。
If I use instead await Task.Run( () => step.Run() ); it awaits only
the first one and resumes the main thread.
那是因为Run
是async void
,无法等待。 async void
仅用于顶级事件处理程序,此处显然不是这种情况。
如果您想等到所有任务完成,您可以执行以下操作:
public async Task RunAsync()
{
var result = Work();
var stepTasks = result.Select(step => Task.Run(() => step.Run()));
await Task.WhenAll(steps);
}
这将保证所有任务在 RunAsync
完成后完成执行。
您似乎没有开始任务。
尝试:
var tasks = new List<Task>();
foreach (var step in result)
{
var t = new Task(() => step.Run());
t.Start();
tasks.Add(t);
}
Task.WhenAll(tasks);
您可以使用 Parallel.ForEach
。
Parallel.ForEach(result, step => step.Run());
这样您甚至不用处理并行框架的较低级别的部分。
我有以下同步代码:
foreach ( var step in result ) {
step.Run();
}
我试图将其转换为任务,但没有成功。我尝试像这样使用 Task.WhenAll
转换它(并且我确实将异步附加到方法签名):
var tasks = new List<Task>();
foreach ( var step in result ) {
tasks.Add( new Task( () => step.Run() ) );
}
await Task.WhenAll( tasks );
此 returns 立即执行并且不执行 Run()
方法。然后我尝试将其转换为以下代码:
var tasks = new List<Task>();
foreach ( var step in result ) {
tasks.Add( new Task( () => step.Run() ) );
}
var task = Task.WhenAll( tasks );
task.Wait();
这将永远阻塞。但是,当我在循环中创建它时,它起作用了:
foreach ( var step in result ) {
var t = Task.Run( () => step.Run() );
t.Wait();
}
如果我改用 await Task.Run( () => step.Run() );
它只等待第一个并恢复主线程。
运行 方法如下所示:
public async void Run() {
var result = Work();
if ( null != result && result.Count > 0 ) {
var tasks = new List<Task>();
foreach ( var step in result ) {
await Task.Run( () => step.Run() );
}
}
}
所有步骤都实现一个 Work() 方法(在基础 class 中是抽象的)。我的第一步是这样的:
class NoWorkStep : WorkerStep {
protected override IList<WorkerStep> Work() {
Console.WriteLine( "HERE" );
List<WorkerStep> newList = new List<WorkerStep>();
for ( int i = 0; i < 10; i++ ) {
newList.Add( new NoWorkStep2() );
}
return newList;
}
}
我的第二步是这样的:
class NoWorkStep2 : WorkerStep {
protected override IList<WorkerStep> Work() {
Console.WriteLine( "HERE-2" );
return new List<WorkerStep>();
}
}
我简单地创建了一个 NoWorkStep 实例并调用 instance.Run()
。
使用 Task.WhenAll
执行步骤时我在哪里遇到问题?
编辑: 将 运行 方法更改为 async Task RunAsync
后调用代码:
private static async void doIt() {
var step = new NoWorkStep();
await step.RunAsync();
}
让我们找出代码中的问题:
new Task(() => step.Run())
这 returns 很冷 Task
,这意味着 Task
并未真正启动。为了启动它,您需要调用:
new Task(() => step.Run()).Start)
但是,无论如何你不应该使用 new Task
,你应该使用 Task.Run
。
If I use instead await Task.Run( () => step.Run() ); it awaits only the first one and resumes the main thread.
那是因为Run
是async void
,无法等待。 async void
仅用于顶级事件处理程序,此处显然不是这种情况。
如果您想等到所有任务完成,您可以执行以下操作:
public async Task RunAsync()
{
var result = Work();
var stepTasks = result.Select(step => Task.Run(() => step.Run()));
await Task.WhenAll(steps);
}
这将保证所有任务在 RunAsync
完成后完成执行。
您似乎没有开始任务。
尝试:
var tasks = new List<Task>();
foreach (var step in result)
{
var t = new Task(() => step.Run());
t.Start();
tasks.Add(t);
}
Task.WhenAll(tasks);
您可以使用 Parallel.ForEach
。
Parallel.ForEach(result, step => step.Run());
这样您甚至不用处理并行框架的较低级别的部分。