Thinkphp+workman+redis实现多线程异步任务处理

前言


PHP本身并不直接支持多线程编程,因为PHP的设计初衷是作为一个脚本语言,主要面向的是Web开发。不过我们可以使用一些扩展和库来实现多线程的功能,比如workerman和swoole。通过多线程异步执行任务,可以大大提高代码的执行效率。

安装workman


  • 简介

    官网:高性能PHP应用容器 workerman

    文档:

    workerman 手册

    Workerman · ThinkPHP5.0完全开发手册 · 看云 (kancloud.cn)

    ThinkPHP 5.1 Workerman 快速上手指南 · ThinkPHP5.1 Workerman上手指南 · 看云 (kancloud.cn)

  • 环境要求

    • PHP >= 7.2
    • Composer >= 2.0
  • 安装扩展

    composer require topthink/think-worker
    

Thinkphp5.0使用workman创建多线程任务


  • 1.在项目根目录(注意不是pubcli目录)下创建文件server.php,文件内容如下

    <?php
    define('APP_PATH', __DIR__ . '/application/');
    define('BIND_MODULE','workman/Worker');
    // 加载框架引导文件
    require __DIR__ . '/thinkphp/start.php';
    
  • 2.在根目录创建\application\workman\controller目录,然后在该目录下新建Worker.php,文件内容如下

    <?phpnamespace app\workman\controller;use think\worker\Server;class Worker extends Server
    {//websocket服务端地址和端口protected $socket = 'websocket://0.0.0.0:2346';//设置进程数,默认为4,根据自己的需要和服务器配置合理设置,一般设置进程数为CPU核数的1倍-3倍protected $processes = 4;/*** 收到信息* @param $connection* @param $data*/public function onMessage($connection, $data){}/*** 当连接建立时触发的回调函数* @param $connection*/public function onConnect($connection){}/*** 当连接断开时触发的回调函数* @param $connection*/public function onClose($connection){}/*** 当客户端的连接上发生错误时触发* @param $connection* @param $code* @param $msg*/public function onError($connection, $code, $msg){echo "error $code $msg\n";}/*** 每个进程启动* @param $worker*/public function onWorkerStart($worker){echo 'workman进程启动,进程id ' . $worker->id . PHP_EOL;//监听redis队列$redis = new \Redis();$redis->connect('192.168.204.128', 6379);while (true) {//读取redis队列$data = $redis->lPop('test-queue');if ($data) {//处理业务echo '进程id ' . $worker->id . ' 开始处理业务数据' . $data . PHP_EOL;//模拟耗时任务sleep(5);echo '进程id ' . $worker->id . ' 处理业务数据' . $data . ' 完成' . PHP_EOL;} else {echo '进程id ' . $worker->id . ' 空闲中,休息5秒'. PHP_EOL;sleep(5);}}}
    }
    

    这里主要的功能就是创建一个workman的websocket服务端(使用其他tcp服务也是可以的),然后在每个进程启动的时候监听redis队列,利用这些进程异步去处理redis队列里的任务,代码里的模拟耗时任务可以直接替换成你在tp框架里写的耗时任务。

  • 3.在tp框架中将任务加入redis队列,例如我这里写一个添加redis列表元素的方法

    <?phpnamespace app\index\controller;class Index
    {//新增队列数据public function addQueue(){$redis = new \Redis();$redis->connect('192.168.204.128', 6379);$redis->rPush('test-queue', '1');$redis->rPush('test-queue', '2');$redis->rPush('test-queue', '3');$redis->rPush('test-queue', '4');$redis->rPush('test-queue', '5');$redis->rPush('test-queue', '6');$redis->rPush('test-queue', '7');echo 'success';}
    }
    
  • 4.启动workman

    直接在根目录下运行第一步创建的server.php

    php server.php start
    

    可以看到下面的输出

    Workerman[server.php] start in DEBUG mode
    -------------------------------------------- WORKERMAN --------------------------------------------
    Workerman version:3.5.35          PHP version:7.4.33           Event-Loop:\Workerman\Events\Select
    --------------------------------------------- WORKERS ---------------------------------------------
    proto   user            worker          listen                      processes    status
    tcp     root            none            websocket://0.0.0.0:2346    4             [OK]
    ---------------------------------------------------------------------------------------------------
    Press Ctrl+C to stop. Start success.
    workman进程启动,进程id 0
    workman进程启动,进程id 3
    workman进程启动,进程id 2
    workman进程启动,进程id 1
    进程id 1 空闲中,休息5秒
    进程id 0 空闲中,休息5秒
    进程id 2 空闲中,休息5秒
    进程id 3 空闲中,休息5秒
    

    注意:如果是在windows下,设置进程数是没有用的,就只会启动一个worker进程,也就是只有单进程,要体验多进程只能在Linux环境下,同时也无法守护进程,cmd窗口关掉后服务即停止

  • 5.访问tp框架中的将任务加入redis队列接口,直接用浏览器或者命令行curl访问http://网站域名/index/index/addQueue即可,然后你就可以看到所有的redis队列将被workman线程分配并执行,以下是我启动workman->添加redis队列->workman处理->队列处理结束打印的结果:

    Workerman[server.php] start in DEBUG mode
    -------------------------------------------- WORKERMAN --------------------------------------------
    Workerman version:3.5.35          PHP version:7.4.33           Event-Loop:\Workerman\Events\Select
    --------------------------------------------- WORKERS ---------------------------------------------
    proto   user            worker          listen                      processes    status
    tcp     root            none            websocket://0.0.0.0:2346    4             [OK]
    ---------------------------------------------------------------------------------------------------
    Press Ctrl+C to stop. Start success.
    workman进程启动,进程id 0
    workman进程启动,进程id 3
    workman进程启动,进程id 2
    workman进程启动,进程id 1
    进程id 1 空闲中,休息5秒
    进程id 0 空闲中,休息5秒
    进程id 2 空闲中,休息5秒
    进程id 3 空闲中,休息5秒
    进程id 2 空闲中,休息5秒
    进程id 1 空闲中,休息5秒
    进程id 3 空闲中,休息5秒
    进程id 0 空闲中,休息5秒
    (这里开始将任务加入redis队列,然后workman开始消费队列)
    进程id 0 开始处理业务数据1
    进程id 1 开始处理业务数据3
    进程id 3 开始处理业务数据4
    进程id 2 开始处理业务数据2
    进程id 0 处理业务数据1 完成
    进程id 1 处理业务数据3 完成
    进程id 2 处理业务数据2 完成
    进程id 1 开始处理业务数据6
    进程id 3 处理业务数据4 完成
    进程id 0 开始处理业务数据5
    进程id 3 开始处理业务数据7
    进程id 2 空闲中,休息5秒
    进程id 1 处理业务数据6 完成
    进程id 0 处理业务数据5 完成
    进程id 3 处理业务数据7 完成
    (到这里所有的7项任务已经处理完成)
    进程id 1 空闲中,休息5秒
    进程id 0 空闲中,休息5秒
    进程id 3 空闲中,休息5秒
    进程id 2 空闲中,休息5秒
    

