Julia: Creating local variables on workers in parallel context - parallel-processing

Using DistributedArrays in cases when the worker only needs to store unshared data seems overly complicated. I would like to do
r=remotecall(2,a=Float64[])
remotecall(2,setindex!,a,5,10) #Error
or
r=remotecall(2,zeros,10)
remotecall(2,setindex!,r,5,10) #Error.
I would like to do this for each worker and then access the array in an async context. Perform some computations and then fetch the results. I am not sure of this is possible because of the let behavior of async
Below I have made an simplified example for which I modified the pmap example form the docs. T
times=linspace(0.1,2.0,10) # times in secs representing different difficult computations
sort!(times,rev=true)
np = nprocs()
n = length(times)
#create local variables
for p=1:np
if p != myid() || np == 1
remotecall(p,stack = Float64p[]) #does not work
end
end
#everywhere function fun(s)
mid=myid()
sleep(s)
#s represents some computation save to local stack
push!(stack,s)
end
#asynchronously do the computations
#everywhere i = 1
function nextidx()
global i
idx=i;
i+=1;
return idx;
end
#sync begin
for p=1:np
if p != myid() || np == 1
#async begin
j=1
res=zeros(40);
while true
idx = nextidx()
if idx > n
break
end
remotecall(fun, times[idx])
end
end
end
end
end
# collect the results of the computations
for p=1:np
if p != myid() || np == 1
tmpStack=fetch(p,stack)
#do someting with the results
end
end

