Невозможно добавить задачу параллелизма - PullRequest
0 голосов
/ 04 ноября 2019

Как добавить параллелизм задач для этого кода? Я добавил в нескольких местах, но он работает не так, как ожидалось.

class Program
{
    static void Main(string[] args)
    {
        Task.Run(() =>PizzaTask());
    }

    static async void PizzaTask()
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        int totalPizza = 10;
        Console.WriteLine($"Started preparing {totalPizza} pizza");
        for (var x = 1; x <= totalPizza; x++)
        {
            //Task.Run(() => MakePizza(x));
            await MakePizza(x);
        }
        stopwatch.Stop();

        Console.WriteLine($"Finished preparing {totalPizza} pizza");
        Console.WriteLine("Elapsed time: " + stopwatch.Elapsed.TotalSeconds);

    }

    static async Task MakePizza(int n)
    {
        PreparePizza(n);
        await BakePizza(n);
    }

    static void PreparePizza(int n)
    {
        Console.WriteLine("Start preparing pizza " + n);
        Thread.Sleep(5000);// synchronous
        Console.WriteLine("Finished preparing pizza " + n);
    }

    static async Task BakePizza(int n)
    {
        Console.WriteLine("Start baking pizza " + n);
        await Task.Delay(15000); // asynchronous 
        //Thread.Sleep(15000); // synchronous 
        Console.WriteLine("Finished baking pizza " + n);
    }
}

Рабочая версия до этого находится в BakePizza, я установил async await. Но если я установлю асинхронное ожидание для PizzaTask (), это не сработает.

1 Ответ

3 голосов
/ 04 ноября 2019

Я изменил код, чтобы сделать его асинхронным, используя параллельный цикл через var tasks = Enumerable.Range(0, totalPizza).Select(i => MakePizza(i));

  • Приведенный ниже код вызывает MakePizza параллельно, а не последовательно через for (var x = 1; x <= totalPizza; x++) { //Task.Run(() => MakePizza(x)); await MakePizza(x); }

  • Используется Task.Delay вместо Thread.Sleep, чтобы убедиться, что текущий поток не заблокирован.

  • Измените код с async void на aysnc Task. Комбинация async+void может привести к сбою системы и обычно должна использоваться только в обработчиках событий на стороне пользовательского интерфейса.
  • Как уже упоминалось @Steve, используйте ConfigureAwait(false) для возврата в любой доступный поток вместо того, чтобы принудительно возвращать контекствызывающая нить.

Обновленный код:

public class Program
{
    public static void Main()
    {
       PizzaTask().GetAwaiter().GetResult();
    }

    static async Task PizzaTask()
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        int totalPizza = 10;
        Console.WriteLine("Started preparing " + totalPizza + "  pizza");

        var tasks = Enumerable.Range(0, totalPizza).Select(i => MakePizza(i));
        await Task.WhenAll(tasks).ConfigureAwait(false);

        stopwatch.Stop();

        Console.WriteLine("Finished preparing " + totalPizza + "  pizza");
        Console.WriteLine("Elapsed time: " + stopwatch.Elapsed.TotalSeconds);

    }

    static async Task MakePizza(int n)
    {
        await PreparePizza(n).ConfigureAwait(false);
        await BakePizza(n).ConfigureAwait(false);
    }

    static async Task PreparePizza(int n)
    {
        Console.WriteLine("Start preparing pizza " + n);
        await Task.Delay(5000);
        //Thread.Sleep(5000);// synchronous
        Console.WriteLine("Finished preparing pizza " + n);
    }

    static async Task BakePizza(int n)
    {
        Console.WriteLine("Start baking pizza " + n);
        await Task.Delay(15000); // asynchronous 
        //Thread.Sleep(15000); // synchronous 
        Console.WriteLine("Finished baking pizza " + n);
    }
}

Вы можете проверить вывод кода в dotnetfiddle - https://dotnetfiddle.net/HepavC

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...