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.phpphp 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秒
相关文章:
Thinkphp+workman+redis实现多进程异步任务处理
前言 PHP本身并不直接支持多线程编程,因为PHP的设计初衷是作为一个脚本语言,主要面向的是Web开发。不过我们可以使用一些扩展和库来实现多进程的功能,提高系统性能,比如workerman和swoole。通过多进程异步执行任务。 安装workman…...
牛客NC196 编辑距离(一)【较难 DFS/DP,动态规划,样本对应模型 Java,Go,PHP】
题目 题目链接: https://www.nowcoder.com/practice/6a1483b5be1547b1acd7940f867be0da 思路 编辑距离问题 什么是两个字符串的编辑距离(edit distance)?给定字符串s1和s2,以及在s1上的如下操作:插入&…...
走进jvm之垃圾回收器篇
这里我想首先说明一下,虽然我们经常会拿垃圾回收器来做比较,虽然想挑选一个最好的收集器出来,但是目前也没有说哪一款收集器是完美的,更不存在万能的收集器,我们也只是对收集器选择最适合场景的一个收集器。 那么作者将…...
rtt自动初始化机制学习
通过以下两篇文章基本能搞懂rtt的自动初始化机制,从此你也可以借鉴写自己的自动初始化段(section)。 1点这里 https://blog.csdn.net/qq_38824401/article/details/119717389 2点这里 https://club.rt-thread.org/ask/article/d686458bbba864f4.html section背景…...
基于SpringBoot和Vue的大学生租房系统的设计与实现
今天要和大家聊的是一款今天要和大家聊的是一款基于SpringBoot和Vue的大学生租房系统的设计与实现。 !!! 有需要的小伙伴可以通过文章末尾名片咨询我哦!!! 💕💕作者:李同…...
ai制图常用的软件有哪些?这5款ai生图工具值得推荐!
过去提起制图,它是一项具备高度专业化的创作活动,需要由熟练掌握制图技能的人完成,且制图通常包含的步骤繁多,很容易劝退想学习或者入门制图的新手,但随着 ai 人工智能技术在各个领域的落地,我们有机会用上…...
一分钟了解JAVA语言
Java语言诞生于1995年,由Sun Microsystems(后被Oracle收购)的工程师James Gosling等人开发。最初被设计用于家用电器控制系统,但很快就在互联网应用开发中得到广泛应用。Java之父詹姆斯高斯林希望开发一种可以适应不同计算机架构的…...
L4 级自动驾驶汽车发展综述
摘要:为了减小交通事故概率、降低运营成本、提高运营效率,实现安全、环保的出行,自动驾驶 技术的发展已成为大势所趋,而搭配有L4 级自动驾驶系统的车辆是将车辆驾驶全部交给系统。据此,介绍了自动驾驶汽车的主流技术解决方案;分析了国内外L4 级自动驾驶汽车的已发布车型、…...
HTML + CSS 核心知识点- 定位
简述: 补充固定定位也会脱离文档流、不会占据原先位置 1、什么是文档流 文档流是指HTML文档中元素排列的规律和顺序。在网页中,元素按照其在HTML文档中出现的顺序依次排列,这种排列方式被称为文档流。文档流决定了元素在页面上的位置和互相之…...
Spring MVC(二)-过滤器与拦截器
过滤器和拦截器在职责和使用场景上存在一些差异。 过滤器 拦截器 作用 对请求进行预处理和后处理。例如过滤请求参数、设置字符编码。 拦截用户请求并进行相应处理。例如权限验证、用户登陆检查等。 工作级别 Servlet容器级别,是Tomcat服务器创建的对象。可以…...
python vtk读取vtk文件
参考: https://cloud.tencent.com/developer/ask/sof/101993637 方法一:使用pyvtk 要使用Python读取VTK文件,可以使用pyvtk库。首先,确保已经安装了pyvtk。如果没有安装,可以通过pip安装: csharp pip ins…...
LeetCode 2671.频率跟踪器:俩计数哈希表
【LetMeFly】2671.频率跟踪器:俩计数哈希表 力扣题目链接:https://leetcode.cn/problems/frequency-tracker/ 请你设计并实现一个能够对其中的值进行跟踪的数据结构,并支持对频率相关查询进行应答。 实现 FrequencyTracker 类:…...
NAT笔记
NAT 用于实现内网和外网之间的互访。 静态NAT 静态NAT实现内网地址和外网地址的一对一转换。 有2种配置方法: 全局模式下设置静态NAT [R1]nat static global 172.10.10.10 inside 192.168.10.10 [R1]int g0/0/1 #外网接口 [R1-GigabitEthernet0/0/1]nat static…...
MySQL 数据库的备份和还原
1.命令行 备份语法 mysqldump -u用户名 -p密码 数据库名称 > 保存的路径还原语法 1.登陆数据库 2.创建数据库 3.使用数据库 4.执行文件 source 文件路径2.图形化(太简单了不写了) 点击返回 MySQL 快速学习目录...
初识CSS样式 与 文本背景样式
目录 前言: 1.什么是CSS: 2.关于css的主要特性: 2.1层叠性: 2.2继承性: 2.3优先级: 2.4.CSS的组成结构: 3.css样式的三种写法: 3.1内联样式: 3.1.2存在的优点和缺点: 3.2内部样式表: 3.2.2存在的优点和缺点:…...
JSR380验证框架
依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>demo Size(min10,max200 ,message"描述需要控制在10到200字符") Min(valu…...
百度paddleocr GPU版部署
显卡:NVIDIA GeForce RTX 4070,Nvidia驱动程序版本:537.13 Nvidia驱动程序能支持的最高cuda版本:12.2.138 Python:python3.10.11。试过python3.12,安装paddleocr失败,找不到相关模块。 飞桨版本…...
node.js 常用命令
Node.js的常用命令包括多种类型,从运行JavaScript文件到管理Node.js的模块和包。以下是一些主要的Node.js常用命令: 运行JavaScript文件: node filename.js 这个命令会调用Node.js程序来运行指定的JavaScript文件。 查看文件和目录…...
Easypoi实现导出Excel(简单高效)
今天做报表导出,网上找了很多导出的方法,最后总结发现以下方法是最简便,更易维护的导出方法,下面来分享给大家。 1、首先引入相关依赖 <!--EasyPoi 报表--><dependency><groupId>cn.afterturn</groupId>…...
python之pathlib库使用介绍
pathlib 是 Python 标准库中用于处理文件路径的模块。它提供了一种面向对象的方式来操作文件和目录路径,简化了路径操作的编码和跨平台的兼容性。下面是 pathlib 库的基本介绍和使用方法: 1.导入 pathlib 模块 from pathlib import Path 2.创建路径对…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
