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   
              …
              …
       }
}
4

1 回答 1

0

Parallel.ForEach()不明白async,所以你的 lambda 编译为async void. 这意味着,只要您点击await,就会ForEach()认为迭代已完成并继续进行另一次迭代。

解决此问题的一种方法是首先同时启动所有服务调用,然后使用以下命令等待所有服务调用完成Task.WhenAll()

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

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

    return await Task.WhenAll(tasks);
}

如果要限制服务调用并行执行的次数,可以使用SemaphoreSlim's WaitAsync()

var semaphore = new SemaphoreSlim(degreeOfParallelism);

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

        try
        {
            return await api.GetResultFromAnotherService(item.id);
        }
        finally
        {
            sempahore.Release();
        }
    });
于 2013-10-08T08:20:50.137 回答