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