# Multi-threads error (undefRefError) in simple ABM with Agents.jl

**URL:** <https://discourse.julialang.org/t/multi-threads-error-undefreferror-in-simple-abm-with-agents-jl/110900>\
**Category:** Modelling & Simulations\
**Tags:** parallel, multithreading, agents, agentsjl\
**Created:** [February 28, 2024, 1:42pm UTC](https://discourse.julialang.org/t/multi-threads-error-undefreferror-in-simple-abm-with-agents-jl/110900 "2024-02-28T13:42:55Z")\
**Posts on this page:** 2\
**Page:** 2

<div class="post-metadata">

**Author:** ![Tortar](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@Tortar](https://discourse.julialang.org/u/Tortar)\
**Post date:** [February 29, 2024, 8:52pm UTC](https://discourse.julialang.org/t/multi-threads-error-undefreferror-in-simple-abm-with-agents-jl/110900/21 "2024-02-29T20:52:30Z")

</div>

thanks to @Dan great idea of using ThreadSafeDicts.jl and as soon as [Enlarge DictABM and VecABM for dispatch by Tortar · Pull Request #993 · JuliaDynamics/Agents.jl · GitHub](https://github.com/JuliaDynamics/Agents.jl/pull/993) is merged, `ThreadSafeDicts` is usable in the `dev` version of Agents.jl (soon v6). I have ported your MWE to v6 (while improving some other perf aspects of it), you can run it with more than 1 thread and it works:

```julia
using Agents, Random, Distributed, ThreadSafeDicts, BenchmarkTools

@agent struct Person(NoSpaceAgent)
    type::Symbol
    height::Int64
end

function random_h!(person, model)
    person.height = rand(abmrng(model), 1:100)
end

function die!(person, model)
    if person.height < model.height_to_die
        remove_agent!(person, model)
    end
end

function add_people!(person, model)
    if person.type === :young && person.height > model.height_to_generate
        for _ in 1:10
            add_agent!(model, rand(abmrng(model), (:baby, :young, :adult)), rand(abmrng(model), 1:100))
        end
    elseif person.type === :adult && person.height > model.height_to_generate
        for _ in 1:10
            add_agent!(model, rand(abmrng(model), (:baby, :young, :adult)), rand(abmrng(model), 1:100))
        end
    end
end

function evolve_environment!(model)
    sum_h = 0.0
    for person in allagents(model)
        sum_h += person.height
    end
    model.sum_h[] = sum_h
end

function complex_step!(model)
    all_ids = collect(allids(model))
    Threads.@threads for i in all_ids
    	person = model[i]
        random_h!(person, model)
        die!(person, model)
    end
    young_adults_ids = collect(Iterators.filter(id -> model[id].type === :young || model[id].type === :adult, allids(model)))
    for i in young_adults_ids
    	person = model[i]
        add_people!(person, model)
    end
    evolve_environment!(model)
    #println("agents now: $(nagents(model))")
end

function create_model()
	properties = (height_to_die = 30, height_to_generate = 90, sum_h = Ref(0.0))
	model = StandardABM(Person; model_step! = complex_step!, properties, 
			    scheduler = Schedulers.fastest, container = ThreadSafeDict,
			    rng = Xoshiro(42))
	for i in 1:100
	    add_agent!(model, rand(abmrng(model), (:baby, :young, :adult)), rand(1:100))
	end
	return model
end

@benchmark run!(create_model(), 10)

```

you can read a rough version of the docs for the new version at [Introduction · Agents.jl](https://juliadynamics.github.io/Agents.jl/dev/)

edit:

even if it works, it is actually 2x slower than the single-thread version with 12 threads 😃 this is somewhat expected, because it’s not easy to do fast multi-threading with non-vector data structures, maybe it is even true that it is faster in the threaded loop, and then it would mean that it is slower because the other parts are not in multi-threading and the multi-threaded structure is slower (maybe it uses a normal `Dict` with 1 thread?), not sure about that.

---

<div class="post-metadata">

**Author:** ![Tortar](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@Tortar](https://discourse.julialang.org/u/Tortar)\
**Post date:** [February 29, 2024, 8:57pm UTC](https://discourse.julialang.org/t/multi-threads-error-undefreferror-in-simple-abm-with-agents-jl/110900/22 "2024-02-29T20:57:26Z")

</div>

unrelated: I just saw now that you use a `type` field, if you happen to need multiple types you can use the new `multiagent` macro, see a perf comparison at [Performance Tips · Agents.jl](https://juliadynamics.github.io/Agents.jl/dev/performance_tips/#multi_vs_union)

[Previous page](https://discourse.julialang.org/t/multi-threads-error-undefreferror-in-simple-abm-with-agents-jl/110900.md?page=1)
