# Function only works if println statements are included

**URL:** <https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210>\
**Category:** General Usage\
**Tags:** compilation\
**Created:** [November 14, 2023, 1:53pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210 "2023-11-14T13:53:50Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![opiateblush](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/opiateblush/32/46925_2.png) [@opiateblush](https://discourse.julialang.org/u/opiateblush)\
**Post date:** [November 14, 2023, 1:53pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/1 "2023-11-14T13:53:50Z")

</div>

Hey, I have the following piece of code that works as intended if the commented lines with the `println` statements are included. If they are commented out the `if` statement that compares the dictionaries evaluates to `true` only once and then never again. However, it does if the `println` statements are included as mentioned above, which doesn’t make sense to me at all.

I know there are large pieces of code missing but I don’t know how to transform this into a minimal example as there are a lot of things happening under the hood. My guess is something related to compilation that is easy to spot for a proficient Julia programmer.

```julia
@kwdef mutable struct PoseLimitedDatasetIterationState{TWrappedDataset <: AbstractSimulationFrameDataset, VS, N <: Integer}
    sensor_locations_wgs84::Dict{String, Tuple{Float64, Float64}} = Dict{String, Tuple{Float64, Float64}}()
    sensor_rotations_deg::Dict{String, Float64} = Dict{String, Float64}()
    sensor_heights_m::Dict{String, Float64} = Dict{String, Float64}()

    wrapped_dataset_iterator::Iterators.Stateful{TWrappedDataset, VS, N}
end

function Base.iterate(dataset::PoseLimitedSimulationFrameDataset)
    return iterate(dataset, PoseLimitedDatasetIterationState(wrapped_dataset_iterator = Iterators.Stateful(dataset.dataset)))
end

function Base.iterate(dataset::PoseLimitedSimulationFrameDataset, state::PoseLimitedDatasetIterationState)
    dataset_iteration_tuple = nothing

    end_wrapped_iteration = false
    start_time = time()

    while !end_wrapped_iteration && !isempty(state.wrapped_dataset_iterator) 
        wrapped_dataset_iteration_value = popfirst!(state.wrapped_dataset_iterator)
                
        simulation_frame = get_simulation_frame(dataset)

        if !isnothing(simulation_frame)
            sensor_locations_wgs84 = Dict{String, Tuple{Float64, Float64}}(map(n -> n => get_sensor_location_wgs84(simulation_frame, n), get_sensor_names(simulation_frame)))
            sensor_rotations_deg = Dict{String, Float64}(map(n -> n => get_sensor_rotation_deg(simulation_frame, n), get_sensor_names(simulation_frame)))
            sensor_heights_m = Dict{String, Float64}(map(n -> n => get_sensor_height_m(simulation_frame, n), get_sensor_names(simulation_frame)))

            if state.sensor_locations_wgs84 != sensor_locations_wgs84 || state.sensor_rotations_deg != sensor_rotations_deg || state.sensor_heights_m != sensor_heights_m
                state.sensor_locations_wgs84 = sensor_locations_wgs84
                state.sensor_rotations_deg = sensor_rotations_deg
                state.sensor_heights_m = sensor_heights_m
                
                dataset_iteration_tuple = (wrapped_dataset_iteration_value, state)
                end_wrapped_iteration = true

            # println("new pose")
            # else
            # println("no new pose")
            end
        end

        # this yield statements does the trick to
        # yield()

        if time() - start_time > dataset.timeout_s
            end_wrapped_iteration = true
        end
    end

    return dataset_iteration_tuple
end

```

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [November 14, 2023, 1:58pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/2 "2023-11-14T13:58:30Z")

</div>

You will get 20x more help if you make the example runnable.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 14, 2023, 2:02pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/3 "2023-11-14T14:02:51Z")

</div>

