【发布时间】:2018-07-14 21:46:42
【问题描述】:
我有将对象列表插入 Mongo DB 的方法。
public class StorageService : IStorageService
{
public Task<BulkWriteResult<Option>> SaveOptions(List<Option> contracts)
{
var context = new MongoContext<Option>();
return context.SaveCollection(contracts);
}
}
var optionIds = Task
.WhenAll(storageService.SaveOptions(optionDetails.Values.ToList()))
.Result;
如果合约列表为空,则没有对象可插入数据库,也没有任务可完成,因此 Task.WhenAll 会无限期地运行,从而造成死锁。
问题
如果列表为空,有没有办法返回空/已完成的任务,或者可能有更好的解决方案来获取插入结果,但同时正确处理没有结果的情况?
更新 #1
大概的结构。
WebApi - MVC 项目
[AcceptVerbs("POST")]
public Response<int> DownloadOptions([FromBody] ContractSelector data)
{
.. some controller code
var optionIds = Task
.WhenAll(storageService.SaveOptions(optionDetails.Values.ToList()))
.Result;
// this method should gather data from multiple APIs
// so I need Task.Result of all previous operations
// I could make this method async and use await, but it's not the case here
}
类库项目,.NET 4.6.1
public class StorageService : IStorageService
{
public Task<BulkWriteResult<Option>> SaveOptions(List<Option> contracts)
{
var context = new MongoContext<Option>();
return context.SaveCollection(contracts);
}
}
更新 #2
为什么异步/等待没有用。有 2 个外部 API 调用,一个是获取有关某些资产的一般信息,第二个是获取该资产的价格,我无法更改。因此,如果我想通过一种方法获取所有信息,我必须请求一般信息,然后等待等待结果,并根据一般信息请求相关价格。在此之后,我想将收集到的信息保存到数据库中,并在对我的 API 的响应中返回保存的 ID 列表。
调用顺序
1. UI
2. WebApi MVC Controller
3. Class Library
3.1 Request asset info - wait for the result
3.2 Get asset info - request prices for selected assets - wait for the result
3.3 Get asset info and prices info - save everything to DB - return response
var contracts = Task.WhenAll(optionService.GetContracts(params)).Result;
var prices = Task.WhenAll(optionService.GetOptionDetails(contracts)).Result;
var ids = Task.WhenAll(storageService.SaveOptions(prices.Values.ToList()));
因此,响应取决于 3.3,3.3 取决于 3.2,3.2 取决于 3.1。如果您知道如何将其全部转换为非阻塞呼叫,我会全力以赴。目前我认为 1 个 HTTP 请求中的 3 个阻塞调用优于 3 个单独的异步 HTTP 请求。
【问题讨论】:
-
这里的快速测试表明
Task.WhenAll确实不,实际上,当没有任务传入时停止...var nothingToDo = new List<Task>(); Task.WhenAll(nothingToDo); Console.WriteLine("All done");- 所以...可能有这里的假设不正确。此外,您应该几乎从不使用.Result或.Wait(),这种情况肯定比“几乎”更倾向于“从不” -
你只有一个任务,不管有没有,一个或多个合同,所以你甚至不需要WhenAll。话虽如此,就像 Marc Gravell 提到的那样,不要使用 Result 或 Wait,而是在需要等待任务/获取结果时使用 await。
-
optionIds在什么框架下运行? -
这个方法应该从几个 API 收集数据,所以我需要得到这个调用的结果,在这里我看不到 Result 的任何替代方法
-
ASP.NET Web API 针对异步代码进行了优化。为什么
DownloadOptions不是async Task<Response<int>> DownloadOptions?你不应该像这样用Result阻塞线程。更重要的是,您不应该创建一个唯一目的是等待另一个Task的Task。充其量(阅读,worst),它应该只是storageService.SaveOptions(optionDetails.Values.ToList()).Result。但你真的应该只使用await storageService.SaveOptions(optionDetails.Values.ToList())
标签: c# mongodb asynchronous