Myślę, że się tutaj mylisz. ConnectionMultiplexer
nie "blokuje się". Tworzenie ConnectionMultiplexer
daje ci obiekt przypominający fabrykę, za pomocą którego możesz utworzyć IDatabase
instancje. Następnie używasz tych wystąpień do wykonywania normalnych zapytań Redis. Możesz także wykonywać zapytania Redis za pomocą samego multipleksera połączenia, ale są to zapytania serwera i raczej nie będą wykonywane często.
W skrócie, może ogromnie pomóc mieć pulę multiplekserów połączeń, niezależnie od synchronizacji /async/mieszane użycie.
Aby dalej rozwinąć, oto bardzo prosta implementacja puli, którą z pewnością można jeszcze bardziej ulepszyć:
public interface IConnectionMultiplexerPool
{
Task<IDatabase> GetDatabaseAsync();
}
public class ConnectionMultiplexerPool : IConnectionMultiplexerPool
{
private readonly ConnectionMultiplexer[] _pool;
private readonly ConfigurationOptions _redisConfigurationOptions;
public ConnectionMultiplexerPool(int poolSize, string connectionString) : this(poolSize, ConfigurationOptions.Parse(connectionString))
{
}
public ConnectionMultiplexerPool(int poolSize, ConfigurationOptions redisConfigurationOptions)
{
_pool = new ConnectionMultiplexer[poolSize];
_redisConfigurationOptions = redisConfigurationOptions;
}
public async Task<IDatabase> GetDatabaseAsync()
{
var leastPendingTasks = long.MaxValue;
IDatabase leastPendingDatabase = null;
for (int i = 0; i < _pool.Length; i++)
{
var connection = _pool[i];
if (connection == null)
{
_pool[i] = await ConnectionMultiplexer.ConnectAsync(_redisConfigurationOptions);
return _pool[i].GetDatabase();
}
var pending = connection.GetCounters().TotalOutstanding;
if (pending < leastPendingTasks)
{
leastPendingTasks = pending;
leastPendingDatabase = connection.GetDatabase();
}
}
return leastPendingDatabase;
}
}