2012-01-18 23 views
12

Tôi đang viết dịch vụ cửa sổ sẽ xử lý "vài thứ" mỗi vài phút.Hành vi hẹn giờ khi thực thi mất nhiều thời gian hơn span?

Dưới đây là một số mã:

public Service() 
     { 
      this.InitializeComponent(); 
      this.ServiceName = Name; 
      this.CanPauseAndContinue = true; 
      this.CanShutdown = true; 

      this.eventLog.Source = Name; 

      // initialize timer 
      this.timer.Elapsed += this.TimerElapsed; 
     } 

     private void TimerElapsed(object sender, ElapsedEventArgs e) 
     { 
      eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information); 

      if (this.processor.PrepareToRun()) 
      { 
       this.processor.Run(); 
      } 
     } 

Tôi tự hỏi điều gì sẽ xảy ra nếu this.processor.Run() sẽ mất thời gian dài và TimerElapsed sự kiện tiếp theo sẽ được nâng lên? Nó sẽ bỏ qua? Nó sẽ chờ và chạy ASAP sau khi hoàn thành? Tôi có nên xem xét các kịch bản và mã đó cho họ không?

Tôi đang sử dụng System.Timers.Timer

EDIT:

private void TimerElapsed(object sender, ElapsedEventArgs e) 
     { 
      eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information); 

      try 
      { 
       this.timer.Stop(); 
       if (this.processor.PrepareToRun()) 
       { 
        this.processor.Run(); 
       } 
      } 
      catch (Exception ex) 
      { 
       LoggingAndNotifications.LogAndNotify(ex); 

      } 
      finally 
      { 
       this.timer.Start(); 
      } 
     } 

EDIT 2

public Service() 
     { 
      this.InitializeComponent(); 
      this.ServiceName = Name; 
      this.CanPauseAndContinue = true; 
      this.CanShutdown = true; 

      this.eventLog.Source = Name; 

      // initialize timer 
      this.timer.AutoReset = false; 
      this.timer.Elapsed += this.TimerElapsed; 
     } 

     private void TimerElapsed(object sender, ElapsedEventArgs e) 
     { 
      eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information); 

      try 
      { 
       if (this.processor.PrepareToRun()) 
       { 
        this.processor.Run(); 
       } 
      } 
      catch (Exception ex) 
      { 
       LoggingAndNotifications.LogAndNotify(ex); 
       throw; 
      } 
      finally 
      { 
       this.timer.Start(); 
      } 
     } 

Trả lời

10

Nó sẽ gọi nó là một lần nữa vào thread khác.

Tuỳ theo tính chất của hoạt động, bạn sẽ muốn một trong hai:

  1. Bỏ qua này, nếu mã được gọi là an toàn cho nhiều cuộc gọi đồng thời thì đây có thể là tốt. Tất nhiên, bạn phải biết là không sao.
  2. Khóa trên thao tác kích hoạt hẹn giờ. Xin lưu ý rằng bạn có thể kết thúc bằng một loạt các hoạt động đang chờ xử lý, tức là rất xấu.
  3. Khóa trên hoạt động được kích hoạt hẹn giờ, cố gắng lấy khóa bằng thời gian chờ bằng 0 và nếu bạn thất bại thì bỏ qua - có một chuỗi vẫn ở đây từ lần cuối.
  4. Đặt hẹn giờ làm bộ hẹn giờ một lần mà bạn khởi động lại ở cuối mỗi cuộc gọi.
+0

Tôi thích # 4 cho tình huống cụ thể của mình. Chỉnh sửa của tôi (trong bài đăng gốc) có chính xác không nếu tôi muốn kịch bản đó? – katit

+4

Dừng bộ hẹn giờ sẽ không giúp đỡ, cuộc gọi xử lý sự kiện đã qua có thể bị trì hoãn nếu có nhiều chuỗi TP hoạt động trong tiến trình. Đặt thuộc tính AutoReset thành false thay thế. –

+0

Tôi rất thận trọng với 2. 1 hoặc là làm việc rõ ràng hay không, nhưng thật tuyệt khi bạn thực sự cần nó mỗi X phút. Sự khác biệt giữa 3 và 4 là giữa "mỗi x phút với một số bỏ qua" và "mỗi x phút sau khi kết thúc lần cuối". Cả hai đều có vị trí của họ và thường là tốt. Bạn không cần '.Stop()' bộ đếm thời gian, nó dễ dàng hơn và an toàn hơn (chỉ trong trường hợp một số trường hợp freaky có nghĩa là bạn thậm chí không nhận được rằng đến nay) để có nó không tự động thiết lập lại ở nơi đầu tiên. Đặt 'AutoReset' thành false hoặc sử dụng System.Threading.Timer với khoảng thời gian' Timeout.Infinite'. –

3

Bạn có thể xem những gì sẽ xảy ra với ứng dụng mẫu này:

