如上圖所示, 問(wèn)題有三:
:11269 --> 即數(shù)字11269前為何會(huì)多出個(gè)冒號(hào)來(lái)?
不同的客戶端為何查詢到了相同的數(shù)據(jù),比如圖示 11271;
如何避免上述2提到的現(xiàn)象?
workerman分為主進(jìn)程和子進(jìn)程,如果主進(jìn)程中創(chuàng)建了redis連接,在fork時(shí)子進(jìn)程會(huì)繼承redis連接,這樣會(huì)導(dǎo)致redis返回?cái)?shù)據(jù)時(shí)所有子進(jìn)程都可讀,導(dǎo)致數(shù)據(jù)錯(cuò)亂。所以不能在主進(jìn)程創(chuàng)建mysql redis等連接資源。這部分在手冊(cè)必讀里有講 http://doc.workerman.net/315119。
如果連接資源先于Worker::runAll()運(yùn)行前創(chuàng)建,那么就屬于主進(jìn)程。所以最好是在onWorkerStart回調(diào)創(chuàng)建連接資源。如果一定要在主進(jìn)程使用一次redis,則必須在使用完畢銷毀它,避免被子進(jìn)程繼承使用。
去掉了初始化redis實(shí)例的主進(jìn)程代碼【即去掉了圖1中第22~25行代碼】之后,發(fā)現(xiàn)圖示諸如帶冒號(hào)的詭異數(shù)據(jù)消失了,但是依然會(huì)出現(xiàn)不同的客戶端讀取到多條相同的數(shù)據(jù),這個(gè)現(xiàn)象正常嗎? 或者代碼的編寫(xiě)邏輯還存在問(wèn)題? 謝謝~~
你程序里的 incr 和 get 并不是一個(gè)原子操作,實(shí)際運(yùn)行時(shí)可能出現(xiàn)多個(gè)進(jìn)程分別執(zhí)行了 incr,然后再分別執(zhí)行 get,就會(huì)得到相同的數(shù)值。不過(guò)總體來(lái)看計(jì)數(shù)是不會(huì)錯(cuò)的。
事實(shí)上,incr 返回的就是自增之后的值,所以其實(shí)你根本不需要再 get 一次。
非常感謝,查了下相關(guān)文檔,一方面說(shuō)get單命令執(zhí)行是原子操作,但是這里的多進(jìn)程get, 實(shí)際上存在你說(shuō)的并發(fā)get,導(dǎo)致出現(xiàn)了相同的數(shù)值,既然是原子性操作的,不應(yīng)該是針對(duì)并發(fā)而言嗎? 理解的不透,能否解釋下? 另一方面文檔說(shuō)incr是屬于原子操作,修改代碼后測(cè)試確實(shí)能如期工作。
可能你對(duì)“原子操作”的理解不是很準(zhǔn)確。
redis 所有的單個(gè)命令都是原子的,因?yàn)?redis server 本身就是單線程的,所有所謂的“并發(fā)請(qǐng)求”到了 redis server 這里都是串行操作,一個(gè)一個(gè)執(zhí)行,所以不會(huì)有互相的干擾。
但是你的程序是先發(fā)送一個(gè) incr 命令,再發(fā)送一個(gè) get 命令,如果把這兩個(gè)命令當(dāng)作一個(gè)“操作”來(lái)看待的話,它就不是“原子操作”了,因?yàn)樗鼈冊(cè)?redis server 上執(zhí)行的時(shí)候很可能中間被另外一個(gè)命令插隊(duì)了。