Исключения и производительность

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

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

При проектировании учитывайте вопросы производительности. В данном разделе описаны два шаблона.

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

Тестер-Doer шаблон делит вызов, который может вызвать исключения на две части: Тестер и исполнитель. Фрагмент Tester выполняет проверку состояния, которое может привести к тому, что фрагмент Doer генерирует исключение. Проверка вставляется непосредственно перед кодом, который может генерировать исключение, не допуская генерации исключения.

В следующем примере кода показан фрагмент Doer этого шаблона. В примере содержится метод, который генерирует исключение, когда ему передается значение null (Nothing в Visual Basic). Если этот метод вызывается достаточно часто, это может негативно сказаться на производительности.

Public Class Doer

    ' Method that can potential throw exceptions often.
    Public Shared Sub ProcessMessage(ByVal message As String)
        If (message = Nothing) Then
            Throw New ArgumentNullException("message")
        End If
    End Sub

    ' Other methods...
End Class
public class Doer
{
    // Method that can potential throw exceptions often.
    public static void ProcessMessage(string message)
    {
        if (message == null)
        {
            throw new ArgumentNullException("message");
        }
    }
    // Other methods...
}
public ref class Doer
{
public:
    // Method that can potential throw exceptions often.
    static void ProcessMessage(String^ message)
    {
        if (message == nullptr)
        {
            throw gcnew ArgumentNullException("message");
       }
    }
    // Other methods...
};

В следующем примере кода показан фрагмент Tester этого шаблона. Этот метод использует проверку для предотвращения вызова фрагмента Doer (ProcessMessage), когда Doer может генерировать исключение.

Public Class Tester

    Public Shared Sub TesterDoer(ByVal messages As ICollection(Of String))
        For Each message As String In messages
            ' Test to ensure that the call 
            ' won't cause the exception.
            If (Not (message) Is Nothing) Then
                Doer.ProcessMessage(message)
            End If
        Next
    End Sub
End Class
public class Tester
{
    public static void TesterDoer(ICollection<string> messages)
    {
        foreach (string message in messages)
        {
            // Test to ensure that the call
            // won't cause the exception.
            if (message != null)
            {
                Doer.ProcessMessage(message);
            }
        }
    }
}
public ref class Tester
{
public:
    static void TesterDoer(ICollection<String^>^ messages)
    {
        for each (String^ message in messages)
        {
            // Test to ensure that the call
            // won't cause the exception.
            if (message != nullptr)
            {
                Doer::ProcessMessage(message);
            }
        }
    }
};

Обратите внимание, что следует учитывать возможность потенциального состояния гонки, если этот шаблон используется в многопоточном приложении, где проверка включает в себя изменяющийся объект. Поток может модифицировать состояние изменяющегося объекта после проверки, но перед вызовом фрагмента Doer. Для решения этих проблем следует использовать синхронизацию потоков.

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

В реализации шаблона TryParse имеются два различных метода для выполнения операции, которая может генерировать исключения в обычных сценариях. В первом методе, X, операция выполняется, и исключение генерируется по мере необходимости. Во втором методе, TryX, исключение не генерируется, но вместо этого возвращается значение Boolean, обозначающее успех или неудачу. Все данные, возвращаемые успешным вызовом TryX, возвращаются при помощи параметра out (ByRef в Visual Basic). Методы Parse и TryParse являются примерами этого шаблона.

Для каждого члена, использующего шаблон TryParse, предоставьте член генерации исключения.

Практически во всех случаях некорректно предоставлять только метод TryX, так как это требует понимания параметров out. Кроме того, влияние исключений на производительность не является проблемой для большинства обычных сценариев; следует предоставлять методы, которые легко использовать в большинстве обычных сценариев.

Охраняется авторским правом Copyright 2005 Microsoft Corporation. Все права защищены.

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

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

См. также

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

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

Правила разработки исключений