当callable是Clojure函数时,从ScheduledFutureTask获取nil而不是返回值

时间:2012-08-20 13:03:07

标签: interface clojure interop scheduled-tasks

我正在尝试使用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),但是不应该输入提示修复那个?

很多,非常感谢任何帮助或提示!

2 个答案:

答案 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)。在通常难以解释的情况下,这通常有效,但有时却无效。最好避免这种情况。