期货永远不会解决并兑现承诺

时间:2017-01-16 17:06:39

标签: concurrency clojure parallel-processing functional-programming lisp

我正在读一本书来教自己Clojure称为 Clojure for the Brave and True 。第9章介绍了基本的并发编程,包括延迟,期货和承诺。本章末尾的第一个练习是:

"编写一个以字符串作为参数的函数,并使用slurp函数在Bing和Google上搜索它。您的函数应返回搜索"

返回的第一页的HTML

我的解决方案如下:

(defn search-bing-google
    [search-term]
    (let [search-results (promise)]
        (future (deliver search-results
                    (slurp (str "https://www.bing.com/search?q%3D" search-term))))
        (future (deliver search-results 
                    (slurp (str "https://www.google.com/search?q%3D" search-term))))
        @search-results))

可以这样称呼:

(search-bing-google "clojure")

第二项练习如下:

"更新你的功能,所以它需要第二个参数,包括要使用的搜索引擎。"

我尝试编辑我的第一个解决方案以满足新的参数要求,如下所示:

(def search-engines
    {:bing "https://www.bing.com/"
     :google "https://www.google.com/"})

(defn search
    [search-term & engines]
    (let [results (promise)]
        (map #(future (deliver results 
                               (slurp (str (% search-engines) 
                                           "search?q%3D" 
                                           search-term)))) engines)
            @results))

可以像:

一样调用
(search "clojure" :bing :google)

然而,这个实现与它的前身不同。它似乎因为" map"而从未被调用过。在第二个实现中。任何人都可以帮我弄清楚当我在REPL中加载它并执行它时导致它挂起的原因是什么?

编辑:

通过下面的Josh的回答,我提出了以下解决方案,使用doseq代替dorunmap不再挂起:

(def search-engines
    {:bing "https://www.bing.com/"
     :google "https://www.google.com/"})

(defn search
    [search-term & engines]
    (let [results (promise)]
        (doseq [engine engines]
            (future (deliver results 
                             (slurp (str (engine search-engines) 
                                         "search?q%3D" 
                                         search-term)))))
        @results))

1 个答案:

答案 0 :(得分:3)

因为map会导致延迟评估,所以需要一些东西来实现它。在你的代码中,没有任何东西,所以期货永远不会真正创建。不只是map,而是:

(dorun (map ...