Entrevista PHP conheceu a co-rotina swoole do entrevistador por três perguntas consecutivas, quase chorando!

O que é um processo?

O processo é a instância de inicialização do aplicativo. Recursos de arquivo independentes, recursos de dados, espaço de memória.

O que é um tópico?

O thread pertence ao processo e é o executor do programa. Um processo contém pelo menos um thread principal e pode ter mais threads filhos. Existem duas estratégias de agendamento para threads, uma é: agendamento de tempo compartilhado e a outra é: agendamento preventivo.

Minha colônia oficial de pinguins

O que é uma co-rotina?

A co-rotina é uma rosca leve, a co-rotina também é uma rosca e a corrotina é executada na rosca. A programação da co-rotina é alternada manualmente pelo usuário, portanto, também é chamada de thread do espaço do usuário. A criação, troca, suspensão e destruição da co-rotina são todas operações de memória e o consumo é muito baixo. A estratégia de escalonamento da co-rotina é: escalonamento colaborativo.

O princípio da co-rotina de Swoole

  • Como o Swoole4 é de thread único e multiprocesso, apenas uma co-rotina está sendo executada no mesmo processo ao mesmo tempo.

  • O servidor Swoole recebe dados e dispara o retorno de chamada onReceive no processo de trabalho para gerar um Ctrip. Swoole cria um Ctrip correspondente para cada solicitação. Uma sub-co-rotina também pode ser criada na co-rotina.

  • A co-rotina é de thread único na implementação subjacente, portanto, apenas uma co-rotina está funcionando ao mesmo tempo e a execução da co-rotina é serial.

  • Portanto, quando multitarefa e multicorrotina são executadas, quando uma co-rotina está em execução, outras co-rotinas param de funcionar. A corrotina atual travará ao executar operações de bloqueio de E / S e o agendador subjacente entrará no loop de eventos. Quando há um evento de conclusão de E / S, o escalonador subjacente retoma a execução da co-rotina correspondente ao evento. . Portanto, não há IO demorado para corrotinas, o que é muito adequado para cenários de alta IO simultânea. (Como mostrado abaixo)

Insira a descrição da imagem aqui

Processo de execução de co-rotina de Swoole

  • A co-rotina não tem IO e aguarda a execução normal do código PHP, não mudando o fluxo de execução

  • Quando a co-rotina encontra IO e espera para cortar imediatamente o controle certo, após a conclusão do IO, mude o fluxo de execução de volta para o ponto onde a co-rotina foi cortada

  • As co-rotinas paralelas são executadas em sequência, igual à lógica anterior

  • O processo de execução aninhado da co-rotina entra camada por camada de fora para dentro até que ocorra o IO, e então corta para a co-rotina externa, a co-rotina pai não irá esperar pelo fim da co-rotina filha

A ordem de execução da co-rotina

Vamos dar uma olhada no exemplo básico:

go(function () {
    
    
    echo "hello go1 \n";
});

echo "hello main \n";

go(function () {
    
    
    echo "hello go2 \n";
});

go()É a \Co::create()sigla usada para criar uma co-rotina, aceita como parâmetro callback, o código de callback é executado nesta nova co-rotina.

Observações: \Swoole\Coroutinepode ser abreviado como\Co

O resultado da execução do código acima:

root@b98940b00a9b /v/w/c/p/swoole# php co.php
hello go1
hello main
hello go2

O resultado da execução e a ordem em que normalmente escrevemos o código parecem ser os mesmos. O processo de execução real:

  • Execute este código, o sistema inicia um novo processo

  • Encontrada go(), uma co-rotina é gerada no processo atual, saída heelo go1na co-rotina e as saídas da co-rotina

  • O processo continua a executar o código, saída hello main

  • Gere outra co-rotina, produza heelo go2na co-rotina e saia da co-rotina

Execute este código, o sistema inicia um novo processo. Se você não entendeu esta frase, você pode usar o seguinte código:

// co.php
<?php

sleep(100);

