2008-12-01 30 views
6

Hãy nói rằng tôi có một thể hiện System.Threading.Timer hiện và tôi muốn kêu gọi thay đổi vào nó để đẩy nó bắn thời gian trở lại:"nguyên tử" thay đổi một System.Threading.Timer

var timer = new Timer(DelayCallback, null, 10000, Timeout.Infinite); 
// ... (sometime later but before DelayCallback has executed) 
timer.Change(20000, Timeout.Infinite); 

tôi đang sử dụng bộ hẹn giờ này để thực hiện "cuộc gọi nhàn rỗi" sau một khoảng thời gian không có hoạt động. ("Không hoạt động" và "không hoạt động" là các điều kiện do ứng dụng xác định trong trường hợp này ... các chi tiết cụ thể không quan trọng lắm.) Mỗi ​​lần tôi thực hiện "hành động", tôi muốn đặt lại bộ hẹn giờ để luôn được đặt để bắn 10 giây sau đó.

Tuy nhiên, có điều kiện chủng tộc cố hữu vì khi tôi gọi Thay đổi, tôi không thể biết Bộ hẹn giờ đã được kích hoạt dựa trên cài đặt cũ của nó hay chưa. (Tôi có thể, tất nhiên, cho biết nếu gọi lại của tôi đã xảy ra nhưng tôi không thể biết liệu chủ đề bộ đếm thời gian nội bộ của CLR đã xếp hàng đợi cuộc gọi lại của tôi đến threadpool và việc thực thi của nó sắp xảy ra chưa.)

Bây giờ tôi biết tôi có thể gọi Vứt bỏ trên trường hợp bộ hẹn giờ và tạo lại mỗi lần tôi cần "đẩy lại". nhưng điều này dường như kém hiệu quả hơn là chỉ thay đổi bộ hẹn giờ hiện có. Tất nhiên nó có thể không được ... Tôi sẽ chạy một số điểm chuẩn vi mô trong một chút và cho bạn biết tất cả.

Ngoài ra, tôi luôn có thể theo dõi thời gian kích hoạt dự kiến ​​(thông qua DateTime.Now.AddSeconds (10)) và nếu Timer ban đầu kích hoạt, bỏ qua nó bằng cách kiểm tra DateTime.Now trong gọi lại. (Tôi có một mối quan tâm dai dẳng rằng điều này có thể không đáng tin cậy 100% trên tài khoản của Timer sử dụng TimeSpan và kiểm tra của tôi bằng cách sử dụng DateTime ... điều này có thể không phải là một vấn đề nhưng tôi không hoàn toàn thoải mái với nó vì lý do nào đó ...)

câu hỏi của tôi là:

  1. có cách nào tốt cho tôi để gọi Timer.Change và có thể biết liệu tôi có cố gắng thay đổi nó trước khi gọi lại được xếp hàng đợi đến threadpool? (Tôi không nghĩ như vậy, nhưng nó không làm tổn thương để yêu cầu ...)
  2. Có ai khác đã triển khai (thuật ngữ tôi gọi) là "bộ đếm thời gian phản hồi" như thế này không? Nếu vậy, tôi rất muốn nghe cách bạn giải quyết vấn đề.

Câu hỏi này có phần giả định về bản chất vì tôi đã có một vài giải pháp làm việc (dựa trên Vứt bỏ và dựa trên DateTime.Now) ... Tôi rất quan tâm đến việc nghe các đề xuất liên quan đến hiệu suất (như tôi sẽ được "đẩy lùi" Timer RẤT thường xuyên).

Cảm ơn!

Trả lời

0

Tôi thực sự phải tạo lớp "Thời gian" của riêng mình cho một MMORPG mà tôi đã tạo. Nó có thể theo dõi hơn 100.000 "thực thể" có bộ hẹn giờ để xử lý AI và các tác vụ khác. Dựa trên các hành động khác nhau có thể được thực hiện, tôi sẽ phải tạm thời trì hoãn một sự kiện.

Bây giờ, lớp thời gian của tôi đã được viết hoàn toàn bằng tay, vì vậy nó sẽ không chính xác những gì bạn đang tìm kiếm. Nhưng một cái gì đó mà bạn có thể làm điều đó sẽ là tương tự như giải pháp tôi đưa ra là để làm một loại:

