Hiệu suất khác nhau trong việc so sánh các biểu tượng và chuỗi


7

Trong sx.el, chúng tôi có một trường hợp chúng tôi cần xác minh xem chúng tôi đã thông qua GEThay POSTlà một đối số.

Hiện tại chúng ta có đối số chuyển qua dưới dạng một chuỗi và đang sử dụng (string= "GET" url-method)để so sánh nó với "GET".

Có bất kỳ lợi thế biên dịch elisp / byte nào để thay đổi nó thành một biểu tượng (equal url-method 'GET)không?


Bất kể tốc độ, các biểu tượng là thành ngữ cho mục đích này trong Lisp. Bên cạnh đó, sử dụng eqđể so sánh với một biểu tượng.

eqsẽ chuyển đổi các đối tượng Emacs intvà so sánh chúng. So sánh ints nhanh hơn nhiều so stringvới s.
abo-abo

1
string=sẽ hoạt động như mong đợi cho dù url-methodlà biểu tượng hay chuỗi. OTOH nếu bạn sử dụng eqhoặc equal, bạn phải đảm bảo các đối số cùng loại.
YoungFrog

Câu trả lời:


11

Những người dùng mới của Lisp đến từ các ngôn ngữ khác đôi khi sử dụng các chuỗi cho các mục đích như vậy theo thói quen.

Biểu tượng có thể được so sánh với eqthay vì chỉ equal. string=sử dụng mã tương tự equal, để kiểm tra từng ký tự cho đến khi tìm thấy sự không phù hợp. Vì vậy, có, so sánh biểu tượng có thể nhanh hơn một chút. Nếu bạn đang sử dụng so sánh trong một vòng lặp, ví dụ, sự khác biệt có thể có vấn đề.

Ngoài ra, tùy thuộc vào mã cụ thể, nó thường có thể làm cho mã đơn giản hơn hoặc dễ đọc hơn để sử dụng các ký hiệu thay vì chuỗi. Và có các hàm (và macro, v.v.) mong đợi các biểu tượng hoặc so sánh mọi thứ bằng cách sử dụng eq(hoặc eql) theo mặc định. Để sử dụng những người có chuỗi, bạn cần phải chuyển đổi thành biểu tượng.


7

Lưu ý rằng các ký hiệu thực tập của người đọc lisp , sao cho các tham chiếu độc lập đến một ký hiệu đã cho cung cấp cho bạn cùng một đối tượng chính xác và do đó bạn có thể so sánh chúng với eq(chỉ cần so sánh các địa chỉ đối tượng).

Ngược lại, các chuỗi độc lập luôn là các đối tượng lisp khác nhau và do đó bạn phải so sánh nội dung của chúng.

Do đó, bạn sẽ mong đợi sự eqso sánh để giành chiến thắng cho hiệu suất.

Thật kỳ lạ (tôi chắc chắn rất ngạc nhiên), một số thử nghiệm tầm thường với benchmark-runviệc mang lại string=chiến thắng khá nhiều. Điều này có vẻ rất kỳ lạ với tôi. YMMV?


Chỉnh sửa: Vì vậy, tôi chỉ nhận thấy câu trả lời này (và nhận xét của nó) một lần nữa, và cảm thấy được truyền cảm hứng để xem liệu tôi có thể tạo lại và giải thích kết quả.

nb Không có gì được biên dịch byte ban đầu.

Nhận thức đầu tiên là các biểu tượng của tôi là quoted còn các chuỗi thì không, và ngay lập tức tôi thấy rằng phần quotechịu trách nhiệm cho phần lớn sự khác biệt về tốc độ:

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

là, đối với các chuỗi nhỏ, luôn nhanh hơn:

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

tuy nhiên, nếu chúng tôi cũng trích dẫn chuỗi:

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

mà gần như phát triển mọi thứ hoàn toàn.

Tuy nhiên, trung bình, trừ khi chuỗi khá lớn, so sánh chuỗi dường như vẫn thắng bằng một sợi tóc.

Một cách tiếp cận khác là liên kết các đối tượng với các biến:

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

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

Một lần nữa, tôi thấy trung bình chuỗi so sánh nhanh hơn bằng mũi.

Sau khi biên dịch byte, tôi chỉ thấy một kết quả nhất quán cho các trường hợp biến bị ràng buộc, trong đó eqnhanh hơn string=(mất khoảng 2/3 thời gian).

Đối với các ví dụ khác, tôi nhận được các kết quả vô nghĩa (với tôi) như các chuỗi được trích dẫn nhanh hơn các chuỗi không được trích dẫn, mà tôi chỉ có thể đoán là nhiễu hiệu quả từ các khía cạnh khác của việc thực thi và / hoặc benchmark-runchính nó. Có đủ sự khác nhau giữa các lần chạy khác nhau của cùng một chức năng để che khuất hoàn toàn mọi khác biệt giữa các lần chạy của các chức năng khác nhau.


Kết luận của tôi là:

(a) eqso sánh với một biểu tượng có thể (hơi phản trực giác) chậm hơn so với so sánh chuỗi, nếu biểu tượng được trích dẫn.

(b) Trừ khi các chuỗi khá lớn, sự khác biệt thực tế là không đáng kể, và vì vậy tôi sẽ không bận tâm chuyển đổi cái này sang cái khác vì lý do hiệu suất hoàn toàn.


3
Có thể do cách bạn thiết lập thử nghiệm của mình khiến mỗi biểu tượng được tạo ra một lần nữa trong mỗi lần chạy vòng lặp, vì vậy bạn đang đọ sức intern+ eqchống lại string=. Hoặc có thể vì một số lý do hoàn toàn khác: không thể biết được nếu không nhìn thấy mã của bạn. Bạn nên đăng mã kiểm tra của bạn dưới dạng một câu hỏi trên trang web này.
Gilles 'SO- ngừng trở nên xấu xa'

Tôi đã thử sử dụng benchmark-run-compiled(với ý tưởng rằng sẽ loại bỏ chi phí intern), nhưng nhiều lần có kết quả âm tính. Tôi nghĩ rằng cả hai hoạt động quá nhanh để đo lường đáng tin cậy.
npostavs
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.