2009-07-24 6 views
8

Tôi đang viết ứng dụng lập kế hoạch công việc trong Ruby cho công việc của mình (chủ yếu để di chuyển tệp bằng cách sử dụng giao thức khác nhau ở tần suất đã cho)Là giấc ngủ tốt() ý tưởng hay cho vòng lặp chính của ứng dụng lập lịch công việc

vòng lặp chính của tôi trông như thế này:

while true do 
    # some code to launch the proper job 
    sleep CONFIG["interval"] 
end 

nó làm việc như một nét duyên dáng, nhưng tôi không thực sự chắc chắn nếu nó là đủ an toàn như các ứng dụng có thể chạy trên một máy chủ với CPU-chuyên sâu các phần mềm đang chạy.

Có cách nào khác để làm điều tương tự không, hoặc là sleep() đủ an toàn trong trường hợp của tôi không?

Trả lời

5

Sử dụng giấc ngủ có khả năng OK cho những thứ nhanh chóng và bẩn. Nhưng đối với những thứ cần một chút mạnh mẽ hơn hoặc độ tin cậy tôi đề nghị ngủ là ác :) Vấn đề với ngủ là thread là (tôi giả định Windows ở đây ...) là thực sự ngủ - scheduler sẽ không chạy thread cho đến khi một khoảng thời gian sau khi khoảng thời gian ngủ trôi qua.

Trong thời gian này, chuỗi sẽ không thức dậy cho bất kỳ thứ gì. Điều này có nghĩa là nó không thể bị hủy bỏ, hoặc thức dậy để xử lý một số loại sự kiện. Tất nhiên, quá trình này có thể bị giết chết, nhưng điều đó không cho chủ đề ngủ một cơ hội để thức dậy và làm sạch bất cứ điều gì lên.

Tôi không quen thuộc với Ruby, nhưng tôi cho rằng nó có một số loại cơ sở để chờ đợi nhiều thứ. Nếu bạn có thể, tôi khuyên bạn nên thay vì sử dụng giấc ngủ, bạn bị mờ hai điều \

  1. Bộ hẹn giờ đánh thức định kỳ để thực hiện công việc.
  2. Sự kiện được đặt khi anh ấy xử lý cần hủy hoặc hoàn toàn (ví dụ như bẫy control-C).

Sẽ tốt hơn nếu có một số loại sự kiện có thể được sử dụng để báo hiệu nhu cầu làm việc. Điều này sẽ tránh bỏ phiếu trên bộ hẹn giờ.Điều này thường dẫn đến việc sử dụng tài nguyên thấp hơn và hệ thống đáp ứng nhanh hơn.

3

Nếu bạn không cần khoảng thời gian chính xác, thì điều đó hợp lý với tôi. Nếu bạn cần phải tỉnh táo vào những thời điểm thường xuyên mà không trôi dạt, bạn có thể muốn sử dụng một số loại hẹn giờ bên ngoài. Nhưng khi bạn đang ngủ, bạn không sử dụng tài nguyên CPU. Đó là công việc chuyển đổi đắt tiền.

7

Bất cứ lúc nào tôi cảm thấy cần phải chặn, tôi sử dụng vòng lặp sự kiện; thường là libev. Dưới đây là một Ruby ràng buộc:

http://rev.rubyforge.org/rdoc/

Về cơ bản, sleep là hoàn toàn tốt đẹp nếu bạn muốn quá trình của bạn để đi vào giấc ngủ mà không cần phải bất cứ điều gì khác đang xảy ra trong nền. Tuy nhiên, nếu bạn muốn làm những việc khác, như ngủ và cũng chờ kết nối TCP hoặc tập tin tay để có thể đọc được, thì bạn sẽ phải sử dụng vòng lặp sự kiện. Vì vậy, tại sao không chỉ sử dụng một lúc đầu?

Dòng chảy của ứng dụng của bạn sẽ là:

main { 
    Timer->new(after => 0, every => 60 seconds, run => { <do your work> }) 
    loop(); 
} 

Khi bạn muốn làm những thứ khác, bạn chỉ cần tạo người quan sát, và nó sẽ xảy ra cho bạn. (Các công việc bạn đang chạy cũng có thể tạo người theo dõi.)

+0

Làm thế nào để bạn phá vỡ vòng lặp này nếu điều kiện được đáp ứng? – Fadi

2

Nó sẽ không sử dụng CPU trong khi đang ngủ nhưng nếu bạn đang ngủ trong một thời gian dài, tôi sẽ quan tâm hơn đến trình thông dịch đang chạy. không làm gì cả. Đây không phải là lớn của một thỏa thuận tho.

+0

Nếu tôi hiểu chính xác, điều này có nghĩa là nó sử dụng tài nguyên bộ nhớ nhưng không phải tài nguyên CPU trong khi ngủ? –

3

Trong khi sleep(timeout) là hoàn toàn phù hợp cho một số thiết kế, có một lưu ý quan trọng cần ghi nhớ.

Ruby cài đặt trình xử lý tín hiệu với SA_RESTART (xem here), có nghĩa là bạn không thể dễ dàng bị gián đoạn sleep (hoặc tương đương select(nil, nil, nil, timeout)). Trình xử lý tín hiệu của bạn sẽ kích hoạt, nhưng chương trình sẽ quay lại ngay sleep. Điều này có thể bất tiện nếu bạn muốn phản ứng kịp thời, ví dụ: SIGTERM.

Hãy xem xét rằng ...

#! /usr/bin/ruby 
Signal.trap("USR1") { puts "Hey, wake up!" } 
Process.fork() { sleep 2 and Process.kill("USR1", Process.ppid) } 
sleep 30 
puts "Zzz. I enjoyed my nap." 

... sẽ mất khoảng 30 giây để thực hiện, chứ không phải 2.

Là một khắc phục, bạn có thể thay vì ném một ngoại lệ trong xử lý tín hiệu của bạn, mà sẽ làm gián đoạn giấc ngủ (hoặc bất cứ điều gì khác!) ở trên. Bạn cũng có thể chuyển sang vòng lặp dựa trên select và sử dụng biến thể của self-pipe trick để đánh thức "sớm" khi nhận được tín hiệu. Như những người khác đã chỉ ra, các thư viện sự kiện đầy đủ tính năng cũng có sẵn.

+1

Đây không phải là rất đẹp, nhưng nó sẽ làm việc để chỉ làm '10.times {sleep 1}'? Điều này sẽ giống như ngủ cho 10 nhưng cung cấp cho bạn một thời gian tối đa để đáp ứng 1 giây. –

+0

@Brian: có, nó sẽ hoạt động. Vâng, nó khá là đẹp. – pilcrow