Task.ContinueWith在异步代码中不是很流行吗?

时间:2019-05-22 09:10:58

标签: continuewith

我们要并行执行调用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;
            }

我想知道是否有更好的模式,continuewith不适合使用!

有时我们会收到此错误,System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError错误)

1 个答案:

答案 0 :(得分:0)

您不应使用ContinueWithContinueWith是一种与await相同的低级危险方法。现代代码应改用await

要结合两个异步操作(例如InvokeSomeAsyncHandleResultAsync),请引入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)));
}