仅处理多个并发Web API请求中的一个

时间:2017-06-12 07:33:30

标签: c# asp.net-web-api concurrency locking

我们正在Android和IOS中实施游戏。在游戏结束时,每个客户端都会调用API来完成游戏。它看起来如下:

/game/finish

和这样的json:

{ GameId:1, WinnerId: 2, .... }

为了确保始终调用Finish,两个玩家都使用相同的参数调用此Api。因此,可以在服务器处同时接收请求。在服务器端,我们应该只处理这些并发请求并丢弃另一个请求(为了正确地增加/减少赢家/输家点和其他一些业务)。

服务器端使用C#,WebAPI

实现

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

任何帮助我提供更好解决方案的帮助都会更加明显。

1 个答案:

答案 0 :(得分:1)

您需要使用lock并且实际上有很多方法可以使用lock执行此操作,正确的方法取决于许多架构问题。它可以在数据库级别,后端级别或仅在前端(webAPI)级别完成 如果您的游戏结束过程可能持续太长时间,也可以通过“锁定 - 分配 - 解锁 - 完成”方式完成,以便第二个用户不会等待回复太长时间。

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

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);
        }
    }
}

即使第二个线程经过第一次检查(如果是竞争条件),它也会等到第一个完成整理过程,然后检查GameIsFinished等于true并且什么都不做。< / p>

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

  1. 如果两个用户在完成之前关闭窗口怎么办?游戏是否被忽视并被遗忘?
  2. 如果用户使用自己的winnerId替换您的请求,并且有两个请求使用相同的GameId,但WinnerId不同,该怎么办?
  3. 如果我只是通过不同的游戏结果向您的服务器发送垃圾邮件怎么办?
  4. 您的服务器应该明确决定谁是赢家,而不是客户。