Ruby的速度慢是公认的(虽然我并不想面对这一点),所以在遇到一些需要大量运算的业务时就会遇到瓶颈,这时可以把这部分的逻辑运算交給其他相对运算较快的语言来做,ruby只用得到返回结果就行了,
可以使用Rubyinline在ruby代码种嵌入C, 也可以使用Erlectricity来实现与Erlang的对接,
除了这种办法之外还可以使用后台运行来处理消耗资源的任务,当然这只能针对于及时性不高的业务。
参考:
监控服务器存活的脚本,用ruby写的,需要安装有action_mailer gem,
功能:检测主机的80端口是否可用
失败次数记录,超过指定次数判定主机Down掉
发送通知邮件到指定邮箱
在前面的日志中有说明怎样连接gmail来发送邮件的
require 'rubygems'
require 'action_mailer'
require 'ping'
require 'fileutils'
require 'tlsmail' #need install tlsmail gem to support TLS connect
Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
#发送通知from账户设置
ActionMailer::Base.smtp_settings = {
:address => 'smtp.gmail.com',
:port => '25',
:domain => 'gmail.com',
:user_name => 'username',
:password => 'passwd',
:authentication => :login
}
#recp: 收到通知的邮箱地址,可以填多个地址,逗号分隔
#sub: 邮件主题
#bo: 邮件内容
class SimpleMailer < ActionMailer::Base
def simple_message(recp, sub, bo)
from 'sender@gmail.com'
recipients recp
subject sub
body bo
end
end
class ServerMonitor
def initialize
#config
@hit = 5 #最大失败次数,达到后才会发送邮件,避免误报
@tmp = "/tmp/server_monitor_tmp" #计数器地址
@recp = 'mytake6@gmail.com, std8545@yahoo.com.cn' #收信的邮箱地址
@host = ['www.ccok.me', 'www.google.com'] #需要监控的主机
#do not touch these
@hosts = Struct.new(:host, :status)
@servers, @msg = [], []
@host.each { |h| @servers << @hosts.new(h, true) }
FileUtils.mkdir(@tmp) unless File.exists? @tmp
end
def run
@servers.each do |s|
num = Ping.pingecho(s.host, 5, 80) ? 0 : rf(s.host) + 1
File.open(dest(s.host), 'w') { |f| f.puts num }
end
@servers.each do |e|
if rf(e.host) == @hit
e.status = false
File.open(dest(e.host), 'w') { |f| f.puts 0 }
end
end
send_mail
end
def rf file
return 0 unless File.exist?(dest(file))
File.open(dest(file), 'r').readlines.to_s.chomp.to_i
end
def dest host
"#{@tmp}/#{host}"
end
def send_mail
@servers.each { |m| @msg << m.host unless m.status }
SimpleMailer.deliver_simple_message @recp,
"server monitor",
@msg.join(', ') + " is Down!!! " unless @msg.empty?
end
end
#go
ServerMonitor.new.run
可以放到crontab中每2分钟运行一次
最近用ruby写了一个随机发扑克的类, 可以指定参加的player个数
class Card54
@@given = [] #the cards already given
@@player_num = nil #players number
@@player_cards = {} #cards players get
@@now_turn = 0 #now player's turn
@@cards = (1..54).to_a #total cards
def initialize(player_num=4)
@@player_num = player_num
@@cards.length.times { run }
end
def run
raise 'no card avaiable' if @@given.length == @@cards.length
card = rand_card(@@cards - @@given)
@@given << card
@@now_turn = 0 if @@now_turn == @@player_num
give @@now_turn.next, card
@@now_turn = @@now_turn.next
end
def player_cards
p @@player_cards
end
private
def rand_card c
c[rand(c.length)]
end
def give turn, card
if @@player_cards[turn].nil?
@@player_cards[turn] = card.to_s
else
@@player_cards[turn] = @@player_cards[turn] + ',' + card.to_s
end
end
end
#require 'card54'
#play = Card54.new 4
#play.player_cards
这样就支持Card54.new.player_cards了
class Card54
attr_reader :player_cards, :player_num
def initialize(player_num=4)
@given = [] #the cards already given
@player_cards = {} #cards players get
@now_turn = 0 #now player's turn
@cards = (1..54).to_a #total cards
@player_num = player_num
@cards.length.times { run }
end
def run
raise 'no card avaiable' if @given.length == @cards.length
card = rand_card(@cards - @given)
@given << card
@now_turn = 0 if @now_turn == @player_num
give @now_turn.next, card
@now_turn = @now_turn.next
end
private
def rand_card c
c[rand(c.length)]
end
def give turn, card
if @player_cards[turn].nil?
@player_cards[turn] = card.to_s
else
@player_cards[turn] = @player_cards[turn] + ',' + card.to_s
end
end
end
最近在看ruby的线程这块的东西,就找了些资料关于linux进程和线程的,因为ruby的线程是基于linux和unix的,所以机制也和linux一样,
Introduction to threads and processes
进程和线程简介
Programs consist of a number of processes, each of which contains one or more conceptually concurrent threads of execution.
程式包含了若干进程,每一个进程包含了一个或多个概念上知执行的线程。
A thread is the unit of execution within a process. Every time a process is initialised, a primary thread is created. For many applications the primary thread is the only one that the application requires; however, processes can create additional threads.
线程是进程的执行单元。当进程被初始化后,主线程就被创建了。对于绝大多数的应用程式来说,通常仅需要有一个主线程。尽管如此进程也能够创建额外的线程。
Each user process has its own private address space, i.e. a collection of memory regions which that process can access. A user process cannot directly address memory areas in the address space of another process. There is also a special process, the Kernel process, whose threads run at supervisor privilege level. This process normally contains two threads:
每一个用户进程拥有自己私有的地址空间,也就是说,进程拥有一定的可被其访问的内存区域。一个用户进程不能够直接访问其他进程的地址空间。另外更有一个特别的进程,内核进程,他运行在终极用户权限模式。这个进程通常包括两个线程:
the Kernel server thread, which is the initial thread whose execution begins at the reset vector, and which is used to implement all Kernel functions requiring allocation or deallocation on the Kernel heap. This is the highest priority thread in the system.
Kernel server (内核服务器)线程:是个初始的进程,在系统启动时就已存在。他能够在heap执行由核心函数请求的内存分配或内存的重分配。这是系统中具备最高权限的线程。
the null thread, which runs only when no other threads are ready to run. The null thread places the processor into idle mode to save power.
null (空)线程:当系统中没有其他可运行的线程时这个线程就开始运行,null 线程使处理器处于空闲状态,减少耗电。
Threads execute individually and are unaware of other threads in a process. The scheduling of threads is pre-emptive, i.e. a currently executing thread may be suspended at any time to allow another thread to run.
线程是单独运行的,他且并不知道进程中更有其他线程存在。线程的执行是抢占式的,也就是说,当前运行的线程在任何时候都可能被挂起,以便另外一个线程能够运行。
Each thread is assigned a priority; at any time, the thread running is the highest priority thread which is ready to run. Threads with equal priority are time-sliced on a round-robin basis. Context switching between threads involves saving and restoring the state of threads. This state includes not only the processor registers (the thread context) but also the address space accessible to the thread (the process context). The process context only needs switching if a reschedule is between threads in different processes.
每一个线程都配置了优先限权;在 任何时候,只要线程已准备就绪,具备高优先权的线程总是首先运行。假如线程具备相同的悠闲权,则根据时间片进行轮转调度。上下文的转换包括了保存和恢复线 程状态。这个状态不但仅包含了处理器寄存器(进程上下文)而且还包含了线程可访问的地址空间(进程上下文)。只有在重新调度是在两个进程间进行的时候,进 程上下文才被转换。
Compare this with active objects which allow non pre-emptive multi-tasking within a single thread.
把这个和活动对象比较,活动对象允许在一个线程中实现非强占式的多任务调度。
A thread can suspend, resume, panic and kill another thread.
一个线程能够被挂起,唤醒、异常抛出和结束其他线程。
When a thread is created it is put into a suspended state, it does not begin to run until that thread’s Resume() member function is called.
线程被创建以后,他处于挂起状态。他没有马上进入运行状态,直到他的Resume()成员函数被调用。
When a thread is created, it is given the priority EPriorityNormal by default. The fact that a thread is initially put into a suspended state means that the thread priority can be changed (RThread::SetPriority()) before the thread is started (RThread::Resume()).
线程创建以后,他具备EPriorityNormal的默认优选级。线程被初始化并处于挂起状态,这意味着在线程开始运行前,线程的运行优先级能够被改变(通过调用RThread::SetPriority())
就是线程被创建的时候默认是没有运行的,即处于挂起(suspend)状态,所以要进行唤醒(wakeup,或者是join)才能运行,在唤醒前可以调整线程的优先级
一直对ruby中yield的使用比较迷惑,今天抽了点时间好好看了下,
下面是内置类File ::open的源码
def File.open(name, mode = "r")
f = os_file_open(name, mode)
if block_given?
begin
yield f
ensure
f.close
end
return nil
else
return f
end
end
这个方法非常简洁明了,block_given?判断是否传递了代码块,有的话就把文件句柄传给代码块进行操作,这个地方就是
yield f
我觉得可以这样理解yield的行为:把yield后面的参数传递给后面的代码块作为参数。
yield的作用可以这样理解:拿学生举个例子,每个学生交的学费是一样的,所以处理交学费的流程就放在方法中,但是每个学生的要花费的生活费不一样,要考虑很多的因素,所以把特殊的因素放在代码块中操作,这样就可以即统一又有区别的计算出总的花费。
另一个例子
def c(v, &block)
return v unless v.is_a? Array
v.each &block
end
c([1,2,3]) { |x| p x + 1 } #2, 3, 4
def c(v, &block)
return v unless v.is_a? Array
v.each { |x| yield x }
end
c([1,2,3]) { |x| p x + 1 } #2, 3, 4
Check out the top 5 most useful ruby gems that you may not have heard of!
Mailfactory is a ruby library designed to allow the simple creation of emails. It offers the following features:
To Install:
gem install mailfactory
Example:
Mailfactory is nice
"require 'rubygems'
require 'net/smtp'
require 'mailfactory'
#Connect to SMTP Server
smtp = Net::SMTP.new('mail.host.com', 25)
smtp.start('mydomain.com')
#Construct Mail Message
mail = MailFactory.new()
mail.to = 'foo@monkey.com'
mail.from = 'jason@dzone.com'
mail.subject = 'An email from Ruby'
mail.add_attachment('/path/to/file')
mail.html = "Hello From Ruby!
Mailfactory is nice
"
#Construct SMTP Message
smtp.send_message mail.construct, 'foo@monkey.com', 'jason@dzone.com'
#Send this (and all other) message
smtp.finish()
Feed-Normalizer normalizes all RSS Feed formats into a generic class. This allows you to access the same properties from any RSS Feed it parses without worrying about the underlying format of the RSS source.
To Install:
gem install feed-normalizer
Example:
FasterCSV is significantly faster than CSV and arguably has an improved CSV interface.
To Install
gem install fastercsv
Example:
require 'rubygems'
require 'fastercsv'
#Read a CSV File
FasterCSV.foreach('/path/to/file') do |row|
element1 = row[0]
element2 = row[2]
element3 = row[3]
end
#Write a CSV File
FasterCSV.open('/path/to/file') do |csv|
csv << ["an", "array", "of", "data"]
end
Bishop is a Bayesian classifier library for Ruby. With Bishop you can effectively train your program to recognize any number of things.
To Install:
gem install bishop
Example:
require 'rubygems'
require 'bishop'
#Initialize the classifier
classifier = Bishop::Bayes.new
classifier.load('spam_or_no_spam.yml') if File.file?('spam_or_no_spam.yml')
#Train the classifier to recognize spam email
classifier.train('spam', 'Amazing results in a few weeks!')
classifier.train('spam', 'Get your free viagra!')
classifier.train('spam', 'A credit card offer!')
#Train the classifier to recognize legit email
classifier.train('not spam', 'Your payment update')
classifier.train('not spam', 'Scheduled Maintenance Reminder')
classifier.train('not spam', 'Can you pick the kids up today?')
#Save classication file so your program can learn
classifier.save('spam_or_no_spam.yml')
#Guess if an email is spam or not
guess = classifier.guess('How would you like a free sample of viagra?')
Linguistics is a generic, language-neutral framework for extending Ruby objects with linguistic methods. This is easily one of the coolest gems. There is simply so much you can do with the Linguistics module.
To Install:
gem install linguistics
Example:
一个创建临时文件的ruby内置class
For certain programming solutions, you might need a temporary file. Different operating systems store temporary files in different locations. Also you don’t want to explicitly name the file since that is irrelevant in the program. How do you ensure that there are no filename conflicts? The solution for all these is to use library for temp file processing.
Ruby comes a with a default library ‘tempfile’ for handling temporary file creation. Given a filename prefix, it creates a temporary file in the following format.
[prefix]-[process].[unique_number]
This ensures that there is no conflict in creating multiple temporary files in the same directory. Once your program terminates the temporary file is automatically deleted. Also by default, the temporary file is created in the operating system’s temporary folder (In my ubuntu system it is /tmp).
In the following program, a temporary file with prefix ‘random’ to store 50 random numbers is created. When the program terminates you cannot see the temp file. Hence I have added a ‘gets’ which stops for user input. In my case I could see a temporary file named ‘random.5789.0′ under \tmp dir.
require 'tempfile' class TempSample temp_file = Tempfile.new('random') 1.upto(50) do num = rand(50) # random number generation in ruby temp_file.print(num,"\n") # print number and newline to the file end temp_file.flush # flush it so that you can see it using cat gets # wait for user input. At this point you can see a temp file /tmp # The filename in my case was random.5789.0 end
If you want to the temp file in a specific directory, you can pass the directory name as the second parameter to new. For example - Tempfile.new(’new1′,’/usr/home/jay’)

just DO NOT support IE