线程安全的Rails控制器操作 – 设置实例变量?

我必须编写一个线程化的Rails应用程序,因为我在Neo4j.rb上运行它,它在Rails进程中嵌入了一个Neo4j图形数据库,因此我必须提供来自同一进程的多个请求。 是的,如果连接到像SQL数据库一样的Neo4j数据库会很酷,但事实并非如此,所以我会放弃抱怨而只是使用它。

我非常担心编写并发代码的含义(我应该这样做),只需要一些关于如何处理常见情况的建议 – 控制器在会话哈希中设置实例变量或变量,然后是一些东西发生。 考虑以下原始代码来certificate我的意思:

# THIS IS NOT REAL PRODUCTION CODE # I don't do this in real life, it is just to help me ask my question, I # know about one-way hashing, etc.! class SessionsController def create user = User.find_by_email_and_password(params[:email], params[:password]) raise 'auth error' unless user session[:current_user_id] = user.id redirect_to :controller => 'current_user', :action => 'show' end end class CurrentUserController def show @current_user = User.find(session[:current_user_id]) render :action => :show # .html.erb file that uses @current_user end end 

问题:此代码中是否存在任何竞争条件?

在SessionsController中,是session散列和params散列线程本地吗? 假设同一个浏览器会话使用不同的凭据对/ sessions #crera(借用Rails路由语法)发出多个请求,登录的用户应该是命中行session[:current_user_id] = user.id的请求session[:current_user_id] = user.id last? 或者我应该在控制器操作周围包装一个互斥锁吗?

在CurrentUserController中,如果两个具有不同会话的请求同时命中了show动作,那么两个都会设置相同的@current_user变量吗? 即第一个请求,因为它正在处理.html.erb文件,发现它的@current_user实例变量突然被第二个线程更改了?

谢谢

每个请求都会获得一个控制器的新实例 。 因此,控制器实例变量是线程安全的。 paramssession也由控制器实例变量(或请求对象本身)支持,因此也是安全的。

重要的是要知道线程之间共享什么,什么不共享。

现在回到你的具体例子。 两个请求同时命中了CurrentUserController#show ,因此它们由两个并发线程处理。 这里的关键是每个线程都有自己的CurrentUserController实例,因此有两个@current_user变量不会干扰。 因此@current_user没有竞争条件。

竞争条件的一个例子是:

 class ApplicationController < ActionController::Base before_each :set_current_user cattr_accessor :current_user def set_current_user self.class.current_user = User.find_by_id(session[:current_user_id]) end end # model class LogMessage < ActiveRecord::Base belongs_to :user def self.log_action(attrs) log_message = new(attrs) log_message.user = ApplicationController.current_user log_message.save end end 

更一般地说,由于GIL(Global Interpreter Lock)在MRI中使用线程的好处,ruby相当有限。 有实施,没有GIL(jruby)。