2013-10-08 54 views
0

我有下面的代码,看起来像ApiClass中的await语句会导致函数“AControllerMethodInAspMVC”在每个api.GetResultFromAnotherService完成之前返回。如何让子线程与主线程同步

主线程在所有子线程完成之前返回。有没有办法解决这个问题?

 private ApiClass api = new ApiClass(); 

     [HttpPost] 
     public Task<JsonResult> AControllerMethodInAspMVC() 
     { 
      var arrayOfItem = …; 

      List<object> resultObjs = new List<object>(); 
      var resultLock = new SemaphoreSlim(1); 

      Parallel.ForEach(
       arrayOfItem, 
       async item => 
       { 
        var result = await api.GetResultFromAnotherService(item.id); 

        var resultObj = new { 
        // prepare resultObj from result 
        }; 
        await resultLock.WaitAsync(); 
        resultObjs.add(resultObj); 
        resultLock.Release(); 
       }); 

      return Task.FromResult(this.Json(resultObjs)); 
     } 



Public class ApiClass 
{ 
     Public async Task<string> GetResultFromAnotherService(string id) 
     { 
       …. 
       … 
       await Call AnAsyncOperationToGetResult 
       … 
       … 
     } 
} 
+0

@ M.Babcock我不知道我明白你的意思。这是一个非常常见的用法。您可以假设ApiClass是HttpClient之上的包装器,并且您需要触发并行请求以从另一个Web服务获取某些信息。 解决我的问题很简单。将GetResultFromAnotherService更改为不返回任务。但是这最终会阻止线程。这不是我想要的。 – jojo

+0

@shrimpy:根据你的例子,我强烈怀疑你的app.config中没有['targetFramework'设置为'4.5'](http://blogs.msdn.com/b/webdev/archive/2012 /11/19/all-about-httpruntime-targetframework.aspx)。 –

回答

0

Parallel.ForEach()不理解async,所以你的拉姆达被编译为async void。这意味着只要您点击awaitForEach()就认为迭代已完成,并继续进行另一次迭代。要解决这个问题

一种方法是首先启动的所有服务电话在同一时间,然后等待他们正在使用Task.WhenAll()完成:

public async Task<JsonResult> AControllerMethodInAspMVC() 
{ 
    var arrayOfItem = …; 

    var tasks = arrayOfItem.Select(
     item => api.GetResultFromAnotherService(item.id)); 

    return await Task.WhenAll(tasks); 
} 

如果你想限制多少次在服务调用并行执行,你可以使用SemaphoreSlimWaitAsync()

var semaphore = new SemaphoreSlim(degreeOfParallelism); 

var tasks = arrayOfItem.Select(
    async item => 
    { 
     await semaphore.WaitAsync(); 

     try 
     { 
      return await api.GetResultFromAnotherService(item.id); 
     } 
     finally 
     { 
      sempahore.Release(); 
     } 
    });