Share via


Uso de tiempos de espera

Utilice los tiempos de espera para especificar el tiempo máximo que un llamador está dispuesto a esperar para finalizar una llamada al método.

Los tiempos de espera pueden adoptar el formato de un parámetro en la llamada al método, como se muestra a continuación.

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

Otra posibilidad es utilizar los tiempos de espera como una propiedad de la clase de servidor, como se muestra a continuación.

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

Conviene utilizar el primer enfoque, porque la asociación entre la operación y el tiempo de espera es más clara. El enfoque basado en la propiedad puede mejorar si la clase de servidor se diseña para ser un componente que se utilice con diseñadores visuales.

Tradicionalmente, los tiempos de espera se han representado mediante enteros. Resulta complicado utilizar números enteros, ya que la unidad del tiempo de espera no es evidente y es difícil convertir las unidades de tiempo a los milisegundos que se utilizan habitualmente.

Un mejor enfoque es utilizar la estructura TimeSpan como el tipo de tiempo de espera. TimeSpan resuelve los problemas con los tiempos de espera enteros mencionados antes. En el siguiente ejemplo de código se muestra cómo utilizar un tiempo de espera de tipo 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());
    }
};

Si el tiempo de espera se establece en TimeSpan(0), el método deberá iniciar una excepción si la operación no se completa inmediatamente. Si el tiempo de espera es TimeSpan.MaxValue, la operación debe esperar siempre sin que se agote el tiempo de espera, como si no se hubiese establecido el tiempo de espera. No es necesario que la clase de servidor sea compatible con ninguno de estos valores, aunque debería iniciar una ArgumentException si se especifica un valor de tiempo espera no admitido.

Si expira el tiempo de espera y se inicia una excepción, la clase de servidor deberá cancelar la operación subyacente.

Si se utiliza un tiempo de espera predeterminado, la clase de servidor debería incluir una propiedad estática que especificara el tiempo de espera que se debería usar si el usuario no lo especifica. El ejemplo de código siguiente muestra cómo implementar una propiedad que especifica el tiempo de espera predeterminado.

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;
       }
    }
};

Los tipos que no pueden resolver los tiempos de espera de un TimeSpan deberán redondear el tiempo de espera al intervalo más cercano. Por ejemplo, un tipo que sólo puede esperar en incrementos de un segundo debería redondearse al segundo más cercano. La excepción a esta regla es cuando se redondea un valor a cero. En este caso, el tiempo de espera debe redondearse hacia arriba al valor de tiempo de espera mínimo posible. Al redondear a un número distinto de cero se evitan los bucles "busy-wait", en los que un tiempo de espera de valor cero provoca un uso del procesador del 100 por ciento.

Además, es conveniente iniciar una excepción cuando expira el tiempo de espera, en vez de devolver un código de error. Si expira el tiempo de espera significa que la operación no se ha podido completar correctamente y, por tanto, se debe tratar y administrar como cualquier otro error en tiempo de ejecución. Para obtener más información, vea Instrucciones de diseño de excepciones.

En el caso de una operación asincrónica con un tiempo de espera, se debe llamar a la función de devolución de llamada e iniciar una excepción la primera vez que se tiene acceso a los resultados de la operación. Esto se muestra en el siguiente ejemplo de código:

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));
}

Portions Copyright 2005 Microsoft Corporation. Reservados todos los derechos.

Portions Copyright Addison-Wesley Corporation. Reservados todos los derechos.

Para obtener más información sobre las directrices de diseño, consulte “las instrucciones de diseño de Framework: Convenciones, frases realizadas y modelos para libro de bibliotecas reutilizables de .NET” de Krzysztof Cwalina y Brad Abrams, publicados por Addison-Wesley, 2005.

Vea también

Conceptos

Instrucciones de uso

Otros recursos

Instrucciones de diseño para desarrollar bibliotecas de clases

Modelos de diseño para la programación asincrónica