2012-02-15 17 views
9

Khi làm việc trên một dự án nhạy cảm thời gian, tôi đã sử dụng mã bên dưới để kiểm tra độ chi tiết của các sự kiện thời gian có sẵn, trước tiên trên máy tính để bàn của tôi trong Firefox, sau đó là mã node.js trên máy chủ Linux của tôi. Chạy Firefox tạo ra kết quả dự đoán được, trung bình 200 khung hình/giây trên thời gian chờ 1ms và cho biết tôi có các sự kiện thời gian với độ chi tiết 5ms.Tại sao node.js xử lý setTimeout (func, 1.0) không chính xác?

Bây giờ tôi biết rằng nếu tôi đã sử dụng giá trị thời gian chờ là 0, công cụ Node.js của Chrome V8 được xây dựng trên thực tế sẽ không ủy thác thời gian chờ cho sự kiện nhưng xử lý ngay lập tức. Theo dự kiến, các con số trung bình 60.000 khung hình/giây, xử lý rõ ràng liên tục ở công suất CPU (và được xác minh bằng đầu). Nhưng với thời gian chờ 1ms, các con số vẫn còn khoảng 3,5-4 nghìn chu kỳ() mỗi giây, có nghĩa là Node.js không thể tôn trọng thời gian chờ 1ms mà sẽ tạo ra tối đa lý thuyết là 1 nghìn chu kỳ() mỗi giây.

Chơi với một loạt các con số, tôi nhận được:

  • 2ms: ~ 100 fps (timeout đúng, cho thấy 10ms granularity của thời gian sự kiện trên Linux)
  • 1.5: cùng
  • 1,0001: cùng
  • 1.0: 3.500 - 4.500 fps
  • 0.99: 2.800 - 3.600 fps
  • 0,5: 1.100 - 2.800 fps
  • 0,0001: 1.800 - 3.300 fps
  • 0.0: ~ 60.000 fps

Hành vi của setTimeout (func, 0) dường như có thể tha thứ, bởi vì đặc tả ECMAScript có lẽ làm cho không có lời hứa của setTimout ủy thác cuộc gọi đến một thực tế Ngắt cấp hệ điều hành. Nhưng kết quả cho bất cứ điều gì 0 < x < = 1.0 rõ ràng là vô lý. Tôi đã cho một khoảng thời gian rõ ràng để trì hoãn, và thời gian tối thiểu lý thuyết cho n cuộc gọi trên x chậm trễ nên được (n-1) * x. V8/Node.js đang hoạt động như thế nào?

var timer, counter = 0, time = new Date().getTime(); 

function cycle() { 
    counter++; 
    var curT = new Date().getTime(); 
    if(curT - time > 1000) { 
     console.log(counter+" fps"); 
     time += 1000; 
     counter = 0; 
    } 
    timer = setTimeout(cycle, 1); 
} 

function stop() { 
    clearTimeout(timer); 
} 

setTimeout(stop, 10000); 
cycle(); 
+0

gì tôi đoán là đội Node.js quan sát mã trong môi trường tự nhiên được sử dụng '1' như một giá trị thời gian chờ để có nghĩa là 'càng sớm càng tốt'. Tôi biết nhiều lập trình viên (bao gồm cả bản thân mình) ngần ngại viết 'setTimeout (someFunc, 0) 'vì' 0' bằng cách nào đó' cảm thấy sai 'ở đây ... Một thời gian chờ bằng 0 không có thời gian chờ. '1' có vẻ là giá trị logic tiếp theo có nghĩa là ASAP trong mã như vậy. Vì vậy, mã Node.js có lẽ chỉ có một kiểm tra như 'if (timeout> 1) {scheduleTimeout (someFunc, timeout);} else {scheduleNextTick (someFunc);}' –

+0

Câu hỏi rất thú vị BTW. Tôi thích loại nghiên cứu này! –

Trả lời

1

Đối với đầy đủ Tôi muốn chỉ ra cho việc thực hiện nodeJS:

https://github.com/nodejs/node-v0.x-archive/blob/master/lib/timers.js#L214

