一、项目背景
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)生产者实现
lPush()从队列左边推入消息,rPush从队列右边推入消息。
// 连接 Redis 服务器
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 消息队列名
$queue = 'message';
// 生成消息
$message = json_encode($jsonData);
// 将消息推送到 Redis 队列中
$redis->lPush($queue, $message);
5)消费者实现
rPop()从队列右边取出消息,与lPush()结合使用弹出最早的消息,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);
}
}