Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use lightweight thread in Clojure?

I was trying to rewrite this Rust code in Clojure:

fn main() {
    let nums = [1, 2];
    let noms = ["Tim", "Eston", "Aaron", "Ben"];

    let mut odds = nums.iter().map(|&x| x * 2 - 1);

    for num in odds {
        spawn(proc() {
            println!("{:s} says hello from a lightweight thread!", noms[num]);
        });
    }
}

Here is the Clojure code that did almost the same with the above mentioned Rust code

(def noms ["Tim", "Eston", "Aaron", "Ben"])
(doseq [i (take-nth 2 (rest noms))]
  (println i "says hello from a lightweight thread!"))

Except it does not use thread.

  1. How to write "lightweight" thread (or something equivalent in Clojure terms)?
  2. This code is almost the direct translate from the imperial programming style. What's the idiomatic way to write?
like image 942
Nick Avatar asked May 11 '26 17:05

Nick


2 Answers

Beware of the terminology: the clojure example using futures doesn't create a lightweight thread but rather a native OS thread. Rust does the same by default but it has a green thread runtime that provides the lightweight semantics. Reference: http://rustbyexample.com/tasks.html

Clojure doesn't support lightweight threads by default but you can create them via the library core.async. So the code would look something like this:

(require '[clojure.core.async :as async :refer :all])
(doseq [i (take-nth 2 (rest noms))]
  (go (print (str i " says hello from a lightweight thread!\n"))))

The go macro above will create a proper lightweight thread *

* The statement wasn't clear as pointed out in the comments so I'll try and clarify: core.async is backed by a Java thread pool, however the go macro turns your code into a state machine that uses "parking" instead of "blocking". This just means you can have tens of thousands of go blocks backed by a limited number of real threads.

When using blocking IO however, this benefit is hindered, as explained by the post @hsestupin refers to below.

To understand how core.async manages to have lightweight threads on the JVM, I recommend starting here: https://www.youtube.com/watch?v=R3PZMIwXN_g - it's a great video into the internals of the go macro.

The macro itself is implemented here

like image 176
leonardoborges Avatar answered May 14 '26 16:05

leonardoborges


You can use future to spawn threads. In this case you could do something like:

(doseq [i (take-nth 2 (rest noms))]
  (future (print (str i " says hello from a lightweight thread!\n"))))
like image 34
Diego Basch Avatar answered May 14 '26 15:05

Diego Basch



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!