将 Ruby 线程的结果作为参数传递给方法
Pass the result of a Ruby Thread as a parameter to a method
我有这些控制器方法
def student_progress_variables(student_email)
dashboard = Dashboard.new
@projects = Thread.new { dashboard.obtain_projects }
@current_student = obtain_student_with_email(student_email)
@reviews = obtain_selected_student_project_reviews(@current_student)
@requests = obtain_student_code_review_requests(@current_student).sort_by do |request|
request[obtain_code_review_requests_id]
end
@review_completions = obtain_student_code_review_completions(@current_student)
@courses = obtain_projects_courses(@projects.join)
end
我想将@projects 的响应传递给@courses 方法调用,但我一直收到此undefined method 'each' for #<Thread:0x00007f30dc83da10>
错误。我已阅读文档但无法取得任何进展。有什么想法吗?
编辑:我采纳了@max pleaner 的建议。这是代码段的当前状态。我已经看到更好的结果:
def student_progress_variables(student_email)
thread1 = Thread.new do
@current_student = obtain_student_with_email(student_email)
end
thread2 = Thread.new do
dashboard = Dashboard.new
@projects = dashboard.obtain_projects
@courses = obtain_projects_courses(@projects)
end
thread1.join
thread3 = Thread.new do
@reviews = obtain_selected_student_project_reviews(@current_student)
end
@requests = obtain_student_code_review_requests(@current_student).sort_by do |request|
request[obtain_code_review_requests_id]
end
@review_completions = obtain_student_code_review_completions(@current_student)
thread2.join
thread3.join
end
线程没有 return 值(Thread 对象本身除外)。
这在 javascript 中是一个非常普遍的问题,您在其中使用许多异步函数(例如 setTimeout),这些函数不会像同步函数那样生成 return 值。
Javascript 通常用来处理这个问题的是回调(以及 promises/async/await)。您可以在 ruby 中以块的形式使用回调:
class AsyncClass
attr_reader :foo, :bar
def async_method(&callback)
Thread.new do
@foo = 1
@bar = @foo + 1
callback.call(self)
end
end
end
虽然您可以在任何线程上调用 join
来暂停代码执行直到它完成,但这种方式完全消除了使用线程的目的(除非您正在进行并行处理)。因此,任何调用 async_method
的方法本身都需要是异步的。
这不适用于同步的控制器操作(除非您使用的是流式响应或服务器推送,但我假设您不是)。
这是一种 'law' 的异步代码,您不能从同步函数调用异步函数,并在不调用 join
的情况下获取 'return value'(并强制它运行 同步)。所以每当你想要一个异步函数的'return value',你需要使调用函数异步,并使用block/callback来读取结果。请注意,这个烦人的过程有时在 javascript 中称为 'callback hell',这就是为什么他们实施 promises/async/await(顺便说一下,ruby-concurrency gem).
但是,假设您从另一个 async 方法调用此方法:
class OtherClass
def initialize
AsyncClass.new.async_method do |async_class_inst|
puts async_class_inst.bar
end
sleep 1
end
end
OtherClass.new
# prints 2
在你的情况下它看起来像这样:
def student_progress_variables(student_email, &blk)
dashboard = Dashboard.new
Thread.new do
@projects = dashboard.obtain_projects
@current_student = obtain_student_with_email(student_email)
@reviews = obtain_selected_student_project_reviews(@current_student)
@requests = obtain_student_code_review_requests(@current_student).sort_by do |request|
request[obtain_code_review_requests_id]
end
@review_completions = obtain_student_code_review_completions(@current_student)
@courses = obtain_projects_courses(@projects.join)
blk.call(self)
end
end
但是,同样,您只能从另一个异步方法调用它:
class AsyncCaller
def initialize(&callback)
SomeClass.new.student_progress_variables("student@email.com") do |some_class_inst|
callback.call(self, some_class_inst)
end
sleep 1
end
end
AsyncCaller.new do |async_caller_inst, some_class_inst|
# .... do things here, thread is done
end
请注意,在这些示例中,我将 self
传递给回调,以便将其分配给块变量(例如 async_class_inst
)。这是因为 self
的值会根据调用块的位置而变化,如您在本例中所见:
class A
def initialize(&blk)
blk.call
sleep 1
end
end
A.new { puts self }
# prints 'main'
因此,如果您要在线程中对 self
进行一些操作(就像您一样,通过设置实例变量),最好将 self
显式传递给 callback/block,因此您不必假设调用者可以访问它。
此外,请不要在您的代码中实际放置 sleep
调用,我只使用这些,所以如果您 运行 将代码片段作为脚本,它将起作用。在实际代码中,如果要等到线程完成,则应使用 Thread#join
。
重申一下,如果您希望及时获得结果以包含在响应中,则不应在控制器操作中使用线程(除非您使用 .join
最后)。
我有这些控制器方法
def student_progress_variables(student_email)
dashboard = Dashboard.new
@projects = Thread.new { dashboard.obtain_projects }
@current_student = obtain_student_with_email(student_email)
@reviews = obtain_selected_student_project_reviews(@current_student)
@requests = obtain_student_code_review_requests(@current_student).sort_by do |request|
request[obtain_code_review_requests_id]
end
@review_completions = obtain_student_code_review_completions(@current_student)
@courses = obtain_projects_courses(@projects.join)
end
我想将@projects 的响应传递给@courses 方法调用,但我一直收到此undefined method 'each' for #<Thread:0x00007f30dc83da10>
错误。我已阅读文档但无法取得任何进展。有什么想法吗?
编辑:我采纳了@max pleaner 的建议。这是代码段的当前状态。我已经看到更好的结果:
def student_progress_variables(student_email)
thread1 = Thread.new do
@current_student = obtain_student_with_email(student_email)
end
thread2 = Thread.new do
dashboard = Dashboard.new
@projects = dashboard.obtain_projects
@courses = obtain_projects_courses(@projects)
end
thread1.join
thread3 = Thread.new do
@reviews = obtain_selected_student_project_reviews(@current_student)
end
@requests = obtain_student_code_review_requests(@current_student).sort_by do |request|
request[obtain_code_review_requests_id]
end
@review_completions = obtain_student_code_review_completions(@current_student)
thread2.join
thread3.join
end
线程没有 return 值(Thread 对象本身除外)。
这在 javascript 中是一个非常普遍的问题,您在其中使用许多异步函数(例如 setTimeout),这些函数不会像同步函数那样生成 return 值。
Javascript 通常用来处理这个问题的是回调(以及 promises/async/await)。您可以在 ruby 中以块的形式使用回调:
class AsyncClass
attr_reader :foo, :bar
def async_method(&callback)
Thread.new do
@foo = 1
@bar = @foo + 1
callback.call(self)
end
end
end
虽然您可以在任何线程上调用 join
来暂停代码执行直到它完成,但这种方式完全消除了使用线程的目的(除非您正在进行并行处理)。因此,任何调用 async_method
的方法本身都需要是异步的。
这不适用于同步的控制器操作(除非您使用的是流式响应或服务器推送,但我假设您不是)。
这是一种 'law' 的异步代码,您不能从同步函数调用异步函数,并在不调用 join
的情况下获取 'return value'(并强制它运行 同步)。所以每当你想要一个异步函数的'return value',你需要使调用函数异步,并使用block/callback来读取结果。请注意,这个烦人的过程有时在 javascript 中称为 'callback hell',这就是为什么他们实施 promises/async/await(顺便说一下,ruby-concurrency gem).
但是,假设您从另一个 async 方法调用此方法:
class OtherClass
def initialize
AsyncClass.new.async_method do |async_class_inst|
puts async_class_inst.bar
end
sleep 1
end
end
OtherClass.new
# prints 2
在你的情况下它看起来像这样:
def student_progress_variables(student_email, &blk)
dashboard = Dashboard.new
Thread.new do
@projects = dashboard.obtain_projects
@current_student = obtain_student_with_email(student_email)
@reviews = obtain_selected_student_project_reviews(@current_student)
@requests = obtain_student_code_review_requests(@current_student).sort_by do |request|
request[obtain_code_review_requests_id]
end
@review_completions = obtain_student_code_review_completions(@current_student)
@courses = obtain_projects_courses(@projects.join)
blk.call(self)
end
end
但是,同样,您只能从另一个异步方法调用它:
class AsyncCaller
def initialize(&callback)
SomeClass.new.student_progress_variables("student@email.com") do |some_class_inst|
callback.call(self, some_class_inst)
end
sleep 1
end
end
AsyncCaller.new do |async_caller_inst, some_class_inst|
# .... do things here, thread is done
end
请注意,在这些示例中,我将 self
传递给回调,以便将其分配给块变量(例如 async_class_inst
)。这是因为 self
的值会根据调用块的位置而变化,如您在本例中所见:
class A
def initialize(&blk)
blk.call
sleep 1
end
end
A.new { puts self }
# prints 'main'
因此,如果您要在线程中对 self
进行一些操作(就像您一样,通过设置实例变量),最好将 self
显式传递给 callback/block,因此您不必假设调用者可以访问它。
此外,请不要在您的代码中实际放置 sleep
调用,我只使用这些,所以如果您 运行 将代码片段作为脚本,它将起作用。在实际代码中,如果要等到线程完成,则应使用 Thread#join
。
重申一下,如果您希望及时获得结果以包含在响应中,则不应在控制器操作中使用线程(除非您使用 .join
最后)。