class Program 
{ 
    static void Main(string[] args) 
    { 
     System.Timers.Timer timer = new System.Timers.Timer(2000); 
     timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedObject); 
     timer.Start(); 

     while (true) 
     { 
     } 

    } 

    static void OnTimedObject(object source, ElapsedEventArgs e) 
    { 
     Console.WriteLine("entered"); 
     Thread.Sleep(3000); 
     Console.WriteLine("exited"); 

    } 
} 

Bạn sẽ thấy hai 'nhập' chuỗi xuất hiện trước khi 'thoát' đầu tiên xuất hiện. No se tiêp tục. Vì vậy, các chủ đề sẽ không bước vào nhau.

(BTW, tôi không ủng hộ vòng lặp vô hạn. :))

+0

Không có lý do gì để không ủng hộ vòng lặp vô hạn. Một vài trường hợp mà một người cố tình có vị trí của nó (ví dụ như bơm thông báo cửa sổ) là một vài trường hợp mà những người cố tình có trường hợp của họ, và phần còn lại là lỗi rõ ràng và không phải trong "có vẻ như là một ý tưởng hay để không ủng hộ nó "trại. –

2

Khi sự kiện hẹn giờ được nâng lên, mã hẹn giờ được lên lịch thực hiện trên hồ bơi chuỗi. Nhiều khả năng nó sẽ được thực hiện trong một chủ đề khác nhưng nó phụ thuộc vào các yếu tố khác nhau (# của bộ xử lý, sử dụng luồng vv). Tuy nhiên nó không có gì với tính giờ - đó là nhiệm vụ của hồ bơi chủ đề.

Cá nhân tôi không bao giờ sử dụng khoảng thời gian hẹn giờ. Tôi thiết lập bộ đếm thời gian để chạy một lần và sau khi mã của tôi được thực hiện thiết lập nó một lần nữa. Vì vậy, tôi đảm bảo rằng mã được thực thi chỉ trong chuỗi đơn.

3

tôi sử dụng sau đây nếu tôi không muốn sa thải hẹn giờ tiếp theo để thực hiện phương pháp này một lần nữa trước khi nó hoàn thành:

private void TimerFired(object sender, System.Timers.ElapsedEventArgs e) { 
    // only execute the code within this method if we are able to 
    // get a lock. This will ensure that any Timer firings will be 
    // ignored that occur while we're already doing work (OnTimer) 
    if (Monitor.TryEnter(lockObj)) { 
     try { 
      // do work here 
     } finally { 
      Monitor.Exit(lockObj); 
     } 
    } 
} 

cách khác, nếu phương pháp này có thể có một thời gian dài hơn khoảng thời gian hẹn giờ, phương pháp này có thể kết thúc bắt đầu thực hiện trên một luồng khác trước khi kết thúc đầu tiên.

+0

Trong trường hợp của bạn nếu thời lượng phương pháp dài hơn khoảng thời gian bạn sẽ kết thúc với nhiều thời gian chờ và phương thức sẽ được thực thi liên tục. –

+0

@ the_joric - Tôi không nghĩ đó là sự thật. TryEnter không phải là phương thức chặn và trả về ngay lập tức, trả về true hoặc false. Nếu nó được khóa, nó thực hiện công việc bên trong. Nếu không, phương pháp TimerFired sẽ thoát nhanh chóng mà không thực hiện bất kỳ công việc nào. – hatchet

+0

có, bạn là chính xác - lỗi của tôi :) –

0

Tôi đã thực hiện việc này để xử lý các tình huống như vậy. Tất nhiên bạn cần phải tinh chỉnh nó cho các trường hợp đặc biệt như các hành động đa luồng.

public Service() 
    { 
     bool _IsProcessRunning = false; 
     this.InitializeComponent(); 
     this.ServiceName = Name; 
     this.CanPauseAndContinue = true; 
     this.CanShutdown = true; 

     this.eventLog.Source = Name; 

     // initialize timer 
     this.timer.Elapsed += this.TimerElapsed; 
    } 

    private void TimerElapsed(object sender, ElapsedEventArgs e) 
    { 
     if(!_IsProcessRunning) 
     { 
      DoSomething(); 
     }   
    } 

    private void DoSomething() 
    { 
     try 
     { 
      _IsProcessRunning = true; 

      // Do our stuff here 
     } 
     catch(Exception Ex) 
     {    
     } 
     finally 
     { 
      _IsProcessRunning = false; 
     } 
    } 
0

Hành vi hẹn giờ khi thực hiện lâu hơn khoảng thời gian?

Khi thời gian thực hiện tác vụ Mất nhiều thời gian hơn Thời gian hẹn giờ Span. Sự kiện TimerElapsed sẽ được đưa vào một Thread mới. Nó sẽ không bị bỏ qua. Đa luồng được triển khai vào System.Timers.Timer

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