我写了一个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;
答案 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。但是,从您显示的代码来看,您似乎不需要这里的任何一种。