# How to start tasks on multiple threads and control terminal output from central thread

**URL:** https://discourse.julialang.org/t/how-to-start-tasks-on-multiple-threads-and-control-terminal-output-from-central-thread/36087
**Category:** General Usage
**Tags:** parallel, multithreading, distributed
**Created:** [March 17, 2020, 8:43am UTC](https://discourse.julialang.org/t/how-to-start-tasks-on-multiple-threads-and-control-terminal-output-from-central-thread/36087 "2020-03-17T08:43:07Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![sloede](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sloede/32/44787_2.png) [@sloede](https://discourse.julialang.org/u/sloede)
#### Post date: [March 17, 2020, 8:43am UTC](https://discourse.julialang.org/t/how-to-start-tasks-on-multiple-threads-and-control-terminal-output-from-central-thread/36087/1 "2020-03-17T08:43:07Z")

</div>

While I am not new to distributed computing, I have trouble wrapping my head around how to implement the following behavior in Julia.

I have a testing tool that takes a bunch of tests (= directories with testing information), runs the tests, and displays the results on the terminal. Since all tests are serial, I would like to parallelize this in the following way (roughly):

- one central tasks/thread/worker (not sure about the correct terminology, let’s call it “root”) distributes the tests among the available CPU cores
- on each core, a single test is run concurrently
- once a test has finished, the result should be displayed on the terminal (with actual output being controlled by root), and the now idle core picks up the next test
- continue until all tests are finished

What would be the Julian way of implementing something like this? Or is this even how you would achieve the desired behavior (tests running on all cores, one core controlling I/O) with Julia?

I tried reading the official docs, but there are so many ways highlighted for doing _something_ in parallel, I am not sure which one to pursue. Also, most tutorials/documentations I found online refer to pre-1.3 Julia (or even pre-1.0), thus I am sure they are at least in parts outdated.

Any help would be highly appreciated, even if it’s just pointing me to a good reference implementation or tutorial!

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [March 17, 2020, 9:48am UTC](https://discourse.julialang.org/t/how-to-start-tasks-on-multiple-threads-and-control-terminal-output-from-central-thread/36087/2 "2020-03-17T09:48:33Z")

</div>

Perhaps use a `Channel` (`RemoteChannel`) to communicate between the test runner and the root and have the root be in charge of all printing.

Julia itself runs its test in parallel but the implementation is quite simple: [julia/runtests.jl at master · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/master/test/runtests.jl). Just `remotecall_fetch` on workers from a bunch of async tasks that pops the first available test from a list of tests to run.

---

<div class="post-metadata">

### Author: ![sloede](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sloede/32/44787_2.png) [@sloede](https://discourse.julialang.org/u/sloede)
#### Post date: [March 17, 2020, 12:37pm UTC](https://discourse.julialang.org/t/how-to-start-tasks-on-multiple-threads-and-control-terminal-output-from-central-thread/36087/3 "2020-03-17T12:37:16Z")

</div>

> [@kristoffer.carlsson](#):
>
> Julia itself runs its test in parallel but the implementation is quite simple: [https://github.com/JuliaLang/julia/blob/master/test/runtests.jl](https://github.com/JuliaLang/julia/blob/master/test/runtests.jl). Just `remotecall_fetch` on workers from a bunch of async tasks that pops the first available test from a list of tests to run.

Are you referencing those lines: [https://github.com/JuliaLang/julia/blob/36241a90bab7256f83392dc302808f04954a1f3b/test/runtests.jl#L193-L209](https://github.com/JuliaLang/julia/blob/36241a90bab7256f83392dc302808f04954a1f3b/test/runtests.jl#L193-L209)? I am not sure whether I understand correctly what is going on there:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/a/3/a35a84d4546ce0fcf137460410640f4893c1e884.png)

Let me see if I get this right…

In 193, a `@sync` block begins that ensures that execution does not proceed until all `@async` blocks are finished. The next line loops over all workers (we are currently on root) and creates a Task (?) using `@async` until we have a task for each worker. The creation of tasks is _non-blocking_.

In line 197, each task (which is associated with a specific worker) loops until the list of tests `tests` is non-empty. In each loop iteration, the next test is retrieved (line 198), which is then to be executed remotely. For this, `remotecall_fetch` is called with the worker id associated with this task. `remotecall_fetch` is blocking, i.e., it waits for the test to be finished.

Once the call to `remotecall_fetch` returns, further operations are performed (e.g., I/O, cleanup etc.) before the next loop iteration begins. If all tests are gone, the end of the `@async` block is reached and thus the code will wait at the end of the `@sync` block until all tasks have reached this position in the code, at which all tasks are dissolved and normal (serial) execution continues.

Did I get this (roughly) right? If not, I’d be happy to learn where I went wrong…

Otherwise, I have to follow-up questions:

1. Is it correct that in this setup the root never runs any tests but only schedules tasks and handles I/O?
2. If yes, why the check for `p != 1` in lines 237-240 ([https://github.com/JuliaLang/julia/blob/36241a90bab7256f83392dc302808f04954a1f3b/test/runtests.jl#L237-L240](https://github.com/JuliaLang/julia/blob/36241a90bab7256f83392dc302808f04954a1f3b/test/runtests.jl#L237-L240)) - shouldn’t this always evaluate to `true` since `workers()` returns a list the excludes `1`?
3. Is it reasonable to assume that on a multicore processor (e.g., 4 cores and 8 HW threads) each task will be executed on a different core?

Sorry for the long post, but I see an opportunity to finally get the knots in my head untied when it comes to Julia’s distributed programming model 🤯

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [March 17, 2020, 12:49pm UTC](https://discourse.julialang.org/t/how-to-start-tasks-on-multiple-threads-and-control-terminal-output-from-central-thread/36087/4 "2020-03-17T12:49:01Z")

</div>

> [@sloede](#):
>
> Did I get this (roughly) right? If not, I’d be happy to learn where I went wrong…

Yes, looks good to me.

> [@sloede](#):
>
> Is it correct that in this setup the root never runs any tests but only schedules tasks and handles I/O?

Yes with the exception of some special tests which run on the root:

> <https://github.com/JuliaLang/julia/blob/36241a90bab7256f83392dc302808f04954a1f3b/test/runtests.jl#L246>

> [@sloede](#):
>
> shouldn’t this always evaluate to `true` since `workers()` returns a list the excludes `1` ?

I think that is correct.

> [@sloede](#):
>
> Is it reasonable to assume that on a multicore processor (e.g., 4 cores and 8 HW threads) each task will be executed on a different core?

AFAIU, it is up to the OS to do the exact scheduling onto physical cores but yes, that should happen.

---

<div class="post-metadata">

### Author: ![sloede](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sloede/32/44787_2.png) [@sloede](https://discourse.julialang.org/u/sloede)
#### Post date: [March 17, 2020, 1:18pm UTC](https://discourse.julialang.org/t/how-to-start-tasks-on-multiple-threads-and-control-terminal-output-from-central-thread/36087/5 "2020-03-17T13:18:48Z")

</div>

@kristoffer.carlsson Thanks a lot for the feedback & clarifications! I have one further question, if I may: Is it reasonable/sensible to run tests also on proc=1? As far as I can tell, the code in the references `runtests.jl` does not execute tests in parallel on it (except for the node1 tests). Or would tests with high CPU utilization prevent other tasks on proc=1 from functioning properly (e.g., for scheduling new tests, I/O etc.)?

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [March 17, 2020, 1:29pm UTC](https://discourse.julialang.org/t/how-to-start-tasks-on-multiple-threads-and-control-terminal-output-from-central-thread/36087/6 "2020-03-17T13:29:40Z")

</div>

There is no real advantage to running tests on `proc=1`, the number of workers is equal to the number of threads so things will be saturated anyway. And yes, if you run a test on `proc=1` that takes a significant time and has no yield points it will block the printing task (and scheduling task) from running which is undesirable.
