Sądząc po starym kodzie (6.7.2), wydaje się, że dostawca mysql ADO.NET nie implementuje poprawnie żadnej funkcji asynchronicznej. Obejmuje to wzorzec TAP i starszy styl Begin..., End... wzory asynchroniczne. W tej wersji metody asynchroniczne Db* wydają się w ogóle nie być napisane; używaliby klas bazowych w .NET, które są synchroniczne i wyglądają mniej więcej tak:
public virtual Task<int> ExecuteNonQueryAsync(...) {
return Task.FromResult(ExecuteNonQuery(...));
}
(100% zsynchronizowany z dodatkowym obciążeniem związanym z pakowaniem go w zadanie; źródło odniesienia tutaj )
Jeśli wersje Begin i End zostały napisane poprawnie (nie są), można by to zaimplementować w następujący sposób:
public override Task<int> ExecuteNonQueryAsync(...) {
return Task<int>.Factory.FromAsync(BeginExecuteNonQueryAsync, EndExecuteNonQueryAsync, null);
}
(źródło odniesienia dla tej metody dla SqlCommand )
Wykonanie tego zależy od pewnego rodzaju wywołania zwrotnego API, z którym bazowe gniazdo ma ostatecznie poradzić sobie we wzorcu, w którym obiekt wywołujący wysyła kilka bajtów przez gniazdo, a następnie zarejestrowana metoda zostaje wywołana z powrotem z bazowego stosu sieciowego, gdy jest gotowa.
Jednak łącznik mysql tego nie robi (nie zastępuje tej metody w pierwszej kolejności; ale jeśli tak, odpowiednie metody początku i końca nie są asynchroniczne w niektórych bazowych interfejsach API gniazd). Do czego służy łącznik mysql zamiast tego kompiluje delegata do metody wewnętrznej w bieżącym wystąpieniu połączenia i wywołuje go synchronicznie w osobnym wątku. W międzyczasie nie możesz na przykład wykonać drugiego polecenia na tym samym połączeniu, coś takiego:
private static void Main() {
var sw = new Stopwatch();
sw.Start();
Task.WaitAll(
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync(),
GetDelayCommand().ExecuteNonQueryAsync());
sw.Stop();
Console.WriteLine(sw.Elapsed.Seconds);
}
private static DbCommand GetDelayCommand() {
var connection = new MySqlConnection (...);
connection.Open();
var cmd = connection.CreateCommand();
cmd.CommandText = "SLEEP(5)";
cmd.CommandType = CommandType.Text;
return cmd;
}
(zakładając, że tworzysz pulę połączeń i liczba zadań jest większa niż maksymalna wielkość puli; jeśli działa asynchroniczna, ten kod otrzyma liczbę zależną od liczby połączeń w puli zamiast liczby zależnej zarówno od tego, jak i od liczby wątki, które mogą działać jednocześnie)
Dzieje się tak, ponieważ kod ma blokada sterownika (rzeczywista rzecz, która zarządza wewnętrznymi elementami sieci; *). A jeśli tak się nie stało (a elementy wewnętrzne były poza tym bezpieczne dla wątków i zastosowano inny sposób do zarządzania pulami połączeń) następuje wykonywanie połączeń blokujących w podstawowym strumieniu sieciowym .
Więc tak, nie widać wsparcia asynchronicznego dla tej bazy kodu. Mógłbym spojrzeć na nowszy sterownik, gdyby ktoś mógł wskazać mi kod, ale podejrzewam wewnętrzny NetworkStream
obiekty oparte nie wyglądają znacząco inaczej, a kod asynchroniczny też nie wygląda zbytnio. async
wspierający sterownik miałby większość elementów wewnętrznych napisanych tak, aby zależeć od asynchronicznego sposobu wykonywania tego i mieć synchroniczne opakowanie dla kodu synchronicznego; alternatywnie wyglądałoby to bardziej jak SqlClient
źródło odniesienia i zależą od niektórych Task
Zawijanie biblioteki, aby oddzielić różnice między działaniem synchronicznym a asynchronicznym.
* blokowanie sterownika nie oznacza, że prawdopodobnie nie może używać nieblokującego IO, tylko że metoda nie mogła zostać napisana za pomocą instrukcji lock i użyć nieblokującego Begin/End IAsyncResult
kod, który mógł zostać napisany przed wzorcami TAP.
Edycja:pobrano 6.9.8; zgodnie z podejrzeniami brak działającego kodu asynchronicznego (nieblokujące operacje IO); jest tu zgłoszony błąd:https://bugs.mysql.com/bug. php?id=70111
Aktualizacja 6 lipca 2016:ciekawy projekt na GitHub, który może wreszcie rozwiązać ten problem pod adresem https://github.com/ mysql-net/MySqlConnector (prawdopodobnie mógłby użyć większej liczby współtwórców, którzy mają udział w jego sukcesie [nie pracuję już nad niczym z MySql]).