Una introducción a la programación de flujo de respuesta de contrapresión de corrientes reactivas

concepto

Una de las razones por las que node.js es tan popular es que node.js adopta tecnología de programación asincrónica sin bloqueo, de modo que node.js puede mejorar el rendimiento del servidor y manejar fácilmente una gran cantidad de solicitudes simultáneas.

Pero hay muchos problemas en la programación asíncrona, como el infierno de devolución de llamadas, el manejo de errores, etc. El modelo de programación en streaming se propone para reducir la dificultad de la programación asíncrona. Nacen muchas bibliotecas de clases de programación de flujos de Java y aplicaciones marco
React streams es una especificación de programación sensible a la contrapresión, que hace que la programación de flujos asincrónicos esté relativamente estandarizada y unificada a través de un conjunto de interfaces, métodos y protocolos mínimos. Entre ellos, el flujo reactivo en jdk9 es la implementación java de los flujos de reacción.

transmisión de programación

La programación de transmisión es un paradigma de programación que trata los datos como una transmisión en lugar de una colección única de datos. La idea central de la programación de transmisión es tratar la recopilación de datos como una serie de elementos, en lugar de una recopilación de datos única.
El proceso de procesamiento de datos es el proceso de procesamiento del flujo de datos. Los datos fluyen de un enlace a otro como un flujo de agua, cada enlace procesa los datos y finalmente obtiene el resultado final.
En lugar de llamar a otros métodos de objetos a través de un método para completar operaciones de datos como el paradigma de programación anterior.
La idea subyacente adoptada por la programación de transmisión es el modelo de publicación de suscriptores. El enlace de procesamiento de datos se suscribe a los datos en forma de suscriptores. Una vez que se generan los datos, el editor envía los datos a los suscriptores.
Los suscriptores procesan los datos de forma asíncrona, en lugar de procesar todos los datos a la vez. Un artículo que escribí sobre el patrón del observador puede ayudar a comprender mejor este patrón de programación.

contrapresión

La contrapresión se refiere a un mecanismo de coordinación entre los productores de datos y los consumidores.Cuando los productores de datos producen datos más rápido de lo que los consumidores consumen datos, se produce una contrapresión. El protocolo de contrapresión de los flujos de reacción estipula que cuando el suscriptor no puede procesar los datos, el editor debe suspender la publicación de los datos.
Los editores deben continuar publicando datos mientras los suscriptores pueden procesar los datos. De esta forma, se puede garantizar que la velocidad entre el productor y el consumidor de los datos sea constante y se puede evitar la pérdida de datos.
Puede entenderse como un mecanismo de publicación de retroalimentación de datos adaptable basado en las capacidades de procesamiento de los suscriptores.

centro

El núcleo de los flujos de reacción es Editor, Suscriptor, Suscripción, Procesador.

  • Editor: El editor es responsable de publicar los datos. El editor puede ser una fuente de datos o un procesador de datos.
  • Suscriptor: Suscriptor, que es responsable de suscribir los datos, el suscriptor puede ser un procesador de datos o un terminal de datos.
  • Suscripción: Suscripción, que se encarga de suscribir los datos del editor, y el suscriptor puede suscribirse a múltiples editores.
  • Procesador: Procesador, que se encarga de procesar los datos.El procesador puede ser una fuente de datos o un terminal de datos.

Mediante el uso de estas cuatro bibliotecas principales proporcionadas por la biblioteca de clases, o la personalización de su propia implementación específica, puede utilizar fácilmente la programación sensible a la contrapresión.

editor

public interface Publisher<T> {
    
    
    void subscribe(Subscriber<? super T> s);
}

El editor es un editor responsable de publicar datos. El editor puede ser una fuente de datos o un procesador de datos.
El método de suscripción es el punto de entrada para que el suscriptor se suscriba al editor.
Puede implementar la interfaz de publicación, donde jdk9 proporciona algunas implementaciones comunes de la interfaz de Flow.Publisher, como:


public class MyPublisher implements Publisher<String> {
    
    
    @Override
    public void subscribe(Subscriber<? super String> s) {
    
    
        s.onSubscribe(new MySubscription(s));
    }
}

Implementaciones de editores comunes proporcionadas por jdk9

  • SubmissionPublisher: un editor que se puede enviar que puede enviar datos a través del método de envío y, cuando se envían los datos, los envía a los suscriptores.

abonado

public interface Subscriber<T> {
    
    
    void onSubscribe(Subscription s);
    void onNext(T t);
    void onError(Throwable t);
    void onComplete();
}

El suscriptor es un suscriptor, que es responsable de suscribir los datos. El suscriptor puede ser un procesador de datos o un terminal de datos.
El método onSubscribe entre ellos es que después de que el suscriptor se suscriba al publicador, el publicador llamará al método onSubscribe del suscriptor para pasar el objeto de suscripción del suscriptor al suscriptor.
El método onNext entre ellos es que cuando el editor publica los datos, llamará al método onNext del suscriptor para pasar los datos al suscriptor.
El método onError entre ellos es que cuando el editor publica datos con una excepción, llamará al método onError del suscriptor para pasar la excepción al suscriptor.
El método onComplete entre ellos es que cuando el publicador termine de publicar los datos, llamará al método onComplete del suscriptor para notificar al suscriptor que la publicación de datos se ha completado.
En general, debe implementar la interfaz de suscriptor usted mismo para completar el procesamiento de datos, como:

