# Multithreading agents.jl with @threads for all agents

**URL:** <https://discourse.julialang.org/t/multithreading-agents-jl-with-threads-for-all-agents/96845>\
**Category:** New to Julia\
**Tags:** question, multithreading, agents\
**Created:** [March 30, 2023, 3:16pm UTC](https://discourse.julialang.org/t/multithreading-agents-jl-with-threads-for-all-agents/96845 "2023-03-30T15:16:03Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![stockholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stockholm/32/48083_2.png) [@stockholm](https://discourse.julialang.org/u/stockholm)\
**Post date:** [March 30, 2023, 3:16pm UTC](https://discourse.julialang.org/t/multithreading-agents-jl-with-threads-for-all-agents/96845/1 "2023-03-30T15:16:03Z")

</div>

My agents.jl users are loosely coupled. It should be possible to run them mostly in parallel. The only congestion point is the model variable, where their computational results are summed up.

So I introduced @threads to the for loop over all the agents and got this stacktrace:

```julia

ERROR: TaskFailedException
Stacktrace:
 [1] wait
   @ ./task.jl:345 [inlined]
 [2] threading_run(fun::var"#13#threadsfor_fun#8"{var"#13#threadsfor_fun#7#9"{StandardABM{Nothing, User, typeof(Agents.Schedulers.fastest), Dict{Symbol, Int64}, Random.TaskLocalRNG}, Base.ValueIterator{Dict{Int64, User}}}}, static::Bool)
   @ Base.Threads ./threadingconstructs.jl:38
 [3] macro expansion
   @ ./threadingconstructs.jl:89 [inlined]
 [4] model_step!
   @ ~/src/masiri/Initial model/demo_agents_thread.jl:49 [inlined]
 [5] step!(model::StandardABM{Nothing, User, typeof(Agents.Schedulers.fastest), Dict{Symbol, Int64}, Random.TaskLocalRNG}, agent_step!::Function, model_step!::typeof(model_step!), n::Int64, agents_first::Bool)
   @ Agents ~/.julia/packages/Agents/kEwy8/src/simulations/step.jl:54
 [6] run!(model::StandardABM{Nothing, User, typeof(Agents.Schedulers.fastest), Dict{Symbol, Int64}, Random.TaskLocalRNG}, agent_step!::typeof(dummystep), model_step!::typeof(model_step!), n::Int64; when::Bool, when_model::Bool, mdata::Vector{Symbol}, adata::Nothing, obtainer::Function, agents_first::Bool, showprogress::Bool)
   @ Agents ~/.julia/packages/Agents/kEwy8/src/simulations/collect.jl:153
 [7] top-level scope
   @ ~/src/masiri/Initial model/demo_agents_thread.jl:58

    nested task error: MethodError: no method matching firstindex(::Base.ValueIterator{Dict{Int64, User}})
    Closest candidates are:
      firstindex(::Any, ::Any) at abstractarray.jl:402
      firstindex(::Union{Tables.AbstractColumns, Tables.AbstractRow}) at ~/.julia/packages/Tables/AcRIE/src/Tables.jl:182
      firstindex(::LinRange) at range.jl:693
      ...
    Stacktrace:
     [1] #13#threadsfor_fun#7
       @ ./threadingconstructs.jl:69 [inlined]
     [2] #13#threadsfor_fun
       @ ./threadingconstructs.jl:51 [inlined]
     [3] (::Base.Threads.var"#1#2"{var"#13#threadsfor_fun#8"{var"#13#threadsfor_fun#7#9"{StandardABM{Nothing, User, typeof(Agents.Schedulers.fastest), Dict{Symbol, Int64}, Random.TaskLocalRNG}, Base.ValueIterator{Dict{Int64, User}}}}, Int64})()
       @ Base.Threads ./threadingconstructs.jl:30

```

This is my code:

```julia

using Agents, Base.Threads

const FIB_NUM = 10

mutable struct User <: AbstractAgent
    id::Int
    fibonacci_num::Int
end

mutable struct MyModel 
    agents::Vector{AbstractAgent}
    step::Int
    total_fib::Float64
end

function fibonacci(n::Int)
    if n <= 1
        return n
    else
        return fibonacci(n - 1) + fibonacci(n - 2)
    end
end

function user_step!(agent::User, model)
    agent.fibonacci_num += fibonacci(FIB_NUM)
        model.properties[:total_fib] += agent.fibonacci_num 
end

function create_my_model()
    n_users = 100
    users = [User(i, 0) for i in 1:n_users]
    agents = users

    properties = Dict(
        :total_fib => 0,
        :tick => 1
    )

    model = ABM(User; properties=properties)
    for agent in agents
        add_agent!(agent, model)
    end

    return model
end

function model_step!(model)
    model.tick += 1
    @threads for agent in allagents(model)
        user_step!(agent, model)
    end
end

model = create_my_model()
n_steps = 356
run!(model, dummystep, model_step!, n_steps-1, mdata = [:total_fib])
println("total Fibonacci:", model.total_fib )

```

What goes on in this stack trace? … WHY? How can I make this run in parallel?  
This must be a common request - how are you supposed to parallelize your agents’ computations?

---

<div class="post-metadata">

**Author:** ![fbanning](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fbanning/32/14972_2.png) [@fbanning](https://discourse.julialang.org/u/fbanning)\
**Post date:** [March 30, 2023, 3:24pm UTC](https://discourse.julialang.org/t/multithreading-agents-jl-with-threads-for-all-agents/96845/2 "2023-03-30T15:24:34Z")

</div>

> [@stockholm](#):
>
> `model.properties[:total_fib] += agent.fibonacci_num`

Updating a model property inside the for-loop that iterates over all agents is not a good idea as concurrent access to the underlying data is likely to occur and that’s certainly not what you want. Instead you should use something like `model.total_fib = sum(model[id].fibonacci_num for id in allids(model))` at the end of the `model_step! ` function.

---

<div class="post-metadata">

**Author:** ![stockholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stockholm/32/48083_2.png) [@stockholm](https://discourse.julialang.org/u/stockholm)\
**Post date:** [March 30, 2023, 3:31pm UTC](https://discourse.julialang.org/t/multithreading-agents-jl-with-threads-for-all-agents/96845/3 "2023-03-30T15:31:25Z")

</div>

But that is not what the error is about, right? I am aware of the race condition - I had hoped Julia would magically (with multiple dispatches?) solve that, as the order of summation or access does not matter - and yes, I didn’t fully understand multiple dispatches yet. 🙂

but you are of course right, your suggestion is very good to resolve the race condition. I will update the example with your change.

---

<div class="post-metadata">

**Author:** ![stockholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stockholm/32/48083_2.png) [@stockholm](https://discourse.julialang.org/u/stockholm)\
**Post date:** [March 30, 2023, 3:37pm UTC](https://discourse.julialang.org/t/multithreading-agents-jl-with-threads-for-all-agents/96845/4 "2023-03-30T15:37:02Z")

</div>

wtf, the error is gone! How can that stack trace point to that race condition?!

---

<div class="post-metadata">

**Author:** ![fbanning](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fbanning/32/14972_2.png) [@fbanning](https://discourse.julialang.org/u/fbanning)\
**Post date:** [March 30, 2023, 3:58pm UTC](https://discourse.julialang.org/t/multithreading-agents-jl-with-threads-for-all-agents/96845/5 "2023-03-30T15:58:06Z")

</div>

Parallelisation of agent iteration is not something I have dealt with so far because all my models run fast enough that I really didn’t have the need to do that. Parallel execution of multiple model replicates were totally enough for me. So I can’t really answer any of your questions about the stacktrace that the @threads macro has thrown at you. Glad that my quick look at the `model_step!` and `user_step!` functions has resolved your issue though. 🙂
