簡體   English   中英

從同步方法調用異步方法

[英]Calling an async method from a synchronous method

我試圖從同步方法運行異步方法。 但我無法等待 異步方法,因為我在同步方法中。 我不能理解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
    }

我在這里等待,但得到一個錯誤

'await'運算符只能在異步方法中使用。 考慮使用'async'修飾符標記此方法並將其返回類型更改為'Task'

但是,如果我使用async修飾符,這將是一個異步操作。 因此,如果我對GetData1調用沒有使用await運算符將無法控制在第一次等待時轉到GetData2,這是我試圖避免的? 是否可以將GetData1保持為調用異步方法的同步方法? 我是否錯誤地設計了異步方法? 你可以看到我很困惑。

這可能是如何從C#中的同步方法調用異步方法的重復 但是,我不確定如何應用那里提供的解決方案,因為我正在啟動多個任務,想要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/questions/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;
    }

首先,我建議您的“內部”任務不要在其實現中使用Task.Run 您應該使用async方法同步執行CPU綁定部分。

一旦你的MyAsyncMethod是一個執行某些CPU綁定處理的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);
}

原始代碼中的並發限制根本不起作用,因此我將其刪除以獲得簡單性。 如果要應用限制,可以使用SemaphoreSlim或TPL Dataflow。

Task<TResult>.Result Task.Wait() (或沒有結果時為Task.Wait() )類似於await ,但是是同步操作。 您應該更改GetData1()以使用它。 這是要改變的部分:

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

您可以撥打以下電話:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM