Task.ContinueWith 异步代码不是很流行?
Task.ContinueWith not very popular with async code?
我们要并行执行 invoke 10 个任务,并并行处理 10 个结果中的每一个。
为了实现,创建了一个任务列表并使用了 continuewith,每个任务都与异步方法相关联,
片段
private async Task<List<bool>> TransformJobsAsync(
List<T> jobs)
{
var result = new List<bool>() { true };
var tasks = new List<Task<bool>>(jobs.Count);
try
{
foreach (var j in jobs)
{
tasks .Add(InvokeSomeAsync(j).ContinueWith(x => HandleResultAsync(x, j)).Unwrap());
}
await Task.WhenAll(tasks);
return tasks.Select(x => x.Result).ToList();
}
catch (Exception ex)
{
result = new List<bool>() { false };
}
return result;
}
Task<(T response, T job)> InvokeSomeAsync (T job)
{
var cts = new CancellationTokenSource();
try
{
cts.CancelAfter(30000);
var response = await SomeThirdPartyApi(request, cts.Token);
if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
{
}
return (response, job);
}
catch (OperationCanceledException opexException)
{
contextMessage = Messages.TranformationExecutionTimedOut;
}
catch (Exception ex)
{
contextMessage = Messages.UnHandledException;
}
finally
{
cts = null; //why? suggested pattern? review.
}
return await Task.FromException<(response, T Job)>(
throw new Exception());
}
async Task<bool> HandleResultAsync(Task<(T response, T job)> task, T job)
{
try
{
if (task.Status == TaskStatus.RanToCompletion)
{
if (task.Result.Status)
{
response = await CallMoreAsync(task.Result.reponse,
job, currentServiceState);
}
else
{
//log returned response = false
}
}
else
{
//log task failed
}
}
catch (Exception ex)
{
response = false;
}
finally
{
await DoCleanUpAsync();
}
return response;
}
想知道有没有更好的pattern,continuewith不适合用!
有时我们会收到此错误,System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError 错误)
你不应该使用 ContinueWith
。 ContinueWith
是一种 low-level,做与 await
相同的事情的危险方式。现代代码应该改用 await
。
要结合两个异步操作(例如,InvokeSomeAsync
和HandleResultAsync
),引入一个async
方法:
async Task<bool> InvokeAndHandleResultAsync<T>(T job)
{
var task = InvokeSomeAsync(job);
return await HandleResultAsync(task, job);
}
这可以用于您的 foreach
:
foreach (var j in jobs)
{
tasks.Add(InvokeAndHandleResultAsync(j));
}
其他说明:
CancellationTokenSource
应该处理掉。
await Task.From*
通常是黄旗。
- 使用
Task.Status
是一个危险信号。
- 在特殊情况下使用例外,而不是在其他地方有
bool
结果和 contextMessage
状态。
我会这样写:
async Task InvokeAndHandleResultAsync<T>(T job)
{
using (var cts = new CancellationTokenSource(30000))
{
try
{
var response = await SomeThirdPartyApi(request, cts.Token);
if (!response.Status)
{
//log returned response = false
return;
}
await CallMoreAsync(response, job, currentServiceState);
}
catch (Exception ex)
{
//log task failed
}
finally
{
await DoCleanUpAsync();
}
}
}
此外,您可以简化该代码,而不是构建任务列表:
private async Task TransformJobsAsync(List<T> jobs)
{
return Task.WhenAll(jobs.Select(j => InvokeAndHandleResult(j)));
}
我们要并行执行 invoke 10 个任务,并并行处理 10 个结果中的每一个。
为了实现,创建了一个任务列表并使用了 continuewith,每个任务都与异步方法相关联,
片段
private async Task<List<bool>> TransformJobsAsync(
List<T> jobs)
{
var result = new List<bool>() { true };
var tasks = new List<Task<bool>>(jobs.Count);
try
{
foreach (var j in jobs)
{
tasks .Add(InvokeSomeAsync(j).ContinueWith(x => HandleResultAsync(x, j)).Unwrap());
}
await Task.WhenAll(tasks);
return tasks.Select(x => x.Result).ToList();
}
catch (Exception ex)
{
result = new List<bool>() { false };
}
return result;
}
Task<(T response, T job)> InvokeSomeAsync (T job)
{
var cts = new CancellationTokenSource();
try
{
cts.CancelAfter(30000);
var response = await SomeThirdPartyApi(request, cts.Token);
if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
{
}
return (response, job);
}
catch (OperationCanceledException opexException)
{
contextMessage = Messages.TranformationExecutionTimedOut;
}
catch (Exception ex)
{
contextMessage = Messages.UnHandledException;
}
finally
{
cts = null; //why? suggested pattern? review.
}
return await Task.FromException<(response, T Job)>(
throw new Exception());
}
async Task<bool> HandleResultAsync(Task<(T response, T job)> task, T job)
{
try
{
if (task.Status == TaskStatus.RanToCompletion)
{
if (task.Result.Status)
{
response = await CallMoreAsync(task.Result.reponse,
job, currentServiceState);
}
else
{
//log returned response = false
}
}
else
{
//log task failed
}
}
catch (Exception ex)
{
response = false;
}
finally
{
await DoCleanUpAsync();
}
return response;
}
想知道有没有更好的pattern,continuewith不适合用!
有时我们会收到此错误,System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError 错误)
你不应该使用 ContinueWith
。 ContinueWith
是一种 low-level,做与 await
相同的事情的危险方式。现代代码应该改用 await
。
要结合两个异步操作(例如,InvokeSomeAsync
和HandleResultAsync
),引入一个async
方法:
async Task<bool> InvokeAndHandleResultAsync<T>(T job)
{
var task = InvokeSomeAsync(job);
return await HandleResultAsync(task, job);
}
这可以用于您的 foreach
:
foreach (var j in jobs)
{
tasks.Add(InvokeAndHandleResultAsync(j));
}
其他说明:
CancellationTokenSource
应该处理掉。await Task.From*
通常是黄旗。- 使用
Task.Status
是一个危险信号。 - 在特殊情况下使用例外,而不是在其他地方有
bool
结果和contextMessage
状态。
我会这样写:
async Task InvokeAndHandleResultAsync<T>(T job)
{
using (var cts = new CancellationTokenSource(30000))
{
try
{
var response = await SomeThirdPartyApi(request, cts.Token);
if (!response.Status)
{
//log returned response = false
return;
}
await CallMoreAsync(response, job, currentServiceState);
}
catch (Exception ex)
{
//log task failed
}
finally
{
await DoCleanUpAsync();
}
}
}
此外,您可以简化该代码,而不是构建任务列表:
private async Task TransformJobsAsync(List<T> jobs)
{
return Task.WhenAll(jobs.Select(j => InvokeAndHandleResult(j)));
}