Clojure dothreads! function

I read Fogus’s book “Joy” by Clojure, and in the chapter on parallel programming I saw a definition of a function that certainly wants to illustrate something important, but I can’t figure out what. Moreover, I do not see what this function is for - when I execute it, it does nothing:

(import '(java.util.concurrent Executors)) (def *pool* (Executors/newFixedThreadPool (+ 2 (.availableProcessors (Runtime/getRuntime))))) (defn dothreads! [f & {thread-count :threads exec-count :times :or {thread-count 1 exec-count 1}}] (dotimes [t thread-count] (.submit *pool* #(dotimes [_ exec-count] (f))))) 

I tried to run like this:

 (defn wait [] (Thread/sleep 1000)) (dothreads! wait :thread-count 10 :exec-count 10) (dothreads! wait) (dothreads! #(println "running")) 

... but it returns zero. Why?

+4
source share
3 answers

So, here the same code has slightly changed, so the function passed to dothreads! gets the counter of internal dotimes .

 (import 'java.util.concurrent.Executors) (def ^:dynamic *pool* (Executors/newFixedThreadPool (+ 2 (.availableProcessors (Runtime/getRuntime))))) (defn dothreads! [f & {thread-count :threads exec-count :times :or {thread-count 1 exec-count 1}}] (dotimes [t thread-count] (.submit *pool* #(dotimes [c exec-count] (fc))))) (defn hello [name] (println "Hello " name)) 

Try running it like this:

 (dothreads! hello :threads 2 :times 4) 

For me, it prints something as a result:

 Hello 0 Hello 1 Hello 2 Hello 3 nil user=> Hello 0 Hello 1 Hello 2 Hello 3 

So, pay attention to one error that you made when calling the function: you passed: thread-count and: exec-count as keys, whereas in reality these are destructuring bindings that occur inside dothreads! . The keywords are words starting with a colon :threads and :times .

What this code really does:

  • Creates a new pool of fixed-size threads that will use the maximum number of cores in your machine + 2 . This pool is called *pool* and is created using the Java Executor Framework. See details in [1].

  • Function dothreads! gets a function that will be called exec-count times in each thread-count . So, in the example above, you can clearly see this called 4 times per thread ( :threads is 2 and :times is 4).

  • The reason this function returns nil is because the dothreads! returns nothing. The submit method of the thread pool returns void in Java, and this means that it returns nil in Clojure. If you need to add another expression at the end of the function, do this:

     (defn dothreads! [f & {thread-count :threads exec-count :times :or {thread-count 1 exec-count 1}}] (dotimes [t thread-count] (.submit *pool* #(dotimes [c exec-count] (fc)))) (* thread-count exec-count)) 

He will return 8 for the example above (2 * 4). Only the last expression in the function is returned, so if the function you were to write (fn [xy] (+ xy) (* xy)) , this will always return the product. The amount will be estimated, but it will be in vain. So do not do this! If you want to add more than one expression to a function, make sure that all but the last have side effects, otherwise they will be useless.

  • You may also notice that the order in which the material is printed is asynchronous. So, on my machine, it greets 4 times, then returns the result of the function, and then again greets 4 times. The order in which the functions are executed is not defined between threads, however hellos are sequential in each thread (there can never be Hello 3 before Hello 2). The reason for the sequence is that the function actually sent to the thread pools is #(dotimes [c exec-count] (fc)) and

[1] http://download.oracle.com/javase/tutorial/essential/concurrency/executors.html

+6
source

Subsequently, he used in the book multiple execution of test functions in several threads. It does not illustrate anything by itself, but it demonstrates locking, promises, and other parallel and parallel things.

+3
source

dotimes , dothreads! and println are not pure functions: they are used to introduce side effects. For instance,

 user=> (println 3) 3 nil 

This piece of code prints 3 on the screen, but returns zero. Similarly, dothreads! useful for its side effects, not its return value.

+1
source

Source: https://habr.com/ru/post/1380206/


All Articles