進(jìn)程A和B都設(shè)置了5個(gè)子進(jìn)程,進(jìn)程A里放了一個(gè)定時(shí)器,同一時(shí)間去redis中查詢5條數(shù)據(jù)并立刻批量刪除,然后調(diào)用AsyncTcpConnection執(zhí)行進(jìn)程B,redis是用的zset類型。
問題:
1、redis雖然是單進(jìn)程,但是因?yàn)?個(gè)定時(shí)器同時(shí)執(zhí)行了進(jìn)程A,導(dǎo)致redis還沒刪除之前,就被其他子進(jìn)程也查詢到了值,導(dǎo)致進(jìn)程A有幾率會(huì)執(zhí)行2~3次,但我只想讓進(jìn)程A執(zhí)行一次。我知道可以設(shè)置$worker->id===0讓定時(shí)器只執(zhí)行1個(gè),那么多個(gè)進(jìn)程里同時(shí)執(zhí)行定時(shí)器是不是不可以呢?我主要是想讓5個(gè)進(jìn)程爭搶定時(shí)任務(wù),比如其中2個(gè)進(jìn)程阻塞了,其他3個(gè)進(jìn)程還在跑,不會(huì)導(dǎo)致定時(shí)器延遲。
2、進(jìn)程B中,同一子進(jìn)程里,居然出現(xiàn)了數(shù)據(jù)錯(cuò)亂問題,代碼如下圖。
3、如果把進(jìn)程A改成1個(gè)進(jìn)程,上述1和2正常,但是進(jìn)程B的count=5,卻只能同時(shí)執(zhí)行4次,可以確定不是因?yàn)檫M(jìn)程A阻塞導(dǎo)致的。
下圖問題2,查詢r(jià)edis后修改并保存,保存的key居然不是查詢的key,5條數(shù)據(jù)會(huì)有兩條數(shù)據(jù)的key相互顛倒了。
下圖問題3,進(jìn)程B的count=5,卻只同時(shí)執(zhí)行了4次,我的理解是,是不是其中有一個(gè)是主進(jìn)程,所以其實(shí)進(jìn)程B只有4個(gè)子進(jìn)程?
1、redis里查詢和刪除是2個(gè)操作,不是原子的,所以會(huì)用并發(fā)問題。改成用list,然后lpush寫入,rpop讀出,rpop是原子操作,不會(huì)有并發(fā)問題。實(shí)際上就是一個(gè)隊(duì)列的操作。
2、終端是共享的,多個(gè)進(jìn)程向同一個(gè)終端打印數(shù)據(jù)看起來就是錯(cuò)亂的。但不是說業(yè)務(wù)邏輯數(shù)據(jù)錯(cuò)亂了。每個(gè)進(jìn)程單獨(dú)寫一個(gè)日志文件,你就明白了。
3、據(jù)我所知,進(jìn)程數(shù)是指子進(jìn)程數(shù),不包括主進(jìn)程。如果數(shù)量不對,打下日志看下是不是獲取的5條數(shù)據(jù),是否建立了5個(gè)異步連接,是否發(fā)送了5次請求給B進(jìn)程。這個(gè)應(yīng)該是邏輯問題了。
如果不需要B進(jìn)程通知A進(jìn)程數(shù)據(jù)處理完畢事件,感覺你這個(gè)進(jìn)程模型可以改成隊(duì)列模式,任何項(xiàng)目(不一定是workerman項(xiàng)目)可以通過redis的lpush向隊(duì)列寫數(shù)據(jù),B進(jìn)程作為消費(fèi)者rpop讀數(shù)據(jù)處理。這種模式相比你的reids+ AsyncTcpConnection缺點(diǎn)是B進(jìn)程沒有通知A進(jìn)程數(shù)據(jù)是否處理完畢的機(jī)制,需要的話其實(shí)也可以想辦法加。
謝謝大神解答,"redis里查詢和刪除是2個(gè)操作,不是原子的",這么解釋的話,我就秒懂了。因?yàn)橐脄set類型做條件查詢,所以list類型不太適合,感覺定時(shí)器還是放在一個(gè)進(jìn)程里可控性強(qiáng)一些。
另外,count=5,確實(shí)是子進(jìn)程=5,只不過不一定全部會(huì)把5個(gè)進(jìn)程用上,多次測試發(fā)現(xiàn),偶爾會(huì)少用一兩個(gè)進(jìn)程(均為重啟后測試結(jié)果,截圖在帖子中)