Как вызвать список задач ‹T› с помощью Parallel

У меня есть список асинхронных вызовов, которые выстроены в определенном порядке, и не имеет значения, какой из них завершится первым или последним. Все эти асинхронные задачи возвращают растровые изображения. Все асинхронные задачи возвращают одно Bitmap accept для одного и возвращает список Bitmaps List.

Для целей тестирования и для того, чтобы я мог лучше понять разницу между использованием Parallel и просто Task, мне нужен кто-то, чтобы показать мне, как вызывать каждую из этих асинхронных задач и устанавливать локальную переменную, которая содержит список всех возвращенных async Результаты.

  1. Как выполнять параллельную работу для каждой из этих задач
  2. Как получить значение каждой выполненной задачи и установить локальную переменную с возвращенным результатом.

--- Код, в котором я просто жду каждую задачу одну за другой.

public async static Task<PdfSharp.Pdf.PdfDocument> RollUpDrawingsPDF(IElevation elevation)
{

    List<Bitmap> allSheets = new List<Bitmap>();

    var processedParts = new PartsProcessor.PartProcessor().ProcessParts(elevation);

    //elevation
    allSheets.Add(await ShopDrawing.Manager.GetElevationDrawing(elevation, true, RotateFlipType.Rotate90FlipNone));

    //door schedules, 3 schedules per sheet
    allSheets.AddRange(await ShopDrawing.Door.GetDoorSecheduleSheets(elevation, RotateFlipType.Rotate90FlipNone, 3));

    //materials list
    allSheets.Add(await MaterialsList.Manager.GetMaterialList(processedParts).GetDrawing());

    //optimized parts
    allSheets.Add(await Optimization.Manager.GetOptimizedParts(processedParts).GetDrawing());

    //cut sheet
    allSheets.Add(await CutSheet.Manager.GetCutSheet(processedParts).GetDrawing());

    return await PDFMaker.PDFManager.GetPDF(allSheets, true);
}

------ Код, который я пытаюсь запустить в Parallel.ForEach, но это не работает, а является отправной точкой для получения помощи. Для каждого возвращенного результата задачи мне нужно установить локальную переменную allSheets этого результата параллельной задачи.

    public async static Task<PdfSharp.Pdf.PdfDocument> RollUpDrawingsPDF(IElevation elevation)
{

    List<Bitmap> allSheets = new List<Bitmap>();

    var processedParts = new PartsProcessor.PartProcessor().ProcessParts(elevation);

    Task[] myTask = new Task[5];
    myTask[0] = ShopDrawing.Manager.GetElevationDrawing(elevation, true, RotateFlipType.Rotate90FlipNone);
    myTask[1] = ShopDrawing.Door.GetDoorSecheduleSheets(elevation, RotateFlipType.Rotate90FlipNone, 3);
    myTask[2] = MaterialsList.Manager.GetMaterialList(processedParts).GetDrawing();
    myTask[3] = Optimization.Manager.GetOptimizedParts(processedParts).GetDrawing();
    myTask[4] = CutSheet.Manager.GetCutSheet(processedParts).GetDrawing();



    var x = Parallel.ForEach(myTask, t => t.Wait());

    ////elevation
    //allSheets.Add(await );

    ////door schedules, 3 schedules per sheet
    //allSheets.AddRange(await);

    ////materials list
    //allSheets.Add(await );

    ////optimized parts
    //allSheets.Add(await );

    ////cut sheet
    //allSheets.Add(await );

    return await PDFMaker.PDFManager.GetPDF(allSheets, true);
}

Как мне реализовать Parallel.ForEach для этого фрагмента кода?

* Пример кода обсуждения. Как вернуть список, когда другие методы возвращают одно растровое изображение *

async Task<Bitmap[]> RollUpHelper(IElevation elevation, PartsProcessor.ProcessedParts       processedParts)
            {
                return await Task<Bitmap[]>.WhenAll(

 ShopDrawing.Manager.GetElevationDrawing(elevation, true, RotateFlipType.Rotate90FlipNone),
                     //ShopDrawing.Door.GetDoorSecheduleSheets(elevation,RotateFlipType.Rotate90FlipNone, 3),
                     MaterialsList.Manager.GetMaterialList(processedParts).GetDrawing(),
                     MaterialsList.Manager.GetMaterialList(processedParts).GetDrawing(),
                     CutSheet.Manager.GetCutSheet(processedParts).GetDrawing()
                      );

            }

person Filling The Stack is What I DO    schedule 07.06.2013    source источник
comment
Вам обязательно нужно использовать async для этого? В противном случае это относительно легко сделать с помощью Parallel.Invoke()   -  person Matthew Watson    schedule 07.06.2013
comment
@MatthewWatson: Если GetDrawing() (правильно) асинхронный, то да.   -  person SLaks    schedule 07.06.2013
comment
@SLaks Я забыл о перегрузке Task.WhenAll(), который возвращает массив результаты - это то, о чем вы, конечно же, говорили.   -  person Matthew Watson    schedule 07.06.2013


Ответы (2)


