2

そのため、 eventmachineに TCP サーバーがあり、サーバーへの操作 (フィルターや拡張機能など) を事前に保留する方法として、rubyracer が使用されていますサーバーが大量のデータを受信して​​いないときはすべて魅力的に機能しますが、フラッディングされているとき (必要な場合もあります) は非常に遅くなります。

そこで、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ことは実際にはオプションではありません (試してみましたが、フラッディングの程度によっては、膨大な数のスレッドが生成される場合があります)。私はプロトコルを設計していないので、フラッディングを回避することはできず、クライアントはプロトコルをそのようにする必要があります (恐ろしいほど)。

ベンチマーク コード:

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

編集

質問: therubyracer によるボトルネックを解消する方法はありますか? 他の方法で JavaScript を Ruby に実装することは許容されます。


2012年03月07日更新

[native code]それで、コードを最適化することができました。なぜなら、ボトルネックの原因はRuby <-> JS通信であると考えたからです.Rubyはクラスのgetterメソッドとsetterメソッドを使用しているため、実行されるたびに発生しました.オブジェクトが言語間で直接渡されたとき。

                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

そのため、JS 側でキャッシングすることにより、Ruby と JS 間の呼び出しの数を減らしましたが、少なくとも 1 つのオブジェクトを関数に渡す必要があるため、期待したほどには最適化されませんでした: aHashまたは少なくともJSONの代わりStringに a を渡すことさえしましたが、Fixnumこれは FML だと叫びましたが、これは文字列を渡すよりも大きな改善ではありませんでした (仮にあったとしても)。

私はまだ私よりも優れた迅速な解決策を望んでいます。

4

1 に答える 1

4

問題は、デフォルトで、Ruby Racerが Ruby から V8 に、またはその逆に文字列をコピーすることです。

ベンチマークでは、これらの 6 つの文字列プロパティにアクセスすると、少なくとも 6 つmemcpy()の操作が発生し、新しいメモリを割り当て、文字列の長さをバイト単位で移動して新しい場所に移動する必要があります。これを、基本的に操作を行わない Ruby 側 (文字列オブジェクトは、既に割り当てられてセットアップされたポインターをラップするだけ) と比較すると、はるかに遅いのも不思議ではありません。

この動作を変更して、値ではなく参照によって文字列を渡すことができます。

class Wrapper
  attr_reader :object

  def inititialize(object)
    @object = object
  end
end

cxt['aString'] = Wrapper.new('not copied')

もちろん、javascript で文字列にアクセスしたい場合は、最終的にコピーの料金を支払う必要があります。Nums、配列、およびハッシュに対してこのラッパー手法を使用できます。これらはすべてデフォルトで JavaScript にコピーされます。

詳細については、 https://github.com/cowboyd/therubyracer/wiki/Converting-ruby-object-to-javascriptを参照してください。

char *V8 は、外部で管理される文字列の概念をサポートしています。これにより、Ruby でを割り当てることができますが、V8 からのアドレスを使用できます。ただし、この機能は現在、Ruby Racer では利用できません。

于 2012-06-19T08:24:38.923 に答える