如何让子线程与主线程同步
本文关键字:线程 同步 | 更新日期: 2023-09-27 18:34:15
>我有以下代码,看起来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
…
…
}
}
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
的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();
}
});