将循环转换为任务

Sas*_*cha 12 c# asynchronous task-parallel-library async-await c#-5.0

我有以下同步代码:

foreach ( var step in result ) {
  step.Run();
}
Run Code Online (Sandbox Code Playgroud)

我试图将其转换为任务,但我没有这样做.我尝试使用Task.WhenAll这样的方式转换它(我确实将async附加到方法签名):

var tasks = new List<Task>();
foreach ( var step in result ) {
    tasks.Add( new Task( () => step.Run() ) );
}
await Task.WhenAll( tasks );
Run Code Online (Sandbox Code Playgroud)

这会立即返回,不会执行该Run()方法.然后我尝试将其转换为以下代码:

var tasks = new List<Task>();
foreach ( var step in result ) {
    tasks.Add( new Task( () => step.Run() ) );
}
var task = Task.WhenAll( tasks );
task.Wait();
Run Code Online (Sandbox Code Playgroud)

这永远阻止.但是,当我在循环中创建它时,它可以工作:

foreach ( var step in result ) {
    var t = Task.Run( () => step.Run() );
    t.Wait();
}
Run Code Online (Sandbox Code Playgroud)

如果我使用await Task.Run( () => step.Run() );它而只等待第一个并恢复主线程.

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() );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所有步骤都实现了一个Work()方法(在基类中是抽象的).我的第一步看起来像这样:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的第二步看起来像这样:

class NoWorkStep2 : WorkerStep {
    protected override IList<WorkerStep> Work() {
        Console.WriteLine( "HERE-2" );
        return new List<WorkerStep>();
    }
}
Run Code Online (Sandbox Code Playgroud)

我简单地创建一个NoWorkStep实例并调用instance.Run().

我在哪里执行步骤有问题Task.WhenAll

编辑:在我将Run方法更改为async Task RunAsync:之后调用代码:

private static async void doIt() {
  var step = new NoWorkStep();
  await step.RunAsync();
}
Run Code Online (Sandbox Code Playgroud)

Yuv*_*kov 20

让我们用你的代码来解决问题:

new Task(() => step.Run())
Run Code Online (Sandbox Code Playgroud)

这会返回一个寒冷Task,这意味着Task实际上并没有开始.要启动它,您需要致电:

new Task(() => step.Run()).Start)
Run Code Online (Sandbox Code Playgroud)

但是,你不应该使用new Task,你应该使用Task.Run.

如果我使用而不是等待Task.Run(()=> step.Run()); 它只等待第一个并恢复主线程.

这是因为Runasync void不能等待.async void仅适用于顶级事件处理程序,这里显然不是这种情况.

如果要等待所有任务完成,您可以执行以下操作:

public async Task RunAsync() 
{
    var result = Work();
    var stepTasks = result.Select(step => Task.Run(() => step.Run()));
    await Task.WhenAll(steps);
}
Run Code Online (Sandbox Code Playgroud)

这将保证所有任务一旦RunAsync完成就完成执行.


Rag*_*lly 6

你似乎没有开始任务.

尝试:

var tasks = new List<Task>();

foreach (var step in result) 
{
    var t = new Task(() => step.Run());
    t.Start();
    tasks.Add(t);
}

Task.WhenAll(tasks);
Run Code Online (Sandbox Code Playgroud)

  • 只需调用Task.Run,​​就不需要创建一个冷任务只是为了在下一行启动它 (2认同)

jdp*_*nix 6

你可以用Parallel.ForEach.

Parallel.ForEach(result, step => step.Run());
Run Code Online (Sandbox Code Playgroud)

这样你甚至不会使用Parallel Framework的低级部分.

  • 这可行,也许我以此结束,但是aync-await模式也应该有效,我想知道我的错误在哪里. (2认同)