我想在 action 中新建一个线程,跑后台任务。
于是直接Thread.new
加一个block
包裹住我希望后台运行的 code,项目也能够正常运行。
但是我记得之前听了 RubyConf 上有同学分享过,说直接在 Rails 工程里起 Thread 并不好。
我想请教一下大家这样的写法不好在哪里呢?能否举一些例子或者提供些文章参考一下。
我搜索了一下,似乎比较通用的做法是这里使用Resque
或者Sidekiq
起一个后台任务运行起来,刚好 Rails 也提供了ActiveJob
模块统一封装了接口。
我觉得在访问量不作为主要考虑因素的时候,直接起 Thread 也可以接受,毕竟开发成本最低 隐约记得之前看过一片文章说过,新 Thread 会起一个自己的数据库链接,所以你需要在操作完毕后手动关闭它 楼主提到的 RubyConf 上的相关分享,能否贴个链接,我也想看一下😄
手动起 Thread,管理起来困难。比如数据库连接,错误处理,重试机制等都比较难以控制。 你可以选择踩坑,但最终还是会回归到 Rails 提供的最佳实践
如果是异步的后台任务,那么选择 ActiveJob 应该是理所当然的。 如果不想依赖 sidekiq/redis 的话,可以考虑用基于线程池的队列,比如 https://github.com/brandonhilkert/sucker_punch
Thread 目的是并行,而不是异步,不要搞混了,无论你开多少个 Thread,最终请求还是需要等待它们都结束了才能完成,这和异步是不一样的。
此外,Thread 在 Ruby 里面还有你需要知道:
赞同@huacnlee的说法
只要看你的应用场景,如果是做 IO 操作并且访问量又比较小的情况下,我觉得还是可以试一试的。 只是在做这个事情,你得清楚的认识到“一台电脑能开的线程数量是有限的”,并且“你需要手动管理数据库连接”。
感谢 LS 同学们的回复。
@xworm 就是 5 楼@lgn21st同学做的一个分享,不过主要是说WebSocket
的,你可以去 RubyConfChina 的资源集合贴里去看看。
@zlx_star 我的 Thread 里主要是发送一堆 api 请求,并没有对异常做任何处理,失败了估计也就失败了。那如果对这些不处理,暂时不知道有没有什么问题。
@huacnlee 感谢提醒,我的原始需求是:直接在 controller 中返回 action 的结果,例如 render json 字符串,然后再接着发送 api 请求。那这应该算是异步的? 我原先的代码逻辑大概是:
def action
post_api
post_api
render json: "true" # 这样需要等待post api全部发送完成之后才会执行
end
现在修改成这样了:
def action
Thread.new do
post_api
post_api
end
render json: "true" # 改成这样就直接返回了,post api可以在后台慢慢做
end
#10 楼 @thxagain 除非是性能要求极为苛刻的环境,否则 Thread.new 这种方式处理逻辑,你就是在跟底层 API 打交道,里面的坑无数,如何写出线程安全的代码是一个很大的命题,可以用一本书来解释,所以现实世界中真的有这样的书:https://pragprog.com/book/jsthreads/working-with-ruby-threads
我会鼓励你学习线程的基础概念,但是不鼓励你直接跟底层 API 打交道,而是用现成的,封装好的库或者是框架,远比你自己手撸要可靠得多。
说了一大堆,光说了不要自己手动写 Thread.new,就是没人说遇到确实需要并行执行的时候怎么解决…… LZ 可以去看看 parallel 这个 gem
#13 楼 @u1373355650 如果没弄错,楼主只是想异步执行那些 post api 的请求而已,并非想要并行。
手动写 Thread 的问题上面基本也都说了