c# - 如果没有要完成的任务,Task.WhenAll 挂起
问题描述
我有将对象列表插入 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 请求。
解决方案
无法详细解释,但看起来问题是由.NET framework 和 Mongo DB driver 之间的不兼容引起的。目前我正在使用 .NET 4.6.1 和 Mongo 2.6.1,它工作正常。
昨天任何尝试将空的对象列表保存到 Mongo DB 中都会导致死锁。
然后我尝试重构代码并安装最新版本的 Mongo DB,即 2.7.0。现在,任何使用 Mongo DB 的 CRUD 操作都会返回此错误。没有关于此异常的调用堆栈和更多详细信息。
MethodAccessException: Attempt by method 'MongoDB.Driver.ClientSession..ctor(MongoDB.Driver.IMongoClient, MongoDB.Driver.ClientSessionOptions, MongoDB.Driver.IServerSession, Boolean)' to access method 'MongoDB.Driver.Core.Clusters.ClusterClock..ctor()' failed.
然后我尝试将 Mongo DB 的版本降低到 2.6.1,当我尝试插入空的对象列表时,我得到了这个异常,这是正确的。当我插入至少一条记录时,它按预期工作。
System.AggregateException: 'One or more errors occurred.'
ArgumentException: Must contain at least 1 request.
Parameter name: requests
测试代码
var item = new Demo
{
Symbol = "SomeSymbol",
Expiration = "2019-01-01"
};
var list = new List<Demo>();
list.Add(item);
list.Add(item); // if I comment these lines, then Mongo 2.6.1 returns correct exception
var optionIds = Task.WhenAll(storageService.Save(list)).Result;
Save 方法作为Mongo 存储库模式的一部分实现
public Task<BulkWriteResult<T>> SaveCollection(List<T> items)
{
var records = new List<ReplaceOneModel<T>>();
var processes = new List<Task<ReplaceOneResult>>();
items.ForEach(contract =>
{
var record = new ReplaceOneModel<T>(Builders<T>
.Filter
.Where(o => o.Id == contract.Id), contract)
{
IsUpsert = true
};
records.Add(record);
});
return Collection.BulkWriteAsync(records);
}
推荐阅读
- ios - 为什么 iOS 在尝试以相反的顺序显示排序结果时会崩溃?
- ruby-on-rails - ruby on rails 应用商店会话在哪里?
- html - 如何填充 glyphicon 的竖起大拇指和大拇指向下,应该使用哪种 css 样式?
- c# - API 等待 Fetch 忽略 FlowListView Setter
- reactjs - React-Admin:如何在没有`source`的情况下访问值?
- path - 不指向有效的 .jar
- javascript - 为什么我无法在我的系统中安装 React 和卸载 create-react-app?
- java - 我在空对象引用上遇到错误请帮助我
- c# - 如何在C#中计算Macauley修改的持续时间?
- angular - 角度应用程序在本地工作,但在实时服务器上仅显示文件列表