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