Verwenden von Timeouts
Verwenden Sie Timeouts, um anzugeben, wie lange ein Aufrufer maximal auf den Abschluss eines Methodenaufrufs warten soll.
Ein Timeout kann wie folgt die Form eines Parameters für den Methodenaufruf annehmen:
server.PerformOperation(timeout)
server.PerformOperation(timeout);
Alternativ dazu kann ein Timeout wie folgt als Eigenschaft für die Serverklasse verwendet werden:
server.Timeout = timeout
server.PerformOperation()
server.Timeout = timeout;
server.PerformOperation();
Der erste Ansatz ist vorzuziehen, da hier die Verknüpfung zwischen der Operation und dem Timeout klarer ist. Die Verwendung einer Eigenschaft ist zu empfehlen, wenn die Serverklasse als Komponente für die Verwendung in grafischen Designeroberflächen konzipiert ist.
Traditionell werden Timeouts durch ganze Zahlen dargestellt. Ganzzahlige Timeoutwerte können jedoch eine Herausforderung darstellen, da nicht offensichtlich ist, welche Einheit für sie verwendet wird und die Übertragung von Zeiteinheiten in die üblichen Millisekunden schwierig ist.
Daher ist die Verwendung der TimeSpan-Struktur als Timeouttyp vorzuziehen. TimeSpan löst die oben erwähnten Probleme mit ganzzahligen Timeoutwerten. Das folgende Codebeispiel veranschaulicht die Verwendung eines Timeouts vom Typ 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());
}
};
Wird für das Timeout TimeSpan(0) festgelegt, sollte die Methode eine Ausnahme auslösen, wenn die Operation nicht sofort abgeschlossen wird. Wenn das Timeout TimeSpan.MaxValue ist, sollte die Operation unendlich lange warten, ohne dass eine Zeitüberschreitung eintritt, als ob gar kein Timeout festgelegt wäre. Eine Serverklasse muss keinen dieser Werte unterstützen. Sie sollte jedoch eine ArgumentException-Ausnahme auslösen, wenn ein nicht unterstützter Timeoutwert angegeben wird.
Wenn ein Timeout abläuft und eine Ausnahme ausgelöst wird, sollte die Serverklasse die zugrunde liegende Operation abbrechen.
Bei Verwendung eines Standardtimeouts sollte die Serverklasse eine statische Eigenschaft enthalten, die das Timeout angibt, das verwendet wird, wenn der Benutzer kein Timeout angibt. Im folgenden Codebeispiel wird das Implementieren einer Eigenschaft veranschaulicht, die das Standardtimeout angibt.
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;
}
}
};
Typen, die Timeouts nicht als TimeSpan auflösen können, sollten das Timeout auf das nächste geeignete Intervall runden. Beispielsweise sollte ein Typ, bei dem die Wartedauer in Ein-Sekunden-Intervallen erhöht wird, auf die nächste volle Sekunde gerundet werden. Eine Ausnahme von dieser Regel liegt vor, wenn ein Wert auf Null abgerundet werden soll. In diesem Fall sollte das Timeout auf das kleinste mögliche Timeout aufgerundet werden. Durch Runden auf andere Werte als 0 (null) werden Busy-Wait-Schleifen verhindert, bei denen ein Timeoutwert von 0 (null) zu einer Prozessorauslastung von 100 % führt.
Es wird außerdem empfohlen, beim Ablauf eines Timeouts eine Ausnahme auszulösen, anstatt einen Fehlercode zurückzugeben. Der Ablauf eines Timeouts bedeutet, dass die Operation nicht erfolgreich abgeschlossen wurde und daher wie jeder andere Laufzeitfehler behandelt werden sollte. Weitere Informationen finden Sie unter Entwurfsrichtlinien für Ausnahmen.
Im Falle einer asynchronen Operation mit einem Timeout sollte die Rückruffunktion aufgerufen und eine Ausnahme ausgelöst werden, wenn zum ersten Mal auf die Ergebnisse der Operation zugegriffen wird. Dies wird im folgenden Codebeispiel gezeigt.
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));
}
Copyright für einzelne Teile 2005 Microsoft Corporation. Alle Rechte vorbehalten.
Copyright für einzelne Teile Addison-Wesley Corporation. Alle Rechte vorbehalten.
Weitere Informationen zu Entwurfsrichtlinien finden Sie unter „Framework-Entwurfs-Richtlinien: Idiome, Konventionen und Muster für wiederverwendbare .NET-Bibliotheken von Krzysztof Cwalina“ book und Brad Abrams, veröffentlicht von Addison-Wesley, 2005.