TP5.1及TP6使用workman创建多线程任务


  • 1.在根目录创建\application\workman\controller目录,然后在该目录下新建Worker.php,文件内容如下

    <?phpnamespace app\workman;use think\worker\Server;class Worker extends Server
    {protected $host = '127.0.0.1';protected $port = 2346;protected $protocol = 'websocket';protected $option = ['count'		=> 4, //设置进程数,默认为4,根据自己的需要和服务器配置合理设置,一般设置进程数为CPU核数的1倍-3倍'name'		=> 'think'];/*** 收到信息* @param $connection* @param $data*/public function onMessage($connection, $data){}/*** 当连接建立时触发的回调函数* @param $connection*/public function onConnect($connection){}/*** 当连接断开时触发的回调函数* @param $connection*/public function onClose($connection){}/*** 当客户端的连接上发生错误时触发* @param $connection* @param $code* @param $msg*/public function onError($connection, $code, $msg){echo "error $code $msg\n";}/*** 每个进程启动* @param $worker*/public function onWorkerStart($worker){echo 'workman进程启动,进程id ' . $worker->id . PHP_EOL;//监听redis队列$redis = new \Redis();$redis->connect('127.0.0.1', 6379);while (true) {//读取redis队列$data = $redis->lPop('test-queue');if ($data) {//处理业务echo '进程id ' . $worker->id . ' 开始处理业务数据' . $data . PHP_EOL;//模拟耗时任务sleep(5);echo '进程id ' . $worker->id . ' 处理业务数据' . $data . ' 完成' . PHP_EOL;} else {echo '进程id ' . $worker->id . ' 空闲中,休息5秒' . PHP_EOL;sleep(5);}}}
    }
    

    这里主要的功能就是创建一个workman的websocket服务端(使用其他tcp服务也是可以的),然后在每个进程启动的时候监听redis队列,利用这些进程异步去处理redis队列里的任务,代码里的模拟耗时任务可以直接替换成你在tp框架里写的耗时任务。

  • 2.指定workman服务类名

    修改config/worker_server.php,将worker_class的值改为app\workman\Worker

    'worker_class'   => 'app\workman\Worker', // 自定义Workerman服务类名 支持数组定义多个服务
    
  • 3.启动workman

    直接在根目录下运行命令php think worker:server或者php think worker:server -d即可启动,如果要调整workman参数,修改config/worker_server.php中的选项即可

    php think worker:server
    

    可以看到下面的输出

    Starting Workerman server...
    ----------------------- WORKERMAN -----------------------------
    Workerman version:3.5.35          PHP version:7.3.4
    ------------------------ WORKERS -------------------------------
    worker               listen                              processes status
    none                 websocket://127.0.0.1:2346          1         [ok]
    workman进程启动,进程id 0
    进程id 0 空闲中,休息5秒
    进程id 0 空闲中,休息5秒
    进程id 0 空闲中,休息5秒
    进程id 0 空闲中,休息5秒
    进程id 0 空闲中,休息5秒
    

    注意:如果是在windows下,设置进程数是没有用的,就只会启动一个worker进程,也就是只有单进程,要体验多进程只能在Linux环境下,同时也无法守护进程,cmd窗口关掉后服务即停止

  • 4.在tp框架中将任务加入redis队列,例如我这里写一个添加redis列表元素的方法

    <?php
    namespace app\controller;use app\BaseController;class Index extends BaseController
    {//新增队列数据public function addQueue(){$redis = new \Redis();$redis->connect('127.0.0.1', 6379);$redis->rPush('test-queue', '1');$redis->rPush('test-queue', '2');$redis->rPush('test-queue', '3');$redis->rPush('test-queue', '4');$redis->rPush('test-queue', '5');$redis->rPush('test-queue', '6');$redis->rPush('test-queue', '7');echo 'success';}
    }
    
  • 5.访问上面的将任务加入redis队列接口,直接用浏览器或者命令行curl访问http://网站域名/index/addQueue即可,然后你就可以看到所有的redis队列将被workman线程分配并执行,以下是我启动workman->添加redis队列->workman处理->队列处理结束打印的结果:

    Starting Workerman server...
    Workerman[think] start in DEBUG mode
    -------------------------------------------- WORKERMAN ---------------------------------------------
    Workerman version:3.5.35          PHP version:7.4.33           Event-Loop:\Workerman\Events\Select
    --------------------------------------------- WORKERS ----------------------------------------------
    proto   user            worker          listen                        processes    status
    tcp     root            think           websocket://127.0.0.1:2346    4             [OK]
    ----------------------------------------------------------------------------------------------------
    Press Ctrl+C to stop. Start success.
    workman进程启动,进程id 0
    workman进程启动,进程id 3
    进程id 0 空闲中,休息5秒
    进程id 3 空闲中,休息5秒
    workman进程启动,进程id 1
    进程id 1 空闲中,休息5秒
    workman进程启动,进程id 2
    进程id 2 空闲中,休息5秒
    进程id 0 开始处理业务数据2
    进程id 3 开始处理业务数据1
    进程id 1 开始处理业务数据3
    进程id 2 开始处理业务数据4
    进程id 0 处理业务数据2 完成
    进程id 0 开始处理业务数据5
    进程id 3 处理业务数据1 完成
    进程id 1 处理业务数据3 完成
    进程id 3 开始处理业务数据6
    进程id 1 开始处理业务数据7
    进程id 2 处理业务数据4 完成
    进程id 2 空闲中,休息5秒
    进程id 0 处理业务数据5 完成
    进程id 1 处理业务数据7 完成
    进程id 3 处理业务数据6 完成
    进程id 0 空闲中,休息5秒
    进程id 1 空闲中,休息5秒
    进程id 3 空闲中,休息5秒
    进程id 2 空闲中,休息5秒
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/753527.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【送书福利!第一期】《ARM汇编与逆向工程》

&#x1f42e;博主syst1m 带你 acquire knowledge&#xff01; ✨博客首页——syst1m的博客&#x1f498; &#x1f618;《CTF专栏》超级详细的解析&#xff0c;宝宝级教学让你从蹒跚学步到健步如飞&#x1f648; &#x1f60e;《大数据专栏》大数据从0到秃头&#x1f47d;&…

202212 CSP认证 | JPEG 解码

JPEG 解码 一道特别幸福简单的第三题…都不敢想象在考场上碰见这种题目会有多幸福。直接按照题目意思做就好了&#xff0c;感觉比第二题还简单…而且数组特别小完全没有超时压力 补充一个对小数处理的部分&#xff0c;包括本题涉及的四舍五入取整以及输出取整&#xff1a;C 实…

<sa8650>sa8650 partition-之-独立新增分区不加img

<sa8650>sa8650 partition-之-独立新增分区不加img 一、 前言二、准备条件三、添加新分区四、分区信息解析4.1 新增分区信息字段解析4.2 guid生成工具五、生成新的刷机文件六、替换刷机文件七、刷机验证八、总结九、参考文献<sa8650>sa8650 partition-之-非基线编译下新增分…

小迪安全42WEB攻防-通用漏洞文件包含LFIRFI伪协议

#知识点: 1、解释什么是文件包含 2、分类-本地LFI&远程RFI 3、利用-配合上传&日志&会话 4、利用-伪协议&编码&算法等 #核心知识: 1、本地包含LFI&远程包含RF1-区别 一个只能包含本地&#xff0c;一个可以远程加载 具体形成原因由代码和环境配置文件决定…

2024智慧农场系统微信小程序前端如何上传以及配置

2024智慧农场系统微信小程序前端如何上传以及配置 首先下载微信开发者工具 下载好以后打开&#xff0c;然后导入项目 前端修改&#xff1a;siteinfo.js 里面的域名信息 改完之后开始在微信开发者工具中开发工具中编译、上传、发布即可

【how2j练习题】HTML部分综合练习

练习题 1 <html><h1>英雄联盟 &#xff08;电子竞技类游戏&#xff09;</h1> <p> <strong>《英雄联盟》</strong>&#xff08;简称lol&#xff09;是由美国<i>Riot Games</i>开发&#xff0c;中国大陆地区由腾讯游戏运营的网络…

系统学习Python——装饰器:“私有“和“公有“属性案例-[在不同Python版本下的使用]

分类目录&#xff1a;《系统学习Python》总目录 对于通过名称显式调用的方法&#xff0c;文章《系统学习Python——装饰器&#xff1a;“私有“和“公有“属性案例-[使用伪私有、破坏私有和装饰器权衡]》中的示例在Python2.X和Python3.X下都能如期工作。然而和大多数软件一样&a…

软考78-上午题-【面向对象技术3-设计模式】-结构型设计模式01

一、适配器模式 1-1、意图 个类的接口转换成客户希望的另外一个接口。 Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 1-2、结构 适配器模式分为&#xff1a; 1、适配器类模式&#xff1b; 2、适配器对象模式 类适配器使用多重继承对一个接口与另…

时间序列中的离群值检测

时间序列中的离群值检测学习资料&#xff1a; Chapter 5 Outlier detection in Time series Anomaly Detection Techniques in Python A review on outlier/anomaly detection in time series data

goland设置保存文件时不将4个空格转为TAB

goland设置保存文件时不将4个空格转为TAB 版本&#xff1a;GoLand 2022.3 设置路径&#xff1a; Settings -> Editor -> Code Style -> Go -> Run gofmt图示&#xff1a;

理解数字证书,守护你的大数据世界

随着大数据时代的来临&#xff0c;信息的安全性和可靠性成为了公众和企业关注的焦点。在这样的背景下&#xff0c;数字证书作为一种保障信息安全的重要工具&#xff0c;其重要性日益凸显。本文将从数字证书的基本概念、工作原理及其在大数据时代的应用等方面&#xff0c;为大家…

数据库管理-第161期 数据库,走着瞧(20240318)

数据库管理161期 2024-03-18 数据库管理-第161期 数据库&#xff0c;走着瞧&#xff08;20240318&#xff09;MySQLSACC走着瞧RACAIOps 总结 数据库管理-第161期 数据库&#xff0c;走着瞧&#xff08;20240318&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文&am…

面试算法-35-长度最小的子数组

题目 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续 子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 示例 1&#xff1a; 输入…

HTML + CSS 核心知识点- 定位

简述&#xff1a; 补充固定定位也会脱离文档流、不会占据原先位置 1、什么是文档流 文档流是指HTML文档中元素排列的规律和顺序。在网页中&#xff0c;元素按照其在HTML文档中出现的顺序依次排列&#xff0c;这种排列方式被称为文档流。文档流决定了元素在页面上的位置和互相之…

QT进阶-----------认识QT相关的模块(第四天)

1、关于Visual Studio与QT Creator的不同导入方式 Visual Studio作为windows宇宙最强编辑器以及编译器&#xff0c;它相当的好用&#xff0c;作为一个学了一年QT的菜鸟&#xff0c;总结了一些关于VS以及QT Creator两者的不同。 首先&#xff0c;在VS中qt是作为第三方库导入到…

怎么做好独立站的SEO优化

随着全球贸易的蓬勃发展&#xff0c;越来越多的企业开始关注外贸市场&#xff0c;并将目光投向了外贸网站。然而&#xff0c;在竞争激烈的外贸市场中&#xff0c;如何写出吸引人的文章&#xff0c;以及如何优化网站以在搜索引擎中脱颖而出&#xff0c;成为了外贸独立网站必须面…

Python 求素数个数

要计算一个给定范围内素数的个数&#xff0c;你可以编写一个Python函数来遍历这个范围&#xff0c;并对每个数检查它是否是素数。下面是一个简单的例子&#xff0c;该函数计算从2到n&#xff08;包括n&#xff09;之间的素数个数&#xff1a; python复制代码 def count_primes…

机器学习-绪论

机器学习致力于研究如何通过计算的手段、利用经验来改善系统自身的性能。在计算机系统中&#xff0c;“经验”通常以“数据”的形式存在&#xff0c;因此&#xff0c;机器学习所研究的主要内容&#xff0c;是关于在计算机上从数据中产生“模型”的算法&#xff0c;即“学习算法…

2024西工大数据结构理论上机作业(头歌 C)持续更新中~

第二章 线性表 1 顺序表的插入运算 #include <stdio.h> #include <stdlib.h>typedef struct node {int val;struct node *next; } Node, List;List *init(void) {List *s (List*) malloc(sizeof(List));Node *tail s; int n;s->next NULL, s->val -1;s…

PHP<=7.4.21 Development Server源码泄露漏洞 例题

打开题目 dirsearch扫描发现存在shell.php 非预期解 访问shell.php&#xff0c;往下翻直接就看到了flag.. 正常解法 访问shell.php 看见php的版本是7.3.33 我们知道 PHP<7.4.21时通过php -S开起的WEB服务器存在源码泄露漏洞&#xff0c;可以将PHP文件作为静态文件直接输…