A implementação e uso ps auxdo sistema Process Viewer:

root@b98940b00a9b /v/w/c/p/swoole# php co.php &
⏎
root@b98940b00a9b /v/w/c/p/swoole# ps aux
PID   USER     TIME   COMMAND
    1 root       0:00 php -a
   10 root       0:00 sh
   19 root       0:01 fish
  749 root       0:00 php co.php
  760 root       0:00 ps aux
⏎

Vamos mudar um pouco e experimentar a programação da co-rotina:

use Co;

go(function () {
    
    
    Co::sleep(1); // 只新增了一行代码
    echo "hello go1 \n";
});

echo "hello main \n";

go(function () {
    
    
    echo "hello go2 \n";
});

\Co::sleep()Recursos e funções sleep()semelhantes, mas simula a implementação de espera IO (IO entrarei em detalhes posteriormente) dos resultados são os seguintes:

root@b98940b00a9b /v/w/c/p/swoole# php co.php
hello main
hello go2
hello go1

Por que não é executado sequencialmente? O processo de execução real:

  • Execute este código, o sistema inicia um novo processo
  • Encontrada go(), uma co-rotina é gerada no processo atual
  • A corrotina encontrou bloqueio de IO (aqui é Co::sleep()para simular a espera de IO), as corrotinas abrem mão do controle, agendando a fila para entrar na co-rotina
  • O processo continua a ser executado para baixo, a saída hello main
  • Execute a próxima co-rotina, saída hello go2
  • A co-rotina anterior está pronta, continue a execução, saída hello go1

Neste ponto, você já pode ver a relação entre a co-rotina e o processo em swoole, bem como o escalonamento da co-rotina, vamos mudar o programa anterior:

go(function () {
    
    
    Co::sleep(1);
    echo "hello go1 \n";
});

echo "hello main \n";

go(function () {
    
    
    Co::sleep(1);
    echo "hello go2 \n";
});

Acho que você já sabe como é a saída:

root@b98940b00a9b /v/w/c/p/swoole# php co.php
hello main
hello go1
hello go2
⏎

Onde está a corrotina rápida? Reduza a perda de desempenho causada pelo bloqueio de IO

Você pode ouvir o motivo mais comum para o uso de corrotinas, talvez porque as corrotinas são rápidas. Por que um código que parece ser escrito de forma semelhante em tempos normais deve ser mais rápido? Um motivo comum é que muitas corrotinas podem ser criadas para execução Tarefa tão rápida. Esta afirmação está correta, mas ainda permanece na superfície.

Em primeiro lugar, as tarefas gerais do computador são divididas em dois tipos:

  • Uso intensivo de CPU, como cálculos científicos, como adição, subtração, multiplicação e divisão
  • IO intensivo, como solicitações de rede, leitura e gravação de arquivos, etc.

Em segundo lugar, existem 2 conceitos relacionados ao alto desempenho:

  • Paralelo: Ao mesmo tempo, a mesma CPU só pode executar a mesma tarefa.Para executar várias tarefas ao mesmo tempo, são necessárias várias CPUs.
  • Simultaneidade: Como a CPU troca as tarefas muito rápido, atingindo o limite que os humanos podem perceber, haverá a ilusão de muitas tarefas sendo executadas ao mesmo tempo

Depois de entender isso, vamos olhar para a corrotina novamente. A corrotina é adequada para aplicações com IO intensivo, porque a corrotina será programada automaticamente quando o IO for bloqueado, reduzindo a perda de tempo causada pelo bloqueio de IO.

Podemos comparar as três seguintes partes de código:

  • Versão normal: Execute 4 tarefas
$n = 4;
for ($i = 0; $i < $n; $i++) {
    
    
    sleep(1);
    echo microtime(true) . ": hello $i \n";
};
echo "hello main \n";
root@b98940b00a9b /v/w/c/p/swoole# time php co.php
1528965075.4608: hello 0
1528965076.461: hello 1
1528965077.4613: hello 2
1528965078.4616: hello 3
hello main
real    0m 4.02s
user    0m 0.01s
sys     0m 0.00s
⏎
  • Versão de co-rotina única:
