同期メソッドから非同期メソッドを実行しようとしています。しかし、同期メソッドにいるため、非同期メソッドを待つことはできません。TPL を使用するのはこれが初めてなので、TPL を理解していないに違いありません。
private void GetAllData()
{
GetData1()
GetData2()
GetData3()
}
最初のデータが 2 番目のメソッドに使用されるため、各メソッドは前のメソッドを完了する必要があります。
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://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;
}