I have adapted the pmap() implementation to my program to do some scheduling and I have a question about the scope of the variables within the tasks. This is the Julia implementation
function pmap(f, lst)
np = nprocs() # determine the number of processes available
n = length(lst)
results = cell(n)
i = 1
# function to produce the next work item from the queue.
# in this case it's just an index.
nextidx() = (idx=i; i+=1; idx)
#sync begin
for p=1:np
if p != myid() || np == 1
#async begin
while true
idx = nextidx()
if idx > n
break
end
results[idx] = remotecall_fetch(p, f, lst[idx])
end
end
end
end
end
results
end
If i substitute the line idx = nextidx() by idx=x; i=i+1; , each task updates its local copy of the variable i. However the variable i within the function nextidx() is shared by all the tasks. Why is this?
Let me first simplifies the above code:
function test()
i=10
nexti() = (inx=i;i+=1;inx)
#sync begin
#async begin
i=i+10
nexti()
println("value of i in another thread => $i")
end
end
println("value of i in test() => $i")
end
test()
# value of i in another thread => 20
# value of i in test() => 11
We declare nexti() in the same process as i was declared, and i in nexti() refers to the same location, so any changes to i inside nexti() alerts i value in outer scope.
On the other hand #async macro forces the block inside, to run on different process so this block use a copy of i value and any changes inside this block do not alert i value in outer scope.
Related
I want to use a for-loop to implement an iterative method. At the end of the loop I also want to check if max_iter is reached:
function iterative_method()
iter_max = 10
for iter in 1:iter_max
# some computations
# ...
# if converged
# break
# end
end
#assert iter!=iter_max "max iteration = $iter_max reached!"
end
Unfortunately the #assert cannot work as iter is out of scope:
julia> iterative_method()
ERROR: UndefVarError: iter not defined
Question: how to make iter visible outside the for loop block?
The solution is to use outer as described in the official doc: Loops-and-Comprehensions
function iterative_method()
iter_max = 10
local iter # <- declare "iter" variable
for outer iter in 1:iter_max # <- use "outer" keyword
# some computations
# ...
# if converged
# break
# end
end
#assert iter!=iter_max "max iteration = $iter_max reached!"
end
which now works as expected:
julia> iterative_method()
ERROR: AssertionError: max iteration = 10 reached!
However, Julia core devs have expressed regret about adding this feature and will likely remove it in Julia 2.0, so it's probably clearer and simpler to express this with the following slightly more verbose version:
function iterative_method()
iter_max = 10
local iter
for i in 1:iter_max
iter = i
# some computations
# ...
# if converged
# break
# end
end
#assert iter!=iter_max "max iteration = $iter_max reached!"
end
I am trying to write a piece of code where i can move to the next iteration of a loop while inside a method called in the loop.
In sample code, this is what i am trying to do
def my a
if a > 3
next
end
end
x = [1,2,3,4,5,6,7]
for i in x
my i
print i
end
This gives a syntax error.
One way to achieve this is by raising an error and catching it.
def my a
if a > 3
raise "Test"
end
end
x = [1,2,3,4,5,6,7]
for i in x
begin
my i
print i
rescue Exception => e
#do nothing
end
end
But exceptions are expensive. I dont want to return anything from the function or set flag variables in the function because i want to keep the code clean of these flags.
Any ideas?
A Ruby way of having a function affect the caller's flow of control is for the caller to pass the function a block, which the function can then execute (or not):
def my a
yield unless a > 3
end
x = [1,2,3,4,5,6,7]
for i in x
my i do
print i
end
end
# => 123
See also: Blocks and yields in Ruby
I am not fluent in ruby and am having trouble with the following code example. I want to pass the array index to the thread function. When I run this code, all threads print "4". They should instead print "0 1 2 3 4" (in any order).
It seems that the num variable is being shared between all iterations of the loop and passes a reference to the "test" function. The loop finishes before the threads start and num is left equal to 4.
What is going on and how do I get the correct behavior?
NUM_THREADS = 5
def test(num)
puts num.to_s()
end
threads = Array.new(NUM_THREADS)
for i in 0..(NUM_THREADS - 1)
num = i
threads[i] = Thread.new{test(num)}
end
for i in 0..(NUM_THREADS - 1)
threads[i].join
end
Your script does what I would expect in Unix but not in Windows, most likely because the thread instantiation is competing with the for loop for using the num value. I think the reason is that the for loop does not create a closure, so after finishing that loop num is equal to 4:
for i in 0..4
end
puts i
# => 4
To fix it (and write more idiomatic Ruby), you could write something like this:
NUM_THREADS = 5
def test(num)
puts num # to_s is unnecessary
end
# Create an array for each thread that runs test on each index
threads = NUM_THREADS.times.map { |i| Thread.new { test i } }
# Call the join method on each thread
threads.each(&:join)
where i would be local to the map block.
"What is going on?" => The scope of num is the main environment, so it is shared by all threads (The only thing surrounding it is the for keyword, which does not create a scope). The execution of puts in all threads was later than the for loop on i incrementing it to 4. A variable passed to a thread as an argument (such as num below) becomes a block argument, and will not be shared outside of the thread.
NUM_THREADS = 5
threads = Array.new(NUM_THREADS){|i| Thread.new(i){|num| puts num}}.each(&:join)
I'm creating a small prime number program, and am confused about one thing.
I have a function called create_numbers, that generates numbers and passes them to a new function called check_for_primes, which passes only prime numbers to a final function called count_primes. I want to collect each prime into an array in the function count_primes, but for some reason each number is collected as its own array.
Any idea of what I'm doing wrong?
Here is the code:
def create_numbers
nums = 1
while nums < 100
nums = nums + 2
check_for_primes(nums)
end
end
def count_primes(nums)
array = []
array << nums
puts array.inspect
end
def check_for_primes(nums)
(2...nums).each do |i|
if nums%i == 0
nums = false
break
end
end
if nums != false
count_primes(nums)
end
end
create_numbers
Try this:
START = 1
STEP = 2
class Integer
def prime?
return if self < 2
(2...self).each do |i|
return if self % i == 0
end
true
end
end
def create_numbers
num = START
while (num + STEP) < 100
num += STEP
primes << num if num.prime?
end
end
def primes
#primes ||= []
end
create_numbers
p primes
When you want to save the 'state' of something, put it in an instance variable (#var).
It'll be accessible outside of the current function's scope.
Also, try naming your variables differently. For instance, instead of 'nums', in the
create_numbers method, use 'num'. Since the variable is only referencing one number at a
time and not a list of numbers, naming it in the plural will confuse people (me included)...
Hope it helps,
-Luke
each time into count_primes you put a value into array (which should have a better name, btw). Unfortunately, each time it's a new variable called array and since no one outside the function can see that variable it's lost when the function ends. If you want to save the values you've already found you'll need to set some state outside your function.
I can think of 2 quick solutions. One would be to declare your storage at the top of create_numbers and pass it into both functions.
def count_primes(num, arr)
def check_for_primes(nums, arr)
The other would be to set a variable outside all the functions, $array, for example to hold the values.
$array = []
...
$array << num
Since the scope of $array is global (i.e. all functions have access to it) you have access to it from anywhere in the file and can just add things to it in count primes. Note that using globals in this way is generally considered bad style and a more elegant solution would pass parameters and use return values.
In How do I limit the number of replacements when using gsub?, someone suggested the following way to do a limited number of substitutions:
str = 'aaaaaaaaaa'
count = 5
p str.gsub(/a/){if count.zero? then $& else count -= 1; 'x' end}
# => "xxxxxaaaaa"
It works, but the code mixes up how many times to substitute (5) with what the substitution should be ("x" if there should be a substitution, $& otherwise). Is it possible to seperate the two out?
(If it's too hard to seperate the two things out in this scenario, but it can be done in some other scenarios, post that as an answer)
How about just extracting the replacement as an argument and encapsulating the counter by having the block close over it inside a method?
str = "aaaaaaaaaaaaaaa"
def replacements(replacement, limit)
count = limit
lambda { |original| if count.zero? then original else count -= 1; replacement end }
end
p str.gsub(/a/, &replacements("x", 5))
You can make it even more general by using a block for the replacement:
def limit(n, &block)
count = n
lambda do |original|
if count.zero? then original else count -= 1; block.call(original) end
end
end
Now you can do stuff like
p str.gsub(/a/, &limit(5) { "x" })
p str.gsub(/a/, &limit(5, &:upcase))
gsub will call the block exactly as often as the regex matches the string. The only way to prevent that is to call break in the block, however that will also keep gsub from producing a meaningful return value.
So no, unless you call break in the block (which prevents any further code in the yielding method from running and thus prevents the method from returning anything), the number of times a method calls a block is solely determined by the method itself. So if you want gsub to yield only 5 times, the only way to do that is to pass in a regex which only matches the given strings five times.
Why are you using gsub()? By its design, gsub is designed to replace all occurrences of something, so, right off the bat you're fighting it.
Use sub instead:
str = 'aaaaaaaaaa'
count = 5
count.times { str.sub!(/a/, 'x') }
p str
# >> "xxxxxaaaaa"
str = 'mississippi'
2.times { str.sub!(/s/, '5') }
2.times { str.sub!(/s/, 'S') }
2.times { str.sub!(/i/, '1') }
p str
# >> "m1551SSippi"