Two question on Channel operation

Qestion1:
Because the max size of chnl is 0, the following code should be blocked. Why the following code is not blocked?

chnl = Channel() do ch
    foreach(i -> put!(ch, i), 1:4)   # not blocked
end;

The following is blocked.

chnl = Channel() 
foreach(i -> put!(ch, i), 1:4)    # blocked here

Question 2:
The following result is not as expected.

function take_channel(c)
    d = take!(c)   
    println("get data: ", d)
    p()
end

function p()
    println("I am here")
end

c = Channel{Int64}(0)
@async take_channel(c)  # 
put!(c, 1)

@async take_channel(c)
put!(c, 2)

The output is

get data: 1 #why `get data 2` is not printed, and no `I am here`
    Testing LDTSimulate tests passed

If I put the code in @testset the result looks as expected,

function take_channel(c)
    d = take!(c)   
    println("get data: ", d)
    p()
end

function p()
    println("I am here")
end

@testset "test channel" begin
    c = Channel{Int64}(0)
    @async take_channel(c)  # 
    put!(c, 1)

    @async take_channel(c)
    put!(c, 2)
end

The results are as expected.

get data: 1
Test Summary: |I am here

get data: 2
I am here
test channel  | No tests
    Testing LDTSimulate tests passed 
chnl = Channel() do ch
    foreach(i -> put!(ch, i), 1:4) 
end

The inner function is blocked, but it’s scheduled asynchronously, so it doesn’t block the main thread. Basically that is similar to doing:

chnl = Channel() 
@async foreach(i -> put!(ch, i), 1:4)

Issue 2 is has to do with scheduling and REPL. I believe if you do:

@sync begin
    c = Channel{Int64}(0)
    @async take_channel(c)  # 
    put!(c, 1)
end

The @sync will cause the execution to pause and allow the @async task to finish. My guess is that the println() is giving up control which allows the REPL to execute again. You might also be able to do a sleep(1) after you do the put!(c, 1) which should give the async task time to finish.

2 Likes

note the Channel() constructor which is similar to Channel(0) creates an unbuffered channel i.e put! blocks until a matching take! is called. And vice-versa.
For me the question 2 works just fine.

function take_channel(c)
    d = take!(c)   
    println("get data: ", d)
    p()
end

function p()
    println("I am here")
end

c = Channel{Int64}(0)
@async take_channel(c)  # 
put!(c, 1);

@async take_channel(c)
put!(c, 2);

And i get the expected output.

Thank you so much for your answer. The code you suggested works as expected. I am surprised that the default REPL does not run as @sync. But it also does not run as @async. There should be some different behaviour not described in the document.

@sync begin
    c = Channel{Int64}(0)
    @async take_channel(c)  # 
    put!(c, 1)
end

I found a very clear explanation, much clearer than the document. Hope it could help other users.
When to use @sync and @async