# Should I use @inbounds on for loop iterating through the values of a Dict?

**URL:** <https://discourse.julialang.org/t/should-i-use-inbounds-on-for-loop-iterating-through-the-values-of-a-dict/42570>\
**Category:** Performance\
**Tags:** question, performance\
**Created:** [July 5, 2020, 7:23pm UTC](https://discourse.julialang.org/t/should-i-use-inbounds-on-for-loop-iterating-through-the-values-of-a-dict/42570 "2020-07-05T19:23:05Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![jchen975](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jchen975/32/8994_2.png) [@jchen975](https://discourse.julialang.org/u/jchen975)\
**Post date:** [July 5, 2020, 7:23pm UTC](https://discourse.julialang.org/t/should-i-use-inbounds-on-for-loop-iterating-through-the-values-of-a-dict/42570/1 "2020-07-05T19:23:05Z")

</div>

Hello,

I’m wondering if it’s appropriate (and necessary) to use `@inbounds` on a for loop that iterates through the keys/values of a `Dict`. After a quick search the examples where `@inbounds` helps are where I’m indexing an `Array`, for example, but I’m working with `Dict`s. Here’s a test with dummy `Dict`s:

```julia
k = collect(1:1:1000);
v = collect(1:2:2000);
dict = Dict(zip(k,v));
a = 0

function test1()
   for v in values(dict)
       a = v
    end
end

function test2()
   for v in values(dict)
       @inbounds a = v
   end
end

```

```julia
julia> using BenchmarkTools

julia> @benchmark test1()
BenchmarkTools.Trial:
  memory estimate: 56.44 KiB
  allocs estimate: 2612
  --------------
  minimum time: 64.799 μs (0.00% GC)
  median time: 66.600 μs (0.00% GC)
  mean time: 75.709 μs (1.30% GC)
  maximum time: 1.054 ms (89.97% GC)
  --------------
  samples: 10000
  evals/sample: 1

julia> @benchmark test2()
BenchmarkTools.Trial:
  memory estimate: 56.44 KiB
  allocs estimate: 2612
  --------------
  minimum time: 64.400 μs (0.00% GC)
  median time: 77.900 μs (0.00% GC)
  mean time: 81.345 μs (1.30% GC)
  maximum time: 1.101 ms (92.41% GC)
  --------------
  samples: 10000
  evals/sample: 1

```

Looks like the performance is slightly worse with `@inbounds` in this case… am I missing anything?

FYI in reality the values of the `dict`s I’d loop through are `mutable struct`s I defined elsewhere, whose fields are mostly either `Float64` or `Int`.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [July 6, 2020, 1:30am UTC](https://discourse.julialang.org/t/should-i-use-inbounds-on-for-loop-iterating-through-the-values-of-a-dict/42570/2 "2020-07-06T01:30:24Z")

</div>

Adding `@inbounds` only affects bounds checks within the expression you’ve marked `@inbounds`. In your case, that’s `a = v`, which doesn’t do any indexing at all. In fact, that expression doesn’t do _anything_, period. The `a` inside each function is a local variable, unrelated to the global variable `a` with the same name, so you’re just setting the value of a local variable `a` which is discarded at the end of the function.

You can, however, do `@inbounds for v in ...` to also disable any bounds checking which may happen in the actual process of iterating over values.

But before doing that, there’s a much more important performance issue with this code: Both of your functions reference a non-const global variable (`dict`). The slowness of iterating over a non-constant global variable dwarfs any small optimization you could get by using `@inbounds`. We can fix that by making `dict` const or, even better, passing it in as an argument:

```julia
julia> function test3(dict)
         for v in dict
           a = v
         end
       end
test3 (generic function with 1 method)

julia> @btime test1()
  57.739 μs (2612 allocations: 56.44 KiB)

julia> @btime test2()
  58.564 μs (2612 allocations: 56.44 KiB)

julia> @btime test3($dict)
  7.269 μs (0 allocations: 0 bytes)

```

With the global variable issue fixed, we can finally see some benefit from using `@inbounds` on the for loop itself:

```julia
julia> function test4(dict)
         @inbounds for v in dict
           a = v
         end
       end
test4 (generic function with 1 method)

julia> @btime test4($dict)
  4.795 μs (0 allocations: 0 bytes)

```

For more info see [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/index.html) and remember to never use non-constant global variables for code whose performance you care about. After all, it’s the very first performance tip in that list for a reason.

---

<div class="post-metadata">

**Author:** ![jchen975](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jchen975/32/8994_2.png) [@jchen975](https://discourse.julialang.org/u/jchen975)\
**Post date:** [July 6, 2020, 2:57am UTC](https://discourse.julialang.org/t/should-i-use-inbounds-on-for-loop-iterating-through-the-values-of-a-dict/42570/3 "2020-07-06T02:57:11Z")

</div>

Thank you very much for your explanation. You’re absolutely right: I forgot to mention that all the loops I was working with were not referencing a global `dict`, but more like

```julia
function foo(dict)
    ...
    for v in values(dict)
        access/change v.field1
        access/change v.field2
        ...
    end
    ...
end

```

And I’d do `dict = load_fn("filename"); foo(dict)`, where `load_fn` is another function that reads a local file and build the `dict`. Lastly, do I need to explicitly call `foo($dict)` with `$`? I thought by default Julia function arguments are passed by reference/sharing?

Thanks again 🙂

---

<div class="post-metadata">

**Author:** ![bernhard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bernhard/32/2619_2.png) [@bernhard](https://discourse.julialang.org/u/bernhard)\
**Post date:** [July 6, 2020, 6:03am UTC](https://discourse.julialang.org/t/should-i-use-inbounds-on-for-loop-iterating-through-the-values-of-a-dict/42570/4 "2020-07-06T06:03:26Z")

</div>

You only need the dollar sign to get meaningful performance testing numbers, ie for `@btime`  
For your code you should not use it (it will produce an error)
