我有WPF程序,我试图在那里使用EF Core和SQLite,我发现了奇怪的行为。即使我调用ToArrayAsync()或SaveChangesAsync()等异步方法,它也会返回已完成的任务。所以这意味着操作实际上是同步完成的。
似乎EF或SQLite连接中应该有一些控制同步/异步执行的标志,但我没有找到它。
我使用此代码进行测试:
Debug
答案 0 :(得分:4)
这是因为ADO.NET类(DbConnection
,DbCommand
)的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;
}
如您所见,没有任何异步的东西,并且返回的任务总是完成。
Async
中的所有默认DbCommand
实施都是如此:它们都使用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));
}
相比之下 - SqlConnection
和SqlCommand
类会覆盖默认(同步)行为,并提供OpenAsync
或ExecuteReaderAsync
等方法的真正异步实现,因此使用sql server provider你不应该有你观察到的行为。
因此,在使用SQLite时,您观察到的行为是预期的,而不是错误的。
由于您在WPF应用程序中使用它 - 这意味着尽管使用async \ await,您的UI线程将在整个操作期间被阻止。因此,在这种情况下最好的做法是不要使用异步版本,并通过Task.Run
或类似的构造将整个事件分发给后台线程。