[英]Calling an async method from a synchronous method
我試圖從同步方法運行異步方法。 但我無法等待 異步方法,因為我在同步方法中。 我不能理解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'運算符只能在異步方法中使用。 考慮使用'async'修飾符標記此方法並將其返回類型更改為'Task'
但是,如果我使用async修飾符,這將是一個異步操作。 因此,如果我對GetData1
調用沒有使用await運算符將無法控制在第一次等待時轉到GetData2,這是我試圖避免的? 是否可以將GetData1保持為調用異步方法的同步方法? 我是否錯誤地設計了異步方法? 你可以看到我很困惑。
這可能是如何從C#中的同步方法調用異步方法的重復? 但是,我不確定如何應用那里提供的解決方案,因為我正在啟動多個任務,想要WaitAny
,為該任務執行更多處理,然后在將控制權交還給調用者之前等待所有任務完成。
UPDATE
以下是基於以下答案的解決方案:
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;
}
首先,我建議您的“內部”任務不要在其實現中使用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。
Task<TResult>.Result
Task.Wait()
(或沒有結果時為Task.Wait()
)類似於await
,但是是同步操作。 您應該更改GetData1()
以使用它。 這是要改變的部分:
Task<Data> dataTask = Task.WhenAny(runningTasks).Result;
runningTasks.Remove(dataTask);
myData = gameTask.Result;
您可以撥打以下電話:
GetData1().Wait();
GetData2().Wait();
GetData3().Wait();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.