Итак, у меня есть TCP-сервер в eventmachine , а therubyracer используется в качестве способа предварительного ожидания операций (таких как фильтры или расширения) для сервера. Все это прекрасно работает, когда сервер не получает много данных, но когда он загружается (иногда это требуется), он становится очень медленным.
Итак, я сделал небольшой тест, чтобы увидеть, насколько медленнее rubyracer по сравнению с Ruby, и я был шокирован , когда увидел результаты:
user system total real
V8: 0.060000 0.000000 0.060000 ( 0.059903)
Ruby: 0.000000 0.000000 0.000000 ( 0.000524)
Я не против, если это будет медленно, если честно, но я не хочу, чтобы он блокировал весь мой сервер, пока он не закончит обработку данных. Использование EM::defer
на самом деле не вариант (я пробовал его, но иногда он порождает потоки gazillion, в зависимости от интенсивности затопления). Я не могу обойти наводнение, так как я не проектировал протоколы, и клиент требует, чтобы они были такими (какими бы ужасными они ни были).
Код теста:
require 'v8'
require 'benchmark'
class User
def initialize
@name = "smack"
@sex = "female"
@age = rand(100)
@health = rand(100)
@level = rand(100)
@colour = rand(14)
end
attr_accessor :name, :sex, :age, :health, :level, :colour
end
# Create context and the function
context = V8::Context.new
code = "obj = {
__incybincy__: function() {
user.name + '' + '' + ''
user.sex + '' + '' + ''
user.age + '' + '' + ''
user.health + '' + '' + ''
user.level + '' + '' + ''
user.colour + '' + '' + ''
}
}"
context.eval(code)
# Insert the user into the context
user = User.new
context["user"] = user
# Benchmark
n = 100
Benchmark.bm do |x|
x.report("V8: ") do
n.times do
context['obj'].__incybincy__
end
end
x.report("Ruby: ") do
n.times do
user.name + "" + ""
user.sex + "" + ""
user.age.to_s + "" + ""
user.health.to_s + "" + ""
user.level.to_s + "" + ""
user.colour.to_s + "" + ""
end
end
end
EDIT
Вопрос: Есть ли способ устранить узкое место, вызванное therubyracer? Реализация JavaScript в Ruby другими способами приемлема.
07 марта 2012 Обновление
Итак, мне удалось оптимизировать код, поскольку я подумал, что узким местом было соединение Ruby <-> JS, которое происходило каждый раз при выполнении [native code]
, то есть постоянно, так как ruby использует getter и методы установки для классов или когда объекты передавались непосредственно между языками.
user system total real
V8-optimized: 0.050000 0.000000 0.050000 ( 0.049733)
V8-normal: 0.870000 0.050000 0.920000 ( 0.885439)
Ruby: 0.010000 0.000000 0.010000 ( 0.015064)
#where n is 1000
Итак, я уменьшил количество вызовов между Ruby и JS, кэшируя на стороне JS, но это не оптимизировало его так сильно, как я надеялся, поскольку при аренде один объект должен был бы быть передан функции: Hash
или, по крайней мере, JSON String
, я даже пошел на длину прохождения Fixnum
- что заставило меня воскликнуть FML - что не было большим улучшением, чем передача строки (если вообще).
Я все еще надеюсь на лучшее и более быстрое решение, чем мое.