新手问题 让 ruby 5 秒之后执行一个任务

guyanbiao · 2013年02月18日 · 最后由 yfractal 回复于 2018年03月27日 · 13283 次阅读

我之前是开了一个新线程

Thread.new do sleep 5 #do something end

但是发现偶尔会出现稳定行的问题,根据现在的结果,这个线程貌似并不是 100% 都会执行到,是 ruby 的线程存在稳定性问题么?或者有没有什么 gem 可以做这件事?delayed_job 可以,但是很依赖 rails。求解决方案

你知道 watch 么?这种事情第一时间想到的应该是 Command tool 呀。

#1 楼 @lgn21st 哦,我理解错了,你是要 delay 一个任务,可能 after 比较合适。

#1 楼 @lgn21st 一头雾水啊,是要在 ruby 里面调用 shell 的命令么?能简单举个 例子么

#3 楼 @guyanbiao 我的意思是你用 shell 命令来调用 ruby 脚本。 类似 after 1000 ruby foobar.rb

#4 楼 @lgn21st 不行啊,这个延时操作是由 ruby 代码中的一个动作 触发的,我找到了一个 gemrufus-scheduler 正在看

我始终觉得问题一定不会在 Ruby 的 Thread 上,你说的情况很可能是由你的业务代码造成的。 rufus-scheduler 我看了下,代码还可以,不过他的 schedule 实现有两种方式,一种是环境中如果已经载入了 EventMachine 的话,会用 EventMachine 来实现调调度,如果没有的话就自己实现了一个 PlainSchedule,而 PlainSchedule 的实现原理跟你的代码是一样的:https://github.com/jmettraux/rufus-scheduler/blob/master/lib/rufus/sc/scheduler.rb#L433

#6 楼 @lgn21st 我具体应用是在 faya.ru 里面,每次客户端 disconnect 的时候就来延时执行一个操作,但现在观察到有时候这个 disconnect 发过来,但是这个线程并没有执行。我现在也不知道该怎样调试

#7 楼 @guyanbiao 你为了确保延时操作被正确执行,你可以先试试看 rufus-scheduler,他的实现可能比你手工要更加完整。或者考虑用一个 queue 实现,这样把所有的延时操作都放入 queue 中,一旦操作未被执行或者其他原因阻塞,也能在 queue 中查到并重新执行。

#8 楼 @lgn21st 但是我要求精确的延时控制,queue 可以实现么?

#9 楼 @guyanbiao 基于内存实现的 queue 是可以做到的。

#10 楼 @lgn21st 有哪些啊,给指条名路哇

#11 楼 @guyanbiao 你 Google 一下看看嘛,看有没有 ruby 的基于 Memory,Memcached 或者 Redis 实现的 queue 嘛。

#12 楼 @lgn21st Thank you very much.

sleep n #一般实际 sleep 的时间 >= n

#9 楼 @guyanbiao 如果想精确控制时间可以参考这个:http://hooopo.iteye.com/blog/757760

#15 楼 @hooopo

精确这个说法是有问题的。应该说明的精度是多少。比如,要求 5 秒后执行的任务,你会在 4.9-5.1 秒之间执行,或者 5.05-5.15 秒之间执行。这个精度在应用场景里能接受么?

而且像 Emacs/Tcl/Twisted/EventMachine/node.js 这一系列坑爹货都是依赖系统时钟的,所谓延时调用,无非就是维护一个 timestamp 列表,每次回调看一下有哪些已经时间到了,去调用一下,回调结束后,就是把 select 的 timeout 设置成列表里最前的 timestamp 减去当前时间,select 什么的超时本来就不准。意外情况,系统时间乱跳了一下,咋办?就算你平时不乱跳,闰秒之前你没做好准备,负载本来就很高了,很容易就悲剧了。

你能 SSH 进去看有哪些正在等待执行的任务么?

EventMachine 进程 crash 了咋办?

#16 楼 @bhuztez 0.5 秒之内能接受

可以看看 timers, 也是 Celluloid 中用到了。不过实现也是 sleep, 代码上使用方便点。

require 'timers'
timers = Timers.new
timers.after(5) { puts 'do something' }
timers.wait # 5s 后 puts...

其实我是上次看 Sidekiq 的 scheduled.rb 找到 Celluloid , 然后再到 timers gem..

#16 楼 @bhuztez 是的都不准,但是大致比轮询的准。而且这种 timer 都有一个问题是,遇到 cup bound 的任务排队会等待,比如有 1000 个耗时 1 秒执行的任务都塞到 5 秒之后执行肯定执行不完,有一些被排到后面。

@guyanbiao 既然你是用 faye 的,faye 在运行期就依赖于 EventMachine, 这种延迟调度的行为可以依靠 EventMachine 的 timer 来支持,基本还是可靠的,如果你要在另一个进程里面运行,那么就要依靠 delayed_job 这样的机制了

@bhuztez 如果真的时间精度要求这么高,不太适合使用 ruby 这种语言来实现...就好像你说的,EventMachine 都是依赖 select 来做的....

#2 楼 @lgn21st 大神,没找到 after 命令?难道要动手编译 linux 才有?

sqsy 整理学习 EventMachine 的一些文章和帖子 提及了此话题。 09月08日 17:05

都依赖线程、并发模型。问题是其线程,线程会死,那就需要 monitor,死了、重启,需要重启 timer。这么多 timer 要怎么调试、管理。一个 timer 死了,其他 timer 要不要一起死。。。

想用 Erlang 了。。。

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