2

我正在尝试使用 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() 方法总是给我 nil(例如调度 #(+ 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 选择 schedule(Runnable, long, TimeUnit) 而不是 schedule(Callable, long, TimeUnit),但不应该输入提示来解决这个问题吗?

非常非常感谢您的帮助或提示!

4

2 回答 2

3

我的直觉是 ScheduledExecutorService 选择 schedule(Runnable, long, TimeUnit) 而不是 schedule(Callable, long, TimeUnit),

我认为你是对的,只有我具体化Callable并且它工作正常。(我还在Callableimport 语句中添加了类列表)。

编辑:我还删除了对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
于 2012-08-20T17:13:05.420 回答
1

^Callable提示对您f没有好处,因为无论如何您都只是调用 bound-fn ,其结果不是类型提示的。你需要提示你实际传递给的东西.schedule。更重要的是,您需要提示目标对象本身(执行程序),因为如果没有提示目标对象,编译器将(相当合理地)忽略任何参数提示:如果它不知道,它无论如何都必须进行反射目标类型!

所以,在 let-binding 1中提示这两件事,你应该没问题。您可能还需要暗示所有其他论点以消除歧义,但我不这么认为。

1注意:不要暗示生成它们的表达式,例如^Callable (bound-fn f). 在难以解释的情况下,这通常有效,但有时无效。最好避免这种情况。

于 2012-08-20T19:08:39.997 回答