Đó là:

// Timeout values > TIMEOUT_MAX are set to 1. 
var TIMEOUT_MAX = 2147483647; // 2^31-1 
... 
exports.setTimeout = function(callback, after) { 
    var timer; 

    after *= 1; // coalesce to number or NaN 

    if (!(after >= 1 && after <= TIMEOUT_MAX)) { 
     after = 1; // schedule on next tick, follows browser behaviour 
    } 

    timer = new Timeout(after); 
    ... 
} 

Ghi tuyên bố này:

IDLE timeouts

Vì thường xuyên nhiều ổ cắm sẽ có cùng thời gian chờ nhàn rỗi, chúng tôi sẽ không sử dụng một trình theo dõi thời gian chờ cho mỗi mục. Đó là quá nhiều chi phí.
Thay vào đó, chúng tôi sẽ sử dụng một trình theo dõi duy nhất cho tất cả các ổ cắm có cùng giá trị thời gian chờ và danh sách được liên kết.

Kỹ thuật này được mô tả trong cuốn hướng dẫn libev: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Be_smart_about_timeouts

Và chúng tôi vượt qua same timeout value (1) đây.

Việc thực hiện cho Timer là ở đây:
https://github.com/nodejs/node-v0.x-archive/blob/master/src/timer_wrap.cc

+0

Nhìn lại, tôi có khuynh hướng suy đoán rằng sự khác biệt về tỷ lệ hoạt động cho các số từ 0 HonoredMule

5

Từ (tôi nhấn mạnh) node.js api docs for setTimeout(cb, ms):

Điều quan trọng cần lưu ý là callback của bạn sẽ lẽ không được gọi chính xác trì hoãn mili giây - Node.js làm không đảm bảo về thời gian chính xác khi cuộc gọi lại sẽ kích hoạt, cũng như các thứ tự sắp xếp sẽ kích hoạt. Cuộc gọi lại sẽ được gọi càng gần thời gian được chỉ định.

Tôi cho rằng "càng gần càng tốt" có nghĩa là điều gì đó khác với nhóm triển khai so với bạn.

[Chỉnh sửa] Ngẫu nhiên, có vẻ như setTimeout() function không được ủy quyền bởi bất kỳ đặc điểm kỹ thuật nào (mặc dù apparently part of the HTML5 draft). Hơn nữa, có vẻ là mức độ chi tiết tối thiểu 4-10ms trên thực tế, do đó, điều này dường như là "chỉ như thế nào".

Điều tuyệt vời về phần mềm nguồn mở là bạn có thể đóng góp một bản vá để bao gồm độ phân giải cao hơn theo nhu cầu của bạn!

+0

@HonoredMule: những con số "không có ý nghĩa gì" do kỳ vọng của bạn hoặc do các chi tiết cụ thể về cách chúng triển khai phần mềm? – maerics

+0

Ngẫu nhiên, setInterval chỉ chạy nếu khoảng thời gian là> = 1.0 trong node.js và dường như luôn sử dụng ngắt đúng ở mọi nơi, hiển thị độ chi tiết 5ms trên Linux và độ chi tiết 4ms trong Firefox. Điều "không đảm bảo" được mong đợi khi chúng ta đang ở lòng thương xót của mức độ gián đoạn cấp hệ điều hành, nhưng điều đó sẽ không tạo ra 4.000 ngắt mỗi giây. Những gì tôi đang tìm kiếm là giải thích về/what/Node.js đang làm, từ cấp API (tức là 0 => gọi ngay lập tức, <= 1.0 => thẳng đến hàng đợi sự kiện của Node,> 1.0 => ngắt thực). Tài liệu không nói gì cả. – HonoredMule

+0

Xin lỗi, không bao giờ có nghĩa là để gửi bình luận đầu tiên như nó đã được (muốn phá vỡ một đoạn) - Tôi đã xóa nó sau khi hết thời gian chỉnh sửa. Dù sao thì, kỳ vọng của tôi khó có thể đặt ra nếu không có tài liệu chi tiết hơn ... do đó câu hỏi. – HonoredMule

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