Condividi tramite


Uso del timeout

Utilizzare i timeout per specificare il tempo massimo che un chiamante è disposto ad attendere per completare la chiamata di un metodo.

Un timeout può assumere la forma di un parametro per la chiamata al metodo, come riportato di seguito.

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

In alternativa, è possibile utilizzare un timeout come una proprietà sulla classe server, come riportato di seguito.

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

È preferibile il primo approccio, poiché l'associazione tra l'operazione e il timeout è più evidente. L'approccio che si basa sulla proprietà è migliore se la classe server è progettata come un componente utilizzato con le progettazioni visive.

I timeout sono stati rappresentati sempre da interi. I timeout con gli interi sono difficili da utilizzare in quanto l'unità del timeout non è chiara ed è complesso tradurre le unità di tempo nei millisecondi comunemente utilizzati.

L'approccio migliore è l'utilizzo della struttura TimeSpan come tipo di timeout. La struttura TimeSpan consente infatti di risolvere i problemi relativi ai timeout con gli interi descritti precedentemente. Nell'esempio di codice seguente viene descritto come utilizzare un timeout del 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());
    }
};

Quando il timeout è impostato su TimeSpan(0), il metodo deve generare un'eccezione se l'operazione non viene completata immediatamente. Se il timeout è TimeSpan.MaxValue il timeout per l'operazione non si verifica, come se non fosse stato impostato alcun timeout. Non è necessaria una classe server per supportare questi valori, ma è necessario generare un'eccezione ArgumentException se viene specificato un valore di timeout non supportato.

Se il timeout scade e viene generata un'eccezione, la classe server deve annullare l'operazione sottostante.

Se viene utilizzato un timeout predefinito, nella classe server deve essere inclusa una proprietà statica che specifica il timeout da utilizzare se questo non è specificato dall'utente. Nell'esempio di codice riportato di seguito viene illustrata l'implementazione di una proprietà che specifica il timeout predefinito.

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

I tipi che non sono in grado di risolvere i timeout alla risoluzione di un tipo TimeSpan devono arrotondare il timeout all'intervallo più vicino possibile. Un tipo che supporta solo incrementi di un secondo, ad esempio, deve essere arrotondato al secondo più vicino. Un'eccezione a questa regola si ha quando un valore viene arrotondato a zero. In questo caso è necessario arrotondare il timeout al valore minimo possibile. L'arrotondamento a un valore che non sia zero evita cicli busy-wait in cui un valore zero per il timeout causa l'utilizzo del 100% del processore.

Inoltre, alla scadenza di un timeout è consigliabile generare un'eccezione anziché restituire il codice di errore. La scadenza di un timeout implica l'impossibilità di completare correttamente l'operazione, la quale deve pertanto essere trattata e gestita come un qualsiasi errore di runtime. Per ulteriori informazioni, vedere Linee guida di progettazione delle eccezioni.

Nel caso di un'operazione asincrona con un timeout, è necessario chiamare la funzione di callback e generare un'eccezione quando si accede per la prima volta ai risultati dell'operazione, come illustrato nell'esempio di codice riportato di seguito.

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. Tutti i diritti riservati.

Portions Copyright Addison-Wesley Corporation. Tutti i diritti riservati.

Per ulteriori informazioni sulle linee guida di progettazione, vedere “le linee guida di progettazione di Framework: Idiomi convenzioni, e modelli per libro raccolte riutilizzabili .NET„ di Krzysztof Cwalina e brad Abrams, emessi da Addison-Wesley, 2005.

Vedere anche

Concetti

Linee guida di utilizzo

Altre risorse

Linee guida di progettazione per lo sviluppo di librerie di classi

Modelli di progettazione della programmazione asincrona