Расширение C # async / await await не ждет - PullRequest
0 голосов
/ 18 октября 2019

Расширение: 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() ); } );            
}

sequentialMethods это Список <<em> Действие> , но ExecuteParallelAsync НЕ является действием. Я попытался разделить список, как предложено. К сожалению, это не помогает.

Способ, предложенный Марком из исходного кода, работает нормально. Но я хочу сделать некоторые дополнительные вещи после каждого (последовательного) вызова метода, поэтому я пытаюсь использовать список и цикл вместо простых вызовов методов.

Но когда я делаю это, я 'Я снова сталкиваюсь с исходной проблемой, что SomeMethod3 выполняется до завершения ExecuteParallelAsync.

Еще раз, все в ExecuteParallelAsync может и должно выполняться одновременно. Все в ExecuteSequential должно выполняться последовательно.

Решение:

Габриэль абсолютно прав. Важным утверждением является следующее:

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

Когда я удаляю каждую асинхронную и каждую задачу, чтобы все, что должно выполняться, выполнялось последовательно, эта строка является ключом:

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

Когда яиспользуйте это последнее утверждение, все работает правильно.

Спасибо всем, все ваши идеи, мысли и усилия помогли и приветствуются.

Ответы [ 3 ]

2 голосов
/ 18 октября 2019

Я снова сталкиваюсь с исходной проблемой, что SomeMethod3 выполняется до завершения ExecuteParallelAsync

Тогда это не вариант использования для асинхронного программирования. Ваше требование заключается в том, что это синхронно.

Это особенно верно, поскольку вы сказали, что MyMethod1 / MyMethod2 / MyMethod3 не являются асинхронными методами. Если бы они были, это была бы совершенно другая вещь . Но поскольку это не так, я не вижу смысла в попытках использовать async и await здесь.

Но не путайте асинхронность с параллелью. Кажется, вы хотите, чтобы методы, вызываемые в ExecuteParallelAsync, выполнялись параллельно, это нормально. Вам просто не нужно async и await.

Например:

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() );            
}
0 голосов
/ 18 октября 2019

Вот версия:

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");
    }
}

Выход

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

My1, My2 иMy3 меняет порядок между исполнениями, но всегда в пределах ||Start и ||End.

0 голосов
/ 18 октября 2019

Вы можете создать Action, который при вызове запустит задачу и будет ждать ее завершения, например:

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