如何让子线程与主线程同步

时间:2013-10-08 04:06:43

标签: c# multithreading asynchronous .net-4.5 async-await

我有下面的代码,看起来像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   
              …
              …
       }
}

1 个答案:

答案 0 :(得分:0)

Parallel.ForEach()无法理解async,因此您的lambda编译为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);
}

如果您想限制并行执行服务调用的次数,可以使用SemaphoreSlim的{​​{1}}:

WaitAsync()