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.
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
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 prints.
Related
In Julia, I am trying out different parallelization libraries, to make my program more performant, and to check if memory consumption is the same as with no parallelization. The unfortunate effect of this is a lot of duplication.
Is there a way to organize my code so that I write the algorithm only once and then some macro with a parameter decides how the code is parallelized? My question is similar to this one. For example, my MWE
using ThreadsX, Folds, FLoops, Polyester
create_data = (n,s) -> [rand(1:n,r) for j=1:n for r∈[rand(1:s)]]
function F!(method ::Int, L ::Vector{Vector{Int}}) ::Nothing
n = length(L)
if method==0 for j=1:n sort!(L[j]) end end
if method==1 Threads.#threads for j=1:n sort!(L[j]) end end
if method==2 ThreadsX.foreach(1:n) do j sort!(L[j]) end end
if method==3 Folds.foreach(1:n) do j sort!(L[j]) end end
if method==4 FLoops.#floop for j=1:n sort!(L[j]) end end
if method==5 Polyester.#batch for j=1:n sort!(L[j]) end end
return nothing end
for mtd=0:5
L = create_data(10^6,10^3);
#time F!(mtd,L) end
returns
17.967120 seconds
4.537954 seconds (38 allocations: 3.219 KiB)
4.418978 seconds (353 allocations: 27.875 KiB)
5.583201 seconds (54 allocations: 3.875 KiB)
5.542852 seconds (53 allocations: 3.844 KiB)
4.263488 seconds (3 allocations: 80 bytes)
so there are different performances already for a very simple problem.
In my actual case, instead of sort!(L[j]) I have lots of intensive code with several Arrays, Vector{Vector}s, Dicts, ..., where different threads read from occasionally the same place, but write to different places, allocate space in memory, mutate the input, etc. Is there a way to create a new macro #Parallel so that my code would be just
function F!(method ::Int, L ::Vector{Vector{Int}}) ::Nothing
n = length(L)
#Parallel(method) for j=1:n sort!(L[j]) end
return nothing end
Note that I have never created a macro, I only used them thus far, so some explanation would be welcome.
A macro-based solution is possible, but seems unnecessary to me. I'd rather organize code like this:
function testfun!(x::Vector{Int})
# here goes the repetitive part
return sort!(x)
end
# entry point for dispatch, and set up data
function F(kernel!, M, N, strategy::Symbol)
L = create_data(M, N)
return F!(kernel!, L, Val{strategy}())
end
# and a function to run the loop for every strategy
function F!(kernel!, L, ::Val{:baseline})
n = length(L)
for j=1:n kernel!(L[j]) end
end
function F!(kernel!, L, ::Val{:Threads})
n = length(L)
Threads.#threads for j=1:n kernel!(L[j]) end
end
function F!(kernel!, L, ::Val{:ThreadsX})
n = length(L)
ThreadsX.foreach(1:n) do j kernel!(L[j]) end
end
# ...
# + rest of the loop functions for Floops, Folds, etc.
function dotests()
for strategy = (:baseline, :Threads, :ThreadsX, ...)
#benchmark F(testfun!, 10^6, 10^3, strategy)
end
end
This is showing a dispatch-based approach. You could equally well use dictionaries or conditions. The important point is separating the "runner" F! from the "kernel" function.
This is a matlab code that uses guide to run a timer. The timer function counts 10 numbers starting from the number provided in the text field. I would like to know how to enter two numbers successively and make matlab counts 10 numbers for both values in parallel.
let's say I entered 0 then I pressed the start button, then I immediately entered 10 and pressed the start button again. what happens now is that it counts only from 0 to 10. I would appreciate if you can share a way to make my code count from 0 to 10 and from 10 to 20 simultaneously in parallel.
guide code :
function startbutton_Callback(hObject, eventdata, handles)
t=timer;
t.TimerFcn = #counter;
t.Period = 15;
t.ExecutionMode = 'fixedRate';
t.TasksToExecute = 1;
start(t);
stop (t);
delete (t);
timer callback function:
function counter(~,~)
handles = guidata(counterFig);
num = str2double(get(handles.edit1,'String'));
for i = 0:10
disp (num);
num = num+1;
pause (1);
end
you can use parrallel toolbox for real parallel computation.
but if you dont have that , you can create another timer object that count from 10 to 20
and run it
I am writing a script that is creating multiple plots and movies from a very big bunch of data. However, sometimes I don't need the whole analysis and I want to limit myself to parts of the analysis. Just to know,
Is there a way to return, break, cycle, or stop on gnuplot?
The exit statement is straightforward and can be used anywhere in the code.
#!/bin/bash
nmin = 1
nmax = 10
nmiddle = (nmin + nmax)/2
isexit = 0
print "---------------------------------"
print "--------- REGULAR OUTPUTS -------"
do for[i=nmin:nmax]{
print sprintf("Running No %4d", i)
}
# if (isexit==1){
# print "here"
# exit
# }
print ""
print "---------------------------------"
print "--------- EXIT OUTPUTS -------"
do for[i=nmin:nmax]{
print sprintf("Running No %4d", i);
if (i == nmiddle){
exit
}
}
For break and continue, it seems they are new features on GNUPLOT 5.2 and above as you can see in Page 21 (see memo), and are explained on page 71 and 73 (see memo).
I have GNUPLOT 5.0 right now. I will just have to upgrade it to version 5.2 and that's it.
Thanks Ethan and EWCZ.
I am implementing a program for feature selection in large academic documents. The first step is to read each file, generate grams and do some pre-computation. I used multiprocessing.pool to make program run faster. Here is my codes of this part:
#number of process
processNum = 4
pool_precompute = mp.Pool(processes = processNum)
fileNum = len(filelist)
offset = fileNum // processNum
ProcessList = []
for i in range(processNum):
if (i == processNum - 1):
start = i * offset
end = fileNum
else:
start = i * offset
end = start + offset
#call the function
print (start, end, i)
ProcessList.append(pool_precompute.apply_async(get_kgrams_df_pmi, args = (start, end, filelist, i)))
#pool_precompute.apply_async(get_kgrams_df_pmi, args = (start, end, filelist, i))
pool_precompute.close()
pool_precompute.join()
My program must wait all the created processes to finish and then go on to the next steps. However, although I used join(), my program can not hang on at all, it seems that the join() function does not have any effect. Note that each process handle some amount of the file, they do not need to communicate with each other and they do not share any variables, there is a return value of get_kgrams_df_pmi, it is an integer computed in the function (the number of words in the document corpus). I would appreciate if anyone can find out the problem.
Just because that there is errors in my function called by the multiprocess pool, they stopped and did not print error information.
I need the macro to loop if one of the criteria is not met. Working with some basic scraping. I need this to loop until ready before I start gathering data.
If ie.document.getElementsByClassName("clicks").Length < 1 Or ie.document.getElementsByClassName("feedback").Length < 1 Then
Do: Loop
End If
I think it would look like this :
Do While ie.document.getElementsByClassName("clicks").Length >= 1 And ie.document.getElementsByClassName("feedback").Length >= 1
'''code
Loop
Your loop does not check with each iteration, only once and if it is not ready then it will enter an infinite loop. You need a solution that checks each time the loop iterates.
Do
If ie.document.getElementsByClassName("clicks").Length < 1 Or ie.document.getElementsByClassName("feedback").Length < 1 Then
DoEvents 'free the processor to work on other things
Else
Exit Do
End If
Loop
This will check each time the loop iterates rather than just once.