$n = 4;
go(function () use ($n) {
    
    
    for ($i = 0; $i < $n; $i++) {
    
    
        Co::sleep(1);
        echo microtime(true) . ": hello $i \n";
    };
});
echo "hello main \n";
root@b98940b00a9b /v/w/c/p/swoole# time php co.php
hello main
1528965150.4834: hello 0
1528965151.4846: hello 1
1528965152.4859: hello 2
1528965153.4872: hello 3
real    0m 4.03s
user    0m 0.00s
sys     0m 0.02s
⏎
  • Versão multi-corrotina: testemunhe o momento do milagre
$n = 4;
for ($i = 0; $i < $n; $i++) {
    
    
    go(function () use ($i) {
    
    
        Co::sleep(1);
        echo microtime(true) . ": hello $i \n";
    });
};
echo "hello main \n";
root@b98940b00a9b /v/w/c/p/swoole# time php co.php
hello main
1528965245.5491: hello 0
1528965245.5498: hello 3
1528965245.5502: hello 2
1528965245.5506: hello 1
real    0m 1.02s
user    0m 0.01s
sys     0m 0.00s
⏎

Por que há uma diferença tão grande de tempo:

  • Gravação comum, encontrará perda de desempenho causada pelo bloqueio de IO

  • Corrotina única: embora o bloqueio de IO tenha acionado a programação da co-rotina, atualmente há apenas uma co-rotina, e a corrotina atual ainda é executada após a programação

  • Multi-corrotina: Realmente exerce as vantagens da corrotina, o agendamento ocorre quando o IO está bloqueado e retoma a operação quando o IO está pronto

Vamos modificar ligeiramente a versão multi-corrotina:

  • Multi-coroutine versão 2: CPU intensiva
$n = 4;
for ($i = 0; $i < $n; $i++) {
    
    
    go(function () use ($i) {
    
    
        // Co::sleep(1);
        sleep(1);
        echo microtime(true) . ": hello $i \n";
    });
};
echo "hello main \n";
root@b98940b00a9b /v/w/c/p/swoole# time php co.php
1528965743.4327: hello 0
1528965744.4331: hello 1
1528965745.4337: hello 2
1528965746.4342: hello 3
hello main
real    0m 4.02s
user    0m 0.01s
sys     0m 0.00s
⏎

Acabou de Co::sleep()mudar sleep(), e o tempo ficou quase igual à versão normal:

  • sleep() Pode ser considerada uma tarefa intensiva de CPU, o que não causará o escalonamento da co-rotina

  • Co::sleep()A simulação é uma tarefa intensiva de E / S, que acionará o escalonamento da co-rotina
    , por isso a co-rotina é adequada para aplicações com E / S intensas.

Aqui está outro conjunto de exemplos comparativos: usando redis

// 同步版, redis使用时会有 IO 阻塞
$cnt = 2000;
for ($i = 0; $i < $cnt; $i++) {
    
    
    $redis = new \Redis();
    $redis->connect('redis');
    $redis->auth('123');
    $key = $redis->get('key');
}

// 单协程版: 只有一个协程, 并没有使用到协程调度减少 IO 阻塞
go(function () use ($cnt) {
    
    
    for ($i = 0; $i < $cnt; $i++) {
    
    
        $redis = new Co\Redis();
        $redis->connect('redis', 6379);
        $redis->auth('123');
        $redis->get('key');
    }
});

// 多协程版, 真正使用到协程调度带来的 IO 阻塞时的调度
for ($i = 0; $i < $cnt; $i++) {
    
    
    go(function () {
    
    
        $redis = new Co\Redis();
        $redis->connect('redis', 6379);
        $redis->auth('123');
        $redis->get('key');
    });
}

Comparação de desempenho:

