从同步方法调用异步方法 [英] Calling an async method from a synchronous method

查看:30
本文介绍了从同步方法调用异步方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从同步方法运行异步方法.但是我不能等待 async 方法,因为我使用的是同步方法.我一定不理解 TPL,因为这是我第一次使用它.

I am attempting to run async methods from a synchronous method. But I can't await the async method since I am in a synchronous method. I must not be understanding TPL as this is the fist time I'm using it.

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

每个方法都需要前一个方法完成,因为第一个方法的数据用于第二个.

Each method needs the previous method to finish as the data from the first is used for the second.

但是,在每个方法中,我想启动多个 Task 操作以加快性能.然后我想等他们都说完.

However, inside each method I want to start multiple Task operations in order to speed up the performance. Then I want to wait for all of them to finish.

GetData1 看起来像这样

GetData1 looks like this

    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 但出现错误

I am using await here but get an Error

'await' 运算符只能在异步方法中使用.考虑使用async"修饰符标记此方法并更改其返回值输入任务"

The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'

但是,如果我使用 async 修饰符,这将是一个异步操作.因此,如果我对 GetData1 的调用不使用 await 运算符将无法控制在第一次等待时转到 GetData2,这是我试图避免的?是否可以将 GetData1 保留为调用异步方法的同步方法?我是否错误地设计了异步方法?正如你所看到的,我很困惑.

However, if I use the async modifier this will be an asynchronous operation. Therefore, if my call to GetData1 doesn't use the await operator won't control go to GetData2 on the first await, which is what I am trying to avoid? Is it possible to keep GetData1 as a synchronous method that calls an asynchronous method? Am I designing the Asynchronous method incorrectly? As you can see I'm quite confused.

这可能是 如何从 C# 中的同步方法调用异步方法? 但是,我不是确定如何在我开始多个任务时应用那里提供的解决方案,想要 WaitAny,对该任务进行更多处理,然后等待所有任务完成,然后再将控制权交还给调用者.

This could be a duplicate of How to call asynchronous method from synchronous method in C#? However, I'm not sure how to apply the solutions provided there as I'm starting multiple tasks, want to WaitAny, do a little more processing for that task, then wait for all tasks to finish before handing control back to the caller.

更新

这是我根据以下答案采用的解决方案:

Here is the solution I went with based on the answers below:

    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.Result(或 Task.Wait()(当没有结果时)与await类似,但是是一个同步操作.您应该更改 GetData1() 以使用它.这是要更改的部分:

Task<TResult>.Result (or Task.Wait() when there's no result) is similar to await, but is a synchronous operation. You should change GetData1() to use this. Here's the portion to change:

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

这篇关于从同步方法调用异步方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