I'm in the following situation: an algorithm from a library uses some randomness, and usually is very fast but sometimes gets stuck (this is common for SAT solvers, e.g.).
I would like to do the following: start many instances of the task, and keep the result of the first one succeeding, killing the others. In Julia pseudocode:
futures = [#spawn myfunction(mydata)]
while true
i = findnext(isready, futures)
if i != nothing
result = fetch(i)
foreach(kill_task, futures)
break
end
sleep(0.1)
end
but I can't find anything like "kill_task"; Distributed.del_client sounded like a good possibility, but doesn't seem to do that.
As a bonus, it would be nice to avoid the polling (sleeps etc.)
Note that it's not acceptable to modify "myfunction" to ask it to die itself, it has to be killed (since it's in an external library).
Here is a complete code that spawns several worker processes, gets the result from the one that completed sooner and once the result is received all workers get terminated.
I think this code is very useful for many scenarios is scientific computing:
using Distributed
addprocs(4)
#everywhere using Distributed
#everywhere function getSomething()
tt = rand(1:20)
println("working for $tt seconds")
for i in 1:tt
sleep(1.0)
end
println("Finally, I am ready")
return 100+myid()
end
function getFirst(workerf::Function, ws_list::Vector{Int}=workers())
res = Vector{Union{Future,Nothing}}(nothing,length(ws_list))
for i in 1:length(ws_list)
#async begin
res[i] = #spawnat ws_list[i] workerf()
end
end
my_res = nothing
while true
for i in 1:length(ws_list)
if res[i]!=nothing && isready(res[i])
my_res = fetch(res[i])
println(ws_list[i]," is ready!")
break
else
println(ws_list[i]," NOT ready!")
end
end
if my_res != nothing
#sync for i in 1:length(ws_list)
#async interrupt(ws_list[i])
end
break
end
sleep(0.5)
end
println(my_res)
return my_res
end
Now let us give it a spin:
julia> value = getFirst(getSomething);
2 NOT ready!
From worker 4: working for 16 seconds
From worker 2: working for 19 seconds
From worker 5: working for 2 seconds
3 NOT ready!
From worker 3: working for 15 seconds
4 NOT ready!
5 NOT ready!
2 NOT ready!
3 NOT ready!
4 NOT ready!
5 NOT ready!
2 NOT ready!
3 NOT ready!
4 NOT ready!
5 NOT ready!
2 NOT ready!
3 NOT ready!
4 NOT ready!
5 NOT ready!
From worker 5: Finally, I am ready
2 NOT ready!
3 NOT ready!
4 NOT ready!
5 is ready!
Worker 3 terminated.
Worker 2 terminated.
Worker 5 terminated.
Worker 4 terminated.
And let us see the result:
julia> println(value)
105
Related
I've put together a command that it takes a decent length of time for discord to execute:
#bot.command()
async def repeat_timer(ctx, *lines):
for line in lines:
await ctx.send(line)
time = "5s"
await ctx.send(time)
you could send $repeat_timer 1 2 3 4 5 6 7 8 9 10 then it will send each numeral back as a seperate message.
I would like to know the time between the loops begining and the final iteration completing executing. i.e. in the above example the message being 10 being posted to the channel.
The above shows the code i have working so far- but i can't see how you could set the timer to know when the task was complete
There's a ton of ways of doing this, probably the easiest and fastest is using the time.perf_counter function:
import time
#bot.command()
async def repeat_timer(ctx, *lines):
start = time.perf_counter()
for line in lines:
await ctx.send(line)
end = time.perf_counter()
total_time = end - start # In seconds
await ctx.send(total_time)
I am using a loop to wait on a keyboard interrupt and then allow for some clean up operation before exit in a multi threaded environment.
begin
loop {}
rescue Interrupt
p "Ctr-C Pressed..Cleaning Up & Shutting Down"
loop do
break if exit_bool.false?
end
exit 130
end
This piece of code runs in the main thread. There are multiple threads performing several file and DB ops. exit_bool is an atomic var set by other threads to indicate they are in the middle of some operation. I check for the value and wait until it turns false and then exit.
I'm wondering what the cost of loop{} is as opposed to loop{sleep x}.
loop {} results in a high CPU utilization (~100%), whereas loop { sleep x } does not.
Another option is to just sleep forever:
begin
sleep
rescue Interrupt
# ...
end
I use the Spyder IDE. Usually, when I am running non-parallelized scripts, I tend to debug using print statements. Depending on which statements are printed (or not), I can see where errors are occurring.
For example:
print "Started while loop..."
doWhileLoop = False
while doWhileLoop == True:
print "Doing something important!"
time.sleep(5)
print "Finished while loop..."
Above, I am missing a line that changes doWhileLoop to False at some point, so I will be stuck perpetually in the while loop, but my print statements let me see where it is in my code that I have hung up.
However, when running scripts that are parallelized, I get no output to the console until after the process has finished. Normally, what I do in this case is attempt to debug with a single process (i.e. temporarily deparallelize the program by running only one task, for instance), but currently, I am dealing with an error that seems to occur only when I am running more than one task.
So, I am having trouble figuring out what this error is using my usual methods -- how should I change my usual debugging practice in order to efficiently debug scripts employing multiprocessing?
Like #roippi said, debugging parallel things is hard. Another tool is using logging over print. Logging gives you severity, timestamps, and most importantly which process is doing something.
Example code:
import logging, multiprocessing, Queue
def myproc(arg):
return arg*2
def worker(inqueue, outqueue):
mylog = multiprocessing.get_logger()
mylog.info('start')
for job in iter(inqueue.get, 'STOP'):
mylog.info('got %s', job)
try:
outqueue.put( myproc(job), timeout=1 )
except Queue.Full:
mylog.error('queue full!')
mylog.info('done')
def executive(inqueue):
total = 0
mylog = multiprocessing.get_logger()
for num in iter(inqueue.get, 'STOP'):
total += num
mylog.info('got {}\ttotal{}', job, total)
logger = multiprocessing.log_to_stderr(
level=logging.INFO,
)
logger.info('setup')
inqueue, outqueue = multiprocessing.Queue(), multiprocessing.Queue()
if 0: # debug 'queue full!' issues
outqueue = multiprocessing.Queue(maxsize=1)
# prefill with 3 jobs
for num in range(3):
inqueue.put(num)
# signal end of jobs
inqueue.put('STOP')
worker_p = multiprocessing.Process(
target=worker, args=(inqueue, outqueue),
name='worker',
)
worker_p.start()
worker_p.join()
logger.info('done')
Example output:
[INFO/MainProcess] setup
[INFO/worker] child process calling self.run()
[INFO/worker] start
[INFO/worker] got 0
[INFO/worker] got 1
[INFO/worker] got 2
[INFO/worker] done
[INFO/worker] process shutting down
[INFO/worker] process exiting with exitcode 0
[INFO/MainProcess] done
[INFO/MainProcess] process shutting down
I have a problem with synchronizing threads, I have no idea how to do it, can someone help me ?
So, the thing is that I have to launch the threads in some specific order.
The order is the following:
Threads 1 and 7 can go simultaneously, and after one of them is finished, the next thread is launched (i.e. thread 2 or/and thread 6), the same way goes with thread 3 and 5.
And the last one, after both thread 3 and 5 are finished running, goes the last one, thread 4.
This is the code, I had begun with, but I am stuck at the queue implementation somehow.
MUTEX = Mutex.new
high_condition = ConditionVariable.new
low_condition = ConditionVariable.new
threads = []
7.times do |i|
threads << Thread.new{
MUTEX.synchronize {
Thread.current["number"] = i
you_shall_not_pass
}
}
end
threads.map(&:join)
def you_shall_not_pass
order = Thread.current["number"]
end
Use Ruby's Queue as a counting semaphore. It has blocking push and pop operations that you can use to hand out a limited number of tokens to threads, requiring that each thread acquire a token before it runs and release the token when it's finished. If you initialize the queue with 2 tokens, you can ensure only 2 threads run at a time, and you can create your threads in whatever order you like.
require 'thread'
semaphore = Queue.new
2.times { semaphore.push(1) } # Add two concurrency tokens
puts "#{semaphore.size} available tokens"
threads = []
[1, 7, 2, 6, 3, 5, 4].each do |i|
puts "Enqueueing thread #{i}"
threads << Thread.new do
semaphore.pop # Acquire token
puts "#{Time.now} Thread #{i} running. #{semaphore.size} available tokens. #{semaphore.num_waiting} threads waiting."
sleep(rand(10)) # Simulate work
semaphore.push(1) # Release token
end
end
threads.each(&:join)
puts "#{semaphore.size} available tokens"
$ ruby counting_semaphore.rb
2 available tokens
Enqueueing thread 1
Enqueueing thread 7
2015-12-04 08:17:11 -0800 Thread 7 running. 1 available tokens. 0 threads waiting.
2015-12-04 08:17:11 -0800 Thread 1 running. 0 available tokens. 0 threads waiting.
Enqueueing thread 2
Enqueueing thread 6
2015-12-04 08:17:11 -0800 Thread 2 running. 0 available tokens. 0 threads waiting.
Enqueueing thread 3
Enqueueing thread 5
Enqueueing thread 4
2015-12-04 08:17:19 -0800 Thread 6 running. 0 available tokens. 3 threads waiting.
2015-12-04 08:17:19 -0800 Thread 5 running. 0 available tokens. 2 threads waiting.
2015-12-04 08:17:21 -0800 Thread 3 running. 0 available tokens. 1 threads waiting.
2015-12-04 08:17:22 -0800 Thread 4 running. 0 available tokens. 0 threads waiting.
2 available tokens
I have a method 'rate_limited_follow' that takes my Twitter useraccount and follows all the users in an array 'users'. Twitter's got strict rate limits, so the method deals with that contingency by sleeping for 15 minutes and then retrying again. (I didn't write this method, rather got it from the Twitter ruby gem api). You'll notice that it checks to see if the number of attempts are less than the MAX_ATTEMPTS.
My users array has about 400 users that I'm trying to follow. It's adding 15 users at a time (when the rate limits seems to kick in), then sleeping for 15 minutes. Since I set the MAX_ATTEMPTS constant to 3 (just to test it), I expected it to stop trying once it had added 45 users (3 times 15) but it's gone past that, continuing to add 15 users around every fifteen minutes, so it seems as if num_attempts is somehow remaining below 3, even though it's gone through this cycle more than 3 times. Is there something I don't understand about the code? Once 'sleep' is finished and it hits 'retry', where does it start again? Is there some reason num_attempts isn't incrementing?
Calling the method in the loop
>> users.each do |i|
?> rate_limited_follow(myuseraccount, i)
>> end
Method definition with constant
MAX_ATTEMPTS = 3
def rate_limited_follow (account, user)
num_attempts = 0
begin
num_attempts += 1
account.twitter.follow(user)
rescue Twitter::Error::TooManyRequests => error
if num_attempts <= MAX_ATTEMPTS
sleep(15*60) # minutes * 60 seconds
retry
else
raise
end
end
end
Each call to rate_limited_follow resets your number of attempts - or, to rephrase, you are keeping track of attempts per user rather than attempts over your entire array of users.
Hoist num_attempt's initialization out of rate_limited_follow, so that it isn't being reset by each call, and you'll have the behavior that you're looking for.