sql >> Database teknologi >  >> RDS >> Mysql

MySQL C# async-metoder virker ikke?

At dømme ud fra noget gammel kode (6.7.2) ser det ud til, at mysql ADO.NET-udbyderen ikke implementerer nogen af ​​asynkron-funktionaliteten korrekt. Dette inkluderer TAP-mønsteret og de ældre stilarter Start..., End... async-mønstre. I den version ser det ud til, at Db* async-metoderne slet ikke er skrevet; de ville bruge basisklassen i .NET, som er synkrone og alle ser nogenlunde sådan ud:

public virtual Task<int> ExecuteNonQueryAsync(...) {
    return Task.FromResult(ExecuteNonQuery(...));
}

(100 % synkront med den ekstra overhead ved at pakke den ind i en opgave; referencekilde her )

Hvis start- og slutversionerne var skrevet korrekt (det er de ikke), kunne det implementeres noget som dette:

public override Task<int> ExecuteNonQueryAsync(...) {
    return Task<int>.Factory.FromAsync(BeginExecuteNonQueryAsync, EndExecuteNonQueryAsync, null);
}

(referencekilde for denne metode til SqlCommand )

At gøre dette er afhængigt af en form for tilbagekalds-API, som den underliggende socket til sidst kan håndtere i et mønster, hvor den, der ringer, sender nogle bytes over socket, og derefter bliver en registreret metode kaldt tilbage fra den underliggende netværksstak, når den er klar.

Imidlertid gør mysql-stikket ikke dette (det tilsidesætter ikke den metode i første omgang; men hvis det gjorde, er de relevante start- og slutmetoder ikke asynkrone på nogle underliggende socket-api). Hvad mysql-stikket gør i stedet bygger en delegeret til en intern metode på den aktuelle forbindelsesforekomst og kalder den synkront på en separat tråd. Du kan ikke i mellemtiden for eksempel udføre en anden kommando på den samme forbindelse, noget som dette:

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;
}

(forudsat at du samler forbindelse og antallet af opgaver er mere end den maksimale puljestørrelse; hvis asynkron fungerede, ville denne kode få et tal afhængigt af antallet af forbindelser i puljen i stedet for et tal afhængigt af både det og antallet af tråde, der kan køre samtidigt)

Dette skyldes, at koden har en lås på driveren (det faktiske, der styrer netværkets interne; *). Og hvis det ikke gjorde det (og det interne var ellers trådsikre, og en anden måde blev brugt til at administrere forbindelsespuljer) det fortsætter med at udføre blokerende opkald på den underliggende netværksstrøm .

Så ja, ingen async-understøttelse i sigte for denne kodebase. Jeg kunne se på en nyere driver, hvis nogen kunne henvise mig til koden, men jeg har mistanke om den interne NetworkStream baserede objekter ser ikke væsentligt anderledes ud, og asynkronkoden ser heller ikke meget anderledes ud. En async understøttende driver ville have det meste af det interne skrevet til at afhænge af en asynkron måde at gøre det på og have en synkron indpakning til den synkrone kode; alternativt ville det ligne SqlClient meget mere referencekilde og afhænger af en eller anden Task indpakningsbibliotek for at abstrahere forskellene mellem at køre synkront eller asynkront.

* låsning på driver betyder ikke, at den muligvis ikke kan bruge ikke-blokerende IO, bare at metoden ikke kunne være skrevet med en låseerklæring og bruge den ikke-blokerende Begin/End IAsyncResult kode, der kunne være skrevet før TAP-mønstre.

Rediger:downloadet 6.9.8; som formodet er der ingen fungerende asynkronkode (ikke-blokerende IO-operationer); der er en fejl gemt her:https://bugs.mysql.com/bug. php?id=70111

Opdatering 6. juli 2016:interessant projekt på GitHub, som måske endelig kan løse dette på https://github.com/ mysql-net/MySqlConnector (kunne nok bruge flere bidragydere, der har en andel i dens succes [Jeg arbejder ikke længere på noget med MySql]).



  1. Hvornår skal jeg bruge MySQL-transaktioner?

  2. Find værdier, der ikke indeholder tal i MySQL

  3. Optimeringstærskler – gruppering og aggregering af data, del 4

  4. Embedded Postgres til fjederstøvletest