从同步方法调用异步方法

我试图从同步方法运行异步方法。 但我无法等待 异步方法,因为我在同步方法中。 我不能理解TPL,因为这是我第一次使用它。

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

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

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

GetData1看起来像这样

  internal static void GetData1 () { const int CONCURRENCY_LEVEL = 15; List<Task> dataTasks = new List<Task>(); for (int item = 0; item < TotalItems; item++) { dataTasks.Add(MyAyncMethod(State[item])); } int taskIndex = 0; //Schedule tasks to concurency level (or all) List<Task> runningTasks = new List<Task>(); while (taskIndex < CONCURRENCY_LEVEL && taskIndex  0) { Task 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 RetrievePageTaskScheduler( List items, List state, Func<WebPageState, Task<List>> func) { int taskIndex = 0; // Schedule tasks to concurency level (or all) List<Task<List>> runningTasks = new List<Task<List>>(); while (taskIndex < CONCURRENCY_LEVEL_PER_PROCESSOR * Environment.ProcessorCount && taskIndex  0) { Task<List> 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() (或没有结果时的Task.Wait() )类似于await ,但是是同步操作。 您应该更改GetData1()以使用它。 这是要改变的部分:

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

首先,我建议您的“内部”任务不要在其实现中使用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。

您可以拨打以下电话:

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