我试图从同步方法中运行异步方法。但由于我在同步方法中,因此无法等待异步方法。我可能没有理解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,但是出现了错误。
'await'操作符只能在异步方法中使用。请考虑用'async'修改器标记此方法,并将其返回类型更改为'Task'
然而,如果我使用async修饰符,这将成为一个异步操作。因此,如果我的对GetData1
的调用不使用await运算符,控制权不会在第一个await时转到GetData2,这正是我想避免的。是否有可能将GetData1保留为调用异步方法的同步方法?我是否设计了异步方法错误?正如您所看到的,我很困惑。
这可能是如何从C#同步方法调用异步方法?的重复问题。然而,我不知道如何应用提供的解决方案,因为我正在启动多个任务,想要WaitAny
,对该任务进行一些处理,然后等待所有任务完成后再将控制权交还给调用者。
更新
以下是我根据下面的答案采用的解决方案:
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://dev59.com/UV_Va4cB1Zd3GeqPRkFz
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
类型有两种完全不同的用途:异步工作(例如async
/await
)和并行处理(例如Task.Factory.StartNew
/Task.WaitAll
)。你正在做什么样的工作(即它是 CPU 绑定的吗)? - Stephen Cleary