C# 使用async/await和System.Threading.Tasks.Parallel时出现奇怪的执行跳转

C# 使用async/await和System.Threading.Tasks.Parallel时出现奇怪的执行跳转,c#,.net,multithreading,asynchronous,async-await,C#,.net,Multithreading,Asynchronous,Async Await,我有以下方法: public async Task ExecuteAsync() { Task<IEnumerable<Comment>> gettingComments = RetrieveComments(); Dictionary<string, ReviewManager> reviewers = ConfigurationFacade.Repositories.ToDictionary(name => name, name

我有以下方法:

public async Task ExecuteAsync()
{
     Task<IEnumerable<Comment>> gettingComments = RetrieveComments();

     Dictionary<string, ReviewManager> reviewers = ConfigurationFacade.Repositories.ToDictionary(name => name, name => new ReviewManager(name));

     IEnumerable<Comment> comments = await gettingComments;

     Parallel.ForEach(reviewers, (reviewer) => {
          Dictionary<Comment, RevisionResult> reviews = reviewer.Value.Review(comments);

          int amountModerated = ModerateComments(reviews.Where(r => r.Value.IsInsult), "hide");
     });
}
最后:

private async Task<bool> ModerateComment(Comment comment, string operation, string authenticationToken = null)
{
      if(comment == null) return false;

      if(String.IsNullOrWhiteSpace(authenticationToken))
             authenticationToken = CreateUserToken(TimeSpan.FromMinutes(1));

      string moderationEndpoint = ConfigurationFacade.ModerationEndpoint;

      using(HttpRequestMessage request = new HttpRequestMessage())
      {
          request.Method = HttpMethod.Post;
          request.RequestUri = new Uri(moderationEndpoint);
          using(HttpResponseMessage response = await _httpClient.SendAsync(request)) //Problem here
          {
               if(!response.IsSuccessStatusCode)
               {
                    if(response.StatusCode == HttpStatusCode.Unauthorized)
                        return await ModerateComment(comment, operation, null); //Retry operation with a new access token
                    else if(response.StatusCode == HttpStatusCode.GatewayTimeout)
                        return await ModerateComment(comment, operation, authenticationToken); //Retry operation

                    return false;
               } 
          }
      }

      return true;
}
当我调试我的应用程序时,这个指令被执行,但就在那之后,它不会抛出任何异常,也不会返回任何东西,它只是完成执行,然后我就被导出到
Parallel.ForEach
循环上的下一条语句

这真的很难解释,所以我将发布一些图片:

到目前为止一切都很好,我达到了以下代码行:

执行一直很顺利,我实现了对调节API的调用

即使我在调试器中按F10(Next语句),执行流也会跳到Parallel.ForEach循环中的下一个循环

正如您所看到的,我在try-catch中有断点,只要抛出任何异常,但断点都不会被激活,
if(moderacion)commentCount++
中的断点也不会被激活

那么这里发生了什么?我的执行流程到哪里去了?它只是在向API发送POST请求后消失

在继续执行之后,枚举表中的所有元素都进行相同的跳转,因此,my
commentCount
变量最终等于0
对常见问题的出色描述。Parallel.ForEach不支持异步lambdas。异步方法在遇到第一个需要阻塞的等待时返回。当您发出HTTP请求时会发生这种情况


对并行异步foreach循环使用一种常见模式。

您不需要
并行.foreach
任务.Factory.StartNew
来执行IO绑定工作:

private async Task<int> ModerateCommentsAsync(IEnumerable<Comment> comments, string operation)
{
      var commentTasks = comments.Select(comment => ModerateCommentAsync(comment, operation));

      await Task.WhenAll(commentTasks);
      return commentTasks.Count(x => x.Result);
}
private async Task mediatecommentsasync(IEnumerable注释,字符串操作)
{
var commentTasks=comments.Select(comment=>mediatecommentasync(comment,operation));
等待任务。WhenAll(评论任务);
返回commentTasks.Count(x=>x.Result);
}

通常的做法是将
Async
postfix添加到异步方法中。

Wow,这确实很有趣!谢谢你的快速回复这真的很有帮助!非常感谢。我从未想过使用
Select
获取一组任务。通常,在将它们转储到
whalll
调用之前,我只是手动将它们添加到集合中。聪明。@Johnathan Select在需要投影集合中的所有值时很好
using(HttpResponseMessage response = await _httpClient.SendAsync(request)) {
      //...
}
private async Task<int> ModerateCommentsAsync(IEnumerable<Comment> comments, string operation)
{
      var commentTasks = comments.Select(comment => ModerateCommentAsync(comment, operation));

      await Task.WhenAll(commentTasks);
      return commentTasks.Count(x => x.Result);
}