gpt4 book ai didi

c# - Entity Framework 核心 + SQlite。异步请求实际上是同步的

转载 作者:IT王子 更新时间:2023-10-29 06:26:10 27 4
gpt4 key购买 nike

我有 WPF 程序,我正在尝试将 EF Core 与 SQLite 一起使用,但我发现了奇怪的行为。即使我调用像 ToArrayAsync() 或 SaveChangesAsync() 这样的异步方法,它也会返回已经完成的任务。所以这意味着操作实际上是同步完成的。

似乎在 EF 或 SQLite 连接中应该有一些控制同步/异步执行的标志,但我没有找到它。

我使用这段代码进行测试:

using (var context = new TestDbContext())
{
//I have about 10000 records here.
var task = context.Users.ToListAsync();
if (task.IsCompleted && task.Result != null)
{
// It is always comes here.
}
await task;
}

最佳答案

那是因为 ADO.NET 类(DbConnectionDbCommand)的 SQLite 实现是同步的。父类提供真正同步的 Async 方法,提供更好的实现是提供者的工作。例如,这里是 DbConnection.OpenAsync 的实现:

public virtual Task OpenAsync(CancellationToken cancellationToken)
{
TaskCompletionSource<object> completionSource = new TaskCompletionSource<object>();
if (cancellationToken.IsCancellationRequested)
{
completionSource.SetCanceled();
}
else
{
try
{
this.Open();
completionSource.SetResult((object) null);
}
catch (Exception ex)
{
completionSource.SetException(ex);
}
}
return (Task) completionSource.Task;
}

如您所见,没有什么异步的,返回的任务总是完成的。

DbCommand 中的所有默认 Async 实现也是如此:它们都使用 TaskCompletionSource 或直接使用 Task.FromResult.

SQLiteCommand 不会覆盖该行为,当它覆盖时 - 它在不支持异步执行的方法的注释中明确说明。例如,这里是 ExecuteReaderAsync 的实现(覆盖):

/// <summary>
/// Executes the <see cref="P:Microsoft.Data.Sqlite.SqliteCommand.CommandText" /> asynchronously against the database and returns a data reader.
/// </summary>
/// <param name="behavior">A description of query's results and its effect on the database.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <remarks>
/// SQLite does not support asynchronous execution. Use write-ahead logging instead.
/// </remarks>
/// <seealso href="http://sqlite.org/wal.html">Write-Ahead Logging</seealso>
public virtual Task<SqliteDataReader> ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult<SqliteDataReader>(this.ExecuteReader(behavior));
}

相比之下 - SqlConnectionSqlCommand 类会覆盖默认(同步)行为并提供真正异步的方法实现,例如 OpenAsyncExecuteReaderAsync,因此对于 sql server 提供程序,您不应该有观察到的行为。

因此,您在使用 SQLite 时观察到的行为是预期的,不会出现错误。

由于您在 WPF 应用程序中使用它 - 这意味着尽管使用 async\await,您的 UI 线程将在整个操作期间被阻塞。因此,在这种情况下,最好的办法是根本不使用异步版本,而是通过 Task.Run 或类似的构造将整个事情分派(dispatch)到后台线程。

关于c# - Entity Framework 核心 + SQlite。异步请求实际上是同步的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42982444/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com