Maison  >  Article  >  cadre php  >  php Swoole implémente des tâches planifiées au niveau de la milliseconde

php Swoole implémente des tâches planifiées au niveau de la milliseconde

藏色散人
藏色散人avant
2020-01-25 19:14:164142parcourir

php Swoole implémente des tâches planifiées au niveau de la milliseconde

Pendant le développement du projet, s'il existe des exigences commerciales pour les tâches planifiées, nous utiliserons la crontab de Linux pour les résoudre, mais sa granularité minimale est de niveau infime. Si la granularité requise est de deuxième niveau, Même au niveau de la milliseconde, crontab ne peut pas le satisfaire. Heureusement, swoole fournit un puissant minuteur en millisecondes.

Apprentissage recommandé : tutoriel swoole

Exemples de scénarios d'application

Nous pouvons rencontrer un tel scénario :

● Scénario 1 : Obtenez l'utilisation de la mémoire locale toutes les 30 secondes

● Scénario 2 : Exécutez la tâche d'envoi du rapport après 2 minutes

● Scénario 3 : Tous les jours à 2 heures du matin matin Demandez régulièrement l'interface tierce. Si l'interface renvoie des données, la tâche sera arrêtée. Si l'interface ne répond pas pour une raison quelconque ou si aucune donnée n'est renvoyée, continuez à essayer de demander l'interface après 5 minutes. échoue après 5 tentatives, arrêtez la tâche

Nous pouvons tous classer les trois scénarios ci-dessus dans la catégorie des tâches planifiées.

Minuterie milliseconde Swoole

Swoole fournit une fonction de minuterie asynchrone en millisecondes :

swoole_timer_tick(int $msec, callable $callback) : définissez une minuterie d'horloge à intervalle, chaque $msec exécute $ rappel une fois toutes les millisecondes, similaire à setInterval() en javascript.

swoole_timer_after(int $after_time_ms, mixed $callback_function) : Exécuter $after_time_ms après l'heure spécifiée $callback_function, similaire à setTimeout() de javascript.

swoole_timer_clear(int $timer_id) : Supprimez la minuterie avec l'identifiant spécifié, similaire à celui de javascript clearInterval().

Solution

Pour le scénario 1, il est souvent utilisé dans les statistiques de détection du système. Les exigences en temps réel sont relativement élevées, mais la fréquence peut être bien contrôlée. est principalement utilisé pour les performances du serveur en arrière-plan. La surveillance peut générer des graphiques visuels. L'utilisation de la mémoire peut être obtenue une fois toutes les 30 secondes ou toutes les 10 secondes, mais la granularité minimale de crontab ne peut être définie que sur 1 minute.

 swoole_timer_tick(30000, function($timer) use ($task_id) { // 启用定时器,每30秒执行一次
     $memPercent = $this->getMemoryUsage(); //计算内存使用率
     echo date('Y-m-d H:i:s') . '当前内存使用率:'.$memPercent."\n";
 });

Pour le scénario deux, si vous définissez directement une certaine tâche après xx temps, il semble que crontab soit plus difficile, mais utiliser swoole_timer_after de swoole peut réaliser :

 swoole_timer_after(120000, function() use ($str) { //2分钟后执行
     $this->sendReport(); //发送报表
     echo "send report, $str\n";
 });

Pour le scénario trois, il est utilisé pour faire des tentatives de requêtes. Si la requête échoue, elle continuera. Si elle réussit, elle arrêtera la requête. Cela peut également être résolu en utilisant crontab, mais c'est plutôt idiot. Par exemple, si vous définissez une requête toutes les 5 minutes, elle sera exécutée quel que soit le succès ou l'échec. Utiliser une minuterie swoole est beaucoup plus intelligent.

swoole_timer_tick(5*60*1000, function($timer) use ($url) { // 启用定时器,每5分钟执行一次
      $rs = $this->postUrl($url);
  
      if ($rs) {
          //业务代码...
          swoole_timer_clear($timer); // 停止定时器
          echo date('Y-m-d H:i:s'). "请求接口任务执行成功\n";
      } else {
          echo date('Y-m-d H:i:s'). "请求接口失败,5分钟后再次尝试\n";
     }
 });

Exemple de code

Créer un nouveau fichier srcAppTask.php :

<?php 
namespace Helloweba\Swoole;

use swoole_server;

/**
* 任务调度
*/
class Task
{
    protected $serv;
    protected $host = &#39;127.0.0.1&#39;;
    protected $port = 9506;
    // 进程名称
    protected $taskName = &#39;swooleTask&#39;;
    // PID路径
    protected $pidPath = &#39;/run/swooletask.pid&#39;;
    // 设置运行时参数
    protected $options = [
        &#39;worker_num&#39; => 4, //worker进程数,一般设置为CPU数的1-4倍  
        &#39;daemonize&#39; => true, //启用守护进程
        &#39;log_file&#39; => &#39;/data/log/swoole-task.log&#39;, //指定swoole错误日志文件
        &#39;log_level&#39; => 0, //日志级别 范围是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR
        &#39;dispatch_mode&#39; => 1, //数据包分发策略,1-轮询模式
        &#39;task_worker_num&#39; => 4, //task进程的数量
        &#39;task_ipc_mode&#39; => 3, //使用消息队列通信,并设置为争抢模式
    ];