Parallel.ForEach() предназначен для параллельного выполнения нескольких синхронных операций.

Вы хотите дождаться завершения нескольких асинхронных Task секунд:

await Task.WhenAll(tasks);
person SLaks    schedule 07.06.2013
comment
В любом случае вы могли бы предложить небольшой код, как я устанавливаю локальную переменную allSheets. allSheets - это список ‹Bitmap›. Помните, что одна из задач возвращает список ‹Bitmap›, а другая задача возвращает только одно растровое изображение. - person Filling The Stack is What I DO; 07.06.2013
comment
Означает ли это, что мне нужно будет выполнить цикл myTask [n] и получить результат от каждого из них, а затем добавить его в локальную переменную allSheest? - person Filling The Stack is What I DO; 07.06.2013
comment
Вы можете использовать ConcurrentBag< List<Bitmap> > для хранения возвращенных результатов; он идеален, когда вам нужен только такой неупорядоченный набор. Вы можете написать функцию-оболочку для той, которая возвращает Bitmap, чтобы превратить ее в List<Bitmap> длины 1, чтобы вы также могли сохранить этот результат. Вы можете передать сумку лямбда-выражению для каждой задачи, которая вызывает нужную функцию и помещает ее возвращаемое значение в сумку. - person Matthew Watson; 07.06.2013
comment
@ AlumCloud.Com: await Task.WhenAll(tasks); вернет массив Bitmaps. - person SLaks; 07.06.2013
comment
Проблема с этой реализацией заключается в том, что один из методов возвращает List ‹Bitmap›, а остальные возвращают Bitmap. - person Filling The Stack is What I DO; 07.06.2013
comment
Затем вы можете вызвать неуниверсальные WhenAll(), а затем await задачи по отдельности, чтобы получить результаты. (поскольку await WhenAll() ждали их раньше, более поздние await вернутся немедленно) - person SLaks; 07.06.2013

Чтобы расширить ответ SLaks:

Task.WhenAll() вернет массив всех результатов, возвращенных заданными задачами. for, поэтому вам не нужно управлять этим самостоятельно.

Вот пример, в котором я использую string вместо Bitmap, как в вашем примере. Обратите внимание, как один из рабочих не возвращает List<string>, и я конвертирую его в List<string> с одним элементом, чтобы он был того же типа, что и другие.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    namespace Demo
    {
        class Data
        {
            public string Value;
            public Data(string value) { Value = value; }
        }

        class Program
        {
            async Task<List<string>[]>  RunAsync()
            {
                return await Task.WhenAll
                (
                    Task.Factory.StartNew(() => 
                        new List<string> {Worker1(new Data("One"))}),

                    Task.Factory.StartNew(() => 
                        Worker2(new Data("Two"))),

                    Task.Factory.StartNew(() => 
                        Worker3(new Data("Three")))
                );

            }

            void Run()
            {
                var results = RunAsync().Result;

                // Now results is an array of List<string>, so we can iterate the results.

                foreach (var result in results)
                {
                    result.Print();
                    Console.WriteLine("--------------");
                }
            }

            string Worker1(Data data)
            {
                Thread.Sleep(1000);
                return data.Value;
            }

            List<string> Worker2(Data data)
            {
                Thread.Sleep(1500);
                return Enumerable.Repeat(data.Value, 2).ToList();
            }

            List<string> Worker3(Data data)
            {
                Thread.Sleep(2000);
                return Enumerable.Repeat(data.Value, 3).ToList();
            }

            static void Main()
            {
                new Program().Run();
            }
        }

        static class DemoUtil
        {
            public static void Print(this object self)
            {
                Console.WriteLine(self);
            }

            public static void Print(this string self)
            {
                Console.WriteLine(self);
            }

            public static void Print<T>(this IEnumerable<T> self)
            {
                foreach (var item in self)
                    Console.WriteLine(item);
            }
        }
    }
person Matthew Watson    schedule 07.06.2013
comment
Нет; он спрашивает об асинхронных операциях - person SLaks; 07.06.2013
comment
Вы по-прежнему не используете асинхронность; это зайдет в тупик. - person SLaks; 07.06.2013
comment
@SLaks Упс пропустил асинхронность ... Кажется, теперь все в порядке, я думаю - person Matthew Watson; 07.06.2013
comment
Хорошо, позволь мне попробовать. - person Filling The Stack is What I DO; 07.06.2013
comment
Я обновил свой исходный пост. Есть ли способ вернуть закомментированный код правильно? Сейчас все остальные методы возвращают одно растровое изображение. Прокомментированный код возвращает список ‹Bitmap›. Есть ли способ сделать .ToArray (). - person Filling The Stack is What I DO; 07.06.2013
comment
@ AlumCloud.Com Легко превратить отдельный элемент в список первого размера, но непросто превратить список в один элемент, поэтому не могли бы вы преобразовать все отдельные растровые изображения в списки размера один (как я делаю при вызове Worker1() в моем примере). В результате общий результат будет массивом List<Bitmap>, где некоторые (большинство?) Из List<Bitmap> будут содержать только один элемент. - person Matthew Watson; 07.06.2013