Reputation: 23
When I run the following code, it runs as expected (that is, it outputs both "endless loop" and "loop in 100"):
@async while true
print("endless loop\n")
end
for i in 1:100
print("loop in 100\n")
end
However, for some reason, when I changed print
to println
, the result was very different
@async while true
println("endless loop")
end
for i in 1:100
println("loop in 100")
end
This code only outputs "loop in 100" a hundred times. Any ideas why?
Actually, println
seems to always impact multithread execution:
## works as expected, prints "loop in 100" 100 times and "endless loop" 3 times in between
@async while true
print("endless loop\n")
end
@sync for i in 1:100
@async print("loop in 100\n")
end
## simply switching to println makes a program that outputs "endless loop" forever
@async while true
println("endless loop")
end
@sync for i in 1:100
@async println("loop in 100")
end
I used println
for debug output but then realised it's unusable for that purposes. Any suggestion why exactly this works the way it works would be very helpful. I'm executing it with Julia 1.6.1 so that I can use automatic thread detection julia -t auto file.jl
.
Upvotes: 2
Views: 338
Reputation: 18943
The println
implementation for julia 1.6.1 includes nested lock
calls:
println(io::IO, xs...) = print(io, xs..., "\n")
function print(io::IO, xs...)
lock(io)
try
for x in xs
print(io, x)
end
finally
unlock(io)
end
return nothing
end
function print(io::IO, x)
lock(io)
try
show(io, x)
finally
unlock(io)
end
return nothing
end
In your simplified example this implementation has a side effect on the order of task scheduling.
Compare test1.jl
using println
:
t = @async for i in 1:3
println("endless loop")
end
for i in 1:3
println("loop in 100")
end
wait(t)
$ julia test1.jl
loop in 100
loop in 100
loop in 100
endless loop
endless loop
endless loop
With test2.jl
using print
:
t = @async for i in 1:3
print("endless loop\n")
end
for i in 1:3
print("loop in 100\n")
end
wait(t)
$ julia test2.jl
loop in 100
endless loop
loop in 100
endless loop
loop in 100
endless loop
Note that the async task should be awaited otherwise the process exits without giving a chance to run the async task.
But the "perturbing" effect of println
on task scheduling disappear
when the tasks block and yield controls to the scheduler, as in real world scenario, simulated intest3.jl
with a sleep
:
t = @async for i in 1:3
println("endless loop")
sleep(1)
end
for i in 1:3
println("loop in 100")
sleep(1)
end
wait(t)
$ julia test3.jl
loop in 100
endless loop
loop in 100
endless loop
loop in 100
endless loop
Upvotes: 1
Reputation: 6086
Clearly println()
behaves differently from print
, and likes to finish before it allows other tasks printing. You could write the \n into the print()
yourself though:
@async while true
print("endless loop\n")
end
for i in 1:100
print("loop in 100\n")
end
if you really need the interleaving between threaded print
s.
Upvotes: 1