Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 在Ruby和Redis中匹配实时玩家的最佳策略?_Ruby On Rails_Ruby_Redis_Actioncable - Fatal编程技术网

Ruby on rails 在Ruby和Redis中匹配实时玩家的最佳策略?

Ruby on rails 在Ruby和Redis中匹配实时玩家的最佳策略?,ruby-on-rails,ruby,redis,actioncable,Ruby On Rails,Ruby,Redis,Actioncable,我使用这种相当简单的方法来匹配两名现场玩家: class Seek def self.create(uuid) if opponent = REDIS.spop("seeks") Game.start(uuid, opponent) else REDIS.sadd("seeks", uuid) end end def self.remove(uuid) REDIS.srem("seeks", uuid) end end

我使用这种相当简单的方法来匹配两名现场玩家:

class Seek
  def self.create(uuid)
    if opponent = REDIS.spop("seeks")
      Game.start(uuid, opponent)
    else
      REDIS.sadd("seeks", uuid)
    end
  end

  def self.remove(uuid)
    REDIS.srem("seeks", uuid)
  end
end
然后,当游戏开始时,我只需执行
Seek.create(uuid)

有时两个人同时寻找时,我几乎没有遇到什么利基问题。我猜
Redis.spop(“seeks”)
会为两个玩家返回
nil
,然后将它们都添加到
Redis.sadd(“seeks”,uuid)
。然后他们都无限期地等待(当然,除非另一个玩家出现)


我的情况似乎很少见,但我很好奇我的
seek.rb
文件是否可以用更好的方式来防止这种情况。

您的问题是
SPOP
SADD
之间存在竞争条件。您应该在事务中运行这两个命令。使用Redis,您可以通过实现这一点,从而确保整个脚本在服务器端以原子方式运行

-- transaction.lua
redis.replicate_commands() -- see https://redis.io/commands/eval#replicating-commands-instead-of-scripts for details

local uuid = ARGV[1]    -- pass uuid by script's arguments
local member = redis.call('SPOP', 'seeks')
if (member) then
    return member    -- get an exist uuid
else
    redis.call('SADD', 'seeks', uuid)   -- add it to the set
end   -- the whole script runs in a transaction

我希望你已经监控了你的日志。除了使用事务,您还可以使用自旋锁来处理redis中的竞争条件。有关更多详细信息,请参阅本文:。但通常情况下,这是您为解决手头的问题而对代码建模的方式

class Seek

  def self.create(uuid)

    if opponent = REDIS.spop("seeks")
      Game.start(uuid, opponent)
    else
      #Check if key(lock) exists in redis. If not then proceed ahead
      #Set key(acquire lock). Raise exception in case redis set key does not return true
      REDIS.sadd("seeks", uuid) #Perform your operation
      #Delete key(release lock)
    end
  end

  def self.remove(uuid)
    REDIS.srem("seeks", uuid)
  end
end
使用如何?