最近在写点多线程的东西(其实就是一个爬虫)简单说就是把远程数据爬下来以后,然后存进数据库里。因为对多线程的代码不够自信,我都会把爬下来的数据再用单线程爬的数据去比较一下。但我发现 activerecord 的 update_attributes 这个方法好像并不是线程安全的。据我所知 Rails 4 是支持线程安全的了。不知道是我的理解有误还是我的代码在别的地方是非线程安全的。欢迎指正。以下是我的代码
class Business < ActiveRecord::Base
def retrieve_logo
threads = []
[[40, 'logo_url_xs'], [80, 'logo_url_sm'], [160, 'logo_url_md'], [320, 'logo_url_lg']].each do |iter|
threads << Thread.new do
begin
ActiveRecord::Base.connection_pool.with_connection do
logo_response = JSON.parse Net::HTTP.get(URI("https://graph.facebook.com/#{account_uid}?fields=picture.width(#{iter[0]}).height(#{iter[0]})&access_token=#{account_user.access_token}"))
if logo_response['error'].nil?
update_attributes(iter[1] => logo_response['picture']['data']['url'])
end
end
rescue
end
end
end
threads.each(&:join)
end
end
爬虫的代码无非就类似
Business.find_each {|b| b.retrieve_logo }
以上代码,多线程跑的结果总会有几个 business 的 log 是空的。但我用 update_column 却没有问题。当然数据量大的时候才会有几个。 准备要补充的是我用的是 Rails 4.1.8 Ruby 2.1.5 (MRI)