如何防止多个Discordrb Bot激活不按顺序处理?

时间:2020-04-13 15:48:46

标签: ruby discord

我写了一个Ruby Discord(discordrb)机器人来管理D&D角色。我注意到,当多个玩家同时提交同一命令时,他们各自收到的结果并不独立。一个玩家的请求(向其角色分配武器)最终被分配给同时提交相同请求的其他角色。我希望每个请求都将按顺序分别执行。如何防止交叉请求?

bot.message(contains:"$Wset") do |event|
    inputStr = event.content; # this should contain "$Wset#" where # is a single digit
    check_user_or_nick(event);  pIndex = nil;  #fetch the value of @user & set pIndex
    (0..(@player.length-1)).each do |y|  #find the @player pIndex within the array using 5 char of @user
        if (@player[y][0].index(@user.slice(0,5)) == 0) then pIndex = y;  end; #finds player Index Value (integer or nil)
    end;
    weaponInt = Integer(inputStr.slice(5,1)) rescue false; #will detect integer or non integer input
    if (pIndex != nil) && (weaponInt != false)  then; 
       if weaponInt < 6 then;
           @player[pIndex][1]=weaponInt;
           say = @player[pIndex][0].to_s + " weapon damage has be set to " + @weapon[(@player[pIndex][1])].to_s;
          else;
              say = "Sorry, $Wset requires this format: $Wset?  where ? is a single number ( 0 to 5 )";         
          end;
    else
       say = "Sorry, $Wset requires this format: $Wset?  where ? is a single number ( 0 to 5 )"; 
    end;
    event.respond say;
end;

1 个答案:

答案 0 :(得分:1)

为避免像这样在多线程代码中出现竞争状况,您要查找的主要内容是副作用

bot.message(contains:"$Wset") do |event|块视为迷你程序线程。此处的所有内容都应自包含-应该没有办法影响其他线程。

最初查看您的代码,我要搜索的是任何共享变量。如果它们同时被多个线程读取/写入,则会产生争用条件。

在这种情况下,有两个明显的犯罪者-@player@user。这些应该重构为局部变量,而不是实例变量。在块中定义它们,这样它们就不会影响任何其他范围,例如:

# Note, for this to work, you will have to change
# the method definition to return [player, user]

player, user = check_user_or_nick(event)

有时,不可避免地会从线程产生副作用(例如,您想对线程运行的次数进行计数)。为了防止在这些情况下出现争用情况,通常在解决方案中使用Mutex,但是如果代码正在多台计算机上运行,有时也可以使用distributed lock。但是,从您显示的代码来看,您似乎不需要这里的任何一种。