【问题标题】:how to have children thread synchronize with main thread如何让子线程与主线程同步
【发布时间】:2013-10-14 20:33:23
【问题描述】:

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

【问题讨论】:

  • @M.Babcock 我不确定我理解你的意思。这是一个非常常见的用法。您可以假设 ApiClass 是 HttpClient 之上的包装器,并且您需要触发并行请求以从另一个 Web 服务获取一些信息。解决我的问题很容易。将 GetResultFromAnotherService 更改为不返回任务。但这最终会阻塞线程。这不是我想要的。
  • @shrimpy:根据你的例子,我强烈怀疑你没有targetFramework set to 4.5 in your app.config

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


【解决方案1】:

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);
}

如果你想限制服务调用并行执行的次数,你可以使用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();
        }
    });

【讨论】:

    猜你喜欢
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    相关资源
    最近更新 更多