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

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

问题描述

我试图运行同步方法异步方法。但我不能的计谋的的的异步的方法,因为我是一个同步的方法。我不能了解TPL,因为这是我使用它的拳头时间。

 私人无效GetAllData()
{
    GetData1()
    GetData2()
    GetData3()
}
 

每个方法需要的previous方法来完成从第一数据被用于第二

不过,每次我想启动多个工作行动,以加速性能的方法内。然后,我想等他们都完成。

GetData1看起来像这样

 内部静态无效GetData1()
    {
        const int的CONCURRENCY_LEVEL = 15;
        名单<任务<数据>> dataTasks =新的名单,其中,任务<数据>>();
        对于(INT项= 0;项目< TotalItems;项目++)
        {
            dataTasks.Add(MyAyncMethod(国发[项目]));
        }
        INT taskIndex = 0;
        //计划任务concurency级别(或全部)
        名单<任务<数据>> runningTasks =新的名单,其中,任务<数据>>();
        而(taskIndex< CONCURRENCY_LEVEL和放大器;&安培; taskIndex< dataTasks.Count)
        {
            runningTasks.Add(dataTasks [taskIndex]);
            taskIndex ++;
        }

        //开始任务,等待他们完成
        而(runningTasks.Count大于0)
        {
            任务<数据> dataTask =等待Task.WhenAny(runningTasks);
            runningTasks.Remove(dataTask);
            myData的=等待dataTask;


            //计划明年并发任务
            如果(taskIndex< dataTasks.Count)
            {
                runningTasks.Add(dataTasks [taskIndex]);
                taskIndex ++;
            }
        }
        Task.WaitAll(dataTasks.ToArray()); //这可能是没有必要的
    }
 

我使用等候在这里,但得到一个错误

  

在'等待'运算符只能异步方法中使用。考虑   标志着这种方法与异步修改和改变其返回   为任务键入

不过,如果我使用异步修改,这将是一个异步操作。因此,如果我呼吁 GetData1 不使用计谋运营商将无法控制去GetData2第一个计谋,这正是我想避免?是否有可能保持GetData1作为调用异步方法的同步方法?我在设计异步方法不正确?正如你所看到的,我很困惑。

这可能是如何从C#中的同步方法调用异步方法的副本?的不过,我不是知道如何申请只要是我开始多任务的解决方案,希望了WaitAny ,做多一点处理这个任务,然后等待所有任务前完成移交控制权返回给调用者。

更新

下面是我去与基于下面的答案的解决方案:

 私有静态列表< T> RetrievePageTaskScheduler< T>(
        名单< T>项目,
        名单< WebPageState>州,
        FUNC< WebPageState,任务<列表< T>>> FUNC)
    {
        INT taskIndex = 0;

        //计划任务concurency级别(或全部)
        名单<任务<列表< T>>> runningTasks =新的名单,其中,任务<列表< T>>>();
        而(taskIndex< CONCURRENCY_LEVEL_PER_PROCESSOR * Environment.ProcessorCount
            &功放;&安培; taskIndex< state.Count)
        {
            runningTasks.Add(FUNC(州[taskIndex]));
            taskIndex ++;
        }

        //开始任务,等待他们完成
        而(runningTasks.Count大于0)
        {
            任务<列表< T>>任务= Task.WhenAny(runningTasks)。结果;
            runningTasks.Remove(任务);

            尝试
            {
                items.AddRange(task.Result);
            }
            赶上(AggregateException前)
            {
                / *抛出此异常意味着如果一个任务失败
                 *不处理任何更多的人* /

                // http://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())抛出();
            }

            //计划明年并发任务
            如果(taskIndex< state.Count)
            {
                runningTasks.Add(FUNC(州[taskIndex]));
                taskIndex ++;
            }
        }

        返回的项目;
    }
 

解决方案

任务< TResult>。结果 (或的 Task.Wait() 时,有没有结果)类似于计谋,但它是一个同步操作。您应该更改 GetData1()来使用它。下面是改变部分:

 任务<数据> dataTask = Task.WhenAny(runningTasks)。结果;
runningTasks.Remove(dataTask);
myData的= gameTask.Result;
 

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.

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 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
    }

I am using await here but get an Error

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'

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.

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.

UPDATE

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 */

                // http://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<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天全站免登陆