2012-11-28 39 views
20

Tôi đã tự hỏi liệu có ai biết cách setTimeout được triển khai trong node.js. Tôi tin rằng tôi đã đọc ở đâu đó rằng đây không phải là một phần của V8. Tôi nhanh chóng cố gắng để tìm việc thực hiện, nhưng không thể tìm thấy nó trong nguồn (BIG). Tôi ví dụ tìm thấy tập tin timers.js này, mà sau đó ví dụ liên kết đến timer_wrap.cc. Nhưng những tập tin này không hoàn toàn trả lời tất cả các câu hỏi của tôi.Cách setTimeout được triển khai trong node.js

  • V8 có thực hiện setTimeout không? Tôi đoán cũng từ nguồn câu trả lời là không.
  • Cách thực hiện setTimeout? javascript hoặc bản địa hoặc kết hợp cả hai? Từ timers.js tôi giả cái gì đó dọc theo dòng của cả hai:

    var Timer = process.binding('timer_wrap').Timer;` 
    
  • Khi thêm nhiều giờ (setTimeout) như thế nào Node.js biết để thực hiện đầu tiên? Liệu nó thêm tất cả các bộ đếm thời gian vào một bộ sưu tập (được sắp xếp)? Nếu nó được sắp xếp thì tìm ra thời gian chờ cần thực hiện là O (1) và O (log n) để chèn? Nhưng sau đó một lần nữa trong timers.js tôi thấy họ sử dụng một danh sách liên kết?

  • Nhưng sau đó lại thêm nhiều bộ tính giờ không phải là vấn đề?
  • Khi thực hiện kịch bản này:

    var x = new Array(1000), 
        len = x.length; 
    
    /** 
    * Returns a random integer between min and max 
    * Using Math.round() will give you a non-uniform distribution! 
    */ 
    function getRandomInt (min, max) { 
        return Math.floor(Math.random() * (max - min + 1)) + min; 
    } 
    
    var y = 0; 
    
    for (var i = 0; i < len; i++) { 
        var randomTimeout = getRandomInt(1000, 10000); 
    
        console.log(i + ', ' + randomTimeout + ', ' + ++y); 
        setTimeout(function() { 
         console.log(arguments); 
        }, randomTimeout, randomTimeout, y); 
    } 
    

    bạn nhận được một chút sử dụng CPU nhưng không có nhiều?

  • Tôi tự hỏi liệu tôi có thực hiện tất cả các cuộc gọi lại này trong danh sách được sắp xếp nếu tôi sẽ có hiệu suất tốt hơn không?

Trả lời

17

Bạn đã hoàn thành hầu hết công việc. V8 không cung cấp triển khai cho setTimeout vì nó không phải là một phần của ECMAScript. Hàm bạn sử dụng được thực hiện trong timers.js, tạo ra một cá thể của đối tượng Timeout là một trình bao bọc xung quanh lớp C.

Có một nhận xét trong nguồn mô tả cách họ quản lý bộ hẹn giờ.

// Because often many sockets will have the same idle timeout we will not 
// use one timeout watcher per item. It is too much overhead. Instead 
// we'll use a single watcher for all sockets with the same timeout value 
// and a linked list. This technique is described in the libev manual: 
// http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Be_smart_about_timeouts 

Điều này cho biết nó đang sử dụng danh sách được liên kết kép là số 4 trong bài viết được liên kết.

Nếu không có một yêu cầu, nhưng nhiều ngàn (triệu ...), tất cả sử dụng một số loại timeout với giá trị timeout cùng, sau đó một có thể làm tốt hơn:

Khi bắt đầu thời gian chờ, tính giá trị thời gian chờ và đặt thời gian chờ ở cuối danh sách.

Sau đó sử dụng ev_timer để kích hoạt khi hết thời gian chờ ở đầu danh sách được kích hoạt (ví dụ, sử dụng kỹ thuật số 3).

Khi có một số hoạt động, loại bỏ các bộ đếm thời gian từ danh sách, tính toán lại thời gian chờ, thêm nó vào cuối danh sách một lần nữa, và đảm bảo cập nhật các ev_timer nếu nó được lấy từ đầu sự danh sách.Bằng cách này, người ta có thể quản lý một số lượng thời gian chờ không giới hạn trong O (1) thời gian để bắt đầu, dừng và cập nhật bộ hẹn giờ, với chi phí của một biến chứng lớn và phải sử dụng thời gian chờ liên tục. Thời gian chờ liên tục đảm bảo rằng danh sách vẫn được sắp xếp.

Node.js được thiết kế xung quanh hoạt động không đồng bộ và setTimeout là một phần quan trọng. Tôi sẽ không cố gắng để có được khôn lanh, chỉ cần sử dụng những gì họ cung cấp. Tin tưởng rằng nó đủ nhanh cho đến khi bạn đã chứng minh rằng trong trường hợp cụ thể của bạn đó là một nút cổ chai. Đừng gặp khó khăn khi tối ưu hóa sớm.

CẬP NHẬT

gì xảy ra là bạn đã có cơ bản một cuốn từ điển của timeouts ở cấp cao nhất, vì vậy tất cả 100ms timeout được nhóm lại với nhau. Bất cứ khi nào một thời gian chờ mới được thêm vào, hoặc thời gian chờ lâu đời nhất kích hoạt, nó được nối vào danh sách. Điều này có nghĩa là thời gian chờ lâu đời nhất, cái sẽ kích hoạt sớm nhất, là ở đầu danh sách. Có một bộ đếm thời gian duy nhất cho danh sách này và được đặt dựa trên thời gian cho đến khi mục đầu tiên trong danh sách được đặt hết hạn.

Nếu bạn gọi setTimeout 1000 lần mỗi lần có cùng giá trị thời gian chờ, chúng sẽ được thêm vào danh sách theo thứ tự bạn gọi là setTimeout và không cần sắp xếp. Đó là một thiết lập rất hiệu quả.

+0

trong ví dụ này, thời gian chờ luôn giống nhau? 60 giây? – Alfred

+0

Vì vậy, bạn muốn có một số điều xảy ra trong 60 giây và bạn đang cố gắng tìm ra liệu có nên gộp tất cả những thứ đó lại với nhau hay tạo ra một setTimeout cho từng thứ riêng biệt không? –

+0

không xin lỗi. Tài liệu mà bạn liên kết có độ trễ 60 giây. Sự chậm trễ của tôi có thể là bất cứ điều gì và rất nhiều! – Alfred

3

Không có vấn đề với nhiều tính giờ! Khi cuộc thăm dò cuộc gọi vòng lặp uv, nó vượt qua đối số hết thời gian cho nó với bộ hẹn giờ gần nhất của tất cả các bộ hẹn giờ.

[timer gần nhất của tất cả các giờ]
https://github.com/joyent/node/blob/master/deps/uv/src/unix/timer.c # 120

RB_MIN(uv__timers, &loop->timer_handles) 

[vượt qua tranh cãi thời gian chờ để thăm dò ý kiến ​​api]
https://github.com/joyent/node/blob/master/deps/uv/src/unix/core.c # 276

timeout = 0; 
if ((mode & UV_RUN_NOWAIT) == 0) 
    timeout = uv_backend_timeout(loop); 

uv__io_poll(loop, timeout); 

Lưu ý: trên Hệ điều hành Windows, nó gần như cùng một logic

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