基于 swoole 下 异步队列和毫秒定时任务 API
1.在 Server 程序中如果需要执行很耗时的操作,比如一个聊天服务器发送广播,Web 服务器中发送邮件。如果直接去执行这些函数就会阻塞当前进程,导致服务器响应变慢。
Swoole 提供了异步任务处理的功能,可以投递一个异步任务到 TaskWorker 进程池中执行,不影响当前请求的处理速度。(官网说明)
1. 服务端代码
执行服务端监听端口
9501。通过设置daemonize这个参数,以守护进程在系统去维护这个TaskWorker进程池。我们客户端将消息传递给服务端,服务端异步将数据请求放入进程池队列运行,从大大缩短了响应时间。
<?php /**
* Created by PhpStorm
* User: pl
* Date: 2020/5/22
* Time: 15:23
*/
class TaskServer
{
private $server;
public function __construct()
{
$this->server = new Swoole\Server('127.0.0.1', 9501);
$this->server->set([
'task_worker_num' => 3, //开启的进程数 一般为cup核数 1-4倍
'daemonize' => 1, //已守护进程执行该程序
'max_request' => 10000, //worker进程最大任务数
'dispatch_mode' => 2, //设置为争抢模式
'task_ipc_mode' => 3, //设置为消息队列模式
]);
$this->server->on('Receive', array($this, 'onReceive'));
$this->server->on('Task', array($this, 'onTask'));
$this->server->on('Finish', array($this, 'onFinish'));
$this->server->start();
}
public function onReceive(swoole_server $server, $fd, $form_id, $data)
{
$this->server->task($data);
}
/**
* @param swoole_server $server
* @param $fd
* @param $from_id
* @param $data
* 执行异步任务
*/
public function onTask($server, $fd, $from_id, $data)
{
$data = json_decode($data, true);
try {
$log_txt = date('Y-m-d H:i:s') . "开始执行任务" . PHP_EOL;
$this->log($log_txt);
$type = $data['data']['type'];
$time = intval($data['data']['timing']);
unset($data['data']['timing']);
unset($data['data']['type']);
if (intval($type) == 1) {
$this->request_curl($data['url'], $data['data'], $data['data']['http_type']);
} else {
Swoole\Timer::after($time, function () use ($data) {
$this->request_curl($data['url'], $data['data'], $data['data']['http_type']);
});
}
} catch (\Exception $exception) {
$log_txt = date('Y-m-d H:i:s') . "执行任务失败发生错误" . PHP_EOL;
$this->log($log_txt);
}
}
public function onFinish($server, $task_id, $data)
{
$log_txt = date('Y-m-d H:i:s') . "$data" . PHP_EOL;
$this->log($log_txt);
}
public function request_curl($url = '', $request_data = '', $request_type = 'get', $headers = [], $is_ssl = false)
{
$ch = curl_init(); //curl初始化
if ($request_type == 'get' && !empty($request_data)) {
$num = 0;
foreach ($request_data as $key => $value) {
if ($num == 0) {
$url .= '?' . $key . '=' . $value;
} else {
$url .= '&' . $key . '=' . $value;
}
$num++;
}
$num = 0;
}
//区分get和post
curl_setopt($ch, CURLOPT_URL, $url); //URL地址
curl_setopt($ch, CURLOPT_HEADER, 0); //头信息不输出
//如果成功只将结果返回,不自动输出任何内容
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//post类型就实现此结果
if ($request_type == 'post') {
//设置为POST方式
curl_setopt($ch, CURLOPT_POST, 1);
//POST数据
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_data);
//当post数据大于1024时强制执行
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:"));
}
//判断是否绕过证书
if ($is_ssl) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//绕过ssl验证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
}
if (!empty($headers)) curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch); //执行
if ($result == FALSE) return false;
curl_close($ch); //关闭资源
return $result;
}
public function log($log_txt)
{
$log = 'log/' . date('Y_m_d') . 'log';
if (!file_exists($log)) {
touch($log);
chown($log, 0777);
}
$file_log = fopen($log, "a");
fputs($file_log, $log_txt);
fclose($file_log);
}
}
$task = new TaskServer();
2.客户端代码
<?php const API_KEY = 'xxx';
class ClientRequest
{
private $client;
private $params; //请求参数
public function __construct($params)
{
$this->client = new swoole_client(SWOOLE_SOCK_TCP | SWOOLE_KEEP);
$this->params = $params;
}
public function connect()
{
if (!$this->client->connect('127.0.0.1', 9501, 1)) {
return json_encode([
'code' => 500,
'err_msg' => '链接异步客户端失败'
]);
}
/**
* 注意请求格式
* $params['url'] 接口地址
* $params['type']接口请求方式
* $params['data']参数
*/
$params = $this->params;
$array['url'] = $params['url'];
unset($params['url']);
$array['data'] = $params;
$this->client->send(json_encode($array, JSON_UNESCAPED_UNICODE));
}
}
if($_SERVER['REQUEST_METHOD']!='POST') throw new ErrorException('路由不存在','404');
if(!array_key_exists('HTTP_TOKEN',$_SERVER)){
header('Content-type: application/json');
echo json_encode(['code'=>'200007','token is not empty']);exit();
}
if($_SERVER['HTTP_TOKEN']!= API_KEY ) {
header('Content-type: application/json');
echo json_encode(['code'=>'200007','error token']);exit();
}
$params = $_POST;
$client = new ClientRequest($params);
$client->connect();
开始执行服务端程序,
php TaskServer.php我们以接口形式上去调用另外一个耗时接口.简单对比一下响应速度。


