当前位置: 首页 > news >正文

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秒
    

相关文章:

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

前言 PHP本身并不直接支持多线程编程&#xff0c;因为PHP的设计初衷是作为一个脚本语言&#xff0c;主要面向的是Web开发。不过我们可以使用一些扩展和库来实现多进程的功能&#xff0c;提高系统性能&#xff0c;比如workerman和swoole。通过多进程异步执行任务。 安装workman…...

牛客NC196 编辑距离(一)【较难 DFS/DP,动态规划,样本对应模型 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/6a1483b5be1547b1acd7940f867be0da 思路 编辑距离问题 什么是两个字符串的编辑距离&#xff08;edit distance&#xff09;&#xff1f;给定字符串s1和s2&#xff0c;以及在s1上的如下操作&#xff1a;插入&…...

走进jvm之垃圾回收器篇

这里我想首先说明一下&#xff0c;虽然我们经常会拿垃圾回收器来做比较&#xff0c;虽然想挑选一个最好的收集器出来&#xff0c;但是目前也没有说哪一款收集器是完美的&#xff0c;更不存在万能的收集器&#xff0c;我们也只是对收集器选择最适合场景的一个收集器。 那么作者将…...

rtt自动初始化机制学习

通过以下两篇文章基本能搞懂rtt的自动初始化机制&#xff0c;从此你也可以借鉴写自己的自动初始化段(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的大学生租房系统的设计与实现。 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同…...

ai制图常用的软件有哪些?这5款ai生图工具值得推荐!

过去提起制图&#xff0c;它是一项具备高度专业化的创作活动&#xff0c;需要由熟练掌握制图技能的人完成&#xff0c;且制图通常包含的步骤繁多&#xff0c;很容易劝退想学习或者入门制图的新手&#xff0c;但随着 ai 人工智能技术在各个领域的落地&#xff0c;我们有机会用上…...

一分钟了解JAVA语言

Java语言诞生于1995年&#xff0c;由Sun Microsystems&#xff08;后被Oracle收购&#xff09;的工程师James Gosling等人开发。最初被设计用于家用电器控制系统&#xff0c;但很快就在互联网应用开发中得到广泛应用。Java之父詹姆斯高斯林希望开发一种可以适应不同计算机架构的…...

L4 级自动驾驶汽车发展综述

摘要:为了减小交通事故概率、降低运营成本、提高运营效率,实现安全、环保的出行,自动驾驶 技术的发展已成为大势所趋,而搭配有L4 级自动驾驶系统的车辆是将车辆驾驶全部交给系统。据此,介绍了自动驾驶汽车的主流技术解决方案;分析了国内外L4 级自动驾驶汽车的已发布车型、…...

HTML + CSS 核心知识点- 定位

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

Spring MVC(二)-过滤器与拦截器

过滤器和拦截器在职责和使用场景上存在一些差异。 过滤器 拦截器 作用 对请求进行预处理和后处理。例如过滤请求参数、设置字符编码。 拦截用户请求并进行相应处理。例如权限验证、用户登陆检查等。 工作级别 Servlet容器级别&#xff0c;是Tomcat服务器创建的对象。可以…...

python vtk读取vtk文件

参考&#xff1a; https://cloud.tencent.com/developer/ask/sof/101993637 方法一&#xff1a;使用pyvtk 要使用Python读取VTK文件&#xff0c;可以使用pyvtk库。首先&#xff0c;确保已经安装了pyvtk。如果没有安装&#xff0c;可以通过pip安装&#xff1a; csharp pip ins…...

LeetCode 2671.频率跟踪器:俩计数哈希表

【LetMeFly】2671.频率跟踪器&#xff1a;俩计数哈希表 力扣题目链接&#xff1a;https://leetcode.cn/problems/frequency-tracker/ 请你设计并实现一个能够对其中的值进行跟踪的数据结构&#xff0c;并支持对频率相关查询进行应答。 实现 FrequencyTracker 类&#xff1a;…...

NAT笔记

NAT 用于实现内网和外网之间的互访。 静态NAT 静态NAT实现内网地址和外网地址的一对一转换。 有2种配置方法&#xff1a; 全局模式下设置静态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层叠性&#xff1a; 2.2继承性&#xff1a; 2.3优先级&#xff1a; 2.4.CSS的组成结构: 3.css样式的三种写法: 3.1内联样式&#xff1a; 3.1.2存在的优点和缺点: 3.2内部样式表&#xff1a; 3.2.2存在的优点和缺点:…...

JSR380验证框架

依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>demo Size(min10,max200 ,message"描述需要控制在10到200字符"&#xff09; Min(valu…...

百度paddleocr GPU版部署

显卡&#xff1a;NVIDIA GeForce RTX 4070&#xff0c;Nvidia驱动程序版本&#xff1a;537.13 Nvidia驱动程序能支持的最高cuda版本&#xff1a;12.2.138 Python&#xff1a;python3.10.11。试过python3.12&#xff0c;安装paddleocr失败&#xff0c;找不到相关模块。 飞桨版本…...

node.js 常用命令

Node.js的常用命令包括多种类型&#xff0c;从运行JavaScript文件到管理Node.js的模块和包。以下是一些主要的Node.js常用命令&#xff1a; 运行JavaScript文件&#xff1a; node filename.js 这个命令会调用Node.js程序来运行指定的JavaScript文件。 查看文件和目录&#xf…...

Easypoi实现导出Excel(简单高效)

今天做报表导出&#xff0c;网上找了很多导出的方法&#xff0c;最后总结发现以下方法是最简便&#xff0c;更易维护的导出方法&#xff0c;下面来分享给大家。 1、首先引入相关依赖 <!--EasyPoi 报表--><dependency><groupId>cn.afterturn</groupId>…...

python之pathlib库使用介绍

pathlib 是 Python 标准库中用于处理文件路径的模块。它提供了一种面向对象的方式来操作文件和目录路径&#xff0c;简化了路径操作的编码和跨平台的兼容性。下面是 pathlib 库的基本介绍和使用方法&#xff1a; 1.导入 pathlib 模块 from pathlib import Path 2.创建路径对…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...