求助,多进程定时器+多进程异步,逻辑乱套了

lxping2

进程A和B都设置了5个子进程,进程A里放了一个定时器,同一时间去redis中查询5条数据并立刻批量删除,然后调用AsyncTcpConnection执行进程B,redis是用的zset类型。

问题:
1、redis虽然是单进程,但是因为5个定时器同时执行了进程A,导致redis还没删除之前,就被其他子进程也查询到了值,导致进程A有几率会执行2~3次,但我只想让进程A执行一次。我知道可以设置$worker->id===0让定时器只执行1个,那么多个进程里同时执行定时器是不是不可以呢?我主要是想让5个进程争抢定时任务,比如其中2个进程阻塞了,其他3个进程还在跑,不会导致定时器延迟。
2、进程B中,同一子进程里,居然出现了数据错乱问题,代码如下图。
3、如果把进程A改成1个进程,上述1和2正常,但是进程B的count=5,却只能同时执行4次,可以确定不是因为进程A阻塞导致的。

下图问题2,查询redis后修改并保存,保存的key居然不是查询的key,5条数据会有两条数据的key相互颠倒了。
截图
截图

下图问题3,进程B的count=5,却只同时执行了4次,我的理解是,是不是其中有一个是主进程,所以其实进程B只有4个子进程?
截图
截图

2644 1 1
1个回答

latin

1、redis里查询和删除是2个操作,不是原子的,所以会用并发问题。改成用list,然后lpush写入,rpop读出,rpop是原子操作,不会有并发问题。实际上就是一个队列的操作。

2、终端是共享的,多个进程向同一个终端打印数据看起来就是错乱的。但不是说业务逻辑数据错乱了。每个进程单独写一个日志文件,你就明白了。

3、据我所知,进程数是指子进程数,不包括主进程。如果数量不对,打下日志看下是不是获取的5条数据,是否建立了5个异步连接,是否发送了5次请求给B进程。这个应该是逻辑问题了。

如果不需要B进程通知A进程数据处理完毕事件,感觉你这个进程模型可以改成队列模式,任何项目(不一定是workerman项目)可以通过redis的lpush向队列写数据,B进程作为消费者rpop读数据处理。这种模式相比你的reids+ AsyncTcpConnection缺点是B进程没有通知A进程数据是否处理完毕的机制,需要的话其实也可以想办法加。

  • lxping 2020-02-23

    谢谢大神解答,"redis里查询和删除是2个操作,不是原子的",这么解释的话,我就秒懂了。因为要用zset类型做条件查询,所以list类型不太适合,感觉定时器还是放在一个进程里可控性强一些。
    另外,count=5,确实是子进程=5,只不过不一定全部会把5个进程用上,多次测试发现,偶尔会少用一两个进程(均为重启后测试结果,截图在帖子中)

年代过于久远,无法发表回答
🔝