Tutorial avanzado de PHP: ¿cómo jugar una rutina de PHP? Este artículo lo guiará a través de la corrutina de swoole

Las corrutinas son complejas y no complicadas, pero difíciles y no difíciles. Una frase se puede resumir: puede mejorar la concurrencia pero no puede acelerar las tareas, el código síncrono implementa IO asíncrono y bloques de código no bloqueantes asíncronos.

Una corrutina es una función especial, una función que se puede suspender y luego reanudar la ejecución desde donde se suspendió. Varias corrutinas en un hilo son en serie, al igual que el proceso de procesamiento de la CPU. Una corrutina se puede ejecutar en un hilo, a menos que se dé control a otras corrutinas para que se ejecuten. La corrutina no puede usar la CPU de múltiples núcleos, por lo que la corrutina solo puede resolver el problema de concurrencia, no el problema de velocidad de procesamiento de la tarea. Una corrutina consiste en dividir una tarea grande en fragmentos más pequeños y encapsular una función del proceso.Cuando una de las corrutinas necesita ser bloqueada por IO, suspende activamente la corrutina actual y transfiere el control a otras corrutinas.

Sabemos que los procesos y subprocesos son programados por el sistema operativo, cuándo ejecutarlo depende de cuándo el sistema operativo le da tiempo de CPU a un proceso o subproceso, y cuándo la corrutina cede el control lo determina el usuario. Los procesos y subprocesos pertenecen al modo kernel y las corrutinas pertenecen a los subprocesos del modo de usuario.

La corrutina es un hilo liviano en el modo de usuario, y la programación de la corrutina está completamente controlada por el usuario. La corrutina tiene su propio contexto de registro y pila. Cuando la corrutina esté programada para cambiar, guarde el contexto de registro y apílelo en otros lugares. Cuando vuelva a cambiar, restaure el contexto de registro y la pila previamente guardados. Operar directamente en la pila básicamente no tiene sobrecarga de conmutación del kernel, y puede acceder a variables globales sin bloquear. , Entonces el cambio de contexto es muy rápido.

Mis pingüinos intercambian oh juntos

Funciones de corrutina

  • Los subprocesos del modo de usuario, cuando se encuentran con IO, renuncian activamente al control

  • Múltiples códigos de rutina siguen siendo seriales, no es necesario bloquearlos

  • Baja sobrecarga, solo ocupa memoria, sin sobrecarga de conmutación de procesos y subprocesos

  • Gran cantidad de simultaneidad, un solo proceso puede abrir corrutinas de 50w

  • En cualquier momento, en cualquier lugar, siempre que desee ser concurrente, llame a go para crear una corrutina

Inserte la descripción de la imagen aquí

Sabemos que los hilos son procesos ligeros, por lo que las corrutinas son hilos ligeros. Las corrutinas se ejecutan en subprocesos y un subproceso puede tener varias corrutinas.

Sabemos que cuando el proceso encuentra un bloqueo, se abre un subproceso más para cambiar dentro del proceso para evitar cambiar el proceso cada vez, de modo que el tiempo disponible asignado por la CPU al proceso se pueda utilizar con más vigor. La relación entre una corrutina y un hilo y un proceso es muy similar, excepto que una corrutina tiene una relación directa con un hilo.

Inserte la descripción de la imagen aquí

La figura anterior es un diagrama esquemático de conmutación entre varios subprocesos, así que consideremos, si un subproceso solo está esperando operaciones de E / S (red o archivo), ¿por qué reutiliza este subproceso como un subproceso reutiliza un proceso? Eliminemos el IO y veamos cómo se ve este gráfico.

Inserte la descripción de la imagen aquí

Eliminando la parte IO de la operación, se puede ver que básicamente este código de aplicación de solicitud concurrente se puede ejecutar en un solo hilo, y la corrutina aprovecha al máximo el tiempo que el hilo espera IO, para que el programa pueda ejecutar otros códigos comerciales mientras espera IO.

Inserte la descripción de la imagen aquí

¿Parece el flujo de ejecución de un hilo? Este es el encanto de una corrutina. Cuando se entrega una corrutina, se suspenderá y transferirá el control a otras corrutinas dentro del hilo, porque se realiza en el hilo. Conmutación, por lo que la sobrecarga es mucho menor que los procesos y los subprocesos.

Inserte la descripción de la imagen aquí

Después de que el programa llama a la corrutina, la corrutina actual cederá activamente el control a otras corrutinas en el mismo hilo para su procesamiento.Como se muestra en la figura, cuando el desarrollador necesita usar IO en el código, renunciará activamente al control de la corrutina. Utilizado por otras corrutinas.

Inserte la descripción de la imagen aquí

Quite la parte IO y observe el procesamiento de la corrutina. Todo lo que se ejecuta directamente es lógica de negocios, evitando que el IO haga que el hilo cambie al estado de espera, y haciendo un uso completo del tiempo de ejecución asignado a este hilo por la CPU.

Nota: La corrutina no acelera las tareas, solo puede realizar más tareas.

Debido a que las corrutinas se basan en subprocesos, no hay forma de aprovechar las ventajas de la CPU de varios núcleos. Las corrutinas son adecuadas para escenarios de computación intensivos en E / S.

¿Cuál es el papel de las corrutinas?

La corrutina es aumentar el uso de la CPU y evitar una gran cantidad de cambios de contexto de subproceso cuando el subproceso está bloqueado.

echo "1-start\n";
sleep(1);
echo "1-end\n";
echo "2-start\n";
sleep(1);
echo "2-end\n";
echo "3-start\n";
sleep(1);
echo "3-end\n";
echo "4-start\n";
sleep(1);
echo "4-end\n";

Inserte la descripción de la imagen aquí

El uso de CPU del código anterior es solo del 1%

