一、项目背景
mes报工需求,原项目接口接收产线上位抛来的数据,处理无误后存储在本地,最后抛给工厂接口。
但是有时候工厂数据响应太慢,也导致mes响应给上位变慢,拖慢了mes系统。
现要求,将原接口中抛给工厂的功能分离出来。即,上位抛来数据处理无误并存储在本地后,直接返回给上位,而将数据抛给工厂的部分实现异步处理。
二、思路
首先想到的是多线程,但是php是不支持多线程的,想要实现多线程需要下载各种插件,十分麻烦。最终我们采用了生产者-消费者的模式来实现。
三、生产者-消费者的简单介绍
通俗讲,A是发糖的,B是吃糖的,但是B只能一个一个吃,如果A发糖的速度高于B吃糖的速度,那么就会出现A发了糖,B还没有吃的情况。那怎么办呢,A找来一个盒子,把要发给B的糖放在里面,B吃完了嘴里的糖就自行从盒子里取,双方各不耽误。
这样就相当于一个简单的生产者-消费者模型。A是生产者,B是消费者,盒子是内存空间。A不需要理会B的状态,他会把数据放在特定的内存中;而B同样不和A有牵扯,在当前数据处理完后,只管从内存中拿数据。
四、实现
1)安装redis服务(也可以选择其他的,我用的是redis,所以只介绍redis)
Releases · microsoftarchive/redis
注意 :安装过程是全英文的,一定要选择将redis添加到环境变量!另外,记住自己的端口!默认是6379。
2)在php安装路径的ext文件夹中添加拓展
下载链接:https://downloads.php.net/~windows/pecl/releases/redis/5.3.3/php_redis-5.3.3-7.3-ts-vc15-x64.zip
3)编辑php.ini
加入extension=redis,如果前面有;删掉即可。
4)生产者实现
// 连接 Redis 服务器$redis = new Redis();$redis->connect('127.0.0.1', 6379);// 消息队列名$queue = 'message';// 生成消息$message = json_encode($jsonData);// 将消息推送到 Redis 队列中$redis->lPush($queue, $message);
5)消费者实现
rPop()弹出最早的消息,lPop()弹出最新的消息。
$redis = new Redis();// 连接到 Redis 服务器
$redis->connect('127.0.0.1', 6379);while (true) {// 从队列 'message' 弹出消息$message = $redis->rPop('message');// 如果有消息,处理消息if ($message) {print_r("上传中...");// 初始化 cURL 会话$ch = curl_init($url);// 设置 cURL 选项curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $message);// 执行 cURL 会话$response = curl_exec($ch);// 检查是否有错误发生if (curl_errno($ch)) {log_write('Error:' . curl_error($ch));}$message = json_decode($message);// 关闭 cURL 会话curl_close($ch);$LogIppsot = $_SERVER['REMOTE_ADDR'];$PostStrpost = json_encode($message, JSON_UNESCAPED_UNICODE);$LogContentpost = $response;$LogTimepost = date("Y-m-d H:i:s", time());$glmesconn_errpost = sql_mes_conn();$logsqlstrpost = "insert into Log_Plc_Api(LogFrom,LogIp,PostStr,LogContent,LogTime) values ('AddEquipInfo','$LogIppsot','$PostStrpost','$LogContentpost','$LogTimepost')";sqlsrv_query($glmesconn_errpost, $logsqlstrpost);sqlsrv_close($glmesconn_errpost);} else {// 如果队列为空,稍等再试print_r("waiting...\n");sleep(1);}
}