public class MySubscriber implements Subscriber<String> {
    
    
    private Subscription subscription;
    @Override
    public void onSubscribe(Subscription s) {
    
    
        this.subscription = s;
        this.subscription.request(1);
    }
    @Override
    public void onNext(String s) {
    
    
        System.out.println("onNext: " + s);
        this.subscription.request(1);
    }
    @Override
    public void onError(Throwable t) {
    
    
        t.printStackTrace();
    }
    @Override
    public void onComplete() {
    
    
        System.out.println("onComplete");
    }
}

suscripción

public interface Subscription {
    
    
    void request(long n);
    void cancel();
}

La suscripción es una suscripción, que es responsable de suscribirse a los datos del editor, y el suscriptor puede suscribirse a varios editores.
El parámetro n en el método de solicitud es la cantidad de datos que el suscriptor solicita al editor que publique.
El método de cancelación es para facilitar que el suscriptor se dé de baja de los datos del editor.

procesador

public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
    
    
}

El procesador es un procesador, que es responsable de procesar los datos. El procesador puede ser una fuente de datos o un terminal de datos.
No es difícil ver a partir de la definición de la interfaz que un Procesador es una combinación de un publicador y un suscriptor, que puede publicar datos o suscribirse a datos.

public class MyProcessor implements Processor<String, String> {
    
    
    private Subscriber<? super String> subscriber;
    @Override
    public void subscribe(Subscriber<? super String> s) {
    
    
        this.subscriber = s;
        this.subscriber.onSubscribe(new MySubscription(s));
    }
    @Override
    public void onSubscribe(Subscription s) {
    
    
        s.request(1);
    }
    @Override
    public void onNext(String s) {
    
    
        System.out.println("onNext: " + s);
        this.subscriber.onNext(s);
    }
    @Override
    public void onError(Throwable t) {
    
    
        t.printStackTrace();
    }
    @Override
    public void onComplete() {
    
    
        System.out.println("onComplete");
    }
}

Cuando el editor genera datos, solo puede fluir a un suscriptor.
Si necesita recibir datos de varios suscriptores en secuencia, necesita usar un procesador.El procesador se puede usar como un enlace intermedio de procesamiento y entrega, ya que puede ser un editor o un suscriptor.

escritura comprensiva

import java.io.IOException;
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;

/**
 * @Author zhangshiyu
 * @Date 2023/1/26 18:25
 * @project reactive-stream-demo
 */
public class ReactiveStreamDemo {
    
    
    //main
    public static void main(String[] args) throws IOException {
    
    

        //创建发布者
        SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
        //创建订阅者
        Flow.Subscriber<String> subscriber = new Flow.Subscriber<String>() {
    
    
            @Override
            public void onSubscribe(Flow.Subscription subscription) {
    
    
                //订阅者处理订阅请求
                System.out.println("onSubscribe");
                subscription.request(Integer.MAX_VALUE);
            }

            @Override
            public void onNext(String s) {
    
    
                //订阅者处理发布者发布的消息
                System.out.println("onNext----\r\n" + s);
            }

            @Override
            public void onError(Throwable throwable) {
    
    
                //订阅者处理发布者发布的异常消息
                System.out.println("onError");
            }

            @Override
            public void onComplete() {
    
    
                //订阅者处理发布者发布的完成消息
                System.out.println("onComplete");
            }
        };
        Flow.Processor<String, String> processor = new Flow.Processor<String, String>() {
    
    
            private Flow.Subscriber<? super String> subscriber;

            @Override
            public void subscribe(Flow.Subscriber<? super String> subscriber) {
    
    
                this.subscriber = subscriber;
            }

            @Override
            public void onSubscribe(Flow.Subscription subscription) {
    
    
                subscriber.onSubscribe(subscription);
            }

            @Override
            public void onNext(String item) {
    
    
                System.out.println("processor----" + item);
                subscriber.onNext(item + "(processed)");
            }

            @Override
            public void onError(Throwable throwable) {
    
    
                subscriber.onError(throwable);
                System.out.println("processor----\r\n" + throwable.getMessage());
            }

            @Override
            public void onComplete() {
    
    
                subscriber.onComplete();
                System.out.println("processor----\r\n" + "onComplete");
            }
        };
        //发布者和订阅者建立订阅关系
        processor.subscribe(subscriber);
        publisher.subscribe(processor);


        //发布者发布消息
        publisher.submit("hello");
        publisher.submit("world");
        publisher.submit("reactive");
        publisher.close();
        System.in.read();
    }
}

Supongo que te gusta

Origin blog.csdn.net/aofengdaxia/article/details/128805103
Recomendado
Clasificación