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的更多相关文章

  1. .Net中的并行编程-7.基于BlockingCollection实现高性能异步队列

    三年前写过基于ConcurrentQueue的异步队列,今天在整理代码的时候发现当时另外一种实现方式-使用BlockingCollection实现,这种方式目前依然在实际项目中使用.关于Blockin ...

  2. 基于异步队列的生产者消费者C#并发设计

    继上文<<基于阻塞队列的生产者消费者C#并发设计>>的并发队列版本的并发设计,原文code是基于<<.Net中的并行编程-4.实现高性能异步队列>>修改 ...

  3. 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储。

    https://github.com/kcloze/swoole-jobs 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储.参考资料:swoole https:/ ...

  4. LaravelS - 基于Swoole加速Laravel/Lumen

    LaravelS LaravelS是一个胶水项目,用于快速集成Swoole到Laravel或Lumen,然后赋予它们更好的性能.更多可能性.Github 特性 内置Http/WebSocket服务器 ...

  5. swoft-个基于 Swoole 原生协程的PHP 微服务框架

    刚才百度了一下swoft框架,官网打不开了,仓库也暂停了.不由感慨.曾经和同事踩了许多坑使用此极其小众的框架完成微服务项目.使用它的唯一目的就是提高程序性能(底层使用了协程),为此大家都学习了很多新知 ...

  6. .Net中的并行编程-4.实现高性能异步队列

    上文<.Net中的并行编程-3.ConcurrentQueue实现与分析>分析了ConcurrentQueue的实现,本章就基于ConcurrentQueue实现一个高性能的异步队列,该队 ...

  7. HQueue:基于HBase的消息队列

    HQueue:基于HBase的消息队列   凌柏   ​1. HQueue简介 HQueue是一淘搜索网页抓取离线系统团队基于HBase开发的一套分布式.持久化消息队列.它利用HTable存储消息数据 ...

  8. PHP实现基于Swoole简单的HTTP服务器

    引用Swoole官方定义: PHP语言的异步.并行.高性能网络通信框架,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTa ...

  9. C# Winform 基于Task的异步与延时执行

    一.Task的机制   Task位于命名空间System.Threading.Tasks中,是.NET 4.0加入的新模块,其实现机制大致类似于线程池ThreadPool,不过对于ThreadPool ...

  10. 基于SEDA的异步框架设计与实现

    基于SEDA的异步框架设计与实现 二.为什么使用SEDA 目前,面对并发环境,主流互联网服务器编程模型有两种:多线程模型以及事件驱动模型.但是这两个模型都不足以解决这个问题.我们来首先看一下这两种编程 ...

随机推荐

  1. Go 应用程序使用 dockerfile multi-stage 的问题

    场景重现 一个简单的go应用,准备通过docker部署,为了减少运行时的镜像和容器体积,使用了multi-stage构建: # dockerfile 大致如下 # 一级构建使用带golang环境的镜像 ...

  2. ASP.NET Web.config Transformations

    ... 参考文档 Web Deployment Content Map for Visual Studio and ASP.NET 微软ASP.NET站点部署指南(3):使用Web.Config文件的 ...

  3. bat脚本之启动MySQL服务

    @echo off :: 获取管理员权限 %1 mshta vbscript:CreateObject("Shell.Application").ShellExecute(&quo ...

  4. AI提示词:一个通用C++ ECS系统实现(事件条件动作系统)

    AI提示词 using eca_cond = bool(*)(...); using eca_action = void(*)(...); class eca_info { public: eca_c ...

  5. Vue横向滚动鼠标控制

    let level_cards // 标记可移动 , move_start // 移动初始的x位置 , move_x // 移动初始的容器偏移量 , move_scroll_left // 判断是否为 ...

  6. GitLab——重置(reset)和还原(revert)

    Git 命令 reset 和 revert 的区别 - 知乎 (zhihu.com) 总结: git reset --hard 9201d9b19dbf5b4ceaf90f92fd4e4019b685 ...

  7. 关于网传微信聊天记录提取工具"留痕"盗取个人信息的分析

    今天早上看到一篇文章,是关于一个微信聊天记录提取工具泄露个人信息的内容,于是我就好奇,看了一下作者的 github,然后也是自己小小的分析了一下 1.官方地址 Github: https://gith ...

  8. 【经验】VScode 远程 SSH 连接 Ubuntu 或 TrueNas 出错,Could not establish connection

    用VScode常常会碰到以下情况,Could not establish connection. 先介绍一下VScode远程连接和终端SSH连接的区别:终端直接用SSH连接时,只需要开启SSH服务,并 ...

  9. 【经验】Ubuntu18.04切换Python版本及环境,及VScode/pdb调试方法(全)

    文章目录 安装Python并切换 创建Python虚拟环境 方案一:virtualenv+virtualenvwrapper 方案二:venv 方案三:Anaconda 方案四:pipenv Pyth ...

  10. codeup之Day of Week(给定日期判断周几

    题目描述 We now use the Gregorian style of dating in Russia. The leap years are years with number divisi ...