如果不使用c#異步/等待功能,什麼纔是循環異步操作而不阻塞的最佳方式?如何在沒有異步/等待的情況下循環異步方法
例如,在for循環內異步下載URL列表的HTML。
我繼續在TPL的while循環中繼續調用自己,如果有更多的工作....但是有沒有更好的方法?
如果不使用c#異步/等待功能,什麼纔是循環異步操作而不阻塞的最佳方式?如何在沒有異步/等待的情況下循環異步方法
例如,在for循環內異步下載URL列表的HTML。
我繼續在TPL的while循環中繼續調用自己,如果有更多的工作....但是有沒有更好的方法?
您描述的模式並不差,但您可以將它抽象爲輔助方法。類似於ForEachAsync
或ConvertAllAsync
。這可以消除代碼中的循環。這將非必要的複雜性降至最低。
這裏是ForEachAsync
實現:
public static Task ForEachAsync<T>(this TaskFactory factory, IEnumerable<T> items, Func<T, int, Task> getProcessItemTask)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
IEnumerator<T> enumerator = items.GetEnumerator();
int i = 0;
Action<Task> continuationAction = null;
continuationAction = ante =>
{
if (ante.IsFaulted)
tcs.SetException(ante.Exception);
else if (ante.IsCanceled)
tcs.TrySetCanceled();
else
StartNextForEachIteration(factory, tcs, getProcessItemTask, enumerator, ref i, continuationAction);
};
StartNextForEachIteration(factory, tcs, getProcessItemTask, enumerator, ref i, continuationAction);
tcs.Task.ContinueWith(_ => enumerator.Dispose(), TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
static void StartNextForEachIteration<T>(TaskFactory factory, TaskCompletionSource<object> tcs, Func<T, int, Task> getProcessItemTask, IEnumerator<T> enumerator, ref int i, Action<Task> continuationAction)
{
bool moveNext;
try
{
moveNext = enumerator.MoveNext();
}
catch (Exception ex)
{
tcs.SetException(ex);
return;
}
if (!moveNext)
{
tcs.SetResult(null);
return;
}
Task iterationTask = null;
try
{
iterationTask = getProcessItemTask(enumerator.Current, i);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
i++;
if (iterationTask != null)
iterationTask.ContinueWith(continuationAction, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, factory.Scheduler ?? TaskScheduler.Default);
}
有一些情況下使用的IEnumerable的iasync結果像powerthreading(異步伺機正是基於這樣的),你不要有淨4.5支持庫。 – NickD
你爲什麼要避免使用'async'''await'? – svick
我正在尋求避免異步/等待,因爲它的一種新的語言功能(在社區還沒有大量的生產時間),我關心它的副作用 - 內存使用情況,錯誤情況等。我寧願看社區先犯錯,然後繼續。 – Micah