while (sleepyTime > 0) 
{ 
    int temp = sleepyTime; 
    sleepyTime = 0; 
    Thread.Sleep(temp); 
} 

// here's where your actual code is. 

Sau đó, bạn có thể thực hiện một "Delay" phương pháp đó về cơ bản chỉ là quảng cáo để sleepyTime.

1

nó có vẻ giống như những gì bạn thực sự muốn là ứng dụng nhàn rỗi sự kiện

System.Windows.Forms.Application.Idle 
1

Im giải thích câu hỏi của bạn như là một yêu cầu cho một implementatation của giao diện IdleNotifier quy định dưới đây. Ngoài ra bạn nói rằng ActionOccured() cần phải nhanh.

public delegate void IdleCallback(); 
public interface IdleNotifier 
{ 
    // Called by threadpool when more than IdleTimeSpanBeforeCallback 
    // has passed since last call on ActionOccured. 
    IdleCallback Callback { set; } 
    TimeSpan IdleTimeSpanBeforeCallback { set; } 
    void ActionOccured(); 
} 

Tôi cung cấp triển khai với System.Threading.Timer bên dưới. Các điểm quan trọng về việc triển khai:

  • Chúng tôi chấp nhận rằng bộ hẹn giờ có thể thức dậy bất cứ lúc nào và đảm bảo điều này là ổn.
  • Vì chúng tôi cho rằng bộ hẹn giờ hoạt động tương đối hiếm khi chúng tôi có thể thực hiện công việc tốn kém vào những thời điểm này.
  • Vì chúng ta có thể thực hiện tất cả logic trong gọi lại bộ hẹn giờ, tất cả những gì chúng ta cần làm để "đẩy bộ hẹn giờ" là để nhớ khi chúng tôi đã đẩy nó lần cuối.

Thực hiện:

public class IdleNotifierTimerImplementation : IdleNotifier 
{ 
    private readonly object SyncRoot = new object(); 
    private readonly Timer m_Timer; 

    private IdleCallback m_IdleCallback = null; 
    private TimeSpan m_IdleTimeSpanBeforeEvent = TimeSpan.Zero; 

    // Null means there has been no action since last idle notification. 
    private DateTime? m_LastActionTime = null; 

    public IdleNotifierTimerImplementation() 
    { 
     m_Timer = new Timer(OnTimer); 
    } 

    private void OnTimer(object unusedState) 
    { 
     lock (SyncRoot) 
     { 
      if (m_LastActionTime == null) 
      { 
       m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero); 
       return; 
      } 
      TimeSpan timeSinceLastUpdate = DateTime.UtcNow - m_LastActionTime.Value; 
      if (timeSinceLastUpdate > TimeSpan.Zero) 
      { 
       // We are no idle yet. 
       m_Timer.Change(timeSinceLastUpdate, TimeSpan.Zero); 
       return; 
      } 
      m_LastActionTime = null; 
      m_Timer.Change(m_IdleTimeSpanBeforeEvent, TimeSpan.Zero); 
     } 
     if (m_IdleCallback != null) 
     { 
      m_IdleCallback(); 
     } 
    } 

    // IdleNotifier implementation below 

    public void ActionOccured() 
    { 
     lock (SyncRoot) 
     { 
      m_LastActionTime = DateTime.UtcNow; 
     } 
    } 

    public IdleCallback Callback 
    { 
     set 
     { 
      lock (SyncRoot) 
      { 
       m_IdleCallback = value; 
      } 
     } 
    } 

    public TimeSpan IdleTimeSpanBeforeCallback 
    { 
     set 
     { 
      lock (SyncRoot) 
      { 
       m_IdleTimeSpanBeforeEvent = value; 
       // Run OnTimer immediately 
       m_Timer.Change(TimeSpan.Zero, TimeSpan.Zero); 
      } 
     } 
    } 
} 

Có rất nhiều cải tiến hiệu suất thẳng về phía trước trên mã này.

Nếu bất cứ ai sẽ bị mê hoặc trong suy nghĩ đầu tiên của tôi về điều này, hãy hỏi tôi.

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