新手问题 在 Rails 的 action 中新建 Thread

thxagain · 2016年01月26日 · 最后由 huacnlee 回复于 2016年01月27日 · 3322 次阅读

我想在 action 中新建一个线程,跑后台任务。

于是直接Thread.new加一个block包裹住我希望后台运行的 code,项目也能够正常运行。

但是我记得之前听了 RubyConf 上有同学分享过,说直接在 Rails 工程里起 Thread 并不好。

我想请教一下大家这样的写法不好在哪里呢?能否举一些例子或者提供些文章参考一下。

我搜索了一下,似乎比较通用的做法是这里使用Resque或者Sidekiq起一个后台任务运行起来,刚好 Rails 也提供了ActiveJob模块统一封装了接口。

不弄个队列的话,有人恶作剧疯狂刷你那个 action 不完蛋了……

开一个线程不是一个很"轻量"的操作

我觉得在访问量不作为主要考虑因素的时候,直接起 Thread 也可以接受,毕竟开发成本最低 隐约记得之前看过一片文章说过,新 Thread 会起一个自己的数据库链接,所以你需要在操作完毕后手动关闭它 楼主提到的 RubyConf 上的相关分享,能否贴个链接,我也想看一下😄

手动起 Thread,管理起来困难。比如数据库连接,错误处理,重试机制等都比较难以控制。 你可以选择踩坑,但最终还是会回归到 Rails 提供的最佳实践

如果是异步的后台任务,那么选择 ActiveJob 应该是理所当然的。 如果不想依赖 sidekiq/redis 的话,可以考虑用基于线程池的队列,比如 https://github.com/brandonhilkert/sucker_punch

赞同@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

业务代码中不该出现 Thread 这种底层调用,为未来埋下一堆 bug。

@xiaoronglv 可能会有什么 bug 呢,能具体说说或者举个例子么?我也是第一次用Thread.new的这种方式

#10 楼 @thxagain 除非是性能要求极为苛刻的环境,否则 Thread.new 这种方式处理逻辑,你就是在跟底层 API 打交道,里面的坑无数,如何写出线程安全的代码是一个很大的命题,可以用一本书来解释,所以现实世界中真的有这样的书:https://pragprog.com/book/jsthreads/working-with-ruby-threads

我会鼓励你学习线程的基础概念,但是不鼓励你直接跟底层 API 打交道,而是用现成的,封装好的库或者是框架,远比你自己手撸要可靠得多。

#11 楼 @lgn21st 正好看过这本小书,内容远比想象中多

说了一大堆,光说了不要自己手动写 Thread.new,就是没人说遇到确实需要并行执行的时候怎么解决…… LZ 可以去看看 parallel 这个 gem

@lgn21st 好的 谢谢啦 周末我来先看看 Ruby 线程的基础概念

#13 楼 @u1373355650 如果没弄错,楼主只是想异步执行那些 post api 的请求而已,并非想要并行。

手动写 Thread 的问题上面基本也都说了

  1. Thread.new 成本不低,大量请求这个 action 会有问题
  2. 异常之类的逻辑需要单独处理

#6 楼 @huacnlee

无论你开多少个 Thread,最终请求还是需要等待它们都结束了才能完成

这句好像有问题,没有主动 join 的话,会直接执行之后的代码的

#10 楼 @thxagain

Hi,抱歉我昨天说的太简略了。 @lgn21st 说出了我想说的理由,还有推荐的书籍。

👍

需要 登录 后方可回复, 如果你还没有账号请 注册新账号