所以,为了提高我们的应用程序的速度,我正在使用我们的rails应用程序试验多线程。 这是代码:
require 'thwait'
require 'benchmark'
city = Location.find_by_slug("orange-county", :select => "city, state, lat, lng", :limit => 1)
filters = ContractorSearchConditions.new()
image_filter = ImageSearchConditions.new()
filters.lat = city.lat
filters.lon = city.lng
filters.mile_radius = 20
filters.page_size = 15
filters.page = 1
image_filter.page_size = 5
sponsored_filter = filters.dup
sponsored_filter.has_advertised = true
sponsored_filter.page_size = 50
Benchmark.bm do |b|
b.report('with') do
1.times do
cities = Thread.new{
Location.where("lat between ? and ? and lng between ? and ?", city.lat-0.5, city.lat+0.5, city.lng-0.5, city.lng+0.5)
}
images = Thread.new{
Image.search(image_filter)[:hits]
}
sponsored_results_extended = Thread.new{
sponsored_filter.mile_radius = 50
@sponsored_results = Contractor.search( sponsored_filter )
}
results = Thread.new{
Contractor.search( filters )
}
ThreadsWait.all_waits(cities, images, sponsored_results_extended, results)
@cities = cities.value
@images = images.value
@sponsored_results = sponsored_results_extended.value
@results = results.value
end
end
b.report('without') do
1.times do
@cities = Location.where("lat between ? and ? and lng between ? and ?", city.lat-0.5, city.lat+0.5, city.lng-0.5, city.lng+0.5)
@image = Image.search(image_filter)[:hits]
@sponsored_results = Contractor.search( sponsored_filter )
@results = Contractor.search( filters )
end
end
end
Class.search正在我们的ElasticSearch服务器上运行搜索。(负载均衡器后面有3台服务器),其中正在我们的RDS实例中运行活动记录查询。
(一切都在同一个数据中心。)
以下是我们的开发服务器上的输出:
Bob@dev-web01:/usr/local/dev/buildzoom/rails$ script/rails runner script/thread_bm.rb -e development
user system total real
with 0.100000 0.010000 0.110000 ( 0.342238)
without 0.020000 0.000000 0.020000 ( 0.164624)
Nota:如果对线程,互斥,GIL没有任何了解,我的知识非常有限。
答案 0 :(得分:1)
由于线程的创建和管理,“with”块中的开销比“without”块的开销要大得多。当代码是IO绑定时,使用线程将最有帮助,并且看起来并非如此。四次搜索在20ms内完成(没有阻止),这意味着这些搜索应该花费更少的时间。 “with”块需要100ms才能执行,因此我们可以推断出至少80ms的时间不用于搜索。尝试使用较长的查询进行基准测试,以了解结果的不同之处。
请注意,我假设所有搜索都具有相同的延迟,这可能是也可能不是,并且始终执行相同的操作。 “无”块可能会受益于某种查询缓存,因为它在“with”块之后运行。交换基准的顺序时结果会有所不同吗?另外,我忽略了迭代(1.times
)的开销。除非将迭代次数更改为大于1的值,否则应删除它。
答案 1 :(得分:1)
即使您正在使用线程,因此并行执行查询IO,您仍然需要反序列化从查询中返回的任何结果。这使用CPU。 MRI Ruby 2.0.0具有全局解释器锁。这意味着Ruby代码一次只能运行一行,而不是并行运行,而且只能运行在一个CPU核心上。为了反序列化所有结果,CPU必须在不同线程之间多次上下文切换。这比按顺序反序列化每个结果集要多得多。
如果通过等待查询的响应占主导地位,并且它们不会同时返回,那么并行化线程可能会有一个优势。但很难预测到这一点。
您可以尝试使用JRuby或Rubinius。这些都将使用多个内核,因此实际上可以按预期加速代码。