Reputation: 13294
I have created a Leiningen project for Exercise 2 from here. My code looks like this:
(ns random-quotes.core
(:require [clojure.string :as str])
(:gen-class))
(defn word-count [s]
(frequencies (str/split (first (str/split s #"\n")) #"\s")))
(def quote-url "http://www.braveclojure.com/random-quote")
(def total-word-count (atom {}))
(defn update-word-count []
(future
(swap! total-word-count
(partial merge-with +)
(word-count (slurp quote-url)))))
(defn quote-word-count [n]
(doseq [quote-future (doall (repeatedly n update-word-count))]
@quote-future)
@total-word-count)
(defn -main [n]
(doseq [entry (sort-by val (quote-word-count (bigdec n)))]
(println entry)))
All pretty straightforward. When I run, e.g., (-main 5)
in lein repl
, it runs, prints, and returns as expected. However, when I try lein run 5
instead, it runs and prints but never exits, so I am forced to use Ctrl+C to get my terminal back.
Any idea why this happens?
Upvotes: 2
Views: 909
Reputation: 91534
Clojure has a thread pool that it keeps running for use by the agents. Because those threads are still alive, the JVM can't tell that you're program is done. It's just sitting there waiting for the agents to exit. You can make them finish by calling (shutdown-agents)
at the end of your program as described here. Futures use agents.
clojure.core/future-call
calls an agent like this:
(let [f (binding-conveyor-fn f)
fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
which actually starts your code running. You would not be the only one to voice some criticism of this, and we all hope a more elegant solution is found.
Upvotes: 3