4

我正在开发 Clojure / Jetty 网络服务。我有一个特殊的 url,我希望一次只处理一个请求。如果请求了 url,并且在它返回之前,再次请求了 url,我想立即返回。所以在更多 core.clj 中,我定义了我的路线,我有这样的东西:

(def work-in-progress (ref false)) 

然后过一段时间

(compojure.core/GET "/myapp/internal/do-work" []
    (if @work-in-progress
        "Work in Progress please try again later"
        (do
            (dosync
                (ref-set work-in-progress true))
            (do-the-work)
            (dosync
                (ref-set rebuild-in-progress false))
            "Job completed Successfully")))

我已经在本地 Jetty 服务器上尝试过这个,但我似乎能够两次点击 url 并将工作加倍。在线程化的 Web 服务器环境中,在 Clojure 中实现这一点的好模式/方法是什么?

4

3 回答 3

4

想象一下问题中提出的解决方案的以下竞争条件。

  1. 线程 A 开始执行处理程序的主体。@work-in-progressfalse,所以它进入do表达式。但是,在它设法将值设置work-in-progresstrue...
  2. 线程 B 开始执行处理程序的主体。@work-in-progress是假的,所以它进入do表达式。

现在两个线程同时执行(do-the-work)。这不是我们想要的。

为防止出现此问题,请检查并设置dosync事务中 ref 的值。

(compojure.core/GET "/myapp/internal/do-work" []
  (if (dosync
        (when-not @work-in-progress
          (ref-set work-in-progress true)))
    (try
      (do-the-work)
      "Job completed Successfully"
      (finally
        (dosync
          (ref-set work-in-progress false))))
    "Work in Progress please try again later"))

在这种情况下您可能会发现另一个有用的抽象是原子和compare-and-set!.

(def work-in-progress (atom false))

(compojure.core/GET "/myapp/internal/do-work" []
  (if (compare-and-set! work-in-progress false true)
    (try
      (do-the-work)
      "Job completed Successfully"
      (finally
        (reset! work-in-progress false)))
    "Work in Progress please try again later"))
于 2013-06-05T20:03:09.600 回答
2

实际上,这是锁的自然用例;特别是,一个java.util.concurrent.locks.ReentrantLock

在我对较早的 SO 问题的回答中出现了相同的模式,即确保只有一个服务实例在 Clojure 中运行/启动/停止的规范方法?; 我将在这里重复相关的代码:

(import java.util.concurrent.locks.ReentrantLock)

(def lock (ReentrantLock.))

(defn start []
  (if (.tryLock lock)
    (try
      (do-stuff)
      (finally (.unlock lock)))
    (do-other-stuff)))

tryLock方法尝试获取锁,true如果成功则返回,false否则,在任何一种情况下都不会阻塞。

于 2013-06-05T21:05:36.623 回答
1

考虑对资源的访问进行排队 - 除了获得与锁/标志等效的功能外,队列还可以让您观察资源争用以及其他优点。

于 2013-06-06T08:23:48.260 回答