sql >> Databáze >  >> RDS >> Mysql

Nefungují asynchronní metody MySQL C#?

Soudě podle starého kódu (6.7.2) se zdá, že poskytovatel mysql ADO.NET neimplementuje správně žádnou asynchronní funkcionalitu. To zahrnuje vzor TAP a starší asynchronní vzory stylu Begin..., End.... V této verzi se zdá, že asynchronní metody Db* nejsou vůbec zapsány; budou používat ty základní třídy v .NET, které jsou synchronní a všechny vypadají nějak jako:

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

(100% synchronní s přidanou režií zabalení do úlohy; referenční zdroj zde )

Pokud by byly verze Begin a End napsány správně (nejsou), mohlo by to být implementováno asi takto:

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

(referenční zdroj pro tuto metodu pro SqlCommand )

To závisí na nějakém druhu zpětného volání api pro podkladový soket, se kterým se nakonec vypořádá ve vzoru, kdy volající odešle nějaké bajty přes soket a poté se registrovaná metoda zavolá zpět z podkladového síťového zásobníku, když je připravena.

Konektor mysql to však nedělá (nepřepisuje tuto metodu na prvním místě, ale pokud ano, příslušné metody zahájení a ukončení nejsou na některém základním rozhraní socket API asynchronní). Co dělá konektor mysql místo sestaví delegáta pro interní metodu na aktuální instanci připojení a vyvolá ji synchronně v samostatném vláknu. Mezitím nemůžete například provést druhý příkaz na stejném připojení, něco takového:

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

(za předpokladu, že sdružujete připojení a počet úloh je větší než maximální velikost fondu; pokud by asynchronní fungoval, tento kód by získal číslo v závislosti na počtu připojení ve fondu namísto čísla v závislosti na tom i počtu vlákna, která mohou běžet souběžně)

Důvodem je, že kód má zamknout ovladač (skutečná věc, která spravuje vnitřnosti sítě; *). A pokud tomu tak nebylo (a interní prvky byly jinak bezpečné pro vlákna a pro správu fondů připojení byl použit jiný způsob) pokračuje v provádění blokování volání na základním síťovém streamu .

Takže ano, pro tuto kódovou základnu není v dohledu žádná asynchronní podpora. Mohl bych se podívat na novější ovladač, kdyby mě někdo mohl nasměrovat na kód, ale mám podezření na interní NetworkStream založené objekty nevypadají výrazně odlišně a asynchronní kód také nevypadá příliš odlišně. async podpůrný ovladač by měl většinu vnitřních součástí zapsána tak, aby závisela na asynchronním způsobu provádění, a měl by synchronní obal pro synchronní kód; alternativně by to vypadalo mnohem více jako SqlClient referenční zdroj a závisí na nějakém Task zabalit knihovnu, aby se odstranily rozdíly mezi synchronním nebo asynchronním spuštěním.

* zamykání ovladače neznamená, že by nemohlo používat neblokující IO, jen to, že metoda nemohla být napsána s příkazem lock a použít neblokující Begin/End IAsyncResult kód, který mohl být napsán před vzory TAP.

Edit:staženo 6.9.8; podle podezření neexistuje žádný funkční asynchronní kód (neblokující IO operace); je zde uložena chyba:https://bugs.mysql.com/bug. php?id=70111

Aktualizace 6. července 2016:zajímavý projekt na GitHubu, který to může konečně vyřešit na https://github.com/ mysql-net/MySqlConnector (pravděpodobně by se dalo použít více přispěvatelů, kteří mají podíl na jeho úspěchu [již na ničem s MySql nepracuji]).



  1. Jak aktualizovat stejnou tabulku při smazání v MYSQL?

  2. Udělit výběr u všech stolů vlastněných konkrétním uživatelem

  3. Excel vs Access:Kdy je čas přejít?

  4. Získejte výsledky z mysql na základě zeměpisné šířky a délky