When I run the following code it basically works how I intend it to, except that it hangs after the future is finished. What am I missing - some kind of "close agents/threads" call? How should I do this?
(def name-to-greet (promise))
(future
(println "Hello," #name-to-greet))
(print "What is your name? ")
(flush)
(deliver name-to-greet (read-line))
Futures use the agent thread pool, which uses non-daemon threads, which means Clojure won't shut down till you call (shutdown-agents). imho, this is bogus (see my comments here) and I've made suggestions that Rich said he would consider post-1.2 around this.
Related
This is piece of code from The Beauty of Clojure I don't understand what alt! is doing here.
(defn listener [f ch]
(let [stop-ch (chan)]
(go-loop []
(alt!
stop-ch ([_] :no-op)
ch ([msg] (f msg)
(recur))))
{:listener ch :stop stop-ch}))
(defn stop-listener [{:keys [stop]}]
(put! stop :stop))
Especially what does second argument to the alt! which is:
ch ([msg] (f msg)
(recur))
does?
And does go-loop mean that after listener function is called it would wait indefinitely to receive values?
The go loop alt! will execute either block depending on which channel has a message.
You’ll notice that the stop-ch does not recur and therefore after receiving a stop, the go loop will end.
If something is received on the listener channel, it is processed by the function f. The recur then takes us back to the start of the go loop, where alt! will wait for further messages on either the listener or the stop channel.
The listener structure created is a map of two channels - put things into listener and they will be f’ed, put anything onto the stop and the listener will stop. This final detail is then abstracted away for the user by the stop-listener fn.
This whole thing is in essence just a simple adaptor between a core.async channel and a function, with clean up logic.
And does go-loop mean that after listener function is called it would wait indefinitely to receive values?
No. Calling listener won’t block the flow of control. The go loop created will “block” until it receives input on one of the channels, however. I’m using quotes because this isn’t a blocked thread - I really recommend you take a look at some of the basic core.async presentations once you’ve had a play at the REPL. Once you can tie the behaviour up to the theory it’s quite straightforward.
(def queue-agent (agent (clojure.lang.PersistentQueue/EMPTY)))
(send queue-agent conj "some data for the queue")
(println "test output")
If I run this code, after a couple (!) of seconds the console will output test output and then nothing happens (program is not terminating). I've just checked against a couple of sources that all said the send function is asynchronous and should return immediately to the calling thread. So what's wrong with this? Why is it not returning? Is there something wrong with me? Or with my environment?
So you have two issues: long startup time, and the program does not exit.
Startup: Clojure does not do any tree shaking. When you run a Clojure program, you load and bootstrap the compiler, and initialize namespaces, on every run. A couple of seconds sounds about right for a bare bones Clojure program.
Hanging: If you use the agent thread pool, you must run shutdown-agents if you want the program to exit. The vm simply doesn't know it is safe to shut them down.
The scenario I try to resolve is a s follows, I have a testing program that makes a web to a web endpoint on a system.
This test program has a jetty web server running on which it expects a callback from the external system that completes a successful test cycle. In case that the callback is not received during an specific time range (timeout), the test fails.
To achieve this, I want the test runner to wait on an "event" that the jetty handler will set upon callback.
I thought about using java's CyclicBarrier but I wonder if there is an idiomatic way in clojure to solve this.
Thanks
You can use promise you asked about recently :) Something like this:
(def completion (promise))
; In test runner.
; Wait 5 seconds then fail.
(let [result (deref completion 5000 :fail)]
(if (= result :success)
(println "Great!")
(println "Failed :(")))
; In jetty on callback
(deliver completion :success)
In straight Clojure, using an agent that tracks outstanding callbacks would make sense, though in practice I would recommend using Aleph, which is a library for asynchronous web programming that makes even driven handlers rather easy. It produces ring handlers, which sounds like it would fit nicely with your existing code.
I am attempting to write a game, Crossfire, that will run in both clojure and ClojureScript and I need a publish-subscribe mechanism that will work in both. I have seen lamina and Shoreleave but both are dependent on their respective environments.
I need to have an event system where a subscriber can wait for a message.
Update:
This question was asked and answered before core.async was released. core.async is designed to solve precisely this problem, you should definitely use it for all projects going forward.
Original answer:
It's not truly asynchronous, but I have grown quite fond of using atoms and watchers for this. Very simple but highly flexible model, and built in to both languages.
An extremely simple example:
(def my-channel (atom nil))
;; subscribe
(add-watch my-channel :watcher1
(fn [_ _ _ message]
(js/alert (str "Received message: " message))))
;; publish
(reset! my-channel "my-message")
;; unsubscribe
(remove-watch my-channel :watcher1)
The beauty of this approach is that the state of the atom can be any object. Here, I'm simply resetting the state of the atom the message, but you could also have the state of the atom be the full history of messages, or the last 5 messages, or a state machine representing your entire system, or whatever you want.
I am trying to use sh from clojure.java.shell. In the REPL, it works fine but from a script, it gets stuck.
(ns tutorial.shell
(:use clojure.java.shell))
(println (:out (sh "ls" )))
What should I fix?
The problem is that sh uses futures and Clojure programs which use futures or agents hang around a bit before quitting when they have nothing more to do due to how some internal machinery works.
To get around this, add
(shutdown-agents)
at the end of your script, which terminates that piece of machinery. (So it does more than the name promises in that futures are also affected.)
Note that this cannot be undone and therefore should not be used at the REPL.