2009-09-10 50 views
5

Gần đây tôi đã bắt đầu học Python và một phần của ứng dụng đơn giản mà tôi đang thực hiện bao gồm bộ hẹn giờ với màn hình hh: mm: ss chạy theo chủ đề riêng.Python sched.scheduler vượt quá độ sâu đệ quy tối đa

Nhìn khắp nơi trên web tôi thấy hai cách để thực hiện điều này:

  1. Sử dụng sched.scheduler
  2. Sử dụng threading.Timer

Con đường tôi đã làm nó trông tương tự cho cả hai hiện thực:

lịch:

def tick(self, display, alarm_time): 

    # Schedule this function to run every minute 
    s = sched.scheduler(time.time, time.sleep) 
    s.enter(1, 1, self.tick, ([display, alarm_time])) 

    # Update the time 
    self.updateTime(display) 

Timer:

def tick(self, display): 

    # Schedule this function to run every second 
    t = Timer(1, self.tick, (display,alarm_time)) 
    t.start() 

    # Update the time 
    self.updateTime(display) 
  1. Hoạt động tốt liên quan đến việc đánh dấu một cách chính xác, nhưng tạo ra các lỗi sau sau một vài phút: RuntimeError: độ sâu đệ quy tối đa vượt quá. Tôi biết bạn có thể tăng mức đệ quy tối đa bằng tay, nhưng chắc chắn điều này không cần thiết ở đây?

  2. Không có lỗi, nhưng đôi khi giây sẽ bỏ qua hoặc đánh dấu bất thường.

Ai đó có thể vui lòng chỉ cho tôi đúng hướng để làm điều này một cách chính xác? Cảm ơn bạn.

+0

Vui lòng đăng liên kết bạn tìm thấy để sử dụng luồng.Timer như thế này. –

+0

Tiêu đề câu hỏi của bạn hoàn toàn sai. Bạn có Bộ đếm thời gian vượt quá độ sâu đệ quy. Không phải sched.scheduler. –

+1

Xin lỗi nếu tôi không rõ ràng. Câu hỏi đã chỉnh sửa. Đề xuất sử dụng Bộ hẹn giờ xuất phát từ đây Xin lưu ý rằng tôi chỉ là người mới bắt đầu và có lẽ đã có ý tưởng sai. – user171331

Trả lời

4

Hẹn giờ là sự kiện một lần. Nó không thể được thực hiện để lặp lại theo cách này.

Sử dụng Bộ hẹn giờ để gọi một chức năng mà sau đó tạo Bộ hẹn giờ khác gọi một chức năng tạo Bộ hẹn giờ gọi hàm tạo Timer, ..., phải đạt giới hạn đệ quy.

Bạn không đề cập đến hệ điều hành của mình, nhưng "bỏ qua" hoặc "đánh dấu bất thường" là vì hai lý do.

  1. Bạn có máy tính đang bận và "1 giây" có nghĩa là "khá gần 1 giây, tùy thuộc vào những gì khác đang xảy ra"

  2. Nếu bạn bắt đầu đếm thời gian của bạn tại 0,9999 giây, và chờ 1 giây , bạn có thể ở mức 1.9999 (giảm xuống 1) hoặc 2.00000. Nó có thể xuất hiện để lặp lại một thời gian hoặc bỏ qua một thời gian. Đồng hồ phần cứng bên trong của máy tính của bạn là rất chính xác, và làm tròn những thứ ra khỏi thứ hai gần nhất (luôn luôn) sẽ dẫn đến khả năng từ xa trùng lặp hoặc bỏ qua.

Sử dụng lịch chính xác. http://docs.python.org/library/sched.html#module-sched

Đoạn mã của bạn cũng không có ý nghĩa gì về lịch biểu. Bạn không cần phải tạo một đối tượng lập lịch biểu mới. Bạn chỉ cần tạo một sự kiện mới.

Đọc http://docs.python.org/library/sched.html#sched.scheduler.enter khi tạo sự kiện mới cho phiên bản trình lên lịch hiện có.

+1

Cảm ơn câu trả lời của bạn. Tôi đã làm rõ các câu hỏi để bao gồm thực hiện lịch trình của tôi và lỗi, nhưng tôi đoán lý do là giống như bạn đã đưa ra cho Timer. Tuy nhiên, nếu lịch biểu chỉ lên lịch một sự kiện vào một ngày sau đó, tôi vẫn không thấy cách tránh giới hạn đệ quy: ( – user171331

+0

giải thích rất rõ ràng – DrFalk3n

+0

Khác với liên kết đến trang tài liệu python, "hướng đi" chính xác là gì sau đó :) – HongboZhu

5

Dưới đây là cách tạo ảnh một lần thành sự kiện định kỳ, ví dụ:với sched: nếu chức năng phải lập lịch trình riêng của mình và là điều duy nhất chạy trên chủ đề của nó:

def tick(self, display, alarm_time, scheduler=None): 
    # make a new scheduler only once & schedule this function immediately 
    if scheduler is None: 
    scheduler = sched.scheduler(time.time, time.sleep) 
    scheduler.enter(0, 1, self.tick, ([display, alarm_time, scheduler])) 
    scheduler.run() 

    # reschedule this function to run again in a minute 
    scheduler.enter(1, 1, self.tick, (display, alarm_time, scheduler])) 

    # do whatever actual work this function requires, e.g.: 
    self.updateTime(display) 

Nếu các sự kiện khác cũng phải được sắp xếp trong cùng một thread thì lịch trình phải được thực hiện và sở hữu "ở đâu đó" - phần if trên có thể được refactored vào phương pháp khác, ví dụ:

def scheduleperiodic(self, method, *args): 
    self.scheduler = sched.scheduler(time.time, time.sleep) 
    self.scheduler.enter(0, 1, method, args) 
    # whatever else needs to be scheduled at start, if any, can go here 
    self.scheduler.run() 

def tick(self, display, alarm_time): 
    # reschedule this function to run again in a minute 
    self.scheduler.enter(60, 1, self.tick, (display, alarm_time)) 

    # do whatever actual work this function requires, e.g.: 
    self.updateTime(display) 

một lần nữa, tất nhiên và như mọi khi với sched, trong khi lịch trình đang chạy, nó (và callbacks sự kiện dự kiến) sẽ "tiếp quản "chuỗi đang được đề cập đến (vì vậy bạn sẽ cần phải ẩn một chuỗi riêng biệt cho nó nếu yo u cần những thứ khác để xảy ra cùng một lúc).

Nếu bạn cần sử dụng loại thành ngữ này trong nhiều chức năng, nó có thể được cấu trúc lại thành một trang trí, nhưng điều đó phần nào sẽ che giấu sự đơn giản của thành ngữ, vì vậy tôi thích sử dụng đơn giản, công khai này. BTW, lưu ý rằng thời gian sử dụng time.time và time.sleep, không phải là phút, là đơn vị thời gian của chúng, vì vậy bạn cần 60, không phải một, để chỉ ra "một phút từ bây giờ" ;-).

+0

Tôi đã giữ đề xuất cho một người trang trí – DrFalk3n

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