シンボルと文字列の比較におけるパフォーマンスの違い


7

ではsx.el、引数として、GETまたはPOST引数として渡したかどうかを確認する必要がある場合があります。

現在、文字列として渡される引数があり、(string= "GET" url-method)それをと比較するために使用してい"GET"ます。

シンボルに変更することによるelisp / byteコンパイルの利点はあります(equal url-method 'GET)か?


速度に関係なく、シンボルはLispでこの目的のために慣用的です。さらに、eqシンボルと比較するために使用します。

eqEmacsオブジェクトを変換しintて比較します。intsの比較は、sの比較よりもはるかに高速ですstring
abo-abo 2014年

1
string=url-methodシンボルであるか文字列であるかにかかわらず、期待どおりに動作します。OTOH eqまたはを使用する場合equal、引数が同じ型であることを確認する必要があります。
YoungFrog

回答:


11

他の言語から来たLispの新しいユーザーは時々習慣のような目的のために文字列を使用します。

シンボルeqはだけではなくと比較できますequalstring=ではequal、と同様のコードを使用して、不一致が見つかるまで各文字をテストします。そのため、はい、シンボルの比較はわずかに速くなります。たとえば、ループで比較を使用している場合、違いが重要になることがあります。

さらに、特定のコードによっては、文字列の代わりに記号を使用することで、コードをより単純または読みやすくすることができます。そして、シンボルを期待する、またはデフォルトでeq(またはeql)を使用して比較する関数(およびマクロなど)があります。これらを文字列で使用するには、とにかくシンボルに変換する必要があります。


7

lispリーダーはシンボルをインターンするので、特定のシンボルへの独立した参照によってまったく同じlispオブジェクトが得られ、結果としてそれらを比較できますeq(オブジェクトアドレスを比較するだけでよい)。

逆に、独立した文字列は常に異なるlispオブジェクトであるため、その内容を比較する必要があります。

したがってeq、パフォーマンスで勝つ比較が期待されます。

不思議なことに十分(私は確かに非常に驚いています)、いくつかの些細なテストbenchmark-runstring=かなりのマージンで勝利を与えています。これは私には非常に奇妙に思えます。YMMV?


編集:それで、私はこの答え(およびそのコメント)に再び気づき、結果を再現して説明できるかどうかを確認するために刺激を受けました。

nb最初は何もバイトコンパイルされません。

最初の認識は、私のシンボルはquotedで、文字列はdではないことでした。そして、すぐquoteに速度の違いの大部分がにあることがわかりました。

(benchmark-run 10000000
  (string= "foo" "foo"))

小さめの文字列の場合、一貫して以下より高速です。

(benchmark-run 10000000
  (eq 'foo 'foo))

ただし、文字列も引用する場合:

(benchmark-run 10000000
  (string= '"foo" '"foo"))

ほぼすべてが均等になります。

ただし、平均して、文字列が非常に大きい場合を除いて、文字列の比較はまだ髪に勝っているようです。

別のアプローチは、オブジェクトを変数にバインドすることです:

(let ((foo 'test)
      (bar 'test))
  (benchmark-run 10000000
    (eq foo bar)))

(let ((foo "test")
      (bar "test"))
  (benchmark-run 10000000
    (string= foo bar)))

もう一度言いますが、平均的には、鼻の方が文字列の比較が速くなっています。

バイトコンパイル後、let-bound変数のケースで一貫した結果のみが表示されます。この場合、(時間の約2/3)eqより一貫して高速ですstring=

他の例では、引用符で囲まれた文字列が引用符で囲まれていない文字列よりも高速であるなど、無意味な(私にとっての)結果が出benchmark-runます。同じ関数の異なる実行の間に十分な多様性があり、異なる関数の実行間の違いを完全に覆い隠しました。


私の結論は:

(a)シンボルが引用符で囲まれている場合、シンボルとの比較は、文字列の比較よりeq(多少直感的には)遅くなる可能性があります

(b)文字列がかなり大きくない限り、実際的な違いはまったく無視できるため、純粋にパフォーマンス上の理由で、一方をもう一方に変換することはありません。


3
あなたのテストを設定した方法は、あなたがピッチングしているように、各シンボルは、ループの実行ごとに新たに発生させる可能性があるためintern+をeq反対string=。あるいは、完全に異なるいくつかの理由が考えられます。コードを見ない限り、それを伝えることは不可能です。このサイトにテストコードを質問として投稿してください。
Gilles「SO-悪をやめる」14年

私はbenchmark-run-compiled(それがのコストを取り除くだろうという考えで)使ってみましたinternが、何回かは負の結果時間を得ました。どちらの操作も速すぎて確実に測定できないと思います。
npostavs 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.