> [@opiateblush](#):
>
> However, it does if the `println` statements are included as mentioned above, which doesn’t make sense to me at all.

It doesn’t, and that indicates that probably the problem is not there. Is this being run multi-threaded? From my experience, bugs that manifest when one add or remove print statements are always some memory corruption, non-initialized variables, something like that.

---

<div class="post-metadata">

**Author:** ![opiateblush](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/opiateblush/32/46925_2.png) [@opiateblush](https://discourse.julialang.org/u/opiateblush)\
**Post date:** [November 14, 2023, 2:31pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/4 "2023-11-14T14:31:58Z")

</div>

Alright, I think I got a clue now. Thanks for your reply. The program indeed incorporates async tasks, which are necessary to run so that the mentioned `if` statement can evaluate to `true`.

If I include the `yield` statement in my edited original post the problem doesn’t occur anymore, as well. So the problem seems to be related with task scheduling. I guess the other tasks (which are required to run) are not scheduled anymore unless the `yield` or `println` statements are included.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 14, 2023, 2:40pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/5 "2023-11-14T14:40:20Z")

</div>

You are probably blocking the task scheduler loop from running when you do not yield. Note that your `@async` tasks are all trying to run on a single thread. You may be interested in `Threads.@spawn` to run tasks on other threads. Make sure to start Julia with multiple threads.

---

<div class="post-metadata">

**Author:** ![opiateblush](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/opiateblush/32/46925_2.png) [@opiateblush](https://discourse.julialang.org/u/opiateblush)\
**Post date:** [November 14, 2023, 2:59pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/6 "2023-11-14T14:59:35Z")

</div>

The tasks are created using the `@spawn` macro just as it is recommended in the documentation. Julia is started with multiple threads, as well. Still, this leaves me a bit confused and shows that I did not really understand how task scheduling works in Julia and when or where `yield` statements are required.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 14, 2023, 5:20pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/7 "2023-11-14T17:20:56Z")

</div>

Basically you are running your loop on the thread where the scheduler event loop is also running.

@gbaraldi has proposed a fixed here:

> <https://github.com/JuliaLang/julia/pull/50880>
>
> This is slightly speculative, but it fixes https://github.com/JuliaLang/julia/is…sues/50643 which is a start. But it hasn't been tested under heavy contention of the uv lock. 
> It also currently uses the normal mutex but we probably need to switch to a lock that has some form of fairness (maybe #50878 )

---

<div class="post-metadata">

**Author:** ![opiateblush](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/opiateblush/32/46925_2.png) [@opiateblush](https://discourse.julialang.org/u/opiateblush)\
**Post date:** [November 15, 2023, 3:37pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/8 "2023-11-15T15:37:59Z")

</div>

Thanks for that reference. I think I narrowed it down. So, there is a task that runs on a different thread that is receiving data using `ZMQ.jl`. This task updates the `simulation_frame` object in the code piece above based on the received data. Only if there are new values in that frame the condition in the if statement comparing the dictionaries can be `true`.

I’m guessing that this receiving operation of `ZMQ.jl` somehow requires the UV loop to run, but since the main thread never has time to go back to it the task will never receive any new data. This is why it doesn’t even matter that it runs on a separate thread. Including the `yield` statement allows the UV loop to be executed again and the new data can be received, which in turn updates the `simulation_frame` object and the condition can be `true`.

Those are my thoughts so far, maybe it helps someone with similar problems.

My current solution to this:

```julia
function main()
    # main program code usually run on the main thread
end

# main()
# instead of calling main directly it is wrapped inside a task
wait(@spawn main())

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 15, 2023, 4:51pm UTC](https://discourse.julialang.org/t/function-only-works-if-println-statements-are-included/106210/9 "2023-11-15T16:51:18Z")

</div>

Julia uses a working fork of libuv for multitasking and I/O.

> **[libuv | Cross-platform asynchronous I/O](https://libuv.org/)**
>
> libuv, a platform abstraction library with focus on asynchronous i/o.

So yes, those two things would be linked.
