【问题标题】:Getting nil instead of a return value from ScheduledFutureTask when the callable is a Clojure function当可调用是 Clojure 函数时,从 ScheduledFutureTask 获取 nil 而不是返回值
【发布时间】:2012-08-20 13:03:06
【问题描述】:

我正在尝试使用 Executors.newSingleThreadScheduledExecutor() 来安排 Clojure 函数。令人烦恼的是,在生成的 ScheduledFutureTask 上调用 .get() 会返回 nil 而不是函数的结果。

我以 Hickey 先生的期货实现为模型。

(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),但输入提示不应该解决这个问题吗?

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

【问题讨论】:

    标签: interface clojure interop scheduled-tasks


    【解决方案1】:

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

    我认为你是对的,只有我 reified Callable 并且它工作正常。 (我还在 import 语句的类列表中添加了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
    

    【讨论】:

    • 很遗憾我不能将两个帖子打勾为“答案”。这和 amalloy 的回复都对我帮助很大。
    • 很高兴它有帮助。我忘了提到我也删除了对bound-fn* 的调用。很抱歉,如果这造成任何混乱。
    【解决方案2】:

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

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

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

    【讨论】:

    • 谢谢!为了将来参考,我必须输入提示所有参数。
    猜你喜欢
    • 2015-03-31
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    • 2013-08-13
    • 1970-01-01
    • 2020-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多