gpt4 book ai didi

ruby - Thin 中的用户线程,Heroku 上的 Sinatra 应用程序

转载 作者:数据小太阳 更新时间:2023-10-29 07:18:25 24 4
gpt4 key购买 nike

我有一组特定于我应用程序的每个用户的耗时操作,它们都封装在一个方法中(例如 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

为了找到特定用户应该等待加入的正确线程,我目前使用 ObjectSpace._id2ref(session[:data_thread])

  • 是否足够安全?

详细:

来自 Object#object_id 的官方 Ruby 文档:

object_id → fixnum: Returns an integer identifier for obj. The same number will be returned on all calls to id for a given object, and no two active objects will share an id.

对于 ObjectSpace:

The ObjectSpace module contains a number of routines that interact with the garbage collection facility and allow you to traverse all living objects with an iterator.

  • 第一个引用中的“事件对象”与第二个引用中的“事件对象”是否相同?

让我们假设以下情况:

  1. 用户 A 访问 '/' [现在 A 线程以 object_id a]
  2. 线程 A 已完成 [它不再处于事件状态并且它的 object_id 已释放]
  3. 用户 B 访问 '/' [现在 B 线程以相同的 object_id 启动 a(* 这可能吗?)]
  4. 用户 A 访问 '/calculate' [session[:data_thread]a 所以 ObjectSpace._id2ref(session[:data_thread]) 实际上是B线程。]
  5. 不一致的状态 - 用户 A 正在等待线程 B

    • 这种情况在 Sinatra、Thin、Heroku 中是否可能?

方法二

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

详细:

我在阅读 Sinatra: README 后试过这个.在配置下:

Run once, at startup, in any environment ... You can access those options via settings ...

Scopes and Binding 下,Application/Class Scope:

Every Sinatra application corresponds to a subclass of Sinatra::Base. If you are using the top-level DSL (require 'sinatra'), then this class is Sinatra::Application, otherwise it is the subclass you created explicitly. At class level you have methods like get or before, but you cannot access the request or session objects, as there is only a single application class for all requests.

我正在使用顶级 DSL。

Options created via set are methods at class level ... You can reach the scope object (the class) like this: settings from within the request scope

  • 请记住 @FrederickCheung 在评论和引用 Scopes and Binding 时所说的话,如果我需要一个以上的 dyno/worker(目前这个应用程序只使用一个 dyno),这种方法是否有效?

总结

  • 在 Sinatra 中,我应该如何处理用户及其相应线程所描述的情况,上述示例中的方法是好是坏?

欢迎任何评论或引用。

最佳答案

我不确定这种设计是否有意义。为什么每个用户都需要自己的线程?为什么一个请求会加入另一个请求创建的线程?即使有可能(通过仅使用一个测力计),我认为这也不是做您想做的事情的好方法。

根据问题中对应用程序的描述,您希望在 write_collections 方法完成后运行一些 calculate 方法。那么,为什么 write_collections 方法不能调用一些 calculate 方法呢?或者,为什么不能使用后过滤器或观察器来进行计算?

更一般地说,您似乎混淆了两个独立的功能:

  1. 计算功能
  2. GET/计算

我认为调用calculate 功能应该只有一个触发器。它要么在 write_collections 完成时,要么在用户请求它时 (GET/calculate)。

更通用的解决方案是让计算功能在后台运行,并将结果保存到数据库中。稍后,当用户提出请求时,它就准备好了,可以快速返回。

关于ruby - Thin 中的用户线程,Heroku 上的 Sinatra 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27756416/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com