对方法调用进行排队,以便它们由Clojure中的单个线程执行

对方法调用进行排队,以便它们由Clojure中的单个线程执行,clojure,parallel-processing,synchronization,orientdb,Clojure,Parallel Processing,Synchronization,Orientdb,我正在Clojure中围绕OrientDB构建一个包装器。OrientDB的一个最大限制(IMHO)是ODatabaseDocumentTx不是线程安全的,但是从.open()到.close()这件事的生命周期应该表示单个事务,实际上强制事务发生的是单个线程。实际上,默认情况下会提供对这些混合数据库/事务对象的线程本地引用。但是,如果我想登录到与我想保持“真实”状态相同的线程,该怎么办?如果我遇到错误,日志条目也会回滚!由于大多数数据库管理系统不允许命名事务范围管理,因此仅此用例就让我远离了几乎

我正在Clojure中围绕OrientDB构建一个包装器。OrientDB的一个最大限制(IMHO)是
ODatabaseDocumentTx
不是线程安全的,但是从
.open()
.close()
这件事的生命周期应该表示单个事务,实际上强制事务发生的是单个线程。实际上,默认情况下会提供对这些混合数据库/事务对象的线程本地引用。但是,如果我想登录到与我想保持“真实”状态相同的线程,该怎么办?如果我遇到错误,日志条目也会回滚!由于大多数数据库管理系统不允许命名事务范围管理,因此仅此用例就让我远离了几乎所有的数据库管理系统/肥皂盒

不管怎样,OrientDB就是这样,对我来说不会改变。我正在使用Clojure,我想要一种优雅的方式来构造一个
with tx
宏,这样
with tx
主体中的所有命令式数据库调用都可以序列化

显然,我可以通过在带有tx生成的主体的
顶层创建一个哨兵,并将每个表单解构到最低层,并将它们包装在一个同步块中来强制执行它。这太糟糕了,我不确定这会如何与
pmap
这样的东西交互

我可以在宏体中搜索对
ODatabaseDocumentTx
对象的调用,并将这些调用包装在同步块中

我想我可以用一个代理创建某种调度系统

或者我可以使用同步方法调用将ODatabaseDocumentTx子类化


我绞尽脑汁想想出其他办法。思想?一般来说,代理方法似乎更具吸引力,因为如果一段代码中散布了数据库方法调用,我宁愿提前进行所有计算,将调用排队,然后在最后向数据库发送一大堆数据。然而,这假设计算不需要确保读取的一致性。IDK。

听起来像是一个任务。

一个选项是在线程池中使用带有1个线程的Executor。如下图所示。您可以围绕这个概念创建一个漂亮的宏

(import 'java.util.concurrent.Executors)
(import 'java.util.concurrent.Callable)

(defmacro sync [executor & body]
  `(.get (.submit ~executor (proxy [Callable] []
                             (call []
                               (do ~@body))))))

(let [exe (Executors/newFixedThreadPool (int 1))
      dbtx (sync exe (DatabaseTx.))]
  (do
    (sync exe (readfrom dbtx))
    (sync exe (writeto dbtx))))

sync
宏确保主体表达式在executor(只有一个线程)中执行,并等待操作完成,以便所有操作逐个执行。

您能解释一下如何使用薄板吗?我不想强迫所有的计算都被序列化,只是I/O位,我不知道Lala会有什么帮助。Lala允许你使用通道和管道以不同的方式将计算与副作用分离。您可以选择在何处使事情同步或异步,以及操作在何处向下游拉动或推动。我并没有完全了解您的问题,但我认为您可以在一个通道上进行多线程计算并将事件排队,以便处理程序(单线程)处理db调用。如果你举一个简单场景的例子,我可能会帮上更多的忙。在我看来,代理做的事情几乎是一样的。代理本身的值将是事务,
send
将应用一个函数,将事务作为第一个参数,并返回事务以允许链接。这种方法会有什么不同?代理使用一个包含多个线程的线程池,因此,如果DB对象的构造函数创建了一些线程本地内容,那么在代理情况下,这将是一个问题,因为表达式可能在不同的线程上执行。您遇到了什么类型的线程不安全:单个“事务对象”不能由两个线程访问,还是数据库不支持并发写入?