A Extensão .Net Reactive oferece aos desenvolvedores um conjunto de recursos para implementar um modelo de programação reativa para desenvolvedores .Net, tornando o manejo de eventos mais simples e expressivo usando ações declarativas. Embora os pilares fundamentais do escalonamento reativo sejam as interfaces IObserver e IObservable, como desenvolvedor, muitas vezes você não precisa implementar essas interfaces por conta própria. A biblioteca suporta o tipo embutido Subject<T>, que implementa interfaces e suporta muitas funções.
Os temas são a base para os diferentes tópicos disponíveis na biblioteca, e há outros temas - <T>ReplaySubject,<T> BehaviorSubject e <T>AsyncSubject. É útil entender as diferenças essenciais entre elas e como usá-las para fazer melhor uso da biblioteca.
Neste artigo, vamos comparar o Sujeito<T> e seu irmão, tentando ilustrar as diferenças entre seus comportamentos.
Assunto<T>
Como mencionado anteriormente, o Subject<T> é a base para os temas disponíveis, oferecendo uma maneira fácil de usar a biblioteca sem precisar implementar as interfaces IObservable<T> e IObserver<T> por conta própria. Uma demonstração simples do tipo de tema é mostrada abaixo.
No código acima, criamos uma <T>instância do Subject e, como ele implementa<T> IObserver e IObserverable<T>, usamos a mesma instância para assinar e publicar o valor no IObserver. Outro ponto importante a se notar aqui é como usamos a sobrecarga do método Subscribe para aceitar ações como entrada. Isso será feito para cada valor publicado, neste caso imprimindo o número no console.
Vamos tentar mostrar os valores publicados e os valores que o IObserver (nesta Ação<T>) imprime no console na imagem a seguir. Isso nos ajudará a comparar facilmente os irmãos restantes e suas variantes.
A primeira linha representa o valor publicado, e a segunda linha representa o valor recebido pelo IObserver. Além disso, adicionamos uma linha para indicar em que ponto o observador assina o fluxo durante a execução. Essa linha é representada por uma linha pontilhada vertical.
No código acima, notamos que o observador assinava o fluxo de dados antes de publicar o primeiro valor. A imagem mostra a linha do assinante colocada antes do primeiro elemento. Como você pode ver pela linha de saída, isso não tem efeito na saída (neste momento).
Mas e se o observador só assinar os dados depois que alguns valores já foram publicados? Isso tem impacto nos dados recebidos pelos observadores? Antes de olhar para a saída, vamos escrever o mesmo código primeiro.
No código acima, podemos observar que o observador subscreve o fluxo de dados apenas após a publicação de dois valores (1 e 2). Como era de se esperar, isso fará com que os observadores não recebam dados publicados antes de chamar o método de assinatura. Como mostrado na figura abaixo.
E se você quiser ler todos os valores publicados, mesmo que o observador assine tarde? É aí que entra o<T> ReplaySubject.
ReplaySubject<T>
O ReplaySubject<T> armazena valores em cache e os reproduz para assinantes posteriores. Isso é útil para evitar condições de corrida. Vamos mudar o código anterior para usar<T> ReplaySubject e ver como isso afeta o que o observador recebe.
Como mostrado no código acima,<T> <T>quase não há mudança no código, exceto que agora usamos ReplaySubject em vez de subject. O diagrama a seguir ilustra o impacto nos dados recebidos pelo observador.
Como mostrado na imagem, o valor em cache agora é reproduzido para o assinante mesmo que ele assine posteriormente. Claro, esse recurso útil tem um preço. Essa implementação armazena em cache todos os valores publicados pelo assinante, o que pode causar problemas de memória ruim quando a quantidade de dados é significativamente maior.
No entanto, o ReplaySubject<T> tem mais de uma forma de resolver esse problema. Para efeitos deste exemplo, vamos analisar dois exemplos que usam restrições de tamanho e tempo para limitar o valor em cache.
No primeiro caso, usaremos o tamanho do cache para limitar o valor do cache. <T>O construtor do ReplaySubject fornece uma sobrecarga, que aceita um inteiro que representa o tamanho do buffer do cache (contagem máxima de elementos). No nosso exemplo, vamos mudar o código para limitar o tamanho do cache a 1.
Note como usamos <T>a sobrecarga do construtor do ReplaySubject para fornecer o tamanho do Cache como 1. Isso limita o cache e garante que apenas um elemento seja armazenado em cache e substituído por um novo assim que for publicado. O impacto da mudança está mostrado abaixo.
Outra forma de limitar o cache é limitar o tempo do item em cache, ou seja, fornecer um tempo de expiração para o item em cache.
Vamos escrever código para ilustrar esse exemplo.
Semelhante ao código anterior, usamos<T> a sobrecarga do construtor ReplaySubject para especificar o tempo de expiração dos itens no cache. Para demonstrar nosso caso, introduzimos um atraso entre a divulgação dos valores.
Como leva 1200ms completos até que o observador assine, quaisquer elementos que excedam o tempo de expiração de 1000ms serão removidos do cache. Neste exemplo, isso fará com que o valor 1 seja removido do cache e não será reproduzido para assinantes atrasados. Como mostrado na figura abaixo.
<T>Existem outras sobrecargas para o ReplaySubject que oferecem mais flexibilidade e ajustam os valores em cache, mas para exemplos, vamos manter os dois exemplos já abordados acima.
ComportamentoSujeito<T>
BehaviourSubject <T>é muito parecido com<T> ReplaySubject no sentido de que ajuda a armazenar valores em cache. Mas há uma diferença significativa. BehaviourSubject<T> armazena apenas o último valor publicado. Antes de entrarmos mais nisso, vamos escrever um pouco de código.
Se o BehaviorSubject<T> armazena em cache apenas um único valor (que é o último conhecido), em que ele difere de um ReplaySubject de tamanho 1<T>? O diagrama a seguir reflete claramente a situação do código acima.
No entanto, isso não é totalmente verdade. Há duas diferenças importantes a serem compreendidas aqui. A primeira é a presença de defaults. Note que no código acima, <T>fornecemos o valor 0 como padrão no construtor do BehaviourSubject. Se não houver valor no cache (ou seja, nenhum dado foi publicado antes do observador assinar), o valor padrão será retornado. Isso é diferente do ReplaySubject, que tem tamanho 1<T>, que não tem valor. O código a seguir e uma representação visual da sequência demonstram esse comportamento.
A segunda diferença é como<T> BehaviorSubject e<T> ReplaySubject se comportam ao assinar uma sequência completa. Quando você assinar após a conclusão, o BehaviorSubject <T> não terá valor, conforme mostrado no código abaixo.
Assinantes têm garantia de não receber nenhum valor porque as assinaturas ocorrem após a conclusão.
No entanto, <T>esse é o caso do ReplaySubject . Não há garantia de que o observador não receberá nenhum valor, como mostrado no código abaixo.
Como mostrado no código acima, o cache tem 1 de tamanho e, mesmo que a assinatura seja chamada após a chamada ser concluída, o cache permanecerá (até que a condição de expiração seja cumprida), então, nesse caso, o último valor publicado será recebido.
AsyncSubject<T>
<T>AsyncSubject é o último irmão do Sujeito que exploraremos neste artigo<T>, e é muito semelhante aos dois anteriores (ReplaySubject e BehaviourSubject) no fato de também armazenar em cache os resultados. Mas, novamente, há uma diferença significativa. O AsyncSubject publica o último valor em cache somente se a sequência for marcada como completa <T> (ele armazena em cache apenas um valor, o último valor).
Considere o seguinte código.
Isso gerará um valor para o observador que a sequência é marcada como o último valor publicado antes da conclusão - valor 4. Como mostrado na figura abaixo.
Mas o que acontece se pularmos a chamada que marca a sequência como completa? Vamos comentar a linha e tentar de novo.
Isso não gera nenhum dado para o observador porque o AsyncSubject<T> publica os resultados somente após a sequência ser marcada como completa.
Essa é uma diferença significativa que qualquer pessoa que <T>use AsyncSubject deve ter em mente.
conclusão
Este artigo demonstra <T>as diferenças entre os vários irmãos do Sujeito e algumas de suas variações. Muitas vezes é útil estar atento a essas diferenças sutis, pois elas podem apresentar comportamentos diferentes do que você esperava se você não perceber.
Link original:O login do hiperlink está visível.
|