繁体   English   中英

扩展 C# 异步/等待等待不等待

[英]Extending C# async/await await doesn't await

扩展: C# async/await await 不等待

如果顺序执行的方法也存储在列表中,我如何将ExecuteParallelAsync添加到该列表中?

private async Task ExecuteSequential()
{
    List<Action> sequentialMethods = new List<Action>()
    {
        SomeMethod1,
        SomeMethod2,
        await ExecuteParallelAsync, // ???
        SomeMethod3,
        SomeMethod4
    };

    for ( int i = 0 ; i < sequentialMethods.Count ; i++ )
    {
        sequentialMethods.ElementAt( i ).Invoke();
    }
}

澄清:

private async Task ExecuteParallelAsync()
{
    List<Action> methods = new List<Action>()
    {
        MyMethod1,
        MyMethod2,
        MyMethod3
    };


    await Task.Run( () => { Parallel.ForEach( methods , ( currentMethod ) => currentMethod.Invoke() ); } );            
}

sequenceMethodsList< Action >ExecuteParallelAsync不是 Action。 我已经尝试拆分列表,就像建议的那样。 不幸的是,它没有帮助。

Marc 从原始代码中建议的方式工作正常。 但是我想在每次(顺序)方法调用之后做一些额外的事情,这就是为什么我尝试使用列表和循环而不是普通方法调用的原因。

但是当我这样做时,我再次面临原来的问题,即 SomeMethod3 在 ExecuteParallelAsync 完成之前执行。

再一次, ExecuteParallelAsync中的所有内容都可以并且应该同时执行。 ExecuteSequential中的所有内容都必须按顺序执行。

解决方案:

加布里埃尔是绝对正确的。 关键的声明是这个

await Task.Run( () => { Parallel.ForEach( methods , ( currentMethod ) => currentMethod.Invoke() ); } );

当我删除每个异步和每个任务时,以便按顺序执行所有内容,这一行是关键:

Parallel.ForEach( methods , ( currentMethod ) => currentMethod.Invoke() );

当我使用最后一条语句时,一切正常。

感谢大家,你所有的想法、想法和努力都得到了帮助和赞赏。

我再次面临原来的问题,即 SomeMethod3 在 ExecuteParallelAsync 完成之前执行

那么这不是异步编程的用例。 您的要求是这是同步的。

尤其如此,因为您说MyMethod1 / MyMethod2 / MyMethod3不是异步方法。 如果他们是,那将是完全不同的事情 但由于它们不是,我认为在这里尝试使用asyncawait没有任何价值。

但不要将异步与并行混淆。 看来您希望ExecuteParallelAsync中调用的方法并行运行,这很好。 你只是不需要asyncawait

例如:

private void ExecuteSequential()
{
    List<Action> sequentialMethods = new List<Action>()
    {
        SomeMethod1,
        SomeMethod2,
        ExecuteParallel,
        SomeMethod3,
        SomeMethod4
    };

    for ( int i = 0 ; i < sequentialMethods.Count ; i++ )
    {
        sequentialMethods.ElementAt( i ).Invoke();
    }
}

private void ExecuteParallel()
{
    List<Action> methods = new List<Action>()
    {
        MyMethod1,
        MyMethod2,
        MyMethod3
    };

    Parallel.ForEach( methods , ( currentMethod ) => currentMethod.Invoke() );            
}

您可以创建一个Action ,当调用它时将启动任务并等待它完成,如下所示:

List<Action> sequentialMethods = new List<Action>()
{
    SomeMethod1,
    SomeMethod2,
    () => ExecuteParallelAsync().Wait(),
    SomeMethod3,
    SomeMethod4
};

这是一个版本:

private async Task  ExecuteSequential()
{
    var sequentialMethods = new List<Func<Task>>()
    {
        () => Task.Run(SomeMethod1),
        () => Task.Run(() => SomeMethod2("Hey!")), 
        ExecuteParallelAsync, 
        () => Task.Run(SomeMethod3),
        () => Task.Run(SomeMethod4)
    };

    for ( int i = 0 ; i < sequentialMethods.Count ; i++ )
    {
        Task t = sequentialMethods[i].Invoke(); 
        await t;
        // or just await sequentialMethods[i]();
    }
}

只是为了记录, ExecuteSequential可能只是一个标准的异步方法(在顺序执行方面非常好)。

private async Task ExecuteSequential()
{
  SomeMethod1();
  SomeMethod2();
  await ExecuteParallelAsync(); 
  SomeMethod3();
  SomeMethod4();
};

编辑:测试

代码

class Program
{
    public void MyMethod1() => Console.WriteLine("||My1");
    public void MyMethod2() => Console.WriteLine("||My2");
    public void MyMethod3() => Console.WriteLine("||My3");

    private async Task ExecuteParallelAsync()
    {
        Console.WriteLine("||Start");
        List<Action> methods = new List<Action>() { MyMethod1, MyMethod2, MyMethod3 };

        await Task.Run(() => { Parallel.ForEach(methods, 
           (currentMethod) => currentMethod.Invoke()); }); // This could be just 'currentMethod();' (no Invoke())
        Console.WriteLine("||End");
    }


    public void SomeMethod1() => Console.WriteLine("Some1");
    public void SomeMethod2(string s) => Console.WriteLine($"Some2: {s}");
    public void SomeMethod3() => Console.WriteLine("Some3");
    public void SomeMethod4() => Console.WriteLine("Some4");

    private async Task ExecuteSequential()
    {
        var sequentialMethods = new List<Func<Task>>()
        {
           () => Task.Run(SomeMethod1),
           () => Task.Run(() => SomeMethod2("Hey!")),
           ExecuteParallelAsync,
           () => Task.Run(SomeMethod3),
           () => Task.Run(SomeMethod4)
        };

        for (int i = 0; i < sequentialMethods.Count; i++)
        {
            await sequentialMethods[i]();
        }
    }

    static async Task Main(string[] args)
    {
        await new Program().ExecuteSequential();
        Console.WriteLine("All done");
    }
}

Output

Some1
Some2: Hey!
||Start
||My3
||My2
||My1
||End
Some3
Some4
All done

My1My2My3将在执行之间更改顺序,但始终在||Start||End内。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM