# Can the threads in the :interactive pool also undertake heavy computing tasks?

**URL:** <https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725>\
**Category:** General Usage\
**Tags:** question, async\
**Created:** [November 7, 2025, 5:52am UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725 "2025-11-07T05:52:03Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [November 7, 2025, 5:52am UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725/1 "2025-11-07T05:52:03Z")

</div>

(_From a related issue [Unsticky Tasks stick to threadpool since 1.10, causing issues since 1.12 · Issue #59936 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/59936)_  
_But here I’m not referring to the functional API `Task`, instead, I’m talking about `@spawn` itself and the interactive threadpool._)

#### Edit: you may skip this post and see post #3 directly, which is more meaningful.

Currently there are only 2 available thread pools—`:default` and `:interactive`.

I want to run a few (e.g. one or two) computing (blocking) tasks in the non-default pool (so the only way out is to spawn them in the interactive pool.) The reason is that the default pool is reserved for other heavier tasks.

I find it not possible to achieve what I want according to the current behavior, as follows.

I launch the julia program `can_it_echo.jl` from the zsh in Linux.

#### can\_it\_echo.jl

```julia-auto
println("$PROGRAM_FILE> threads_setting = $((Threads.nthreads(), Threads.nthreads(:interactive)))")
function bzwt(t) # it's merely a busy waiting function that blocks a thread for t seconds
    tdue = time() + t
    while true
        try
            @assert time() < tdue
        catch e
            return
        end
    end
end;
function main()
    Threads.@spawn :interactive println("main()> begins...")
    Threads.@spawn :interactive bzwt(2.5)
    Threads.@spawn :interactive bzwt(2.5)
    Threads.@spawn :interactive println("main()> echo")
end;
main()

```

Here is what I get in zsh

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

The results suggest that `@spawn :interactive bzwt(2.5)` is **not** flexibly scheduled so it can be run on any available idle threads within the `:interactive` pool—I’m having sufficiently 4 threads in this test.

(The behavior seems to be a bit random, so you are certain to reproduce the reported behavior above—the `main() > echo` is unseen immediately after `main()> begins...`—as long as you try multiple times. And this behavior is not due to insufficient threads—it occurs even if I use `--threads=64,64`)

* * *

The direct consequence is that: the `:interactive` pool is unusable other than logging messages. So given this, I’m wondering

- is there any other methods that I can create some other user pools other than the existing two? (e.g. `:default2`, `:default3`…). So I can schedule tasks within those new pools?
- What is a solution to the current situation?

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [November 7, 2025, 7:10am UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725/3 "2025-11-07T07:10:16Z")

</div>

Sorry, it seems that my test was improper.

* * *

The proper test file should be

### can\_it\_echo.jl

```julia-auto
println("$PROGRAM_FILE> " *
"threads_setting = $((Threads.nthreads(), Threads.nthreads(:interactive))), " *
"id = $(Threads.threadid()), " *
"pool = $(Threads.threadpool())"
)
function bzwt(t) # it's merely a busy waiting function that blocks a thread for t seconds
    tdue = time() + t
    while true
        try
            time() < tdue || error()
        catch e
            return
        end
    end
end
f(v, i, t0) = (v[i] = time() - t0; nothing)
function main()
    v = [NaN, NaN]
    t0 = time()
    tp = (
        Threads.@spawn(:interactive, f(v, 1, t0)),
        Threads.@spawn(:interactive, bzwt(2.0)),
        Threads.@spawn(:interactive, bzwt(2.0)),
        Threads.@spawn(:interactive, bzwt(2.0)),
        Threads.@spawn(:interactive, f(v, 2, t0))
    )
    println("main> Tasks spawned. Now begins to wait...")
    foreach(wait, tp)
    println("main> v = $v")
    println("main> quit.")
end
main()

```

Now it is expected (I think so).

```julia-auto
❯ julia --threads=2,4 can_it_echo.jl
can_it_echo.jl> threads_setting = (2, 4), id = 1, pool = interactive
main> v = [0.012079954147338867, 0.017039060592651367]
main> quit.

```

The above result seems to be deterministic and stable behavior.

By comparison, if you duplicate one more line of `Threads.@spawn(:interactive, bzwt(2.0))`, the results becomes non-deterministic, sometimes with an \>2.0 entry.

* * *

So, my conclusion is:

- The threads in `:interactive` pool can indeed serve as a separate computing resource from the threads in the `:default` pool, as long as you leave one non-busy thread to print desired texts.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [November 7, 2025, 11:04am UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725/4 "2025-11-07T11:04:53Z")

</div>

Printing in threads can be done with `printf` to avoid serialization to thread 1. I.e. with something like

```julia-auto
@ccall printf("Hi %d\n"::Cstring; 23::Cint)::Cint

```

Note the semicolon after the initial format string. It’s important because the C `printf` is a function with variable number of arguments. The `;` ensures this is coded properly.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [November 7, 2025, 12:55pm UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725/5 "2025-11-07T12:55:32Z")

</div>

It appears that it won’t automatically flush (update the printing status) without adding a `\n`.

Why? How to resolve this, e.g. manual flush? is this normal operation?

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [November 7, 2025, 1:25pm UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725/6 "2025-11-07T13:25:05Z")

</div>

That’s right. You can call `Libc.flush_cstdio()` to flush.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [November 7, 2025, 1:37pm UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725/7 "2025-11-07T13:37:29Z")

</div>

To be honest, until here I notice that some operations I do everyday is slow.

e.g. `print` in julia is very slow.  
e.g. `t = time()` in julia is slow (relatively), (it appears that `time_ns()` could be a bit faster).

Because I need to use these functions to monitor my program so that I can ensure they are running properly. I guess I will again adjust my code accordingly…

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [November 7, 2025, 2:44pm UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725/8 "2025-11-07T14:44:37Z")

</div>

> [@WalterMadelim](#):
>
> e.g. `t = time()` in julia is slow (relatively), (it appears that `time_ns()` could be a bit faster).

It’s not very accurate to measure such short intervals, anyway. The fastest timer is to do it directly in llvm, but I’m not sure how it does with memory fencing and similar. And it’s not calibrated in nanoseconds, it’s just clock ticks. And the clock speed may vary. Unless very specific measurements, I would stick to `time_ns()`.

```julia-auto
function clockticks()
    Core.Intrinsics.llvmcall(
        ("""
         declare i64 @llvm.readycyclecounter()
         define i64 @entry() {
           %cycles = call i64 @llvm.readcyclecounter()
           ret i64 %cycles
         }
         """, "entry"), Int64, Tuple{})
end
start = clockticks()
sleep(1)
elapsed = clockticks() - start

```

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [November 8, 2025, 1:15am UTC](https://discourse.julialang.org/t/can-the-threads-in-the-interactive-pool-also-undertake-heavy-computing-tasks/133725/9 "2025-11-08T01:15:17Z")

</div>

I’m curious that why the “early exit” behavior doesn’t happen here, since I didn’t wait the async task

#### s.jl

```julia
println("$PROGRAM_FILE> " *
"threads_setting = $((Threads.nthreads(), Threads.nthreads(:interactive))), " *
"id = $(Threads.threadid()), " *
"pool = $(Threads.threadpool())"
)
function bzwt(t)
    tdue = time_ns() + 1e9t
    while true
        try
            time_ns() < tdue || error()
        catch
            return
        end
    end
end;
function a()
    @ccall printf("a> begins... \n"::Cstring)::Cint
    bzwt(1.5)
    @ccall printf("a> 1.5s... \n"::Cstring)::Cint
    bzwt(1.4)
    @ccall printf("a> 1.4s... \n"::Cstring)::Cint
    bzwt(1.3)
    @ccall printf("a> 1.3s... \n"::Cstring)::Cint
    bzwt(1.2)
    @ccall printf("a> 1.2s... \n"::Cstring)::Cint
    bzwt(1.1)
    @ccall printf("a> 1.1s... \n"::Cstring)::Cint
end;
@ccall printf("s.jl> begins... \n"::Cstring)::Cint
const t0 = time_ns()
Threads.@spawn(a())
bzwt(3.6)
@ccall printf("s.jl> 3.6s... \n"::Cstring)::Cint
(3.59e9 < time_ns() - t0 < 3.8e9) || error()

```

#### in the shell

```julia-auto
❯ julia --threads=1,1 s.jl
s.jl> threads_setting = (1, 1), id = 1, pool = interactive
s.jl> begins... 
a> begins... 
a> 1.5s... 
a> 1.4s... 
s.jl> 3.6s... 
a> 1.3s... 
a> 1.2s... 
a> 1.1s... 
~/somedir 7s some@some
❯ 

```

Why didn’t the `s.jl` early return to the shell? (i.e. why can I still see the `a> 1.3s...` and its subsequent lines)

* * *

Edit: Let’s create a new topic to discuss this sort of behavior.