# 多协程版
root@0124f915c976 /v/w/c/p/swoole# time php co.php
real    0m 0.54s
user    0m 0.04s
sys     0m 0.23s
⏎

# 同步版
root@0124f915c976 /v/w/c/p/swoole# time php co.php
real    0m 1.48s
user    0m 0.17s
sys     0m 0.57s
⏎

Comparação de co-rotina swoole e co-rotina go: processo único vs multiencadeamento

Estive em contato com o codificador da corrotina go, e o contato inicial com a corrotina swoole será um pouco confuso, por exemplo, compare o seguinte código:

package main

import (
    "fmt"
    "time"
)

func main() {
    
    
    go func() {
    
    
        fmt.Println("hello go")
    }()

    fmt.Println("hello main")

    time.Sleep(time.Second)
}
> 14:11 src $ go run test.go
hello main
hello go

Basta ir escrever codificador de co-rotina, ao escrever este código será dito para não esquecer time.Sleep(time.Second), ou não ver a saída hello go, e em segundo lugar, hello gocom hello maina ordem e também na co-rotina swoole não é o mesmo.

O motivo é que swoole and go têm modelos diferentes para implementar o agendamento de co-rotina.

O processo de execução do código acima:

  • Execute o código go, o sistema inicia um novo processo
  • Encontre package maine executefunc mian()
  • Ao encontrar uma co-rotina, entregue-a ao programador da co-rotina para executar
  • Continue a executar para baixo, saída hello main
  • Se você não o adicionar time.Sleep(time.Second), a função principal é executada, o programa termina e o processo sai, fazendo com que a co-rotina na programação também termine

A co-rotina em go, o modelo MPG usado:

  • M refere-se à máquina, um M está diretamente associado a um thread do kernel
  • P se refere ao processador, que representa o contexto exigido por M, e também é um processador que processa a lógica do código no nível do usuário
  • G refere-se a Goroutine, que é essencialmente um segmento leve

Modelo MPG

O agendamento de goroutine em swoole usa um modelo de processo único. Todas as goroutines são agendadas no processo atual. Os benefícios de um único processo também são óbvios - simples / sem bloqueios / alto desempenho.

Seja o modelo MPG de go ou modelo de processo único de swoole, é uma implementação da teoria CSP.

O método de comunicação CSP já estava disponível em artigos de 1985. Para quem faz pesquisa teórica, pode ser difícil melhorar sem as suposições ousadas que podem ser feitas com vários anos, dez ou mesmo décadas de antecedência.

Preste atenção, não se perca

Tudo bem, pessoal, o acima é todo o conteúdo deste artigo. As pessoas que podem ver aqui são todos talentos . Como eu disse antes, há muitos pontos técnicos em PHP, porque são muitos, é realmente impossível escrever, e você não vai ler muito depois de escrever, então irei organizá-los em PDF e documentos aqui, se necessário lata

Clique para inserir o código secreto: PHP + 「Plataforma」

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui


Para obter mais conteúdo de aprendizado, você pode visitar o Catálogo [Comparative Standard Factory] de Tutoriais de Excelente PHP Architect, contanto que você possa lê-lo para garantir que o salário suba um nível (atualização contínua)

O conteúdo acima espera ajudar a todos . Muitos PHPers sempre encontram alguns problemas e gargalos quando são avançados. Não há nenhum senso de direção ao escrever muito código comercial. Não sei por onde começar a melhorar. Compilei algumas informações sobre isso, incluindo Mas não se limitando a: arquitetura distribuída, alta escalabilidade, alto desempenho, alta simultaneidade, ajuste de desempenho do servidor, TP6, laravel, YII2, Redis, Swoole, Swoft, Kafka, otimização Mysql, scripts de shell, Docker, microsserviços, Nginx etc. Muitos pontos de conhecimento, produtos secos avançados avançados, podem ser compartilhados com todos gratuitamente, e aqueles que precisam podem se juntar ao meu grupo de intercâmbio de tecnologia PHP

Acho que você gosta

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