IAsyncEnumerable 的早期 Disposable 需要永远
Early Disposable of an IAsyncEnumerable Takes Forever
我有一个查询,我正在 运行 使用 EF Core 3.1 和 Postgresql 对我的数据库进行查询,根据请求的参数,有时 return 可能会产生一个很大的结果集。我正在使用 Async Enumerable 流式传输结果,有时可能需要一分钟多的时间才能完成:
try
{
IAsyncEnumerable<Entity> ae = ctxt.Entity.Where(e => e.Value > 5).AsAsyncEnumerable();
await foreach(Entity e in ae.ConfigureAwait(false))
{
//Do some work on each one here that could potentially throw an exception
}
}
catch(Exception ex)
{
//This code can take over a minute after the exception is thrown to begin executing
}
然后我摆脱了 await foreach
循环以更好地了解发生了什么:
IAsyncEnumerable<Entity> ae = ctxt.Entity.Where(e => e.Value > 5).AsAsyncEnumerable();
var enumerator = ae.GetAsyncEnumerator();
await enumerator.MoveNextAsync();
await enumerator.DisposeAsync();
Console.WriteLline("Done Disposing");
并且发现 DisposeAsync
调用是花费时间的地方。我回到 await foreach
并能够确认在循环内使用 break
表现出相同的行为。
接下来,我尝试创建一个非 ef IAsyncEnumerable
以查看此行为是否与实体框架隔离。
private async IAsyncEnumerable<int> IntEnumerator()
{
await Task.Delay(0).ConfigureAwait(false);
for(int i = 0; i < int.MaxValue; i++)
{
yield return i;
}
}
使用此代码,Dispose 是即时的。
IAsyncEnumerable<int> ae = IntEnumerator();
var enumerator = ae.GetAsyncEnumerator();
await enumerator.MoveNextAsync();
await enumerator.DisposeAsync();
Console.WriteLline("Done Disposing");
这让我相信这个问题是 EF 核心特有的,但我不确定这是他们实现中的错误,还是我做错了什么。有没有其他人看到过类似的情况并找到了解决方案?
我想在 EF github 页面上打开问题之前先查看这里。
看起来这实际上是 postgresql 的问题。 See the issue I opened on the Npgsql github page。根据维护者的说法,它是不可解析的。
我有一个查询,我正在 运行 使用 EF Core 3.1 和 Postgresql 对我的数据库进行查询,根据请求的参数,有时 return 可能会产生一个很大的结果集。我正在使用 Async Enumerable 流式传输结果,有时可能需要一分钟多的时间才能完成:
try
{
IAsyncEnumerable<Entity> ae = ctxt.Entity.Where(e => e.Value > 5).AsAsyncEnumerable();
await foreach(Entity e in ae.ConfigureAwait(false))
{
//Do some work on each one here that could potentially throw an exception
}
}
catch(Exception ex)
{
//This code can take over a minute after the exception is thrown to begin executing
}
然后我摆脱了 await foreach
循环以更好地了解发生了什么:
IAsyncEnumerable<Entity> ae = ctxt.Entity.Where(e => e.Value > 5).AsAsyncEnumerable();
var enumerator = ae.GetAsyncEnumerator();
await enumerator.MoveNextAsync();
await enumerator.DisposeAsync();
Console.WriteLline("Done Disposing");
并且发现 DisposeAsync
调用是花费时间的地方。我回到 await foreach
并能够确认在循环内使用 break
表现出相同的行为。
接下来,我尝试创建一个非 ef IAsyncEnumerable
以查看此行为是否与实体框架隔离。
private async IAsyncEnumerable<int> IntEnumerator()
{
await Task.Delay(0).ConfigureAwait(false);
for(int i = 0; i < int.MaxValue; i++)
{
yield return i;
}
}
使用此代码,Dispose 是即时的。
IAsyncEnumerable<int> ae = IntEnumerator();
var enumerator = ae.GetAsyncEnumerator();
await enumerator.MoveNextAsync();
await enumerator.DisposeAsync();
Console.WriteLline("Done Disposing");
这让我相信这个问题是 EF 核心特有的,但我不确定这是他们实现中的错误,还是我做错了什么。有没有其他人看到过类似的情况并找到了解决方案?
我想在 EF github 页面上打开问题之前先查看这里。
看起来这实际上是 postgresql 的问题。 See the issue I opened on the Npgsql github page。根据维护者的说法,它是不可解析的。