【问题标题】:How to prevent concurrent access in MVC Controller?如何防止 MVC Controller 中的并发访问?
【发布时间】:2014-05-31 02:18:28
【问题描述】:

我有一个可通过特定 URL 访问的 MVC 控制器,当调用该控制器时,它会运行一系列耗时的过程(后处理来自 db 的数据)。

我需要确保当用户调用该方法时,该过程会启动一次。如果任何其他用户在运行后处理时访问该特定 URL,则不会同时发生后处理。

我的问题:

  • 我应该在 C# 中使用 locks 吗?
  • 我是否应该在 DB 中使用类似 inProgress 的标志,以便标记处理开始和结束的时间?
  • 还有其他解决方案吗?

【问题讨论】:

标签: c# .net asp.net-mvc asp.net-mvc-4


【解决方案1】:

如果你想扩展到多台机器,内存锁不是一个选项,但数据库中的锁可能是最简单的。

例如,您可以创建一个带有唯一 id 字段的锁表。收到请求时,尝试插入 id 为 1 的行。如果成功,则后处理并删除密钥。

在另一个运行期间存在密钥时尝试插入密钥的任何其他请求都将导致插入失败并且不会运行作业。

【讨论】:

  • 这是迄今为止我见过的最简单的方法,可以确保在任何时候在 Web 应用程序中只运行一个进程,并且我已经寻找了提供单个作业运行进程的不同方法.
【解决方案2】:

每个并发请求都有自己的线程。

这是确保线程安全所需的一组正在进行的任务。此资源将是共享资源,因此多个 Web 请求将尝试同时访问。

从 .Net 4.0 开始有并发集合,这让您的生活更轻松。您需要的是一个并发集,但是不存在这样的类。您可以改用 ConcurrentDictionary,只使用请求 ID 的键。

这假设您只有一个 Web 服务器,否则您将需要数据库或共享服务解决方案。

【讨论】:

  • @GibboK 是的,但是引入性能问题或死锁会更容易,所以我不建议这样做。
  • "每个并发请求都有自己的线程。" - 有点错误 - 每个请求由控制器的唯一实例处理,这些控制器在实际执行代码时租用可用线程,这对于具有异步控制器的现代(MVC4 +)代码尤其如此,其中多个并发请求可能最终在同一个线程上运行而其他一个是“等待”。
  • @GibboK - 锁定时要非常小心 - 通常你应该在快速可预测的操作中使用lock,而不是在几乎无限执行(如网络或数据库访问)的情况下减慢一次。
  • @AlexeiLevenkov 如果一个请求正在等待,它不会与其他正在运行的请求并发
  • @GibboK Lock in db 可能更适合您的情况(正如 Joachim Isaksson 的回答所建议的那样)-您想标记“这部分工作已经完成”-因此将该信息存储在其余与“工作”相关的数据是。 IE。在内存结构的情况下,lock 通常是很好的解决方案,对于外部数据(尤其是可能被多个进程使用),进程内状态可能不合适。
【解决方案3】:

更准确地说:它们是线程安全的,因为控制器是为每个请求创建新的。 2 个请求不共享一个控制器。

【讨论】:

  • +1。回答帖子的标题。更准确 - 控制器的方法/实例数据不是“线程安全”的通常含义(如“可以随时从任何线程访问”),而是线程安全本身没有问题。请注意,问题主体涉及完全不同的问题(确保特定请求仅运行一个实例)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
  • 2012-11-02
相关资源
最近更新 更多