gpt4 book ai didi

multithreading - 确保只有一个服务实例在 Clojure 中运行/启动/停止的规范方法?

转载 作者:行者123 更新时间:2023-12-04 04:28:03 26 4
gpt4 key购买 nike

我正在用 Neo4j 支持的 Clojure 编写一个有状态服务器,它可以处理套接字请求,例如 HTTP。当然,这意味着我需要能够从此服务器中启动和停止套接字服务器。在设计方面,我希望能够在此服务器中声明一个“服务”并启动和停止它。

我在 Clojure 中试图思考的是如何确保启动和停止这些服务是线程安全的。我正在编写的这个服务器将在其中嵌入 NREPL 并以并行方式处理传入的请求。其中一些请求将是管理性的:启动服务 X,停止服务 Y。这开启了同时进入两个启动请求的可能性。

  1. 启动应该同步检查“正在运行”标志和“正在启动”标志,如果设置了其中一个则失败。在同一笔交易中,应设置“开始”标志。
  2. 设置“开始”标志后,交易结束。这使得“开始”标志对其他事务可见。
  3. 然后 (start) 函数实际启动服务。
  4. 如果 (start) 成功,则同步设置“running”和“starting”标志。
  5. 如果 (start) 失败,则设置“starting”标志并返回异常。

停止需要同样的东西,检查“运行”标志并检查和设置它自己的“停止”标志。

我正在尝试通过 (start) 和 (stop) 的所有可能组合进行推理。

我错过了什么吗?

是否已经有一个图书馆?如果不是,像这样的图书馆应该是什么样的?我会将其开源并放在 Github 上。

编辑:

这就是我目前所拥有的。不过我能看到一个洞。我错过了什么?

(ns extenium.db
(:require [clojure.tools.logging :as log])
(:import org.neo4j.graphdb.factory.GraphDatabaseFactory))

(def ^:private
db- (ref {:ref nil
:running false
:starting false
:stopping false}))

(defn stop []
(dosync
(if (or (not (:running (ensure db-)))
(:stopping (ensure db-)))
(throw (IllegalStateException. "Database already stopped or stopping."))
(alter db- assoc :stopping true)))
(try
(log/info "Stopping database")
(.shutdown (:ref db-))
(dosync
(alter db- assoc :ref nil))
(log/info "Stopped database")
(finally
(dosync
(alter db- assoc :stopping false)))))

在 try block 中,我记录,然后调用 .shutdown,然后再次记录。如果第一个日志失败(可能发生 I/O 异常),则 (:stopping db-) 设置为 false,这会解除阻塞并且没问题。 .shutdown 是 Neo4j 的 void 函数,所以我不必计算返回值。如果失败,(:stopping db-) 将设置为 false,这样也没关系。然后我将 (:ref db-) 设置为 nil。如果失败了怎么办? (:stopping db-) 设置为 false,但 (:ref db-) 保持挂起状态。所以这是一个洞。与第二个日志调用相同的情况。我错过了什么?

如果我只使用 Clojure 的锁定原语而不是 ref dance 会更好吗?

最佳答案

这实际上很适合简单的锁:

(locking x
(do-stuff))

此处 x 是要同步的对象。

详细说明:启动和停止服务是一种副作用;不应从事务内部启动副作用,除非可能作为代理操作。在这里,锁正是设计所需要的。请注意,当它们非常适合手头的问题时,在 Clojure 中使用它们并没有错,事实上,我会说 locking 是这里的规范解决方案。 (参见 Stuart Halloway 的 Lancet,在 Clojure 编程(第 1 版)中介绍,这是一个使用锁的 Clojure 库示例,该库已被广泛使用,主要在 Leiningen。)

更新:添加快速失败行为:

这仍然很适合锁,即 java.util.concurrent.locks.ReentrantLock (点击 Javadoc 链接):

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

(def lock (ReentrantLock.))

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

(do-stuff) 获取锁成功后执行;否则,(do-other-stuff) 将会发生。在任何一种情况下,当前线程都不会阻塞。

关于multithreading - 确保只有一个服务实例在 Clojure 中运行/启动/停止的规范方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16131420/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com