Вызов метода асинхронного синхронного метода

Я пытаюсь запустить асинхронные методы из синхронного метода. Но я не могу ждать асинхронного метода, так как я синхронно. Я не должен понимать TPL, поскольку это первый раз, когда я его использую.

private void GetAllData()
{
    GetData1()
    GetData2()
    GetData3()
}

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

Однако внутри каждого метода я хочу запустить несколько операций Task, чтобы ускорить работу. Затем я хочу подождать, пока все они закончатся.

GetData1 выглядит следующим образом

    internal static void GetData1 ()
    {
        const int CONCURRENCY_LEVEL = 15; 
        List<Task<Data>> dataTasks = new List<Task<Data>>();
        for (int item = 0; item < TotalItems; item++)
        {
            dataTasks.Add(MyAyncMethod(State[item]));
        }
        int taskIndex = 0;
        //Schedule tasks to concurency level (or all)
        List<Task<Data>> runningTasks = new List<Task<Data>>();
        while (taskIndex < CONCURRENCY_LEVEL && taskIndex < dataTasks.Count)
        {
            runningTasks.Add(dataTasks[taskIndex]);
            taskIndex++;
        }

        //Start tasks and wait for them to finish
        while (runningTasks.Count > 0)
        {
            Task<Data> dataTask = await Task.WhenAny(runningTasks);
            runningTasks.Remove(dataTask);
            myData = await dataTask;


            //Schedule next concurrent task
            if (taskIndex < dataTasks.Count)
            {
                runningTasks.Add(dataTasks[taskIndex]);
                taskIndex++;
            }
        }
        Task.WaitAll(dataTasks.ToArray()); //This probably isn't necessary
    }

Я использую ожидание здесь, но получаю сообщение об ошибке

Оператор "ожидание" может использоваться только в асинхронном методе. Рассматривать маркировка этого метода модификатором "async" и изменение его возврата введите "Задача"

Однако, если я использую модификатор async, это будет асинхронная операция. Поэтому, если мой вызов GetData1 не использует оператор ожидания, он не будет управлять GoData2 при первом ожидании, чего я пытаюсь избежать? Можно ли сохранить GetData1 в качестве синхронного метода, который вызывает асинхронный метод? Я неправильно проектирую асинхронный метод? Как вы можете видеть, я очень смущен.

Это может быть дубликат Как вызвать асинхронный метод из синхронного метода на С#? Однако я не уверен, как применять предоставленные там решения, как я 'm запускать несколько задач, хотите WaitAny, сделать немного больше обработки для этой задачи, а затем дождаться завершения всех задач до передачи управления обратно вызывающему.

UPDATE

Вот решение, на которое я пошел, основываясь на ответах ниже:

    private static List<T> RetrievePageTaskScheduler<T>(
        List<T> items,
        List<WebPageState> state,
        Func<WebPageState, Task<List<T>>> func)
    {
        int taskIndex = 0;

        // Schedule tasks to concurency level (or all)
        List<Task<List<T>>> runningTasks = new List<Task<List<T>>>();
        while (taskIndex < CONCURRENCY_LEVEL_PER_PROCESSOR * Environment.ProcessorCount
            && taskIndex < state.Count)
        {
            runningTasks.Add(func(state[taskIndex]));
            taskIndex++;
        }

        // Start tasks and wait for them to finish
        while (runningTasks.Count > 0)
        {
            Task<List<T>> task = Task.WhenAny(runningTasks).Result;
            runningTasks.Remove(task);

            try
            {
                items.AddRange(task.Result);
            }
            catch (AggregateException ex)
            {
                /* Throwing this exception means that if one task fails 
                 * don't process any more of them */

                // https://stackoverflow.com/info/8853693/pattern-for-implementing-sync-methods-in-terms-of-non-parallel-task-translating
                System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(
                    ex.Flatten().InnerExceptions.First()).Throw();
            }

            // Schedule next concurrent task
            if (taskIndex < state.Count)
            {
                runningTasks.Add(func(state[taskIndex]));
                taskIndex++;
            }
        }

        return items;
    }

Ответы

Ответ 1

Task<TResult>.Result (или Task.Wait(), когда нет результата) аналогичен await, но является синхронной операцией. Вы должны изменить GetData1(), чтобы использовать это. Здесь часть для изменения:

Task<Data> dataTask = Task.WhenAny(runningTasks).Result;
runningTasks.Remove(dataTask);
myData = gameTask.Result;

Ответ 2

Во-первых, я рекомендую, чтобы ваши "внутренние" задачи не использовали Task.Run в своей реализации. Вы должны использовать метод async, который синхронно выполняет привязку к процессору.

Как только ваш MyAsyncMethod представляет собой метод async, который обрабатывает некоторую обработку с привязкой к процессору, вы можете обернуть его в Task и использовать параллельную обработку как таковую:

internal static void GetData1()
{
    // Start the tasks
    var dataTasks = Enumerable.Range(0, TotalItems)
        .Select(item => Task.Run(() => MyAyncMethod(State[item]))).ToList();

    // Wait for them all to complete
    Task.WaitAll(dataTasks);
}

Ограничение вашего concurrency в исходном коде не будет работать вообще, поэтому я удалил его для простоты. Если вы хотите применить ограничение, вы можете использовать SemaphoreSlim или TPL Dataflow.

Ответ 3

Вы можете вызвать следующее:

GetData1().Wait();
GetData2().Wait();
GetData3().Wait();