# Bug in sleep() function - main thread work affecting sleep duration on running tasks

**URL:** https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911
**Category:** General Usage
**Tags:** question, multithreading, task, potential-bug
**Created:** [July 21, 2023, 9:14pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911 "2023-07-21T21:14:09Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)
#### Post date: [July 21, 2023, 9:14pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/1 "2023-07-21T21:14:09Z")

</div>

What triggered the present experiment was my failure to find a reasonable solution for the issue raised by [this topic](https://discourse.julialang.org/t/how-to-run-a-http-jl-server-in-parallel-while-doing-computations-in-the-foreground/101889).

It turned out that the issue was unrelated to the `HTTP.jl` package and went deeper.

Now, the experiment (with `nthreads() > 2`).

**Important note** : to avoid “what if” scenarios about the resource allocation to the running tasks when using 1-2 threads, I suggest running this with `-t 3` or above. Also, for this MWE it doesn’t make any difference if the tasks are spawned on `:interactive` or `:default`. Variations like `-t 12,6` `-t 12` are also not impacting the showcased issue - so if you run the MWE with at least `-t 3`, I think we can be on the same page when discussing the issue.

```julia
using Base.Threads, Dates

@info "started with $(nthreads()) threads"
@info "interactive threadpool: $(nthreads(:interactive))"
@info "default threadpool: $(nthreads(:default))"
println(repeat("*", 40))

function mainspin(s, c; withyield=false)
    @info "mainspin executing on thread $(threadid()) "
    ms = Millisecond(s * 1000)
    r = 0.0
    counter = 0
    while counter < c
        t = now()
        while (now() - t) < ms
            r += rand()
        end
        counter += 1
        if withyield
            yield()
        end

    end
end

function sleeper(s, c, id)
    @info "sleeper $id executing on thread $(threadid()) "
    counter = 0
    @time "sleeper $id" while counter < c
        sleep(s)
        counter += 1
    end
end

function realworker(s, c, id)
    @info "worker $id executing on thread $(threadid()) "
    ms = Millisecond(s * 1000)
    r = 0.0
    counter = 0
    @time "worker $id" while counter < c
        t = now()
        while (now() - t) < ms
            r += rand()
        end
        counter += 1
        yield()
    end
end

begin
    # phase 1
    @info "phase 1: control run - no main thread work"

    # yields 10 times (total time ~10 seconds)
    task1 = @spawn realworker(1.02, 10, 1) # 1.02 because weird @time printing overlap
    # yields 10 times (total time ~10 seconds)
    task11 = @spawn sleeper(1, 10, 1)

    wait(task1)
    wait(task11)

    # we waited for task1 and task11 to finish

    # phase 2
    println(repeat("*", 40))
    @info "phase 2: main thread work without yield"

    # yields 10 times (total time ~10 seconds)
    task2 = @spawn realworker(1, 10, 2)

    # yields 10 times (total time ~10 seconds)
    task22 = @spawn sleeper(1, 10, 2)

    # we wait 5 seconds before starting to spin
    # the main thread
    sleep(5)

    # now we start spinning 
    # while task2 and task22 are already running
    mainspin(1, 7)

    # main thread work does not impact the real worker
    # total time ~10 seconds
    wait(task2)

    # main thread work heavily impacting the sleeper
    # total time >15 seconds
    wait(task22)

    # phase 3
    println(repeat("*", 40))
    @info "phase 3: main thread work with yield"

    # yields 10 times (total time ~10 seconds)
    task3 = @spawn realworker(1, 10, 3)

    # yields 10 times (total time ~10 seconds)
    task33 = @spawn sleeper(1, 10, 3)

    # we wait 5 seconds before starting to spin
    # the main thread
    sleep(5)

    # now we start spinning with yield
    # while task3 and task33 are running
    mainspin(1, 7, withyield=true)

    # main thread work does not impact 
    # the real worker - total time ~10 seconds
    wait(task3)

    # main thread work (with yield) still impacting the sleeper
    # but we consistently get better times (total time ~13 seconds)
    wait(task33)
end

```

Outcome:

```julia
[ Info: started with 6 threads
[ Info: interactive threadpool: 6
[ Info: default threadpool: 6
****************************************
[ Info: phase 1: control run - no main thread work
[ Info: sleeper 1 executing on thread 12 
[ Info: worker 1 executing on thread 8 
sleeper 1: 10.021080 seconds (52.62 k allocations: 3.531 MiB)
worker 1: 10.199292 seconds (266 allocations: 12.484 KiB, 0.22% compilation time)
****************************************
[ Info: phase 2: main thread work without yield
[ Info: worker 2 executing on thread 7 
[ Info: sleeper 2 executing on thread 10 
[ Info: mainspin executing on thread 1 
worker 2: 9.999581 seconds (48.15 k allocations: 3.303 MiB, 0.31% compilation time)
sleeper 2: 16.951009 seconds (13.87 k allocations: 957.833 KiB, 0.18% compilation time)
****************************************
[ Info: phase 3: main thread work with yield
[ Info: worker 3 executing on thread 8 
[ Info: sleeper 3 executing on thread 12 
[ Info: mainspin executing on thread 1 
worker 3: 9.999368 seconds (36.94 k allocations: 2.611 MiB, 0.12% compilation time)
sleeper 3: 13.989446 seconds (2.67 k allocations: 249.790 KiB, 0.08% compilation time)

```

If the task does real work, the overall time needed to finish is as expected (real parallelism).

However, if `sleep` is used and a task is expected to sleep N seconds, the N value is extended with a factor dependent on the main thread’s work. I advise running the MWE for more details.

Here is `sleep` function [documentation](https://docs.julialang.org/en/v1/base/parallel/#Base.sleep):

> Block the current task for a specified number of seconds. The minimum sleep time is 1 millisecond or input of `0.001` .

Reality? The description should be approximately this:

> Block the current task for the specified number of seconds - but add a penalty depending on the work done by the main thread.

That means that if we are doing the heavy lifting on the main thread while a task using `sleep` is running… that task is basically halted.

For the results above, I used the following Julia versions: 1.8.5 (with small changes), 1.9.2, and 1.10.0-alpha1 - and ran the experiment with various interactive/regular threads combinations.

The initial topic was likely too complex, and it turns out that it is not an issue of communication between tasks - main thread work seems to be translated in running tasks halting when using `sleep()` inside running tasks.

Thank you, @Benny, for adding more clarity to the MWE.

P.S. I added multiple MWEs in the thread discussion in reply to various hypotheses trying to explain the behavior. Some of them showcase the issue by keeping the main thread free and comparing the `worker` vs. `sleeper` behavior in a context with multiple spawned tasks (the equivalent in the real world would be the non-blocking `HTTP.jl` server which spawns a new task for each new connection). `HTTP.jl`-related MWE can also be found in the current discussion thread.

---

<div class="post-metadata">

### Author: ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)
#### Post date: [July 21, 2023, 9:44pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/2 "2023-07-21T21:44:59Z")

</div>

Does the same thing happen when you use ThreadPools.jl ?

---

<div class="post-metadata">

### Author: ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)
#### Post date: [July 21, 2023, 9:54pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/3 "2023-07-21T21:54:57Z")

</div>

> [@dlakelan](#):
>
> Does the same thing happen when you use ThreadPools.jl ?

Yes, tested with `@tspawnat n` only - but the same result as in the OP.

---

<div class="post-metadata">

### Author: ![Ralph\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ralph_smith/32/10344_2.png) [@Ralph\_Smith](https://discourse.julialang.org/u/Ralph_Smith)
#### Post date: [July 22, 2023, 2:46am UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/4 "2023-07-22T02:46:55Z")

</div>

The problem seems to be not just `Base.sleep()`, which uses a `libuv`-based `Timer`, but anything which accesses the `libuv` event loop, such as normal Julia IO. IIUC the event loop has to be started as an early part of the runtime, and is stuck on the main thread, so this may be tricky to fix. Please file an issue.

---

<div class="post-metadata">

### Author: ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)
#### Post date: [July 22, 2023, 3:09am UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/5 "2023-07-22T03:09:42Z")

</div>

This is crazy.

`HTTP.jl` is also affected by this disease (I checked - not explicit/direct `Base.sleep()` that can explain the behavior). There are also projects that depend on `HTTP.jl` - like Genie.

At this point, it seems that the answer to the whole `Task`-related functionality is _maybe it works_ - it depends if your task invokes anything `libuv` related - but it also depends on the amount of work you run on the main thread.

Things like this make me feel that parts of Julia didn’t reach version 1 yet (and decent multithreading is a very important part).

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [July 22, 2023, 4:01am UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/6 "2023-07-22T04:01:38Z")

</div>

I’m a bit confused by your experiment - `Base.sleep` is a runtime aware sleep and only blocks the current task, leaving other tasks available for being run by the scheduler. `Libc.systemsleep` on the other hand puts the OS thread the task is running on to sleep, which potentially blocks other tasks from running if no other OS thread is available.

Which combination exactly is the one you’re encountering an issue on, and with which setting for `-t`?

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [July 22, 2023, 5:37am UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/7 "2023-07-22T05:37:56Z")

</div>

Made some printing changes so it’s easier to track as I time it with a stopwatch. I also added comments on when things happened (on nthreads=1) according to the stopwatch vs what `@time` printed. To summarize, `mainspin` and `realworker` don’t yield so they hold things up. `sleeper` does its sleep in 1s bursts, so when other tasks are holding things up, `sleeper` is stuck at an iteration. `@time` keeps track of absolute time, so it includes the time `sleeper` was stuck.

If I change `sleeper` so that `counter` only goes up to 1 and `sleep(s)` occurs the full 10s at once, then the 14s timing becomes 10s.

> **Expand this code**
>
> ```julia
> using Base.Threads, Dates
> 
> function mainspin(s, id)
> @info "mainspin $id executing on thread $(threadid()) "
> ms = Millisecond(s * 1000)
> t = now()
> r = 0.0
> @time while (now() - t) < ms
> r += rand()
> end
> @info "mainspin $id finished "
> end
> 
> function sleeper(s, id; libc=false)
> @info "sleeper $id executing on thread $(threadid()) "
> counter = 0
> @time while counter < s
> libc ? Libc.systemsleep(1) : sleep(1)
> counter += 1
> end
> @info "sleeper $id finished"
> end
> 
> function realworker(s, id)
> @info "worker $id executing on thread $(threadid()) "
> ms = Millisecond(s * 1000)
> t = now()
> r = 0.0
> @time while (now() - t) < ms
> r += rand()
> end
> @info "worker $id finished. result: $r"
> end
> 
> begin
> # phase 1
> 
> task0 = @spawn mainspin(10, 1) # 0-10s: @time 10s
> # mainspin(10, 1) does not yield, runs for 10s
> task00 = @spawn sleeper(10, 1) # 10-20s: @time 10s
> 
> wait(task0)
> wait(task00) # waits for sleeper(10, 1) to finish
> 
> # phase 2
> 
> rw = @spawn realworker(10, 1) # 20-30s: @time 10s 
> # realworker(10, 1) does not yield, runs for 10s
> sleepy = @spawn sleeper(10, 2) # 30-44s: @time 14s
> # sleeper(10, 2) counter=0 yields in <<1s
> 
> sleep(5) # 30-35s
> # sleep(5) yields
> # 31s sleeper(10, 2) runs counter=1 then yields
> # 32s sleeper(10, 2) runs counter=2 then yields
> # 33s sleeper(10, 2) runs counter=3 then yields
> # 34s sleeper(10, 2) runs counter=4 then yields
> # 35s sleeper(10, 2) runs counter=5 then yields
> mainspin(5, 2) # 35-40s: time 5s
> # mainspin(5, 2) does not yield, runs for 5s
> 
> wait(rw)
> wait(sleepy) # now sleeper(10,2) runs
> # 40s sleeper(10, 2) runs counter=6 then yields
> # 41s sleeper(10, 2) runs counter=7 then yields
> # 42s sleeper(10, 2) runs counter=8 then yields
> # 43s sleeper(10, 2) runs counter=9 then yields
> # 44s sleeper(10, 2) runs counter=10 then finishes
> end
> 
> ```

---

<div class="post-metadata">

### Author: ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)
#### Post date: [July 22, 2023, 11:04am UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/8 "2023-07-22T11:04:38Z")

</div>

Thank you for the edits (for clarity, can I update the OP with your version)?

> [@Benny](#):
>
> If I change `sleeper` so that `counter` only goes up to 1 and `sleep(s)` occurs the full 10s at once, then the 14s timing becomes 10s.

> [@algunion](#):
>
> and ran the experiment with various interactive/regular threads combinations.

Now, let’s settle for a multithreading context and add the following assumptions: besides the main thread, there are at least two additional available threads.

Now, for the phase 2: if I set the sleeper to do a unique 10-seconds it happens to work well by coincidence (e.g., `sleeper` already started about 5 seconds before the start of `mainspeen` and after 5-seconds `mainspin` finishes allowing the `sleeper` to also finish (more exactly, it allows the `Timer` which uses `libuv` to function properly).

Try running the phase-2 `mainspin(7,2)` instead of `mainspin(5,2)` - and you’ll realize that the `sleeper` total time is now 12-seconds.

In a real world project we do not have the luxury to synchronize our tasks with the work done by the main thread: if I schedule a task on the `:interactive` for example I expect to have a responsive/interactive task (real-world example: `HTTP.jl`: it 100% dependent on the work done on the main thread - e.g., if I have a non-blocking server, which is scheduled on `:interactive` by default, and I do bursts of 5-second work on main… well, this server will respond at an interval of 5 seconds).

---

<div class="post-metadata">

### Author: ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)
#### Post date: [July 22, 2023, 11:07am UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/9 "2023-07-22T11:07:30Z")

</div>

> [@Sukera](#):
>
> `Base.sleep` is a runtime aware sleep and only blocks the current task

I am not saying that `Base.sleep` is blocking other tasks.

The statement is that work on the main thread alters the expected (documented) `sleep` functionality on all the other tasks running on other threads.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [July 22, 2023, 11:21am UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/10 "2023-07-22T11:21:48Z")

</div>

> [@algunion](#):
>
> for clarity, can I update the OP with your version

ofc

> [@algunion](#):
>
> …if I set the sleeper to do a unique 10-seconds…  
> Try running the phase-2 `mainspin(7,2)` instead of `mainspin(5,2)` - and you’ll realize that the `sleeper` total time is now 12-seconds.

I got 10s again, I can only increase it if I run `mainspin 2` for 11s or more to stall the `sleeper 2` task. What’s your code for the unique 10s sleeper? Here’s mine:

```julia
function sleeper(s, id; libc=false)
    @info "sleeper $id executing on thread $(threadid()) "
    counter = 0
    @time while counter < 1 ##change###
        libc ? Libc.systemsleep(s) : sleep(s) ##change##
        counter += 1
    end
    @info "sleeper $id finished"
end

```

---

<div class="post-metadata">

### Author: ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)
#### Post date: [July 22, 2023, 11:57am UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/11 "2023-07-22T11:57:30Z")

</div>

> [@Benny](#):
>
> I got 10s again, I can only increase it if I run `mainspin 2` for 11s or more to stall the `sleeper 2` task. What’s your code for the unique 10s sleeper?

It has nothing to do with a 10-second timespan: any configuration that is showcasing the issue will do.

We can change the experiment from `sleep` altogether if you want:

1. Start a non-blocking `HTTP.jl` server (which is scheduled on `:interactive`).
2. Run bursts of work on the main thread (putting `mainspin(5,1, steps=20)` in a loop might do the job - see the updated `mainspin`).
3. Try to get a response from that server - the responsivity will highly depend on when you _hit_ the server (e.g., for `mainsping(5,1, steps=20)` you’ll get delays depending on `main` working behavior). Not something that you would expect from a task running on the `:interactive`.

```julia
using Base.Threads, Dates
using HTTP

function mainspin(s, id; steps=1)
    @info "mainspin $id executing on thread $(threadid()) "
    ms = Millisecond(s * 1000)

    r = 0.0
    for _ in 1:steps
        t = now()
        @time while (now() - t) < ms
            r += rand()
        end    
        sleep(1)    
    end
    @info "mainspin $id finished "
end

HTTP.serve!(Returns(HTTP.Response("ok")))

# steps is not relevant, it only buys you time to
# play around with the server
# not counting the sleep in `mainspin`, here we will have about 100 seconds
# and 200 seconds if we do mainspin(10, 1, steps=20)
mainspin(5, 1, steps=20) 

# now go in the terminal and play around
# curl 127.0.0.1:8081

```

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [July 22, 2023, 12:13pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/12 "2023-07-22T12:13:30Z")

</div>

> [@algunion](#):
>
> The statement is that work on the main thread alters the expected (documented) `sleep` functionality on all the other tasks running on other threads.

Aah, gotcha!

I think that is to be expected though 🤔 There’s certainly an argument to be made for seperating the scheduler from the `:interactive` thread(s), but if you saturate all interactive threads, I would expect tasks also running on the interactive threads to stall. That’s the downside of cooperative multitasking in Julia, in contrast to preemptive multitasking (which e.g. the linux kernel does).

There have been wishes for preemption in the past though, so it might become a thing some day. I don’t know of any concrete efforts towards that yet. Some arguments against that are that some programs may rely on cooperative multitasking for correctness, or that it can introduce overhead in programs that expect to have exclusive access to all threads.

---

<div class="post-metadata">

### Author: ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)
#### Post date: [July 22, 2023, 12:18pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/13 "2023-07-22T12:18:38Z")

</div>

> [@Sukera](#):
>
> There’s certainly an argument to be made for seperating the scheduler from the `:interactive` thread(s), but if you saturate all interactive threads, I would expect tasks also running on the interactive threads to stall.

But this is not the case in the MWE - because even if I start with 12 interactive threads and schedule a single task on `:interactive` (which mostly sleeps), the work on the main will still impact the working task (which can migrate on any o the `:interactive` threads). And - for additional clarity: in the MWE, no other work is done besides the main thread related work and the actual `realworker` - which behaves OK. `realwoker` is only added as a control: `realworker` behaves correctly, `sleeper` depends on the main thread.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [July 22, 2023, 12:27pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/14 "2023-07-22T12:27:05Z")

</div>

That’s definitely a bug then; please do open an issue at [Issues · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues)

---

<div class="post-metadata">

### Author: ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)
#### Post date: [July 22, 2023, 12:42pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/15 "2023-07-22T12:42:53Z")

</div>

I think this explains what is going on:

> [@Ralph\_Smith](#):
>
> The problem seems to be not just `Base.sleep()`, which uses a `libuv`-based `Timer`, but anything which accesses the `libuv` event loop, such as normal Julia IO. IIUC the event loop has to be started as an early part of the runtime, and is stuck on the main thread, so this may be tricky to fix. Please file an issue.

I had a Genie-related issue for weeks now - and I wasn’t able to track it down until yesterday when I tried to help solving this [issue](https://discourse.julialang.org/t/how-to-run-a-http-jl-server-in-parallel-while-doing-computations-in-the-foreground/101889). I assumed that the complexity of my project and the difficulty to write proper tests to catch the responsivity issue was on me - and I was in the process of refactoring stuff.

~10 hours later - trying to invalidate my conclusions (I initially assumed that it is just about communication between tasks - so I did invalidate some) I arrived at an even more upsetting conclusion: you cannot do proper (or predictible/interactive) multithreading in Julia if your project involves medium-heavy work on main and your tasks are somehow using `libuv`. Just run my HTTP.jl MWE from an above post.

So - there is hard to say how many Julia packages are poisoned in this way:

1. It is not straightforward what tests should be run to determine if there is an issue.
2. If you want to go into source code for anything you use, it is pretty time-consuming (the language users should not need to do such things).
3. Many toy examples from documentation will not reveal the issue.

For me, it is just incredible that this is happening. Imagine not being able to properly run a server on a different thread because its responsivity will be conditioned on not doing anything significant on the main thread.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [July 22, 2023, 1:16pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/16 "2023-07-22T13:16:08Z")

</div>

> [@algunion](#):
>
> For me, it is just incredible that this is happening. Imagine not being able to properly run a server on a different thread because its responsivity will be conditioned on not doing anything significant on the main thread.

I wholeheartedly agree with you - these kinds of things need to be fixed if people want Julia to expand beyond HPC & scientific computing (though I imagine this can also happen in those domains).

---

<div class="post-metadata">

### Author: ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)
#### Post date: [July 22, 2023, 3:09pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/18 "2023-07-22T15:09:03Z")

</div>

> [@algunion](#):
>
> Imagine not being able to properly run a server on a different thread because its responsivity will be conditioned on not doing anything significant on the main thread.

Agreed this should be fixed. But for a server, does the problem go away if you just spawn a new thread for any nontrivial work? Like the main task could just literally be

```julia
function main()
  spawn_stuff()
  wait_til_done()
end

```

Or is that not sufficient?

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [July 22, 2023, 3:13pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/19 "2023-07-22T15:13:36Z")

</div>

That would probably work around it, but you have to be very careful to not run any non-trivial computation on the main thread which can be very annoying.  
It’s similar to the advice to not block the thread running the event-loop in GUI programming. Usually, the event loop should run in its own thread though, i.e., not on main.

---

<div class="post-metadata">

### Author: ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)
#### Post date: [July 22, 2023, 3:21pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/20 "2023-07-22T15:21:20Z")

</div>

> [@bertschi](#):
>
> very careful to not run any non-trivial computation on the main thread which can be very annoying.

In Julia as I understand it there’s sometimes confusing terminology. People talk about spawning threads with `@spawn` for example. Unless I’m mistaken:

1. `@spawn` creates _tasks_ which can run on any thread
2. Thread migration was introduced a while back, maybe version 1.5 ish
3. If you create a task that can migrate you don’t really have control over what thread that task runs on

Given all of that, is the issue that if you have a high compute task and it gets scheduled onto thread number 1 everything borks? Or is it if you do computation in the task running the REPL it borks?

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [July 22, 2023, 3:39pm UTC](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911/21 "2023-07-22T15:39:21Z")

</div>

Good point, how I understand the discussion everything borks if the task happens to run on the thread that’s listening to events – which happens to be the main one, i.e., running all top-level and single threaded code?

[Next page](https://discourse.julialang.org/t/bug-in-sleep-function-main-thread-work-affecting-sleep-duration-on-running-tasks/101911.md?page=2)
