0

我们希望并行执行调用 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 error)

4

1 回答 1

1

你不应该使用ContinueWith. ContinueWith是一种低级的、危险的方式来做同样的事情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)));
}
于 2019-05-22T13:18:55.773 回答