は、私はC# https://github.com/mysql/mysql-connector-netC#のMySQLドライバ - 非同期オペレーション最近
が非同期での作業のためのMySQLドライバで働き始めてきた/これは基本的にどのように私は並列タスク
に単純なSELECTクエリを実行しようとした待ちますコードが見えます:私は両方のクエリを並列で実行するためだったと予想何
private async Task<List<string>> RunQueryA()
{
List<string> lst = new List<string>();
using (MySqlConnection conn = new MySqlConnection(someConnectionString))
using (MySqlCommand cmd = conn.CreateCommand())
{
await conn.OpenAsync();
cmd.CommandText = "select someField from someTable ...";
using (var reader = await cmd.ExecuteReaderAsync())
{
// ...
}
}
return lst;
}
private async Task<List<string>> RunQueryB()
{
List<string> lst = new List<string>();
using (MySqlConnection conn = new MySqlConnection(someConnectionString))
using (MySqlCommand cmd = conn.CreateCommand())
{
await conn.OpenAsync();
cmd.CommandText = "select someField2 from someTable2 ...";
using (var reader = await cmd.ExecuteReaderAsync())
{
// ...
}
}
return lst;
}
public async Task Run()
{
await Task.WhenAll(RunQueryA(), RunQueryB());
}
は、私が見たことRunQueryAは()を実行し始めたということでしたし、それが行われていただけたらRunQueryBを始めることができます。
当然、クエリで使用された1つまたは複数のメソッドがブロックされていることが示唆されます。 最新のMySQLドライバのソースコード(githubリポジトリから)をダウンロードし、非同期メソッドの実装を探しました。
私はそのクラスを見上げ、私はExecuteReaderAsyncの実装でインスタンスを探し、それがBCL
の一部である基本クラスたSystem.Data.Common.DbCommandに私を導きました
public Task<DbDataReader> ExecuteReaderAsync() {
return ExecuteReaderAsync(CommandBehavior.Default, CancellationToken.None);
}
public Task<DbDataReader> ExecuteReaderAsync(CancellationToken cancellationToken) {
return ExecuteReaderAsync(CommandBehavior.Default, cancellationToken);
}
public Task<DbDataReader> ExecuteReaderAsync(CommandBehavior behavior) {
return ExecuteReaderAsync(behavior, CancellationToken.None);
}
public Task<DbDataReader> ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) {
return ExecuteDbDataReaderAsync(behavior, cancellationToken);
}
protected virtual Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) {
if (cancellationToken.IsCancellationRequested) {
return ADP.CreatedTaskWithCancellation<DbDataReader>();
}
else {
CancellationTokenRegistration registration = new CancellationTokenRegistration();
if (cancellationToken.CanBeCanceled) {
registration = cancellationToken.Register(CancelIgnoreFailure);
}
try {
return Task.FromResult<DbDataReader>(ExecuteReader(behavior));
}
catch (Exception e) {
registration.Dispose();
return ADP.CreatedTaskWithException<DbDataReader>(e);
}
}
}
:.NETリファレンスソース
https://referencesource.microsoft.com/#System.Data/System/Data/Common/DBCommand.cs,1875e74763fd9ef2
そして、何私が見たが本当に私を混乱しました
それはすべてがこのラインに沸く:
return Task.FromResult<DbDataReader>(ExecuteReader(behavior));
をこの行では、ExecuteReaderのは、同期的に実行し、呼び出し元のスレッドをブロックします。
のExecuteReaderは、抽象メソッドを呼び出しMySQLドライバ内部オーバーライドさ
abstract protected DbDataReader ExecuteDbDataReader(CommandBehavior behavior);
:
MySQLの内部実装は基本的にのExecuteReaderの同期バージョンをコール...
つまり、ExecuteReaderAsync()はExecuteReader()を同期して実行し、呼び出しスレッドをブロックします。
私が間違っている場合は私を修正してくださいが、実際にはそうであるようです。
一方は、MySQLドライバは、アカウントにそれを撮影したはずです
私はまさに、ここにBCLまたはMySQLドライバの実装のたDbCommandクラスを非難するが誰であるかを正確に特定することはできません...、 一方、DbCommandはExecuteDbDataReaderAsyncの基本実装を提供するので、少なくとも実際の非同期I/Oを使用せずにワーカースレッドでExecuteReaderの同期バージョンを起動する必要があります。
どう思いますか?
私は回避策として何ができますか? 自分でタスクとしてExecuteReaderAsyncを起動できましたが、私はこの解決策が嫌いです。
あなたはどう思いますか?
おかげで、
アリック