Estou apenas começando com async e Task e meu código parou de processar. Isso acontece quando tenho um pacote de rede recebido e tento me comunicar com o banco de dados dentro do manipulador de pacotes.
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");
}
}
O método Handle é chamado de uma tarefa assíncrona
if (_packetRepository.TryGetPacketByName(packetName, out var packet))
{
await packet.Handle(this, new ClientPacketReader(packetName, packetData));
}
else
{
Console.WriteLine("Unknown packet: " + packetName);
}
Aqui está o método que eu acho que está causando o problema
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);
}
Método GetConnection do DatabaseProvider:
public DatabaseConnection GetConnection()
{
var connection = new MySqlConnection(_connectionString);
var command = connection.CreateCommand();
return new DatabaseConnection(_logFactory.GetLogger(), connection, command);
}
Construtor DatabaseConnection:
public DatabaseConnection(ILogger logger, MySqlConnection connection, MySqlCommand command)
{
_logger = logger;
_connection = connection;
_command = command;
_connection.Open();
}
Quando eu comento esta linha, ela atinge o Console.WriteLine
_connection.Open();
await
nele. Isso é muito mais difícil de diagnosticar.Connection.open
não retorna enquanto está tentando se conectar, mas finalmente desiste após um tempo limite definido. Ou você pode alterar o valor do tempo limite no objeto de conexão para um número menor maior que 0 e ver se há exceção.Respostas:
Executei um projeto POC girando 100 tarefas paralelas, tanto com o MySql.Data 8.0.19 como com o MySqlConnector 0.63.2 no aplicativo de console do .NET Core 3.1. Crio, abro e descarro a conexão no contexto de cada tarefa. Ambos os provedores são executados sem erros.
As especificidades são que as consultas MySql.Data são executadas de forma síncrona, embora a biblioteca forneça assinatura de métodos assíncronos, por exemplo, ExecuteReaderAsync () ou ExecuteScalarAsync (), enquanto o MySqlConnector é executado de maneira verdadeiramente assíncrona .
Você pode estar se deparando com:
fonte
Multi-threading com MySQL deve usar conexões independentes. Dado que, o multithreading não é uma questão do MySQL, mas um problema para a linguagem do cliente, C # na sua pergunta.
Ou seja, construa seus threads sem considerar o MySQL, então crie uma conexão em cada thread que precise fazer consultas. Ele estará em seus ombros se você precisar passar dados entre os threads.
Normalmente, acho que a otimização de consultas elimina a tentação de multi-thread de meus aplicativos.
fonte