私が Ruby シンボルについて読んだすべてのテキストは、文字列に対するシンボルの効率について語っています。しかし、これは 1970 年代ではありません。私のコンピューターは、余分なガベージ コレクションを少し処理できます。私が間違っている?私は最新かつ最高の Pentium デュアル コア プロセッサと 4 ギガの RAM を持っています。いくつかの文字列を処理するにはそれで十分だと思います。
5 に答える
お使いのコンピューターは「少し余分なガベージ コレクション」を処理できるかもしれませんが、その「少し」が何百万回も実行される内部ループで行われる場合はどうでしょうか? メモリが限られている組み込みシステムで実行している場合はどうでしょうか?
文字列を意地悪に使って逃げることができる場所はたくさんありますが、そうでない場所もあります。それはすべて文脈に依存します。
確かに、メモリ上の理由から、トークンはそれほど必要ありません。お使いのコンピューターは、間違いなくあらゆる種類の危険な文字列処理を処理できます。
しかし、高速であることに加えて、トークンには視覚的に叫ぶという追加の利点があります (特にコンテキストの色付けを使用する場合)。それは私のためにそれらを使用するのに十分な理由です。
他の理由もあります...そして、特に比較のようなことを行うと、多くの場合、パフォーマンスの向上はあなたが思っている以上のものになるかもしれません.
2 つのルビ記号を比較するとき、インタプリタは 2 つのオブジェクト アドレスを比較しているだけです。2 つの文字列を比較する場合、インタープリターはすべての文字を一度に 1 つずつ比較する必要があります。この種の計算は、これをたくさん行っている場合に追加できます。
ただし、シンボルには独自のパフォーマンスの問題があります... ガベージコレクションは行われません。
この記事を読む価値があります: http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol
違いの本当の理由は次のとおりです。文字列は決して同じではありません。文字列のすべてのインスタンスは、内容が同一であっても個別のオブジェクトです。また、文字列に対するほとんどの操作では、新しい文字列オブジェクトが作成されます。次の点を考慮してください。
a = 'zowie'
b = 'zowie'
a == b #=> true
a
表面的には、とb
が同じであると主張するのは簡単です。ほとんどの常識的な操作は、期待どおりに機能します。しかし:
a.object_id #=> 2152589920 (when I ran this in irb)
b.object_id #=> 2152572980
a.equal?(b) #=> false
見た目は同じですが、別のオブジェクトです。Ruby はメモリを 2 回割り当て、String#initialize
メソッドを 2 回実行する必要がありました。これらはメモリ内の 2 つの別々の場所を占有しています。そしてねえ!それらを変更しようとすると、さらに楽しくなります。
a += '' #=> 'zowie'
a.object_id #=> 2151845240
ここでは何も追加せず、コンテンツをまったく同じままにa
しますが、Ruby はそれを知りません。新しい String オブジェクト全体を割り当て、変数a
を再割り当てし、古い String オブジェクトは最終的なガベージ コレクションを待機します。ああ、空の''
文字列は、そのコード行の間だけ割り当てられた一時的な String オブジェクトも取得します。試してみてください:
''.object_id #=> 2152710260
''.object_id #=> 2152694840
''.object_id #=> 2152681980
これらのオブジェクト割り当ては、洗練されたマルチギガヘルツ プロセッサで高速ですか? 確かにそうです。彼らはあなたの 4 GB の RAM の多くを食い尽くしますか? いいえ、そうしません。しかし、それを数百万回繰り返すと、加算され始めます。ほとんどのアプリケーションはあらゆる場所で一時的な文字列を使用しており、コードはおそらくメソッドやループ内に文字列リテラルでいっぱいです。これらの文字列リテラルなどは、そのコード行が実行されるたびに、新しい String オブジェクトを割り当てます。本当の問題はメモリの浪費ではありません。ガベージ コレクションが頻繁にトリガーされ、アプリケーションがハングし始めると、無駄な時間が発生します。
対照的に、シンボルを見てみましょう。
a = :zowie
b = :zowie
a.object_id #=> 456488
b.object_id #=> 456488
a == b #=> true
a.equal?(b) #=> true
シンボル:zowie
が作成されると、別のシンボルが作成されることはありません。特定のシンボルを参照するたびに、同じオブジェクトを参照しています。新しい割り当てに時間やメモリが浪費されることはありません。ガベージ コレクションが行われないため、ユーザー入力から無数のシンボルを動的に作成し始めると、無限のメモリ リークが発生する危険があります。ただし、定数値やハッシュ キーなど、コード内の単純なリテラルの場合は、ほぼ完璧です。
それは役に立ちますか?アプリケーションが一度何をするかは問題ではありません。それは何百万回も何をするかについてです。
It's nice that symbols are guaranteed unique--that can have some nice effects that you wouldn't get from String (such as their addresses are always exactly equal I believe).
Plus they have a different meaning and you would want to use them in different areas, but ruby isn't too strict about that kind of stuff anyway, so I can understand your question.
入力する文字が1つ少なくなります。ハッシュキーなどの文字列に対してそれらを使用する必要があるのは、これですべてです。