Swoole\Runtime::enableCoroutine(true);
go(function () {
    
    
    echo "go1-start\n";
    sleep(1);
    echo "go1-end\n";
});
go(function () {
    
    
    echo "go2-start\n";
    sleep(1);
    echo "go2-end\n";
});
go(function () {
    
    
    echo "go3-start\n";
    sleep(1);
    echo "go3-end\n";
});
go(function () {
    
    
    echo "go4-start\n";
    sleep(1);
    echo "go4-end\n";
});

Inserte la descripción de la imagen aquí

Usando la corrutina, el uso de la CPU se incrementó con éxito al 4%, por lo que la CPU no necesita funcionar inactiva para el bloqueo de E / S o realizar cambios de contexto. ¿No decía que las corrutinas no se pueden acelerar? Después de usar la corrutina aquí, ¿por qué se ejecuta en más de 1 segundo, que es diferente del código anterior? El tiempo obtenido aquí depende del momento en que finalice la última ejecución de la corrutina.

El orden de ejecución de la corrutina

Swoole\Runtime::enableCoroutine(true);
go(function(){
    
    
   sleep(2);
   echo "go1\n";
});
go(function(){
    
    
    sleep(1);
    echo "go2\n";
});
echo "main\n";

Primera salida: main-> go2-> go1

Comunicación entre corrutinas

Channel realiza la comunicación entre múltiples corrutinas, y múltiples corrutinas ayudan a completar tareas comunes.

Swoole\Runtime::enableCoroutine(true);
$chan = new Swoole\Coroutine\Channel();
go(function () use ($chan){
    
    
    sleep(1);
    $chan->push(['name'=>'sunny']);
});

go(function() use ($chan){
    
    
    $data = $chan->pop();
    print_r($data);
});
echo "结束\n";

Combate real: realiza la función waitGroup

Utilice el canal proporcionado por Swoole para implementar un grupo de espera, la función principal es esperar a que se completen todas las corrutinas.

<?php
class WaitGroup{
    
    
    private $count;
    private $chan;
    public function __construct()
{
    
    
        $this->chan = new Swoole\Coroutine\Channel();
    }

    public function add(){
    
    
        $this->count++;
    }
    public function done(){
    
    
        $this->chan->push(true);
    }

    public function wait(){
    
    
        for($i=0;$i<$this->count;$i++){
    
    
            $this->chan->pop();
        }
    }

}

<?php
include 'waitgroup.php';
Swoole\Runtime::enableCoroutine(true);
echo "start".PHP_EOL;
$t = microtime(true);
go(function() use ($t){
    
    
    $wg = new WaitGroup();
    $wg->add();
    go(function() use ($t,&$wg){
    
    
        echo file_get_contents("https://www.sunnyos.com/swoole.php");
        echo "协程1:".(microtime(true)-$t).PHP_EOL;
        $wg->done();
    });
    $wg->add();
    go(function() use ($t,&$wg){
    
    
        echo file_get_contents("https://www.sunnyos.com/swoole.php");
        echo "协程2:".(microtime(true)-$t).PHP_EOL;
        $wg->done();
    });
    $wg->add();
    go(function() use ($t,&$wg){
    
    
        echo file_get_contents("https://www.sunnyos.com/swoole.php");
        echo "协程3:".(microtime(true)-$t).PHP_EOL;
        $wg->done();
    });
    $wg->wait();
    echo '全部结束:'.(microtime(true)-$t).PHP_EOL;
});
echo "end".PHP_EOL;
echo microtime(true)-$t.PHP_EOL;

En el código: https://www.sunnyos.com/swoole.php swoole.php code

<?php
sleep(1);
echo "My name is Sunny\n";

Solicitud de red de simulación de vacuna inactiva que requiere mucho tiempo

Inserte la descripción de la imagen aquí

A continuación, se muestran las tres rutinas gor que se utilizan para realizar solicitudes de red. Cada solicitud toma 1 segundo, pero cuando las tres solicitudes se ejecutan aquí, solo toma 1.2 segundos para ejecutarse, pero la tasa de uso de la CPU es 6 %, esto muestra que la corrutina usa completamente la CPU.

Presta atención, no te pierdas

Muy bien, todos, lo anterior es todo el contenido de este artículo. Las personas que pueden ver aquí son todos talentos . Como dije antes, hay muchos puntos técnicos en PHP, porque hay demasiados, es realmente imposible de escribir, y no leerás demasiado después de escribirlo, así que lo organizaré en PDF y documentos aquí, si es necesario. lata

Haga clic para ingresar el código secreto: PHP + 「Plataforma」

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí


Para obtener más contenido de aprendizaje, visite el excelente catálogo de tutoriales de arquitecto PHP de [Comparative Standard Factory], siempre que pueda leerlo para asegurarse de que el salario aumentará un paso (actualización continua)

El contenido anterior espera poder ayudarte . Muchos PHPers siempre encuentran algunos problemas y cuellos de botella cuando están avanzados. No hay sentido de dirección cuando escriben demasiado código comercial. No sé por dónde empezar a mejorar. He compilado información sobre esto, incluyendo Pero no se limita a: arquitectura distribuida, alta escalabilidad, alto rendimiento, alta concurrencia, ajuste del rendimiento del servidor, TP6, laravel, YII2, Redis, Swoole, Swoft, Kafka, optimización de Mysql, scripts de shell, Docker, microservicios, Nginx, etc. Muchos puntos de conocimiento, productos secos avanzados avanzados, se pueden compartir con todos de forma gratuita, y aquellos que lo necesiten pueden unirse a mi grupo de intercambio de tecnología PHP

Supongo que te gusta

Origin blog.csdn.net/weixin_49163826/article/details/109189754
Recomendado
Clasificación