Document directory
- Agents
- Concurrency Functions
- Futures and promises
- Java-based threading
Agents
Agent is an asynchronous data update mechanism.
But it is also a concurrency mechanism because the agent is implemented based on the thread pool and is sent to different thread pools by sending and sending-off respectively.
The number of threads in the thread pool corresponding to send is basically equal to the number of cup cores. Therefore, multiple send commands are automatically processed concurrently Based on the concurrency of the number of cup cores.
Use this mechanism to implement concurrency
Concurrency functionspmap
Pmap is an evolutionary version of map, but it submits elements in each set to a thread to execute the function.
Pmap is partiallyLazyIn that the entire result set is not realized unless required, but the parallel computation does run ahead of the consumption to some degree.
For example, define the test function first, and sleep 1 s before actually executing the function.
(defn make-heavy [f] (fn [& args] (Thread/sleep 1000) (apply f args)))
Through the simple comparison of the following time, we will understand the difference.
user=> (time (doall (map (make-heavy inc) [1 2 3 4 5])))"Elapsed time: 5002.96291 msecs"(2 3 4 5 6)user=> (time (doall (pmap (make-heavy inc) [1 2 3 4 5])))"Elapsed time: 1031.941815 msecs"(2 3 4 5 6)
Pvalues
Pvalues takes any number of expressions and returns a lazy sequence of the values of each expression, evaluated in parallel.
User => (pvalues (+ 5 5) (-5 3) (* 2 4 ))
(10 2 8)
Pcils
Pcalltakes any number of No-Argument functions and returns a lazy sequence of their return values, executing them in parallel.
User => (pcils # (+ 5 2) # (* 2 5 ))
(7 10)
Overhead and Performance
Concurrency is so good. Is it necessary to use concurrency in all situations?
Certainly not. Concurrency itself also requires overhead. If the thread concurrency saves too little time, it will be worth the candle.
Let's look at the following extreme example. Concurrency is much slower, because the time is spent on the overhead of concurrency.
user=> (time (dorun (map inc (range 1 1000))))"Elapsed time: 9.150946 msecs"user=> (time (dorun (pmap inc (range 1 1000))))"Elapsed time: 182.349073 msecs"
Futures and promises
Futures and promises are two slightly more low-level threading constructs, too red by the similar features available in the Java 6 concurrency API. they are simple to understand, simple to use, and provide a very direct way to spawn threads using native clojure syntax.
Futures
A clojure future represents a computation, running in a single thread.
User => (DEF my-Future (* 100 100) # 'user/My-futureuser => @ My-future; if the thread is not executed, it will block 10000
You can see that macro future encapsulates the future-call function. You can also call this function directly, but it is more troublesome.
(defmacro future [& body] `(future-call (fn [] ~@body)))
Future-cancel
It is possible to attempt to cancel a future that hasn't yet finished executing.
Future-canceled?
Future-canceled? Takes a single future as an argument and returns true if it has been canceled.
Future-done?
Future-done? Takes a single future as an argument and returns true if the future's execution is complete, otherwise false.
Future?
Future? Takes a single value as an argument and returns true if it is a future, otherwise false.
Promises
A promise is a value that may not yet exist. If a promise is dereferenced before its value is set, the dereferencing thread blocks until a value is delivered to the promise.
It can be used for synchronization and coordination among multiple threads and is used with caution, which may easily lead to deadlocks.
User => (DEF mypromise (promise) # 'user/mypromiseuser => @ mypromise; causes the main thread to block user => (DEF mypromise (promise )) # 'user/mypromiseuser => (deliver mypromise 5) # <AFN $ ideref $ db53459f @ c0f1ec: 5> User => @ mypromise 5
Java-based threading
If none of clojure's other concurrency tools meet your needs for any reason, there's always the option
Falling back to Java's native threading capabilities.
user=> (.start (Thread. #(println "hello")))nilhello