By using 'global' when you modify the global variable of the worker (e.g., set by #everywhere a = 3), you may be able to resolve your problem. Check out the example code below.
#everywhere a = 0
remotecall_fetch(2, ()->a) # print 0
#everywhere function change_a(b)
global a
a = b
end
b = 10
remotecall_fetch(2, change_a, b)
remotecall_fetch(2, ()->a) # print 10

Related

How to run two functions simultaneously in julia?

I'm trying to run two functions simultaneously in julia, but I don't know how to do it. Here you can see my code:
function area(side::Float64)
return side*side
end
function f(n::Int64)
mat = zeros(n,n)
for i=1:n
for j=1:n
mat[i,j] = area(rand())
end
end
return mat
end
function g(n::Int64)
mat = zeros(n,n)
for i=1:n
for j=1:n
mat[i,j] = area(rand()*rand())
end
end
return mat
end
s1 = f(10)
s2 = g(10)
hcat(s1,s2)
In Julia 1.3 you can spawn tasks that will get scheduled on different threads using Threads.#spawn:
begin
s1 = Threads.#spawn f(10)
s2 = Threads.#spawn g(10)
s1 = fetch(s1)
s2 = fetch(s2)
end
See the announcement blog post for more info: https://julialang.org/blog/2019/07/multithreading.
Generally, there are different notions of "simultaneous" in parallel computing.
Since you tagged your question as "multiprocessing" let me give you a straightforward multi process solution (which should work for any Julia version >= 0.7). As such, it utilizes Julias built-in Distributed computing tools.
using Distributed
nworkers() < 2 && addprocs(2) # add two worker processes if necessary
#everywhere begin # define your functions on both workers
area(side::Float64) = side*side
function f(n::Int64)
mat = zeros(n,n)
for i=1:n
for j=1:n
mat[i,j] = area(rand())
end
end
return mat
end
function g(n::Int64)
mat = zeros(n,n)
for i=1:n
for j=1:n
mat[i,j] = area(rand()*rand())
end
end
return mat
end
end
# spawn tasks on the two workers (non-blocking)
t1 = #spawn f(10)
t2 = #spawn g(10)
# fetch the results (blocking until workers have finished)
r1 = fetch(t1)
r2 = fetch(t2)
hcat(r1,r2)
For more on how to use Distributed for parallel computing checkout, for example, this part of the Julia documentation or this Jupyter workshop from one of my workshops: Parallel Computing in Julia.

Julia 1.0 UndefVarError - Scope of Variable

I am moving from Julia 0.7 to 1.0. It seems that Julia's rule for the scope of variables changed from 0.7 to 1.0. For example, I want to run a simple loop like this:
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
print(num)
In Julia 0.7 (and in most of other languages), we could expect num = 1 after the loop. However, it will incur UndefVarError: num not defined in Julia 1.0. I know that by using let I can do this
let
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
print(num)
end
It will print out 1. But I do want to get the num = 1 outside the loop and the let block. Some answers suggest putting all code in a let block, but it will incur other problems including UndefVarError while testing line-by-line. Is there any way instead of using let blocking? Thanks!
This is discussed here.
Add global as shown below inside the loop for the num variable.
num = 0
for i = 1:5
if i == 3
global num = num + 1
end
end
print(num)
Running in the Julia 1.0.0 REPL:
julia> num = 0
0
julia> for i = 1:5
if i == 3
global num = num + 1
end
end
julia> print(num)
1
Edit
For anyone coming here new to Julia, the excellent comment made in the answer below by vasja, should be noted:
Just remember that inside a function you won't use global, since the scope rules inside a function are as you would expect:
See that answer for a good example of using a function for the same code without the scoping problem.
Just remember that inside a function you won't use global, since the scope rules inside a function are as you would expect:
function testscope()
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
return num
end
julia> t = testscope()
1
The unexpected behaviour is only in REPL.
More on this here

use different arrays for each workers instead of SharedArrays in Julia

I have a function like this:
#everywhere function bellman_operator!(rbc::RBC)
...
#sync #parallel for i = 1:m
....
for j = 1:n
v_max = -1000.0
...
for l = Next : n
......
if v > vmax
vmax = v
Next = l
else
break
end
end
f_v[j, i] = vmax
f_p[j, i] = k
end
end
end
f_v and f_p are sharedArrays, I want to give different arrays for result of each workers, I saw some sample but I can't fix it.How can I use arrays for result of each workers and finally combine the results instead of using SharedArrays?
Is this what you want?
Example 1. Combining results using +:
a = #parallel (+) for i in 1:1000
rand(10, 10)
end
Example 2. Just collecting the results without combining them:
x = Future[]
for i in 1:1000
push!(x, #spawn rand(10,10))
end
y = fetch.(x)

Why is my Julia shared array code running so slow?

I'm trying to implement Smith-Waterman alignment in parallel using Julia (see: Figure 1 of http://www.cs.virginia.edu/~rl6sf/paper_dump/2011:12:33:22.pdf), but the algorithm is running much slower in Julia than the serial version. I'm using shared arrays to do this and figure I am doing something silly that is making the code run slow. Could someone take a look and see if my code is optimized as possible? The parallel version should run faster than in serial….
The basic concept of it is to compute the anti-diagonal elements of a matrix in parallel from the upper left to lower right corner and to update them. I'm trying to use 32 cores on a shared array machine to do this. I have a SharedArray matrix that I am using to do this and am computing the elements of each anti-diagonal in parallel as shown below. The while loops in the spSW function submit tasks to workers in sync for each anti-diagonal using the helper function shared_get_score(). The main goal of this function is to fill in each element in the shared arrays "matrix" and "path".
function spSW(seq1,seq2,p)
indel = -1
match = 2
seq1 = "^$seq1"
seq2 = "^$seq2"
col = length(seq1)
row = length(seq2)
wl = workers()
matrix,path = shared_initialize_path(seq1,seq2)
for j = 2:col
jcol = j
irow = 2
#sync begin
count = 0
while jcol > 1 && irow < row + 1
#println(j," ",irow," ",jcol)
if seq1[jcol] == seq2[irow]
equal = true
else
equal = false
end
w = wl[(count % p) + 1]
#async remotecall_wait(w,shared_get_score!,matrix,path,equal,indel,match,irow,jcol)
jcol -= 1
irow += 1
count += 1
end
end
end
for i = 3:row
jcol = col
irow = i
#sync begin
count = 0
while irow < row+1 && jcol > 1
#println(j," ",irow," ",jcol)
if seq1[jcol] == seq2[irow]
equal = true
else
equal = false
end
w = wl[(count % p) + 1]
#async remotecall_wait(w,shared_get_score!,matrix,path,equal,indel,match,irow,jcol)
jcol -= 1
irow += 1
count += 1
end
end
end
return matrix,path
end
The other helper functions are:
function shared_initialize_path(seq1,seq2)
col = length(seq1)
row = length(seq2)
matrix = convert(SharedArray,fill(0,(row,col)))
path = convert(SharedArray,fill(0,(row,col)))
return matrix,path
end
#everywhere function shared_get_score!(matrix,path,equal,indel,match,i,j)
pathvalscode = ["-","|","M"]
pathvals = [1,2,3]
scores = []
push!(scores,matrix[i,j-1]+indel)
push!(scores,matrix[i-1,j]+indel)
if equal
push!(scores,matrix[i-1,j-1]+match)
else
push!(scores,matrix[i-1,j-1]+indel)
end
val,ind = findmax(scores)
if val < 0
matrix[i,j] = 0
else
matrix[i,j] = val
end
path[i,j] = pathvals[ind]
end
Does anyone see an obvious way to make this run faster? Right now it's about 10 times slower than the serial version.

Trouble with Return Values

I am taking a lesson on codecademy in which I am currently stuck do not know how to proceed - it is regarding return values.
The instructions are:
Write a method that takes an integer as an argument, and returns that integer times ten. Call times_ten in your code after you define it and print out its return value.
What is given in the script is:
def times_ten(integer)
# your code here
end
# call times_ten here
This is the example it gives but I am having a hard time understanding:
def first_squares(number_of_squares)
squares = []
idx = 0
while idx < number_of_squares
squares.push(idx * idx)
idx = idx + 1
end
return squares
end
puts("How many square numbers do you want?")
number_of_squares = gets.to_i
squares = first_squares(number_of_squares)
idx = 0
while idx < squares.length
puts(squares[idx])
idx = idx + 1
end
Thanks for your help
It should be:
def ten_times(n)
n*10 # you don't have to use 'return' explicitly
end
ten_times(n) -- but put in an actual integer instead of n (or maybe you have to puts or print it, depending on what they want)
Your example is not really related to your outcome.
The example script should be like this:
def ten_times(integer)
# integer * 10 #for implicit return
return integer * 10 #for explicit return
end
print ten_times(any number you want goes in here)
You can run the following code at www.rubyplus.biz:
Implicit return:
def times_ten(integer)
integer * 10
end
p times_ten(1)
Explicit return:
def times_ten(integer)
return integer * 10
end
p times_ten(2)

Resources