Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running threads inside my rails controller method

I've got a set of data that I'd like to do some calculations on inside my rails application, each calculation is independent of each other so I'd like to thread them so my response is much faster.

Here's what I've got ATM:

def show

  @stats = Stats.new

  Thread.new {
    @stats.top_brands = #RESULT OF FIRST CALCULATION     
  }

  Thread.new {
    @stats.top_retailers = #RESULT OF SECOND CALCULATION
  }

  Thread.new {
    @stats.top_styles = #RESULT OF THIRD CALCULATION
  }

  Thread.new {
     @stats.top_colors = #RESULT OF FOURTH CALCULATION
  }

  render json: @stats
end

Now this returns a bunch of empty arrays for each of the member instances of @stats, however, if I join the threads together, it runs, but defeats the purpose of threading since each of the threads block.

Since I'm very new to threads, I'm wondering what I'm doing wrong here or if its even possible to accomplish what I'm trying do, that is, run 4 calcs in paralell and return the result to the client.

Thanks,

Joe

like image 242
TheDelChop Avatar asked Nov 18 '13 22:11

TheDelChop


People also ask

Is RoR multi-threaded?

It's not a common production platform among the RoR community. As a result, Eventhough Rails itself is thread-safe since version 2.2, there isn't yet a good multi-threaded server for it on Windows servers. And you get the best results by running it on *nix servers using multi-process/single-threaded concurrency model.

Does Ruby support multithreading?

Ruby makes it easy to write multi-threaded programs with the Thread class. Ruby threads are a lightweight and efficient way to achieve concurrency in your code.

What is Rails_max_threads?

RAILS_MAX_THREADS is a way to set the number of threads each of your workers will use under the hood. In the example above, the min_threads_count is equal to the max_threads_count , so the number of threads is constant.

What are threads in rails?

Threads are workers, or units of execution. Every process has at least one thread & you can create more on demand. I know you want to see a code example.


1 Answers

It first depends if your calculations are doing processor heavy operations or are doing a lot blocking IO like reading from databases, the file system or the network. It wouldn't do much good if they're doing the former since each thread is taking up CPU time and no other thread can be scheduled - worse even if you're using Ruby MRI which has a Global Interpreter Lock. If the threads are doing blocking IO however, they can at least wait, let another thread run, wait, let another run and so on until they all return.

At the end you do have to join all the threads together because you want their return values. Do this below all your Thread.new calls. Save the return value of each Thread.new to an array:

threads = []
threads << Thread.new ...

Then join them together before you render:

threads.each &:join

If you want to really be sure this helps you out just benchmark the entire action:

def show
  start_time = Time.now.to_f
  @stats = Stats.new

  Thread.new {
    @stats.top_brands = #RESULT OF FIRST CALCULATION     
  }
  Thread.new {
     @stats.top_colors = #RESULT OF FOURTH CALCULATION
  }

  @elapsed_time = Time.now.to_f - start_time
  # do something with @elapsed_time, like putsing it or rendering it in your response

  render json: @stats
end

Hope that helps.

like image 159
DiegoSalazar Avatar answered Nov 10 '22 23:11

DiegoSalazar