Slowing threads

Hi!

I have written a program that simulates three "consoles" that accept
keyboard input and run concurrently. You can type commands which each
run at different speeds without interfering with other commands. It
works but it's complex and I think it can be simpler if I have each
command run in it's own thread - at the moment I don't use threads at
all.

So I have been creating threads to test and playing with priorities.
I'd like to be able to control the speed at which processes run but if
I set a thread to just one priority higher than another, it is
scheduled tens of thousands of times more often.

So:

1. What do the priorities actually mean?
2. If I have to slow one thread just a little, that means messy
sleep() commands on every second line. Is there a way I can call just
parts of a passed-in block?
ie. can I do something similar to this:

def sleeper(&block)
        block.each_command do |c|
              eval(c)
              sleep(0.5)
        end
end

sleeper do
        puts "one"
        puts "two"
        puts "three"
end

If it's too much magic I'll just intersperse with sleep, just thought
there might be a better way.

If you really want this much fine grained control over the thread scheduler it probably means patching ruby itself. OTOH that would probably be cool.

···

On May 10, 2006, at 3:48 PM, Leslie Viljoen wrote:

Hi!

I have written a program that simulates three "consoles" that accept
keyboard input and run concurrently. You can type commands which each
run at different speeds without interfering with other commands. It
works but it's complex and I think it can be simpler if I have each
command run in it's own thread - at the moment I don't use threads at
all.

So I have been creating threads to test and playing with priorities.
I'd like to be able to control the speed at which processes run but if
I set a thread to just one priority higher than another, it is
scheduled tens of thousands of times more often.

So:

1. What do the priorities actually mean?
2. If I have to slow one thread just a little, that means messy
sleep() commands on every second line. Is there a way I can call just
parts of a passed-in block?
ie. can I do something similar to this:

def sleeper(&block)
       block.each_command do |c|
             eval(c)
             sleep(0.5)
       end
end

sleeper do
       puts "one"
       puts "two"
       puts "three"
end

If it's too much magic I'll just intersperse with sleep, just thought
there might be a better way.

It's rarely a good idea to modify the priorities of threads in Unix systems.
Almost all thread-schedulers will never schedule a thread if there is at
least one runnable thread with a higher priority, which explains the results
you describe. Your lower-priority threads will basically only get scheduled
when they're lucky enough to find the highest-priority thread non-runnable.
If you mess with priorities, you also face the risk of priority inversions,
where a high-priority thread requires a resource held by a lower-priority
thread, and they lock each other.

Keep it simple. Sounds like the semantics of your application is to simulate
users working at different rates. There's nothing there that implies a
dependence among the threads. I'd use random sleep intervals.

Insert the following code somewhere in your main thread:

class Thread
   attr_accessor :execution_speed
end

def set_execution_speed(seconds_per_line)
   Thread.current.execution_speed = seconds_per_line
   set_trace_func proc { |event, file, line, id, binding, classname|
     if event == "line" and !Thread.current.execution_speed.nil?
       sleep Thread.current.execution_speed
     end
   }
end

Then, at the beginning of any thread you want slowed down, call the set_execution_speed method. This will limit the rate that each line of code in the thread is executed. You can also modify the method so that it limits based on other criteria such as method calls.

- Jake McArthur

Thanks. I'll probably have a command put together a list of
"micro-tasks" and "execute" each one with a random sleep afterwards.
Not too bad.

Like so:

def command_ls(processorLoad)
  microCommands = << makeReadDiskMicroCommands(10)

  filesText = getFiles.join("\n")
  microCommands = << filesText.makeWritelineMicroCommands

  loop do
    doMicroCommand(microCommands.shift)
    sleep(rand(processorLoad))
    break if microCommands.empty?
  end
end

···

On 5/10/06, Francis Cianfrocca <garbagecat10@gmail.com> wrote:

It's rarely a good idea to modify the priorities of threads in Unix systems.
Almost all thread-schedulers will never schedule a thread if there is at
least one runnable thread with a higher priority, which explains the results
you describe. Your lower-priority threads will basically only get scheduled
when they're lucky enough to find the highest-priority thread non-runnable.
If you mess with priorities, you also face the risk of priority inversions,
where a high-priority thread requires a resource held by a lower-priority
thread, and they lock each other.

Keep it simple. Sounds like the semantics of your application is to simulate
users working at different rates. There's nothing there that implies a
dependence among the threads. I'd use random sleep intervals.

set_trace_proc will make your program run much slower than you expect.

···

On May 11, 2006, at 9:00 AM, Jake McArthur wrote:

Insert the following code somewhere in your main thread:

class Thread
  attr_accessor :execution_speed
end

def set_execution_speed(seconds_per_line)
  Thread.current.execution_speed = seconds_per_line
  set_trace_func proc { |event, file, line, id, binding, classname|
    if event == "line" and !Thread.current.execution_speed.nil?
      sleep Thread.current.execution_speed
    end
  }
end

Then, at the beginning of any thread you want slowed down, call the set_execution_speed method. This will limit the rate that each line of code in the thread is executed. You can also modify the method so that it limits based on other criteria such as method calls.

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Thanks Jake, this is a very cool idea! Pretty sure it won't be fast
enough (this is for a game) - but I have been playing with
set_trace_func quite a bit since your post.

···

On 5/11/06, Jake McArthur <jake.mcarthur@gmail.com> wrote:

Insert the following code somewhere in your main thread:

class Thread
   attr_accessor :execution_speed
end

def set_execution_speed(seconds_per_line)
   Thread.current.execution_speed = seconds_per_line
   set_trace_func proc { |event, file, line, id, binding, classname|
     if event == "line" and !Thread.current.execution_speed.nil?
       sleep Thread.current.execution_speed
     end
   }
end

Then, at the beginning of any thread you want slowed down, call the
set_execution_speed method. This will limit the rate that each line
of code in the thread is executed. You can also modify the method so
that it limits based on other criteria such as method calls.