# Channel gets emptied and stays that way

**URL:** <https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237>\
**Category:** General Usage\
**Tags:** question, guis\
**Created:** [July 10, 2019, 7:54pm UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237 "2019-07-10T19:54:04Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [July 10, 2019, 7:54pm UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/1 "2019-07-10T19:54:04Z")

</div>

I want to use a `@async` task to `put!` video frames (from `VideoIO`) in a `Channel` and use that channel as a buffer of frames to update a `Makie.Scene` with. The idea is that while the user plays with the `slider` to explore a video the buffer will have all the frames the user needs and as the user uses them the task will `put!` more frames in the buffer _in the background_.

My problem is that the channel always gets empty, even if I leave the slider alone. It’s like some background task never yields to allow that `@async`ed task to fill back the buffer.

Any idea what’s going on?

Here is a bare-bone MWE (ignore the scaling and rotation of the image, just trying to keep it super simple):

```julia
using Makie, VideoIO
avf = VideoIO.testvideo("annie_oakley")
f = VideoIO.openvideo(avf)
seek(f, 5.0) # skip the beginning
img = Node(read(f))
buff = Channel{typeof(img[])}(500) # have a buffer with 500 frames
task = @async begin # this is the task that fills that buffer
    while !eof(f)
        put!(buff, read(f))
    end
end
scene = Makie.image(img)
slider_h = slider(1:500, raw = true, camera = campixel!, start = 2)
old_slider_pos = Node(1)
lift(slider_h[end][:value]) do frame
    if old_slider_pos[] ≤ frame
        for i in old_slider_pos[]:frame
            img[] = take!(buff)
        end
        old_slider_pos[] = frame
    else
        println("can't go back in time! Yet…")
    end
end
hbox(slider_h, scene)

```

Now slide the slider _a little_ to the right and then check the `buff` variable, it should show something like this:

```julia
julia> buff
Channel{PermutedDimsArray{ColorTypes.RGB{FixedPointNumbers.Normed{UInt8,8}},2,(2, 1),(2, 1),Array{ColorTypes.RGB{FixedPointNumbers.Normed{UInt8,8}},2}}}(sz_max:500,sz_curr:500)

```

Nice, the channel is _still_ full, it has 500 frames ready.

OK, now be nasty and pull the slider to the right more vigorously. Check `buff` again:

```julia
julia> buff
Channel{PermutedDimsArray{ColorTypes.RGB{FixedPointNumbers.Normed{UInt8,8}},2,(2, 1),(2, 1),Array{ColorTypes.RGB{FixedPointNumbers.Normed{UInt8,8}},2}}}(sz_max:500,sz_curr:128)

```

Now it has lost tons of frames. It will stay like that no matter what.

Why? And how can I get it to do what I want: fill up the buffer in the background (like when the user isn’t playing with the slider)?

---

<div class="post-metadata">

**Author:** ![asinghvi17](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/asinghvi17/32/8272_2.png) [@asinghvi17](https://discourse.julialang.org/u/asinghvi17)\
**Post date:** [July 11, 2019, 6:06am UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/2 "2019-07-11T06:06:03Z")

</div>

Could be a `put!` without a corresponding `take!`? You might have to `empty!`…

This is just what I got from reading the docstring, YMMV.

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [July 11, 2019, 6:52am UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/3 "2019-07-11T06:52:30Z")

</div>

> [@asinghvi17](#):
>
> Could be a `put!` without a corresponding `take!` ?

Yea, that’s what’s happening, but why? Why is the `put!` task halted? Why does it never catch up with all the `take!`s?

> [@asinghvi17](#):
>
> You might have to `empty!`

Empty what? The buffer? That’s exactly the opposite of what I’m looking for. The buffer is emptied no matter what, which is the problem.

---

<div class="post-metadata">

**Author:** ![smldis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/smldis/32/1735_2.png) [@smldis](https://discourse.julialang.org/u/smldis)\
**Post date:** [July 11, 2019, 10:27am UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/4 "2019-07-11T10:27:16Z")

</div>

It seems you consumed the frames. Isn’t `eof(f)` reached very soon? ~580 frames is the total

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [July 11, 2019, 10:34am UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/5 "2019-07-11T10:34:43Z")

</div>

Nope, the video isn’t close to its end. Try it, you’ll see!

---

<div class="post-metadata">

**Author:** ![smldis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/smldis/32/1735_2.png) [@smldis](https://discourse.julialang.org/u/smldis)\
**Post date:** [July 11, 2019, 10:48am UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/6 "2019-07-11T10:48:15Z")

</div>

It is closed as soon as you move to ~80 the slider. And then you have a problem at the end of the slider because of a 1-off error on the take loop, it should be:

```julia
        for i in old_slider_pos[]+1:frame
            img[] = take!(buff)
        end

```

so there where more `take!`s than `put!`s

---

<div class="post-metadata">

**Author:** ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)\
**Post date:** [July 11, 2019, 10:55am UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/7 "2019-07-11T10:55:42Z")

</div>

Pretty sure the problem is that the `lift` function might be called concurrently, and the slider value might be updated multiple times – that means that multiple tasks might try `take!`ing stuff out of the buffer at the same time (not really at the same time, but in an undefined order).

Your code works fine if you set the slider value programmatically with e.g. `slider_h[end][:value] = 500`, or adjust your code as follows:

```julia
lift(slider_h[end][:value]) do frame
    while old_slider_pos[] ≤ frame
        img[] = take!(buff)
        old_slider_pos[] += 1
    end
end

```

A better option would be to debounce the invocation of the function called by `lift`.

Edit: Or the above is completly wrong and Makie already debounces the slider output. @smldis solution works just fine 😉

---

<div class="post-metadata">

**Author:** ![smldis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/smldis/32/1735_2.png) [@smldis](https://discourse.julialang.org/u/smldis)\
**Post date:** [July 11, 2019, 11:02am UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/8 "2019-07-11T11:02:16Z")

</div>

Definitely the `while` solution has a better style and avoids the 1-off bug in the for loop.

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [July 11, 2019, 11:15am UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/9 "2019-07-11T11:15:56Z")

</div>

> [@pfitzseb](#):
>
> ```julia
> lift(slider_h[end][:value]) do frame
> while old_slider_pos[] ≤ frame
> img[] = take!(buff)
> old_slider_pos[] += 1
> end
> end
> 
> ```

this worked! Awesome!

> [@pfitzseb](#):
>
> A better option would be to debounce the invocation of the function called by `lift` .

What…? How would I do that?

---

<div class="post-metadata">

**Author:** ![smldis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/smldis/32/1735_2.png) [@smldis](https://discourse.julialang.org/u/smldis)\
**Post date:** [July 11, 2019, 12:50pm UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/10 "2019-07-11T12:50:38Z")

</div>

If the called function is expensive you could try to avoid to run it too often, this gets trickier soon and I think you would need to schedule it based on time, not only on the change of the slider value.  
This is not your case, since the function is not that expensive, but you might want to insert a `yield()` inside the while loop in order to avoid to block on all the `put!`s needed to fill the channel.

Another issue I found is that the called function errors if you don’t return nothing. I am not familiar with the slider API so I cannot explain what’s happening.  
The final code is (eventually put the while loop solution for better style):

```julia
using Makie, VideoIO
avf = VideoIO.testvideo("annie_oakley")
f = VideoIO.openvideo(avf)
seek(f, 5.0) # skip the beginning
img = Node(read(f))
buff = Channel{typeof(img[])}(500) # have a buffer with 500 frames
task = @async begin # this is the task that fills that buffer
    i=0
    while !eof(f)
        put!(buff, read(f))
        yield()
    end
end
scene = Makie.image(img)
slider_h = slider(1:500, raw = true, camera = campixel!, start = 2)
old_slider_pos = Node(1)
lift(slider_h[end][:value]) do frame
    @show frame
    if old_slider_pos[] < frame
        for i in old_slider_pos[]+1:frame
            img[] = take!(buff)
        end
        old_slider_pos[] = frame
    else
        if old_slider_pos[] > frame
            println("can't go back in time! Yet…")
        end
    end
    nothing
end
hbox(slider_h, scene)

```

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [July 11, 2019, 1:48pm UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/11 "2019-07-11T13:48:00Z")

</div>

So the yield in that async while loop is great (Simon recommended the very same thing on slack). Thanks!

Not sure about that spurious `i` in that async while loop, is that doing anything?

---

<div class="post-metadata">

**Author:** ![smldis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/smldis/32/1735_2.png) [@smldis](https://discourse.julialang.org/u/smldis)\
**Post date:** [July 11, 2019, 4:54pm UTC](https://discourse.julialang.org/t/channel-gets-emptied-and-stays-that-way/26237/12 "2019-07-11T16:54:43Z")

</div>

> [@yakir12](#):
>
> Not sure about that spurious `i` in that async while loop, is that doing anything?

Sorry, delete it, I had a counter there for debugging
