Использование времени ожидания

Используйте тайм-ауты для задания максимального времени, в течение которого вызывающий объект ожидает завершения вызова метода.

Тайм-аут может принимать форму параметра при вызове метода, как показано ниже.

server.PerformOperation(timeout)
server.PerformOperation(timeout);

С другой стороны, тайм-аут может использоваться как свойство в классе серверов.

server.Timeout = timeout
server.PerformOperation()
server.Timeout = timeout;
server.PerformOperation();   

Предпочтительным является первый подход, поскольку в нем более понятна связь между операцией и тайм-аутом. Подход на основе свойства может оказаться лучше, если разработанный класс серверов должен представлять собой компонент, используемый с визуальным конструктором.

Исторически тайм-ауты представляются целыми числами. Тайм-аут, выраженный целыми числами, может оказаться неудобным, поскольку неясна его единица измерения и сложен ее перевод в общепринятые миллисекунды.

Лучше всего использовать в качестве типа таймаута структуру TimeSpan. TimeSpan устраняет проблемы с целыми таймаутами, о которых говорилось выше. В следующем примере кода показано, как использовать тайм-аут типа TimeSpan .

Public Class Server
   Public Sub PerformOperation(timeout As TimeSpan)
      ' Insert code for the method here.
      Console.WriteLine("performing operation with timeout {0}", _
        timeout.ToString())
   End Sub
End Class

public class Server
{
   public void PerformOperation(TimeSpan timeout)
   {
      // Insert code for the method here.
      Console.WriteLine("performing operation with timeout {0}", 
        timeout.ToString());
   }
}
public ref class Server
{
public:
    void PerformOperation(TimeSpan timeout)
    {
        // Insert code for the method here.
        Console::WriteLine("performing operation with timeout {0}",
            timeout.ToString());
    }
};

Если значение тайм-аута устанавливается в TimeSpan(0), то метод должен сгенерировать исключение, если операция не завершена немедленно. Если тайм-аут равен TimeSpan.MaxValue, эта операция должна ожидать неограниченно долго, как если бы тайм-аут не был задан. Для поддержки любого из этих значений серверный класс не требуется, но при задании неподдерживаемого значения тайм-аута должно быть сгенерировано исключение ArgumentException.

Если тайм-аут истек и сгенерировано исключение, серверный класс должен отменить основную операцию.

Если используется тайм-аут по умолчанию, серверный класс должен включать в себя статическое свойство, описывающее тайм-аут, которое будет использоваться, если тайм-аут не задается пользователем. В следующем примере кода демонстрируется реализация свойства, которое задает значение тайм-аута по умолчанию.

Class ServerWithDefault
   Private Shared defaultTimeout As New TimeSpan(1000)

   Public Overloads Sub PerformOperation()
      Me.PerformOperation(DefaultOperationTimeout)
   End Sub 

   Public Overloads Sub PerformOperation(timeout As TimeSpan)
      ' Insert code here.
      Console.WriteLine("performing operation with timeout {0}", _
        timeout.ToString())
   End Sub 

   Public Shared ReadOnly Property DefaultOperationTimeout As TimeSpan
      Get
         Return defaultTimeout
      End Get
   End Property
End Class 

class ServerWithDefault
{
   static TimeSpan defaultTimeout = new TimeSpan(1000); 

   public void PerformOperation()
   {
      this.PerformOperation(DefaultOperationTimeout);
   }

   public void PerformOperation(TimeSpan timeout)
   {
      // Insert code here.
      Console.WriteLine("performing operation with timeout {0}", 
        timeout.ToString());
   }

   public static TimeSpan DefaultOperationTimeout
   {
      get
      {
         return defaultTimeout;
      }
   }
}
ref class ServerWithDefault
{
private:
    static TimeSpan defaultTimeout = TimeSpan(1000);

public:
    void PerformOperation()
    {
        this->PerformOperation(DefaultOperationTimeout);
    }

    void PerformOperation(TimeSpan timeout)
    {
        // Insert code here.
        Console::WriteLine("performing operation with timeout {0}",
            timeout.ToString());
    }

    static property TimeSpan DefaultOperationTimeout
    {
       TimeSpan get()
       {
           return defaultTimeout;
       }
    }
};

Для типов, у которых отсутствует возможность округления с точностью TimeSpan, должно применяться округление тайм-аута до ближайшего подходящего интервала. Например, для типа, интервал ожидания которого может иметь только односекундные приращения, должно применяться округление тайм-аута до ближайшей секунды. Исключением из этого правила является округление значения в меньшую сторону до нуля. В этом случае тайм-аут должен округляться вверх до минимально возможного значения. Округление до ненулевого значения предотвращает возникновения циклов вида "занят ожиданием", когда нулевое значение тайм-аута приводит к 100-процентной загрузке процессора.

Кроме того, по истечении тайм-аута рекомендуется генерация исключения вместо возврата кода ошибки. Истечение тайм-аута означает, что операция не могла быть успешно завершена, и, следовательно, оно должно рассматриваться и обрабатываться как любая другая ошибка времени выполнения. Дополнительные сведения см. в разделе Правила разработки исключений.

При первом обращении к результатам асинхронной операции с тайм-аутом следует вызвать функцию обратного вызова и сгенерировать исключение. Это показано в следующем примере кода.

Sub OnReceiveCompleted(ByVal sender As System.Object, ByVal asyncResult As ReceiveCompletedEventArgs)
   Dim queue As MessageQueue = CType(sender, MessageQueue)
   ' The following code will throw an exception
   ' if BeginReceive has timed out.
   Dim message As Message = queue.EndReceive(asyncResult.AsyncResult)
   Console.WriteLine(("Message: " + CStr(message.Body)))
   queue.BeginReceive(New TimeSpan(1, 0, 0))
End Sub 
void OnReceiveCompleted(Object sender, ReceiveCompletedEventArgs asyncResult)
{
   MessageQueue queue = (MessageQueue) sender;
   // The following code will throw an exception
   // if BeginReceive has timed out.
   Message message = queue.EndReceive(asyncResult.AsyncResult);
   Console.WriteLine("Message: " + (string)message.Body);
queue.BeginReceive(new TimeSpan(1,0,0));
}

Фрагменты — © Корпорация Майкрософт (Microsoft Corp.), 2005. Все права защищены.

Фрагменты — © Addison-Wesley Corporation. Все права защищены.

Для дополнительной информации о разработке руководящих принципов, смотрите "руководства по разработке рамок: Конвенций, идиомы и шаблоны для повторного использования.NET библиотек"книга, Кшиштоф Cwalina и Брэд Абрамс, опубликованных Addison-Wesley, 2005 года.

См. также

Основные понятия

Правила использования

Другие ресурсы

Руководство по разработке библиотек классов

Шаблоны разработки для асинхронного программирования