Zaczynam od asynchronizacji i zadań, a mój kod przestał przetwarzać. Zdarza się to, gdy mam przychodzący pakiet sieciowy i próbuję komunikować się z bazą danych wewnątrz modułu obsługi pakietów.
public class ClientConnectedPacket : IClientPacket
{
private readonly EntityFactory _entityFactory;
public ClientConnectedPacket(EntityFactory entityFactory)
{
_entityFactory= entityFactory;
}
public async Task Handle(NetworkClient client, ClientPacketReader reader)
{
client.Entity = await _entityFactory.CreateInstanceAsync( reader.GetValueByKey("unique_device_id"));
// this Console.WriteLine never gets reached
Console.WriteLine($"Client [{reader.GetValueByKey("unique_device_id")}] has connected");
}
}
Metoda Handle jest wywoływana z zadania asynchronicznego
if (_packetRepository.TryGetPacketByName(packetName, out var packet))
{
await packet.Handle(this, new ClientPacketReader(packetName, packetData));
}
else
{
Console.WriteLine("Unknown packet: " + packetName);
}
Oto metoda, która moim zdaniem powoduje problem
public async Task<Entity> CreateInstanceAsync(string uniqueId)
{
await using (var dbConnection = _databaseProvider.GetConnection())
{
dbConnection.SetQuery("SELECT COUNT(NULL) FROM `entities` WHERE `unique_id` = @uniqueId");
dbConnection.AddParameter("uniqueId", uniqueId);
var row = await dbConnection.ExecuteRowAsync();
if (row != null)
{
return new Entity(uniqueId, false);
}
}
return new Entity(uniqueId,true);
}
Metoda GetConnection programu DatabaseProvider:
public DatabaseConnection GetConnection()
{
var connection = new MySqlConnection(_connectionString);
var command = connection.CreateCommand();
return new DatabaseConnection(_logFactory.GetLogger(), connection, command);
}
Konstruktor DatabaseConnection:
public DatabaseConnection(ILogger logger, MySqlConnection connection, MySqlCommand command)
{
_logger = logger;
_connection = connection;
_command = command;
_connection.Open();
}
Kiedy komentuję tę linię, dociera do Console.WriteLine
_connection.Open();
await
na nim działa. O wiele trudniej jest zdiagnozować.Connection.open
nie wraca podczas próby połączenia, ale w końcu zrezygnuje po upływie limitu czasu. Lub możesz zmienić wartość limitu czasu obiektu połączenia na mniejszą liczbę większą niż 0 i sprawdzić, czy istnieje wyjątek.Odpowiedzi:
Uruchomiłem projekt POC spinning 100 równoległych zadań zarówno z MySql.Data 8.0.19 i MySqlConnector 0.63.2 w aplikacji konsoli .NET Core 3.1. Tworzę, otwieram i rozmieszczam połączenie w kontekście każdego zadania. Obaj dostawcy biegną do końca bez błędów.
Specyfika polega na tym, że zapytania MySql.Data działają synchronicznie, chociaż biblioteka zapewnia podpis metod asynchronicznych, np. ExecuteReaderAsync () lub ExecuteScalarAsync (), podczas gdy MySqlConnector działa naprawdę asynchronicznie .
Możesz napotkać:
źródło
Wielowątkowość z MySQL musi korzystać z niezależnych połączeń. Biorąc to pod uwagę, wielowątkowość nie jest pytaniem MySQL, ale problemem dla języka klienta, C # w twoim pytaniu.
Oznacza to, że buduj wątki bez względu na MySQL, a następnie utwórz połączenie w każdym wątku, który musi wykonywać zapytania. To będzie na twoich barkach, jeśli będziesz musiał przesyłać dane między wątkami.
Zazwyczaj uważam, że optymalizacja zapytań eliminuje pokusę wielowątkowości moich aplikacji.
źródło