C# 只处理多个并发Web API请求中的一个

C# 只处理多个并发Web API请求中的一个,c#,asp.net-web-api,concurrency,locking,C#,Asp.net Web Api,Concurrency,Locking,我们正在用Android和IOS实现一个游戏。在游戏结束时,每个客户端调用一个API来完成游戏。如下所示: /game/finish 以及类似以下的json: { GameId:1, WinnerId: 2, .... } 为了确保始终调用Finish,两个播放器使用相同的参数调用此Api。因此,可以在服务器上同时接收请求。在服务器端,我们应该只处理其中一个并发请求,而丢弃另一个请求(以便正确地增加/减少赢家/输家点数和其他一些业务) 服务器端使用C#,WebAPI实现 我正在考虑使用loc

我们正在用Android和IOS实现一个游戏。在游戏结束时,每个客户端调用一个API来完成游戏。如下所示:

/game/finish
以及类似以下的json:

{ GameId:1, WinnerId: 2, .... }
为了确保始终调用Finish,两个播放器使用相同的参数调用此Api。因此,可以在服务器上同时接收请求。在服务器端,我们应该只处理其中一个并发请求,而丢弃另一个请求(以便正确地增加/减少赢家/输家点数和其他一些业务)

服务器端使用C#,WebAPI实现

我正在考虑使用lock语句,但它可能会影响性能


任何能为我提供更好解决方案的帮助都会更值得赞赏。

您需要使用
lock
,实际上使用
lock
有很多方法,正确的方法取决于许多体系结构问题。它可以在数据库级、后端级或前端(webAPI)级完成。
如果你的游戏结束过程持续时间太长,也可以用“锁定-分配-解锁-完成”的方式完成,这样第二个用户就不会等待太长时间的回复

您可以简单地使用并发字典来存储锁,并使用双重检查锁定来最小化<代码>锁>,但有些人认为它是反模式。 在您的情况下,第一个提交结果的玩家将获得锁并完成游戏:

private readonly ConcurrentDictionary<int, object> _gameLocks = new ConcurrentDictionary<int, object>();

// Finish process:
if (!GameIsFinished(gameId))
{    
    lock (_gameLocks.GetOrAdd(gameId, new object())
    {
        if (!GameIsFinished(gameId)) {
            FinishGame(gameId);
        }
    }
}
私有只读ConcurrentDictionary\u gameLocks=new ConcurrentDictionary();
//完成过程:
如果(!GameIsFinished(gameId))
{    
lock(_gameLocks.GetOrAdd(gameId,new object())
{
如果(!GameIsFinished(gameId)){
FinishGame(gameId);
}
}
}
即使第二个线程通过了第一个检查(在竞争条件下),它也将等待第一个线程完成完成完成过程,然后检查
GameIsFinished
equal
true
,什么也不做

我对你的设计有几个问题:

  • 如果两个用户在游戏结束前都关闭了窗口呢?游戏是否被忽略和遗忘了
  • 如果用户用自己的
    winnerId
    替换您的请求,并且有两个请求具有相同的GameId,但不同的
    winnerId
    ,该怎么办
  • 如果我只是给你的服务器发垃圾邮件,告诉你实际上从未玩过的游戏的不同结果会怎么样

  • 您的服务器应该明确决定谁是赢家,而不是客户端。

    如果只有赢家发送请求怎么办?在API调用时,确保只有一个客户端发送请求,或者将游戏标记为已解决,只需检查游戏是否已处理,例如已完成。(
    如果(!isGameHandled(gameID)){//handle and save state}
    )所以,如果赢家在游戏结束时失去了互联网连接,会发生什么?我们将在@Oscar游戏中失败。这就是为什么我们强迫两个客户都打电话finish@Nasseh创建一个本地文件,将游戏结果标记为未发送,并在获胜者正确发送请求后将其删除。以下是答案:1.如果一名玩家离开gam,则有一项政策e、 第二个玩家是赢家。2.你是对的,他们可以。但我们是一个团队,我相信两个客户都正确地设置了赢家3.对此没有答案:)我们使用Socket IO进行实时游戏,服务器端是nodeJS。我们无法在nodeJS中处理这一点,因为我们对“交叉手指解决方案”还不熟悉(可能,但我相信它永远不会发生)是万恶之源。但这个答案也表明了这样一个解决方案:希望没有人会提高工作进程计数我应该在提交结果(调用Finish Api)时首先提到每个玩家都经过了身份验证