C#异常过滤器性能

时间:2015-07-11 12:09:59

标签: c# performance visual-studio-2015

VS2015中引入的C#异常过滤器是否会在抛出异常时对性能,内存使用或堆栈产生影响?

异常过滤器:

try { … }
catch (Exception e) when (e.Message == "Hello world")
{
    // do stuff
}

传统捕获和重新投掷:

try { … }
catch (Exception e)
{
    if (e.Message == "Hello world")
    {
        // do stuff
    }
    else
    {
        throw;
    }
}

2 个答案:

答案 0 :(得分:2)

异常过滤的新C#6.0特性基本上颠覆了捕获异常然后检查条件的逻辑。

区别在于:

  • 在第一个示例中,首先检查条件,然后可能捕获异常。
  • 在第二个示例中,您每次都会捕获异常,然后根据内部条件决定要执行的操作。

所以我不确定具体的性能影响是什么,但我认为你的整体情况会更好。

如果条件没有达到,那么你不必展开堆栈,或者招致捕获和重新抛出的成本(异常没有被捕获/重新抛出......它根本就没有被捕获),或执行任何您可能已包含在catch语句中的其他逻辑。

答案 1 :(得分:2)

摘要

BenchmarkDotNet = v0.11.5,操作系统= Windows ..

Intel Core i7,.NET Core 2.2.5

+-----------------+--------+----------------------+-----------------+----------------+-----------------+------+------------+-------+-------+------------+
| Method          | N      | SearchedQueryIsMatch | Mean            | Error          | StdDev          | Rank | Gen 0      | Gen 1 | Gen 2 | Allocated  |
+-----------------+--------+----------------------+-----------------+----------------+-----------------+------+------------+-------+-------+------------+
| ExceptionFilter | 1      | False                | 21.29 us        | 0.3780 us      | 0.6912 us       | 2    | 0.0916     | -     | -     | 440 B      |
| IfStatement     | 1      | False                | 40.35 us        | 0.7339 us      | 0.6505 us       | 3    | 0.0610     | -     | -     | 440 B      |
| ExceptionFilter | 1      | True                 | 19.28 us        | 0.3831 us      | 0.8409 us       | 1    | 0.0305     | -     | -     | 216 B      |
| IfStatement     | 1      | True                 | 19.08 us        | 0.4230 us      | 0.6331 us       | 1    | 0.0305     | -     | -     | 216 B      |
| ExceptionFilter | 1000   | False                | 20,813.47 us    | 413.2388 us    | 537.3272 us     | 5    | 93.7500    | -     | -     | 440000 B   |
| IfStatement     | 1000   | False                | 40,412.30 us    | 645.9158 us    | 604.1901 us     | 6    | 76.9231    | -     | -     | 440000 B   |
| ExceptionFilter | 1000   | True                 | 18,433.85 us    | 257.8815 us    | 228.6052 us     | 4    | 31.2500    | -     | -     | 216000 B   |
| IfStatement     | 1000   | True                 | 18,510.49 us    | 366.2362 us    | 324.6588 us     | 4    | 31.2500    | -     | -     | 216000 B   |
| ExceptionFilter | 100000 | False                | 2,037,740.01 us | 46,797.1438 us | 57,471.0953 us  | 8    | 10000.0000 | -     | -     | 44000000 B |
| IfStatement     | 100000 | False                | 4,057,642.15 us | 80,944.2280 us | 179,366.8182 us | 9    | 10000.0000 | -     | -     | 44000000 B |
| ExceptionFilter | 100000 | True                 | 1,835,382.75 us | 35,810.5411 us | 42,629.9019 us  | 7    | 5000.0000  | -     | -     | 21600000 B |
| IfStatement     | 100000 | True                 | 1,833,703.56 us | 34,189.6215 us | 31,980.9932 us  | 7    | 5000.0000  | -     | -     | 21600000 B |
+-----------------+--------+----------------------+-----------------+----------------+-----------------+------+------------+-------+-------+------------+

传奇

  • N:“ N”参数的值
  • SearchedQueryIsMatch:“ SearchedQueryIsMatch”参数的值
  • 平均值:所有测量值的算术平均值
  • 错误:99.9%置信区间的一半
  • StdDev:所有测量的标准偏差
  • 排名:当前基准均值在所有基准(阿拉伯风格)中的相对位置
  • 第0代:GC的第0代每1000次操作收集一次
  • 第1代:GC第1代每1000次操作收集一次
  • 第2代:GC第2代每1000次操作收集一次
  • 已分配:每项操作的已分配内存(仅受管理的内存,包括1KB = 1024B)
  • 1 us:1微秒(0.000001秒)

示例代码

    public class Program
    {
        [CoreJob]
        [RPlotExporter, RankColumn, MemoryDiagnoser]
        public class CollectionsContains
        {
            private const string SearchedMessage = "hello world";

            [Params(1, 1_000, 100_000)]
            private int N;

            [Params(true, false)]
            private bool SearchedQueryIsMatch;

            [Benchmark]
            public void ExceptionFilter() => ExecuteTestFor(exception =>
            {
                try
                {
                    throw exception;
                }
                catch (Exception ex) when (ex.Message == SearchedMessage)
                {

                }
            });

            [Benchmark]
            public void IfStatement() => ExecuteTestFor(exception =>
            {

                try
                {
                    throw exception;
                }
                catch (Exception ex)
                {
                    if (ex.Message == SearchedMessage)
                    {
                        return;
                    }

                    throw;
                }

            });

            private void ExecuteTestFor(Action<Exception> testedExceptionHandling)
            {
                for (int i = 0; i < N; i++)
                {
                    try
                    {
                        var exception = new Exception(SearchedQueryIsMatch ? SearchedMessage : Guid.NewGuid().ToString());
                        testedExceptionHandling(exception);
                    }
                    catch
                    {
                    }
                }
            }
        }

        private static void Main() => BenchmarkRunner.Run<CollectionsContains>();
    }