Em Rx, como agrupar eventos por id e estrangular cada grupo por vários TimeSpans?
Eu entrei em uma onda Rx, por assim dizer, e esta questão está relacionada com o meuAqui eAqui. No entanto, talvez sejam de ajuda para alguém como eu poderia vê-los como variações úteis do mesmo tema.
Questão: Como alguém poderia agrupar um fluxo aleatório deint
(digamos, no intervalo [0, 10] produzido em intervalo aleatório) objetos em grupos e fornecem para o grupo de busca um número variável de ausência de alarmes de eventos (pela falta de melhor definição, para um segundo plano ver os posts vinculados). Mais especificamente com o código, como definir as configurações de aceleração multiponto por grupo da seguinte maneira:
var idAlarmStream = idStream
.Select(i => i)
.GroupByUntil(key => key.Id, grp => grp.Throttle(Timespan.FromMilliseconds(1000))
.SelectMany(grp => grp.TakeLast(1))
.Subscribe(i => Console.WriteLine(i));
Aqui a função de assinatura será chamada se houver mais de um segundo de ausência de IDs por grupo. E se você quiser definir três valores diferentes para a ausência de eventos (digamos, um segundo, cinco segundos e dez segundos) e todos cancelados quando um evento chegar? O que eu posso pensar são:
Divida cada ID emidStream
em vários sintéticos e fornecem um mapeamento bijetivo entre os IDs reais e os sintéticos. Por exemplo, neste caso, ID: 1 -> 100, 101, 102; ID: 2 -> 200, 201, 203 e, em seguida, defina uma função de seletor emThrottle
igual aFunc<int, Timespan>(i => /* switch(i)...*/)
e então quandoSubscribe
será chamado, mapeie o ID de volta. Veja também as perguntas relacionadas para mais informações.Crie um agrupamento aninhado no qual os IDs são agrupados e, posteriormente, os grupos de IDs serão copiados / replicados / bifurcados (não sei o termo adequado) em grupos de acordo com os valores de limitação. Essa abordagem, na minha opinião, é bastante complicada e não tenho certeza se seria a melhor opção. Eu certamente estaria interessado em ver tal consulta, no entanto.Em um cenário mais geral, suspeito, essa é uma situação em que há vários manipuladores por algum grupo, embora eu não tenha conseguido encontrar nada relacionado a isso.
<edit: Como (espero esclarecer) um exemploidStream
envia um ID: 1 no qual três contadores diferentes seriam iniciados, cada um esperando o próximo evento ocorrer ou alarmando se nenhum novo ID 1 for detectado a tempo. O contador 1 (C1) aguarda por cinco segundos, contador 2 (C2) por sete segundos e contador 3 (C3) por dez segundos. Se um novo ID 1 for recebido no intervalo de [0, 5] segundos, todos os contadores serão reinicializados com os valores acima mencionados e nenhum alarme será enviado. Se um novo ID for recebido dentro de um intervalo de [0, 7) segundos, os alarmes C1 e C2 e C3 serão reinicializados. Da mesma forma, se um novo ID for recebido dentro de um intervalo [0, 10], os segundos C1 e C2 serão acionados, mas o C3 será reinicializado.
Ou seja, haveria múltiplos "alarmes de ausência" ou, em geral, ações tomadas em relação a um ID, dadas algumas condições. Não tenho certeza do que seria um bom analógico ... Talvez empilhar "luzes de alerta" em uma torre, de modo que primeiro seja verde, depois amarelo e por último vermelho. Como a ausência de um ID continua cada vez mais longa, uma cor após a cor será acesa (nesse caso, vermelho é o último). Então, quando um ID for detectado, todas as luzes serão apagadas.
<edite 2: Após a adaptação do código de James para o exemplo da seguinte forma e deixando o resto como escrito, descobri oSubscribe
será chamado diretamente no primeiro evento em ambos os dois níveis de alarme.
const int MaxLevels = 2;
var idAlarmStream = idStream
.Select(i => i)
.AlarmSystem(keySelector, thresholdSelector, MaxLevels, TaskPoolScheduler.Default)
.Subscribe(i =>
{
Debug.WriteLine("Alarm on id \"{0}\" at {1}", i, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture));
});
Vamos ver o que está acontecendo aqui e seMaxLevels
poderia ser fornecido dinamicamente ...
<edit 3: O código de James funciona. O problema estava entre a cadeira e o teclado! Mudar o tempo para algo mais sensato com certeza ajudou. Na verdade, eu mudei para figuras maiores, mas foi.FromTicks
e isso me escapou por alguns minutos.