2015-10-01 21 views
11

xem xét mã này:Tại sao chạy vòng lặp này 9 lần mất 100x dài hơn chạy 8 lần?

Test = function() { 
} 

t = new Test(); 

for (var i = 0; i < 8; i++) { 
    result = t instanceof Test; 
} 

Nếu bạn thay đổi số lần lặp lại từ để , vòng lặp sẽ đột nhiên mất khoảng 100 lần còn để hoàn thành trong phiên bản mới nhất của Firefox (41,0 .1). Tôi đã thử nghiệm này trên hai máy tính khác nhau và giới hạn ma thuật luôn luôn là 8.

Đây là thử nghiệm JSPerf mà tôi đã sử dụng: http://jsperf.com/instanceof-8-times-vs-9-times

Có ai có bất kỳ ý tưởng tại sao điều đó có thể xảy ra? Có vẻ như cụ thể là instanceof. Nó không xảy ra nếu bạn làm điều gì đó khác với đối tượng, ví dụ như kiểm tra một thuộc tính.


Lưu ý: Tôi cũng đã gửi Bugzilla bug về việc này.

+1

Điều thú vị là nó không xảy ra khi bạn thực hiện nội tuyến 8/9 lần: http://jsperf.com/instanceof-8-times-vs-9-times/3. Cũng không xảy ra trên Firefox 40.3. – ralh

+1

Làm một vòng lặp đệ quy vào một hàm có vẻ nhanh hơn. Quirky. – Chris

+1

Cảm ơn bạn đã mở một lỗi cho vấn đề này (https://bugzilla.mozilla.org/show_bug.cgi?id=1210342). Đoán mù của tôi sẽ là đây chỉ là chi phí của việc biên dịch trình biên dịch cơ bản xuất hiện khi chúng ta nhập vòng lặp thêm một lần nữa. Nếu bạn sử dụng số lần lặp lại lớn hơn, chi phí của mỗi lần lặp lại sẽ được khấu hao. – nbp

Trả lời

-2

Khi giá trị là 9, bạn lặp lại 10 lần sao cho 100x có lẽ là 10^2 - tức là hai ký tự thay vì một ký tự. Người ta cũng có thể xác định xem làm việc đó 100 lần sẽ cho kết quả chậm hơn 10^3 hay không. Âm thanh hạt, nhưng Javascript này.

1

Jan de Mooij từ nhóm Mozilla đã đăng một số chi tiết trong số Bugzilla thread. Dưới đây là cách giải thích đơn giản của tôi về các câu trả lời kỹ thuật cao của mình:

Trong trường hợp i < 8, Firefox đủ thông minh để tránh câu trả lời result = t instanceof Test; (theo thử nghiệm của tôi, dường như nó không hoàn toàn bỏ qua). Trong trường hợp i < 9, dường như không thực hiện tối ưu hóa đó.

Tại sao? Lý do không rõ ràng, nhưng nó có lẽ liên quan đến thực tế là 9 lần lặp lại là ngưỡng trên mà hàm được coi là "nóng" đủ để chạy nó thông qua trình biên dịch JIT. Trường hợp i < 8 vẫn còn trong thông dịch viên. (Tôi không thấy lý do tại sao JIT-ing sẽ loại trừ cẩu, nhưng dường như nó có trong phiên bản hiện tại của động cơ.)

Điều thú vị là ngưỡng 8 lần không có vẻ phổ quát. Ví dụ, nếu chúng ta thay thế nguyên mẫu của chúng ta (Test) với một built-in nguyên mẫu (ví dụ CustomEvent), cẩu dường như không xảy ra không phụ thuộc vào số lần lặp (relevant JSPerf):

for (var i = 0; i < 8; i++) { //or i < 9 
    t instanceof CustomEvent; 
} 

Coming back to mã ban đầu sử dụng nguyên mẫu Test, tại sao hiệu suất lại xấu như vậy trong trường hợp i < 9? Điều này liên quan đến cách JSPerf hoạt động. Mã "thiết lập" không chỉ được thực hiện một lần - nó được chạy một lần "cho mỗi thử nghiệm". Mỗi khi bạn nhấp vào Chạy, JSPerf chạy hàng trăm "kiểm tra", mỗi thử nghiệm bao gồm hàng nghìn lần lặp. Vì vậy, mã thiết lập được chạy hàng trăm lần.Điều này có nghĩa rằng có hàng trăm đối tượng nguyên mẫu khác nhau được đặt tên Test trong chương trình, tất cả tạo ra với các dòng:

Test = function(){ 
} 

Các Ion JIT tối ưu hóa trình biên dịch có thể dễ dàng tối ưu hóa các trường hợp mà chúng ta đang sử dụng instanceof trên đối tượng nguyên mẫu cùng nhiều lần (như chúng ta làm với CustomEvent trong this test case), nhưng khi nó nhận thấy rằng có nhiều hơn một đối tượng có cùng tên, dường như nó ném tay trong không khí.

Jan đã chỉ ra rằng điều này không có khả năng ảnh hưởng đến quá nhiều tập lệnh thực tế vì thông thường một mã định danh duy nhất được liên kết với một đối tượng mẫu đơn (ví dụ: bạn có một lớp Foobar, được xác định chỉ một lần và không bao giờ trở lại -defined). Nhưng JSPerf định nghĩa lại nguyên mẫu hàng trăm lần. Dường như với tôi rằng thực tế này thực hiện nghi ngờ nghiêm trọng về tất cả các kết quả JSPerf được công bố bao gồm các định nghĩa nguyên mẫu, ngoại trừ những định nghĩa rõ ràng tránh định nghĩa lại bằng cách sử dụng các hình cầu (như trong test case) - đó có lẽ là kết luận quan trọng nhất.

Ví dụ: các kiểm tra JSPerf được liên kết từ câu hỏi này: Is using instanceof operator in javascript a performance issue? có thể vô giá trị vì chúng đều xác định nguyên mẫu trong mã thiết lập.

Các vấn đề liên quan