我之前是开了一个新线程
Thread.new do sleep 5 #do something end
但是发现偶尔会出现稳定行的问题,根据现在的结果,这个线程貌似并不是 100% 都会执行到,是 ruby 的线程存在稳定性问题么?或者有没有什么 gem
可以做这件事?delayed_job
可以,但是很依赖 rails
。求解决方案
我始终觉得问题一定不会在 Ruby 的 Thread 上,你说的情况很可能是由你的业务代码造成的。
rufus-scheduler
我看了下,代码还可以,不过他的 schedule 实现有两种方式,一种是环境中如果已经载入了 EventMachine 的话,会用 EventMachine 来实现调调度,如果没有的话就自己实现了一个 PlainSchedule,而 PlainSchedule 的实现原理跟你的代码是一样的:https://github.com/jmettraux/rufus-scheduler/blob/master/lib/rufus/sc/scheduler.rb#L433
#7 楼 @guyanbiao 你为了确保延时操作被正确执行,你可以先试试看 rufus-scheduler
,他的实现可能比你手工要更加完整。或者考虑用一个 queue 实现,这样把所有的延时操作都放入 queue 中,一旦操作未被执行或者其他原因阻塞,也能在 queue 中查到并重新执行。
#11 楼 @guyanbiao 你 Google 一下看看嘛,看有没有 ruby 的基于 Memory,Memcached 或者 Redis 实现的 queue 嘛。
精确这个说法是有问题的。应该说明的精度是多少。比如,要求 5 秒后执行的任务,你会在 4.9-5.1 秒之间执行,或者 5.05-5.15 秒之间执行。这个精度在应用场景里能接受么?
而且像 Emacs/Tcl/Twisted/EventMachine/node.js 这一系列坑爹货都是依赖系统时钟的,所谓延时调用,无非就是维护一个 timestamp 列表,每次回调看一下有哪些已经时间到了,去调用一下,回调结束后,就是把 select 的 timeout 设置成列表里最前的 timestamp 减去当前时间,select 什么的超时本来就不准。意外情况,系统时间乱跳了一下,咋办?就算你平时不乱跳,闰秒之前你没做好准备,负载本来就很高了,很容易就悲剧了。
你能 SSH 进去看有哪些正在等待执行的任务么?
EventMachine 进程 crash 了咋办?
可以看看 timers, 也是 Celluloid 中用到了。不过实现也是 sleep, 代码上使用方便点。
require 'timers'
timers = Timers.new
timers.after(5) { puts 'do something' }
timers.wait # 5s 后 puts...
其实我是上次看 Sidekiq 的 scheduled.rb 找到 Celluloid , 然后再到 timers gem..
@guyanbiao 既然你是用 faye 的,faye 在运行期就依赖于 EventMachine, 这种延迟调度的行为可以依靠 EventMachine 的 timer 来支持,基本还是可靠的,如果你要在另一个进程里面运行,那么就要依靠 delayed_job 这样的机制了
@bhuztez 如果真的时间精度要求这么高,不太适合使用 ruby 这种语言来实现...就好像你说的,EventMachine 都是依赖 select 来做的....
都依赖线程、并发模型。问题是其线程,线程会死,那就需要 monitor,死了、重启,需要重启 timer。这么多 timer 要怎么调试、管理。一个 timer 死了,其他 timer 要不要一起死。。。
想用 Erlang 了。。。