我正在尝试使用Executors.newSingleThreadScheduledExecutor()安排Clojure函数。令人烦恼的是,在生成的ScheduledFutureTask上调用.get()会返回nil而不是函数的结果。
我将希基先生的期货实施作为典范。
(ns my.ns
(:import (java.util.concurrent Executors ThreadFactory TimeUnit)))
(def ^:private thread-pool-scheduler (atom nil))
(def ^:private thread-pool-counter (agent 0))
(defn- get-and-increment-thread-id []
(-> thread-pool-counter (send inc) deref))
(def ^:private thread-factory
(reify ThreadFactory
(newThread [this f]
(let [thread (Thread. f)]
(.setName thread (format "clojure-scheduled-future-thread-pool-%d"
(get-and-increment-thread-id)))
thread))))
(defn scheduled-future-call [^Callable f ^long delay ^TimeUnit unit]
(.schedule (scheduled-futures-executor) (bound-fn* f) delay unit))
(defn start-scheduled-futures-executor! []
(reset! thread-pool-scheduler
(Executors/newSingleThreadScheduledExecutor thread-factory)))
(defn scheduled-futures-executor []
(or @thread-pool-scheduler
(start-scheduled-futures-executor!)))
一切正常,并在适当的时候激发副作用(例如安排#(println“ok”))。 但是,调用生成的ScheduledFutureTask的get()方法总是给我零 (例如,安排#(+ 5 5))。
我尝试显式扩展Callable,尝试省略bound-fn *,但结果是一样的:
(defprotocol ISchedule
(schedule [this delay time-unit]))
(extend Callable
ISchedule
{:schedule (fn [this delay time-unit]
(.schedule (scheduled-futures-executor) this delay time-unit))})
我的直觉是ScheduledExecutorService正在按计划选择计划(Runnable,long,TimeUnit)(Callable,long,TimeUnit),但是不应该输入提示修复那个?
很多,非常感谢任何帮助或提示!
答案 0 :(得分:3)
我的直觉是ScheduledExecutorService正在按计划选择计划(Runnable,long,TimeUnit)(Callable,long,TimeUnit),
我认为你是对的,只有我知道Callable
并且它运作正常。 (我还在导入语句的类列表中添加了Callable
。
编辑:我也删除了对bound-fn*
检查出来:
(defn make-callable [f] (reify Callable (call [this] (f))))
(def cat (make-callable (fn [] (println "meeow") "i am a cat")))
(def who-are-you? (scheduled-future-call cat 2 TimeUnit/SECONDS))
(println "Tell me who you are!\n\t" (.get who-are-you?))
输出:
meeow
Tell me who you are!
i am a cat
答案 1 :(得分:1)
^Callable
上的f
提示对你没有好处,因为你无论如何都要调用bound-fn,其结果不是类型暗示的。您需要提示您实际传递给.schedule
的内容。更重要的是,您需要提示目标对象本身(执行程序),因为如果目标对象没有被暗示,编译器将(非常合理地)忽略对参数的任何提示:如果它不知道它,它必须进行反射。目标的类型!
所以,在let-binding 1 中暗示这两件事你应该没问题。您可能需要提示所有其他参数以及消除歧义,但我不这么认为。
1 注意:不提示生成它们的表达式,例如^Callable (bound-fn f)
。在通常难以解释的情况下,这通常有效,但有时却无效。最好避免这种情况。