我写了一个管理脚本,每个n秒记录一个heroku日志,它总结了平均值并通知我,如果我越过某个阈值(是的我知道并喜欢新的遗物 - 但我想做自定义的东西)。< / p>
我从未成为IO和线程的主人,我想知道我是否犯了一个愚蠢的错误。我有几个守护程序线程while(true){}
可能是罪魁祸首。例如:
# read new lines
f = File.open(file, "r")
f.seek(0, IO::SEEK_END)
while true do
select([f])
line = f.gets
parse_heroku_line(line)
end
我使用一个守护进程来监视日志的新行,另一个用于定期汇总。
是否有人认为可以降低处理器密集度?
答案 0 :(得分:6)
这可能很热,因为从临时文件读取时你从未真正阻止过。 IO::select
是POSIX select(2)上的薄层。看起来你试图阻止,直到文件准备好读取,但select(2)认为EOF准备就绪(“文件描述符也准备好在文件结尾”),所以你总是立即返回从select然后调用gets在EOF返回nil。
通过避免写入临时文件的线程,而不是使用IO::popen
来分叉连接到ruby IO对象的%x[heroku logs --ps router --tail --app pipewave-cedar]
日志记录器,您可以获得更真实的EOF读取和良好的阻塞行为您可以循环gets
,当gets
返回nil
时退出(表示日志标题已完成)。当没有任何内容可读时,来自分页器的管道上的gets
将被阻止,并且您的脚本只会像执行行解析和报告一样热。
IO.popen( %w{ heroku logs --ps router --tail --app my-heroku-app } ) do |logf|
while line = logf.gets
parse_heroku_line(line) if line =~ /^/
end
end
我还注意到您的报告线程没有做任何事情来同步对@total_lines
,@total_errors
等的访问。因此,您有一些较小的竞争条件,您可以从实例变量中获取不一致的值parse_heroku_line
方法更新。
答案 1 :(得分:1)
select
是关于读取是否会阻止。 f只是一个普通的旧文件,所以当你到最后读取时不要阻塞,它们只是立即返回nil。结果select
立即返回,而不是等待某些内容附加到文件中,因为我认为你正在期待。因此,你正处于一个紧张的繁忙循环中,因此需要很高的cpu。
如果你在eof(你可以检查f.eof?
或gets
是否返回nil),那么你可以开始睡觉(可能有某种退避)或使用类似{{{ 3}}通知文件系统更改