我试图删除代码即时写作。
在我们需要编写的每个FindAsync
中都有这段代码:
using (var cursor = await SomeCollection.FindAsync(filter, options))
{
while (await cursor.MoveNextAsync())
{
var batch = cursor.Current;
foreach (var item in batch)
{
//do something
}
}
}
我想出了一个延伸。我的代码:
public static async Task<List<T>> GetResultsFromFindAsync<T>(this Task<IAsyncCursor<T>> find)
{
List<T> result = new List<T>();
using (var cursor = await find)
{
while (await cursor.MoveNextAsync())
{
var batch = cursor.Current;
foreach (var item in batch)
{
result.Add(item);
}
}
}
return result;
}
现在,我只使用:
List<MyObject> lst = await SomeCollection.FindAsync(filter, options).GetResultsFromFindAsync();
问题是:它是否会导致死锁,因为在具有单个Await
caluse的进程中涉及2个异步任务。
我知道这个过程确实包含2个Await
calus,但是,它们不会相互冲突,或者可能导致数据丢失?
我使用此扩展程序执行了FindAsync并获取了我的数据,因此它的工作正常,但如果可能发生,测试不会100%发生死锁。
我非常想知道原因或原因。 感谢。
答案 0 :(得分:2)
这会导致死锁吗?是的,但不是因为你列出的原因。
如果有人决定同步调用您的方法并在返回的Wait
上使用Result
或Task
,则他们可能会死锁。因为这个确切的原因,所以充满了“为什么我的任务永远不会完成”的问题。在ConfigureAwait(false)
内等待的所有Task
上使用GetResultsFromFindAsync
来保护自己。
话虽如此,如果GetResultsFromFindAsync
总是异步消耗,则没有问题。
关于只有“单await
条款” - 实际上并非如此。您在await
实施中Task
FindAsync
返回GetResultsFromFindAsync
,从而传播其完成和例外(如果有)。当你打电话
SomeCollection.FindAsync(filter, options).GetResultsFromFindAsync()
,您实际上正在等待Tasks
(外部Task
等待内部Task
)。如果FindAsync
恰好抛出(异步),Task
返回的GetResultsFromFindAsync
将自动转换为Faulted
状态,并且当外部{{1}时将重新抛出异常等待。
总之,你所编写的方法在技术上没有任何错误,尽管引入Task
不会受到伤害。
修改强>
说完上述所有内容之后,我个人会考虑将两个调用合并为一个,因此调用ConfigureAwait(false)
是FindAsync
的责任。这是为了防止消费者重用GetResultsFromFindAsync
返回的游标,因为我预计以下内容将失败:
FindAsync
答案 1 :(得分:1)
The .NET driver already offers extension methods for this type of thing. ToList, ToListAsync, and ForEachAsync are all available.
http://mongodb.github.io/mongo-csharp-driver/2.2/reference/driver/crud/reading/#iteration