    public function __construct($options = [])
    {
        date_default_timezone_set(&#39;PRC&#39;); 
        // 构建Server对象,监听127.0.0.1:9506端口
        $this->serv = new swoole_server($this->host, $this->port);

        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
        $this->serv->set($this->options);

        // 注册事件
        $this->serv->on(&#39;Start&#39;, [$this, &#39;onStart&#39;]);
        $this->serv->on(&#39;Connect&#39;, [$this, &#39;onConnect&#39;]);
        $this->serv->on(&#39;Receive&#39;, [$this, &#39;onReceive&#39;]);
        $this->serv->on(&#39;Task&#39;, [$this, &#39;onTask&#39;]);  
        $this->serv->on(&#39;Finish&#39;, [$this, &#39;onFinish&#39;]);
        $this->serv->on(&#39;Close&#39;, [$this, &#39;onClose&#39;]);
    }

    public function start()
    {
        // Run worker
        $this->serv->start();
    }

    public function onStart($serv)
    {
        // 设置进程名
        cli_set_process_title($this->taskName);
        //记录进程id,脚本实现自动重启
        $pid = "{$serv->master_pid}\n{$serv->manager_pid}";
        file_put_contents($this->pidPath, $pid);
    }

    //监听连接进入事件
    public function onConnect($serv, $fd, $from_id)
    {
        $serv->send( $fd, "Hello {$fd}!" );
    }

    // 监听数据接收事件
    public function onReceive(swoole_server $serv, $fd, $from_id, $data)
    {
        echo "Get Message From Client {$fd}:{$data}\n";
        //$this->writeLog(&#39;接收客户端参数:&#39;.$fd .&#39;-&#39;.$data);
        $res[&#39;result&#39;] = &#39;success&#39;;
        $serv->send($fd, json_encode($res)); // 同步返回消息给客户端
        $serv->task($data);  // 执行异步任务
    }

    /**
    * @param $serv swoole_server swoole_server对象
    * @param $task_id int 任务id
    * @param $from_id int 投递任务的worker_id
    * @param $data string 投递的数据
    */
    public function onTask(swoole_server $serv, $task_id, $from_id, $data)
    {
        swoole_timer_tick(30000, function($timer) use ($task_id) { // 启用定时器,每30秒执行一次
            $memPercent = $this->getMemoryUsage();
            echo date(&#39;Y-m-d H:i:s&#39;) . &#39;当前内存使用率:&#39;.$memPercent."\n";
        });
    }


    /**
    * @param $serv swoole_server swoole_server对象
    * @param $task_id int 任务id
    * @param $data string 任务返回的数据
    */
    public function onFinish(swoole_server $serv, $task_id, $data)
    {
        //
    }


    // 监听连接关闭事件
    public function onClose($serv, $fd, $from_id) {
        echo "Client {$fd} close connection\n";
    }

    public function stop()
    {
        $this->serv->stop();
    }

    private function getMemoryUsage()
    {
        // MEMORY
        if (false === ($str = @file("/proc/meminfo"))) return false;
        $str = implode("", $str);
        preg_match_all("/MemTotal\s{0,}\:+\s{0,}([\d\.]+).+?MemFree\s{0,}\:+\s{0,}([\d\.]+).+?Cached\s{0,}\:+\s{0,}([\d\.]+).+?SwapTotal\s{0,}\:+\s{0,}([\d\.]+).+?SwapFree\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buf);
        //preg_match_all("/Buffers\s{0,}\:+\s{0,}([\d\.]+)/s", $str, $buffers);

        $memTotal = round($buf[1][0]/1024, 2);
        $memFree = round($buf[2][0]/1024, 2);
        $memUsed = $memTotal - $memFree;
        $memPercent = (floatval($memTotal)!=0) ? round($memUsed/$memTotal*100,2):0;

        return $memPercent;
    }
}

Prenons scénario 1 Par exemple, activez les tâches planifiées dans onTask et calculez l'utilisation de la mémoire toutes les 30 secondes. Dans les applications réelles, la mémoire calculée peut être écrite dans une base de données et dans un autre stockage en fonction du temps, puis utilisée pour restituer des graphiques statistiques en fonction des exigences frontales, telles que :

php Swoole implémente des tâches planifiées au niveau de la milliseconde

puis le Code serveur publictaskServer.php :

<?php 
require dirname(__DIR__) . &#39;/vendor/autoload.php&#39;;
use Helloweba\Swoole\Task;
$opt = [
    &#39;daemonize&#39; => false
];
$ser = new Task($opt);
$ser->start();

Code client publictaskClient.php :

<?php 
class Client
{
    private $client;
    public function __construct() {
        $this->client = new swoole_client(SWOOLE_SOCK_TCP);
    }
    public function connect() {
        if( !$this->client->connect("127.0.0.1", 9506 , 1) ) {
            echo "Error: {$this->client->errMsg}[{$this->client->errCode}]\n";
        }
        fwrite(STDOUT, "请输入消息 Please input msg:");
        $msg = trim(fgets(STDIN));
        $this->client->send( $msg );
        $message = $this->client->recv();
        echo "Get Message From Server:{$message}\n";
    }
}
$client = new Client();
$client->connect();

Vérification effet

1. Démarrez le serveur :

php taskServer.php

2. Saisie du client :

Ouvrez une autre fenêtre de ligne de commande. et exécutez

[root@localhost public]# php taskClient.php

Veuillez saisir msg : bonjour

Get Message From Server:{"result":"success"}
[root@localhost public]#

3. Le serveur renvoie :

php Swoole implémente des tâches planifiées au niveau de la milliseconde

Si vous revenons à ce qui précède Le résultat dans l'image montre que la tâche planifiée s'exécute normalement et nous constaterons qu'un message sera émis toutes les 30 secondes.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer
Article précédent:Comment quitter SwooleArticle suivant:Comment quitter Swoole