Async hangs with continue

I have a function that listens to a redis stream in a while loop but it hangs and doesnt release back to the REPL. I managed to create a MWE.

function foo()
    i = 0
    while true
        if i==0
            continue   # hangs
            #nothing # doesnt hang
        end
        println(i)
        sleep(5)
        i = i+1
   end
end

@async foo() # this hangs

In your example, i is always 0, so the branch with continue is always hit. If you want your code to yield to some other asynchronous code, explicitly call yield().

Also, how many threads are you starting julia with and what version are you running? On some older versions, the REPL didn’t run on its own thread by default, so if another task hogs the sole thread without yielding, it’ll never regain control by itself.

1 Like

In other words, your code is stuck looping these lines indefinitely, you never reach the sleep that goes back to the task queue. You probably intended the i = i+1 to happen earlier, maybe at the very beginning of the while true loop (you sure you want that to go on forever though?).

The expected behavior would be that the function foo would just get put into a task and move on, freeing up the REPL.

I run into the same issue if I do

julia> function foo()
       i = 0
       while true
           i += 1
       end
       end
foo (generic function with 1 method)

julia> @async foo() #hangs

Your REPL is freed, it just yields to the scheduler when idle and ends up running your task, which has nothing in the loop or the method that would yield back to the scheduler.

foo() is getting put into a task, but it runs on the main thread, and it’s fast enough to use the thread’s whole resources, which starves the thread for the REPL. If you use something like

function foo()
       i = 0
       while true
           sleep(.1)
       end
       end

then you’ll see control returned to the REPL as promised.

Julia uses cooperative scheduling, so by default you’re not going to see anything interrupt foo() if it continuously has work to do.

You could start it on another thread:

Threads.@spawn foo()

Or use an explicit yield() (the task will still keep working whenever there’s nothing else to do):

function yielding_foo()
    i = 0
    while true
        i = i + 1
        yield()
    end
end

@async yielding_foo()
2 Likes