最后补充:基于swoole 一个简单的异步队列就完成了。可以将此队列封装成api队列接口,将它丢到task里面去慢慢执行吧~哈哈
<a name="introduction1"></a>
补充新增的一次定时器任务,支持毫秒级
3.定时任务和异步接口
说明:
1、在swoole 中 毫秒【如 1000 表示 1 秒,v4.2.10 以下版本最大不得超过 86400000【一天】】
2、后台定时器操作接口:操作方法如下
当操作时间在一天内 则直接执行定时器
3、大于一天时
系统执行一个定时crontab任务 ->
每隔12-24小时 运行一次 将数据库执行接口时间大于当前时间且不超过一天的数据数据执行该接口
关 于用户执行撤销则通过推送数据接口去判断该数据是否进行推送
4、当该需要给执行接口添加参数时 直接将参数放入接口
接口文档
ClientRequest.php
请求方法 post
参数
| 参数 | 是否必选 | 备注 | 限制 | 新增 |
|---|---|---|---|---|
| token | 是 | 密钥【header】xxxx
|
||
| url | 是 | 执行接口的地址 | ||
| type | 是 | 1、异步执行该接口 2、定时执行该接口 | ||
| http_type | 是 | get、post | ||
| timing | 否 | 定时执行该接口的时间 单位【毫秒】 |
基于 swoole 下 异步队列和毫秒定时任务 API的更多相关文章
- .Net中的并行编程-7.基于BlockingCollection实现高性能异步队列
三年前写过基于ConcurrentQueue的异步队列,今天在整理代码的时候发现当时另外一种实现方式-使用BlockingCollection实现,这种方式目前依然在实际项目中使用.关于Blockin ...
- 基于异步队列的生产者消费者C#并发设计
继上文<<基于阻塞队列的生产者消费者C#并发设计>>的并发队列版本的并发设计,原文code是基于<<.Net中的并行编程-4.实现高性能异步队列>>修改 ...
- 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储。
https://github.com/kcloze/swoole-jobs 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储.参考资料:swoole https:/ ...
- LaravelS - 基于Swoole加速Laravel/Lumen
LaravelS LaravelS是一个胶水项目,用于快速集成Swoole到Laravel或Lumen,然后赋予它们更好的性能.更多可能性.Github 特性 内置Http/WebSocket服务器 ...
- swoft-个基于 Swoole 原生协程的PHP 微服务框架
刚才百度了一下swoft框架,官网打不开了,仓库也暂停了.不由感慨.曾经和同事踩了许多坑使用此极其小众的框架完成微服务项目.使用它的唯一目的就是提高程序性能(底层使用了协程),为此大家都学习了很多新知 ...
- .Net中的并行编程-4.实现高性能异步队列
上文<.Net中的并行编程-3.ConcurrentQueue实现与分析>分析了ConcurrentQueue的实现,本章就基于ConcurrentQueue实现一个高性能的异步队列,该队 ...
- HQueue:基于HBase的消息队列
HQueue:基于HBase的消息队列 凌柏 1. HQueue简介 HQueue是一淘搜索网页抓取离线系统团队基于HBase开发的一套分布式.持久化消息队列.它利用HTable存储消息数据 ...
- PHP实现基于Swoole简单的HTTP服务器
引用Swoole官方定义: PHP语言的异步.并行.高性能网络通信框架,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTa ...
- C# Winform 基于Task的异步与延时执行
一.Task的机制 Task位于命名空间System.Threading.Tasks中,是.NET 4.0加入的新模块,其实现机制大致类似于线程池ThreadPool,不过对于ThreadPool ...
- 基于SEDA的异步框架设计与实现
基于SEDA的异步框架设计与实现 二.为什么使用SEDA 目前,面对并发环境,主流互联网服务器编程模型有两种:多线程模型以及事件驱动模型.但是这两个模型都不足以解决这个问题.我们来首先看一下这两种编程 ...
随机推荐
- 【Linux】速查手册
查看Linux系统信息 arch #显示机器的处理器架构(1) uname -m #显示机器的处理器架构(2) uname -r #显示正在使用的内核版本 dmidecode -q #显示硬件系统部件 ...
- 【C#】SuperSocket配置启动UDP服务器
SuperSocket配置UDP服务器 零.需求 两个设备局域网联机,需要用广播自动搜寻,而SuperSocket1.6的默认AppServer使用的是TCP,但只有UDP才支持广播. 一.解决 推荐 ...
- 《机器人SLAM导航核心技术与实战》先导课:SLAM的应用价值与技术难点
<机器人SLAM导航核心技术与实战>先导课:SLAM的应用价值与技术难点 视频讲解 [先导课]3.SLAM的应用价值与技术难点-视频讲解 [先导课]3.1.SLAM的应用价值与技术难点-S ...
- 又一款眼前一亮的Linux终端工具!
大家好,我是良许. 最近二舅视频刷爆了全网,大家有没去看呢?强烈推荐大家观看一波,也就 11 分钟,保证会触动你的泪点. 不过今天不讲二舅哈,还是来聊聊技术. 今天给大家介绍一款最近发现的功能十分强大 ...
- 云备份技术解析:云容灾 CT-CDR 关键技术介绍
本文分享自天翼云开发者社区<云备份技术解析:云容灾 CT-CDR 关键技术介绍>,作者:沈****军 1.CDP+存储快照,实现秒级RPO (1)CDP技术:云容灾CT-CDR(Cloud ...
- RL · Exploration | 使用时序距离构造 intrinsic reward,鼓励 agent 探索
论文标题:Episodic Novelty Through Temporal Distance. ICLR 2025,8 8 6 5 poster. arxiv:https://arxiv.org/a ...
- 你了解 Java 的逃逸分析吗?
Java 的逃逸分析 1. 定义 逃逸分析(Escape Analysis)是 JVM 的一种优化技术,用于分析对象的作用域,从而决定对象的分配方式或优化手段. 主要目的是判断一个对象是否会逃离当前方 ...
- 接入Google认证Google Authenticator
介绍 既然来看该文章就应该知道Google的两步认证是干什么的,如果需要APP(Google Authenticator)的可以私信我. 验证原理讲解: 为每个用户在注册之前生成32位随机码(该码一般 ...
- vue3 基础-插件 plugin
前几篇我们介绍了 mixin 混入的的方式能实现对代码的复用, 而本篇将要介绍的 plugin 将会更加适合这种通用性功能的代码的复用和扩展. 最常用的场景, 比如轮播图就非常实用 plugin 来实 ...
- 集成学习双雄:Boosting和Bagging简介
在机器学习的世界里,集成学习(Ensemble Learning)是一种强大的技术,它通过组合多个模型来提高预测性能. 集成学习通过组合多个基学习器的预测结果,获得比单一模型更优秀的性能.其核心思想是 ...