fok*_*oki 5 ruby multithreading heroku sinatra
我有一组耗时的操作,这些操作特定于我的应用程序的每个用户,它都被封装在一个方法(例如write_collections方法)中.在这个方法中,程序与Facebook和MongoDB进行通信.我想在每个用户的线程中运行此方法.
在get '/'Sinatra路由中调用此线程,但仅需要线程(数据库中的状态)的结果get '/calculate'.我的想法是运行线程get '/'并加入它get '/calculate'以确保在计算用户启动结果之前,所有用户的数据都已在数据库中正确写入.
为了显示:
get "/" do
@user = @graph.get_object("me")
data_thread = Thread.new do
write_collections(@user)
end
session[:data_thread] = data_thread.object_id
erb :index
end
get "/calculate" do
begin
# Is this safe enough?
if ObjectSpace._id2ref(session[:data_thread]).alive?
data_thread = ObjectSpace._id2ref(session[:data_thread])
data_thread.join
end
rescue RangeError => range_err
# session[:data_thread] is not id value
# direct access to /calculate without session
rescue TypeError => type_err
# session[:data_thread] is nil
end
# do calculations based on state in database
# and show results to user
"<p>Under construction</p>"
end
Run Code Online (Sandbox Code Playgroud)
要找到特定用户应该等待加入的正确线程,我当前正在使用ObjectSpace._id2ref(session[:data_thread]).
从官方Ruby文档Object#object_id:
object_id→fixnum:返回obj的整数标识符.对于给定对象的所有id调用都将返回相同的数字,并且没有两个活动对象将共享id.
并为ObjectSpace:
ObjectSpace模块包含许多与垃圾收集工具交互的例程,允许您使用迭代器遍历所有活动对象.
我们假设以下情况:
'/'[现在一个线程以object_id a启动]object_id被释放]'/'[现在B线程以相同的object_id a启动(*可能吗?)]'/calculate'[ session[:data_thread]是一个这样ObjectSpace._id2ref(session[:data_thread])实际上是乙线程.]不一致的状态-用户一个等待线程乙.
configure do
# map user_id to corresponding user's thread
data_threads_hash = {}
set :data_threads_hash, data_threads_hash
end
get "/" do
@user = @graph.get_object("me")
data_thread = Thread.new do
write_collections(@user)
end
session[:user_id] = @user['id']
settings.data_threads_hash[session[:user_id]] = data_thread
erb :index
end
get "/calculate" do
if settings.data_threads_hash[session[:user_id]].alive?
data_thread = settings.data_threads_hash[session[:user_id]]
data_thread.join
settings.data_threads_hash.delete session[:user_id]
end
# do calculations based on state in database
# and show results to user
"<p>Under construction</p>"
end
Run Code Online (Sandbox Code Playgroud)
在启动时,在任何环境中运行一次......您可以通过设置访问这些选项...
在Scopes和Binding,Application/Class Scope下:
每个Sinatra应用程序都对应于Sinatra :: Base的子类.如果您使用顶级DSL(需要'sinatra'),那么这个类是Sinatra :: Application,否则它是您明确创建的子类.在类级别,您有get或之前的方法,但您无法访问请求或会话对象,因为所有请求只有一个应用程序类.
我正在使用顶级DSL.
通过set创建的选项是类级别的方法...您可以像这样访问范围对象(类):来自请求范围内的设置
欢迎任何评论或参考.
我不确定这个设计是否有意义。为什么每个用户需要自己的线程?为什么一个请求会加入另一个请求创建的线程?即使这是可能的(仅使用一个测功机),我也不认为这是做你想做的事情的好方法。
根据问题中应用程序的描述,您希望在方法完成calculate后运行某些方法write_collections。那么,为什么该方法不能write_collections调用某些calculate方法呢?或者,为什么不能使用后过滤器或观察器来进行计算?
更一般地说,您似乎混淆了两个单独的功能:
calculate性GET /calculate我认为应该只有一个触发器来调用该calculate功能。它是在完成时write_collections 或在用户请求时 ( GET /calculate)。
更通用的解决方案是让该calculate功能在后台运行,并将结果保存到数据库中。稍后,当用户发出请求时,它就准备好了并且可以快速返回。
| 归档时间: |
|
| 查看次数: |
248 次 |
| 最近记录: |