我正在尝试从同步方法运行异步方法。但是我不能等待异步方法,因为我处于同步方法中。我一定不理解 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 修饰符,这将是一个异步操作。因此,如果我的调用GetData1
不使用 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://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;
}