# Lightweight tasks, Julia vs Elixir/OTP

**URL:** <https://discourse.julialang.org/t/lightweight-tasks-julia-vs-elixir-otp/35082>\
**Category:** Performance\
**Tags:** multithreading\
**Created:** [February 24, 2020, 6:30pm UTC](https://discourse.julialang.org/t/lightweight-tasks-julia-vs-elixir-otp/35082 "2020-02-24T18:30:48Z")\
**Posts on this page:** 2\
**Page:** 2

<div class="post-metadata">

**Author:** ![pbayer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pbayer/32/11675_2.png) [@pbayer](https://discourse.julialang.org/u/pbayer)\
**Post date:** [February 26, 2020, 3:57pm UTC](https://discourse.julialang.org/t/lightweight-tasks-julia-vs-elixir-otp/35082/21 "2020-02-26T15:57:13Z")

</div>

> [@c42f](#):
>
> you might just be seeing competition with other tasks doing background work

You are right, this seems to be the cause of the problem. I extended my last example:

```julia
function machin_series(n::Int; handover=false)
    qpi = 0.0
    for i in 1:n
        qpi += (-1)^(i+1)/(2i-1)
        handover && yield() # we yield here!
    end
    qpi*4
end

function startonthread(id::Int, f::F) where {F<:Function}
    t = Task(nothing)
    @threads for i in 1:nthreads()
        if i == id
            t = @async f()
        end
    end
    fetch(t)
end

```

This gives the following results:

```julia
julia> @btime startonthread(1, ()->machin_series(10_000))
  491.870 μs (43 allocations: 4.20 KiB)
3.1414926535900345

julia> @btime startonthread(2, ()->machin_series(10_000))
  511.001 μs (45 allocations: 4.23 KiB)
3.1414926535900345

julia> @btime startonthread(1, ()->machin_series(10_000, handover=true))
  147.722 ms (10044 allocations: 160.47 KiB) !!!!!!!!!
3.1414926535900345

julia> @btime startonthread(2, ()->machin_series(10_000, handover=true))
  2.477 ms (10045 allocations: 160.48 KiB)
3.1414926535900345

julia> @btime startonthread(3, ()->machin_series(10_000, handover=true))
  2.499 ms (10045 allocations: 160.48 KiB)
3.1414926535900345

```

If I `yield()` inside my loop, things take longer on thread 1 than on other threads! Applications involving tasks, @async, yield and friends run faster on threads other than 1.

---

<div class="post-metadata">

**Author:** ![pbayer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pbayer/32/11675_2.png) [@pbayer](https://discourse.julialang.org/u/pbayer)\
**Post date:** [February 27, 2020, 6:37pm UTC](https://discourse.julialang.org/t/lightweight-tasks-julia-vs-elixir-otp/35082/22 "2020-02-27T18:37:37Z")

</div>

Now in concluding this journey, I provide the following function for executing functions on specified threads:

```julia
function onthread(f::F, id::Int) where {F<:Function}
    t = Task(nothing)
    @assert id in 1:nthreads() "thread $id not available!"
    @threads for i in 1:nthreads()
        if i == id
            t = @async f()
        end
    end
    fetch(t)
end

```

Anyone having **single threaded applications involving tasks** can speed things up with it. With the above (contrived) example you can do

```julia
julia> @btime machin_series(10_000, handover=true)
  158.559 ms (10000 allocations: 156.25 KiB)
3.1414926535900345

julia> @btime onthread(2) do; machin_series(10_000, handover=true); end
  2.467 ms (10045 allocations: 160.48 KiB)
3.1414926535900345

```

More realistically I still get dramatic speedups of my [simulation benchmarks](https://github.com/pbayer/Simulate.jl/tree/dev/benchmarks) with this:

| date | channel [ms] | dice [ms] | heating [ms] | action [μs] | comment |
| --- | --- | --- | --- | --- | --- |
| 2020-02-20 | 42.431 | 296.433 | 59.631 | 38.156 | before |
| 2020-02-27 | 44.630 | 36.641 | 5.091 | 8.269 | dice and heating onthread(2) |

Maybe, now you can see why I went after this thing 🙂 .

You can just copy/paste `onthread` from above or get it [from my repo](https://github.com/pbayer/ThreadingExperiments.jl) by

```julia
] add "https://github.com/pbayer/ThreadingExperiments.jl"

julia> using ThreadingExperiments

```

Its compat is Julia 1.3. Maybe someone of you could test (by copying from this thread) if this thing works as well in Julia 1.2 and below.

[Previous page](https://discourse.julialang.org/t/lightweight-tasks-julia-vs-elixir-otp/35082.md?page=1)
