skynet實踐(9)-隨機數重複問題

    最近在使用skynet的過程當中,遇到須要爲玩家的每次請求產生一個隨機序列的場景。簡化以下:linux

main.lua中每隔1S便發出一次隨機數請求:windows

local skynet = require "skynet" skynet.start(function() skynet.error("Server start") rand = skynet.newservice("testrand") skynet.sleep(100) local i = 0
     while i < 10 do i = i + 1 skynet.send(rand, "lua", "rand") skynet.sleep(100) end
end)

testrand.lua:安全

local skynet = require "skynet" skynet.start(function() skynet.dispatch("lua", function(session, address, cmd, ...) print(math.random()) end) end)

    開發時使用的是skynet-mingw版本,測試結果以下: session

0.001251220703125
0.001251220703125
0.001251220703125
0.001251220703125
0.56356811523438
0.19329833984375
0.56356811523438
0.56356811523438
0.19329833984375
0.001251220703125

    能夠看到,出現了不少重複的隨機數,失去了隨機的效果。經測試發現,若是在main.lua中再也不sleep,而是連續發出隨機數請求,那麼生成的隨機數便不會重複了。由前面對skynet的分析你們已經瞭解到,skynet服務在處理消息時,不一樣的消息多是由不一樣的工做線程處理的。而後間隔請求和連續請求惟一的區別是目標服務testrand在處理消息時,間隔請求被不一樣線程處理的概率比較大,而連續請求被不一樣線程處理的概率比較小。記得以前的分析麼,工做線程拿到目標的message-queue後,是會連續處理一部分消息的,處理完以後若是沒事兒會休息一下子。數據結構

    既然如此,那麼就在配置中將工做線程數目thread配置爲1,測試結果以下: dom

0.00125122070312
0.56356811523438
0.19329833984375
0.8087158203125
0.58499145507812
0.4798583984375
0.35028076171875
0.89593505859375
0.82281494140625
0.74658203125

     能夠看到沒有重複了,驗證了咱們的想法。而實際中咱們又發現,多個工做線程時在linux上是不會出現重複的,測試結果以下:函數

0.84018771676347
0.39438292663544
0.78309922339395
0.79844003310427
0.91164735751227
0.19755136920139
0.33522275555879
0.76822959445417
0.27777471067384
0.55396995553747

    這個又是什麼緣由呢?天然得從平臺的差別上去查了。咱們調用的是math.random()函數,它最終調用的是rand()函數,查閱文檔後咱們瞭解到,它在linux和windows平臺上是有很大區別的。在linux平臺上,rand()函數不是線程安全的,它隱藏了一個全局狀態,每次調用都會修改這個全局狀態。因此這裏你會發現間隔調用時雖然可能由不一樣的線程執行,可是產生的隨機數倒是不一樣的。windows平臺則否則,相關的狀態是儲存在線程的數據結構體中的,由於咱們這裏沒有設置隨機數種子,不一樣線程都是以默認隨機數種子開始,因而出現了不一樣線程的隨機數序列相同的狀況。測試

相關文章
相關標籤/搜索