当前位置: 首页 > 知识库问答 >
问题:

Clojure中的未来失败

邹俊拔
2023-03-14

在Scala中,未来可能会失败,这可以异步发现:

f onComplete {
  case Success(_) => println("Great!")
  case Failure(t) => println("An error has occurred: " + t.getMessage)
}

你将如何“翻译”成Clojure?我的阅读让我相信Clojure未来/promise模型没有Scala的强大,你不能就这样抓住失败。那么该怎么办呢?

Scala的未来永远不需要被问到它的价值——当它好并准备好时,它会告诉你发生了什么(包括它是否失败——这是这个问题的关键)。这就是我所说的“异步”的意思。Scala的未来可以处于三种可能的状态之一——未完成、以失败告终、以成功告终。

Scala中一个典型的用例是一个返回Future[T]的远程调用,其中T是你真正想要得到的类型。如果远程JVM关闭,那么在超时之后,将会发生< code>case Failure(t)。

这是一个非常简单的模型。在这个问题中,我问的是一个简单的选择。顺便提一下,听说Clojure打算在某个时候采用Scala Futures模型是件好事。

共有3个答案

锺高翰
2023-03-14

未来宏只是包装一个Java未来,而deref阅读器宏只是针对未来调用. get()的语法糖:


user=> (source future)
(defmacro future
  "Takes a body of expressions and yields a future object that will
  invoke the body in another thread, and will cache the result and
  return it on all subsequent calls to deref/@. If the computation has
  not yet finished, calls to deref/@ will block, unless the variant of
  deref with timeout is used. See also - realized?."
  {:added "1.1"}
  [& body] `(future-call (^{:once true} fn* [] ~@body)))
nil
user=> (source future-call)
(defn future-call 
  "Takes a function of no args and yields a future object that will
  invoke the function in another thread, and will cache the result and
  return it on all subsequent calls to deref/@. If the computation has
  not yet finished, calls to deref/@ will block, unless the variant
  of deref with timeout is used. See also - realized?."
  {:added "1.1"
   :static true}
  [f]
  (let [f (binding-conveyor-fn f)
        fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
    (reify 
     clojure.lang.IDeref 
     (deref [] (deref-future fut)) clojure.lang.IBlockingDeref (deref [ timeout-ms timeout-val]
      (deref-future fut timeout-ms timeout-val))
     clojure.lang.IPending
     (isRealized [] (.isDone fut)) java.util.concurrent.Future (get [] (.get fut))
      (get [_ timeout unit] (.get fut timeout unit))
      (isCancelled [] (.isCancelled fut)) (isDone [] (.isDone fut))
      (cancel [_ interrupt?] (.cancel fut interrupt?)))))
nil
user=>

因此,测试失败与在java中没有什么不同:您捕捉到一个< code>ExecutionException,请参阅java文档以了解更多信息:

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get()

因此,解决方案是从 deref 中捕获异常,如其他答案所示。

瞿宏儒
2023-03-14

我想知道Clojure是否需要特定的结构来处理这种失败期货的情况。以下行为我提供了相同的功能:

(defn f-cond[f func-ok func-fail] 
   (future (try (func-ok @f) (catch Exception e (func-fail e))))) 

然后:

@(f-cond (future (throw (Exception. "hi"))) 
   identity #(println "Failed: " (.getCause %)))

结果

Failed:  #<Exception java.lang.Exception: hi>
谢正初
2023-03-14

我记得Scala中的期货是单子,所以在< code>algo.monads和< code > fluo kiten 中搜索合适的东西。最后,我找到了雷纳多·博尔赫斯的《迫在眉睫》图书馆。我想这是你想要的。

有了这个名称空间声明

(ns imminent-proof.core
  (:require [imminent.core :as i]
            [clojure.core.match :refer [match]])
  (:import  [imminent.result Success Failure]))

这就是失败案例

(-> (i/future (/ 1 0))
    (i/on-complete #(match [%]
                     [{Success v}] (prn "success: " v)
                     [{Failure e}] (prn "failure: " e))))

这就是成功的例子

(-> (i/future (Thread/sleep 1000) 42)
    (i/on-complete #(match [%]
                     [{Success v}] (prn "success: " v)
                     [{Failure e}] (prn "failure: " e))))

这是超时的情况

(-> (i/future (Thread/sleep 1000) 42)
    (i/await 500)
    (i/on-complete #(match [%]
                     [{Success v}] (prn "success: " v)
                     [{Failure e}] (prn "failure: " e))))
 类似资料:
  • 我正在寻找一种将任意长度的期货列表转换为期货列表的方法。我使用的是Playframework,所以最终,我真正想要的是一个<code>未来〔结果〕,但为了让事情更简单,让我们说<code>将来〔List[Int]]通常的方法是使用<code>Future.sequence(…) 例如,执行以下操作不起作用: 我希望能够将1和3从那里拉出来,而不是只得到异常。我尝试将来使用<code>。折叠,但这显

  • Scala中有没有不会失败的< code >未来这个概念? 我正在将可能失败,因此我同时处理和--到,并带有从失败或成功状态派生的可选错误消息。目前为止,一切都好。 现在的情况是,我想正式地(即在类型系统的帮助下)记住,这个未来将始终保持,并且我将来不需要处理失败案例。 有什么聪明的方法可以做到这一点吗?

  • 在scala中失败的最干净的方法是什么? 说我有: 如果未来以成功,我想保留它,但是如果它失败了,我想将更改为其他。 我能想出的最好的是转换,但是这需要我为成功案例做一个不必要的函数: 有什么原因没有< code > mapFailure(partial function[Throwable,Throwable])?

  • 我一直在使用助手来创建聚合期货,只有当它们的复合期货被标记为完成时才会成为“完成”,即: 我想对这一功能稍作改动,在以下情况下,总的未来市场是完整的: 所有期货均已成功完成或 在后一种情况下,总期货应立即完成(例外),而不必等待其他期货完成,即快速失败。 对比

  • 我有一个未来[T],我想在成功和失败上映射结果。 比如说 如果我使用< code>map或< code>flatmap,它将只映射成功的未来。如果我使用< code>recover,它将只映射失败的期货。< code>onComplete执行回调,但不返回修改后的未来值。< code>Transform可以工作,但是需要两个函数而不是一个部分函数,所以有点难看。 我知道我可以做出一个新的,并用或/

  • 我希望下面的代码在其中一个方法<code>callfuture1()</code>或<code>callfuture2()</code>抛出异常时返回自定义消息。我的理解是,如果任何一个未来失败,都将是失败的未来。 但是,当 引发异常时。 不执行。相反,我看到调用堆栈停止在 中的代码行,其中发生了异常并返回了标准内部错误。为什么会这样? ====更新==== 我从响应中看到,潜在的问题是异常被抛出