0

I am trying to benchmark the below code and see that the non-threaded version runs faster than the treaded version.

      puts Benchmark.measure{
        100.times do |i|
          carrier.services.map do |service_obj|
            Thread.new {
              rate << Rate.rate_by_service(service_obj,@package,@from,@to,@credentials)
            }
          end.each(&:join)
        end
      }

below are the timings

#threading
4.940000   0.730000   5.670000 (  5.795008)
4.740000   0.740000   5.480000 (  5.554500)
4.740000   0.730000   5.470000 (  5.436129)
4.840000   0.710000   5.550000 (  5.524418)
4.710000   0.720000   5.430000 (  5.431673)

#no threading
3.640000   0.190000   3.830000 (  3.962347)
3.670000   0.220000   3.890000 (  4.402259)
3.430000   0.200000   3.630000 (  3.780768)
3.480000   0.190000   3.670000 (  3.830547)
3.650000   0.210000   3.860000 (  4.065442)

one thing i have observed in the log is when non-threaded version runs, the queries results are returned from cache like below and in threaded version it does not fetch from cache but accessed the DB.

  CACHE (0.0ms)  SELECT 
  CACHE (0.0ms)  SELECT 
  CACHE (0.0ms)  SELECT 
  CACHE (0.0ms)  SELECT  
  CACHE (0.0ms)  SELECT  
  CACHE (0.0ms)  SELECT  
  CACHE (0.0ms)  SELECT 
  CACHE (0.0ms)  SELECT 
  CACHE (0.0ms)  SELECT  
  CACHE (0.0ms)  SELECT  
  CACHE (0.0ms)  SELECT 

Note: I have removed the actual queries for readability purpose.

Can anyone please explain as to what could be causing the threaded version to run a bit slow than non-threaded

opensource-developer
  • 2,826
  • 4
  • 38
  • 88
  • Looks like a [`N+1` problem](https://stackoverflow.com/questions/97197/what-is-n1-select-query-issue). One should prefetch the data needed upfront to prevent different threads reading the same values multiple times. – Aleksei Matiushkin Dec 05 '17 at 13:13

1 Answers1

1
  1. According to Caching with Rails # SQL Caching,

    If Rails encounters the same query again for that request, it will use the cached result set as opposed to running the query against the database again... Query caches are created at the start of an action and destroyed at the end of that action and thus persist only for the duration of the action.

  2. ActiveRecord checks out from the pool one connection per thread.

  3. If your Ruby implementation is MRI, then because of the GVL, CPU works are not in parallel.

So when you run the code in single threaded mode inside an action, the query result is cached. When you run the code in multi-threaded mode, each thread acquires its own database connection, and the query result is not cached, so each thread has to access the database, so it could be slow.

Aetherus
  • 8,720
  • 1
  • 22
  • 36