I read that using try-catch very resource intensive. Is it so?

If so, how should try-catch properly be used?

Theoretically, you can practically do everything in the old manner, through return codes, bypassing the use of try-catch , but then the code will suffer in terms of readability due to cumbersome if or switch sequences.

  • one
    To cope with the loss of readability when using if / switch you can use the functional paradigm, namely the Either monad. But if you have not encountered this before, then this approach may seem rather unusual. Here is the implementation of monads (in that chile and Either ) in C #. - awesoon
  • 2
    @soon, do you think the code will get faster with monads? :-) - Tagir Valeev
  • one
    @TagirValeev, I think that the code will become clearer than the option with a garden if / switch - this is what I focused on. - awesoon

4 answers 4

To begin with, determine for yourself what “resource-intensive” is. Any performance issue should be considered in context with the performance of the rest of the program. If you have an algorithm on integer arithmetic, then try/catch can significantly slow down performance (or not slow) in it. If you are writing to files or accessing a database, then the exception handling will be orders of magnitude faster than other operations, so there is no point in optimizing it.

Usually try/catch does not slow down the program at all if there are practically no exceptions. That is, throwing an exception only in case of an error, you will not lose in performance when there are no errors. If an error has occurred, then the operation of your algorithm will still be interrupted, so it is not so important that you once lose an additional pair of microseconds (hardly more) before issuing an error to the user.

You only need to worry if you throw a million exceptions in a loop, then catch them, ignore them and go to the next iteration. But this code just smacks: it turns out that you use exceptions to control the flow of computations, and not to inform about the exception. But even in such a situation, the JIT compiler can figure it out. If within the inline code he sees both throwing out exceptions and catching and noticing that you catch ignore the catch (in particular, do not read the template from it), then it can potentially replace throwing the exception to the usual goto without creating an exception object at all. In general, usually the slowest thing in an exception is the creation of the frame.

The general rule: write the code as recommended by the authors of the language and recognized experts in this field. If the performance of the code does not suit you, profile it, find the bottlenecks and optimize them (perhaps, retreating from the beauty of the code for the sake of speed). But do not optimize what takes half a percent of the total execution time. No need to optimize prematurely.

    Should not use return codes to communicate errors .

    You approach the problem from the wrong side. The real choice is not whether to use try / catch or return code. And, rather, "throw an exception or return the code."

    There are a couple of basic rules :

    • exceptions should not be used for normal control flow.
    • exceptions in the code should always indicate an error - an exceptional situation - something went wrong, as planned.
    • in case of error, you should always use the use exception, not the return code.

    It all comes down to the definition of “as planned” and “what was expected,” “whether an error occurred, or everything goes fine” in a specific context. Here are a couple of examples:

    1. The developer calls File.OpenRead . It is unlikely that he expects that the file does not exist, or that there will not be enough rights to open. Therefore, File.OpenRead should throw an exception (which it does).

    2. The developer gets the value from the cache by calling Page.Cache["news"] . Does he expect that the values ​​in the cache will not be - most likely yes, and even if the value in the cache was 5 minutes ago. What he does not exactly expect is the exceptions and the need to wrap the calls to the cache in try / catch.

    Is there a catch exception ? It depends on what you are going to do with them. There are only a few possible reasons for catching exceptions:

    • Your code can recover after the exception - it is normal to continue working. This is a rather rare situation. Usually, recovery comes down to trying to repeat the dropped call — and it applies only to remote services, such as databases. A typical example is a retry command to SQL Server when retrieving a deadlock.
    • Your code can add valuable data to the exception — to add something that will facilitate further debugging. In this case, the exception must be caught and thrown a new exception with the old one as an InnerException.
    • Your code is the top level code, for example, the UI or the main worker method. Then it is necessary to catch an exception in it, write it to the log and show the user a beautiful error message (if there is a user).

    In all other cases, there is no point in catching exceptions.

    All this is detailed enough in MSDN, Design Guidelines for Exceptions

    • Under the link I read about the Tester-Doer template, but did not understand its essence. Why do you need an exception that will never be thrown? msdn.microsoft.com/ru-ru/library/vstudio/… - iluxa1810
    • 3
      @ iluxa1810 there is a general sense of the example - if possible, check the data / state before transferring it somewhere deeper. This, rather, another answer to your question is not to intercept an exception or return code, but beforehand, in the calling method, check the data for validity, if possible. - PashaPash

    This is true only in theory, or in extreme cases, like cycles with a huge number of iterations. You can come up with a number of examples where using try would be undesirable because of slowness, but all of these are quite rare cases, most of which mean that either the author of the code writes very bad code that needs optimization and / or refactoring, or wants to use c # for some tasks that are too sensitive in terms of performance, and then probably C # and managed code are not the best choice.

    But in 99% of cases, concerns about the “slowness” of try / catch are savings on matches and the voluntary deprivation of the ability to write easily maintained code (all these torments with return codes can bring a lot of headaches).

    A little experiment. Do this code here.

      static void SomeAction() { var rand = new Random(); for (int i = 0; i < 1000; i++) rand.Next(); } static void Handle() { // просто заглушка } static void WithException(int iterations) { var watch = Stopwatch.StartNew(); try { for (int i = 0; i < iterations; i++) SomeAction(); throw new Exception(); } catch (Exception e) { Handle(); } watch.Stop(); NumberFormatInfo nfi = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone(); nfi.NumberGroupSeparator = " "; Console.WriteLine("with exception {1} iteration {0} ms", watch.ElapsedMilliseconds, iterations.ToString("n0", nfi)); Console.WriteLine(); } static void WithoutException(int iterations) { var watch = Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) SomeAction(); Handle(); watch.Stop(); NumberFormatInfo nfi = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone(); nfi.NumberGroupSeparator = " "; Console.WriteLine("without exception {1} iteration {0} ms", watch.ElapsedMilliseconds, iterations.ToString("n0", nfi)); } static void Main(string[] args) { WithoutException(1); // этот и следующий вызов для "прогрева" WithException(1); WithoutException(1); WithException(1); WithoutException(1000); WithException(1000); WithoutException(100000); WithException(100000); WithoutException(500000); WithException(500000); Console.ReadLine(); } 

    and see the results (you can try to execute it directly on ideone, but it will most likely fall off with a timeout due to the large number of iterations) My results were as follows:

    enter image description here

    As you can see, the execution time of the code that throws and handles an exception is slightly different from the code without exceptions. But the convenience of error handling is much higher. Of course, the handicraft test is far from perfect, but I assure you that in 99% of cases the problem of throwing and exception handling performance is not worth a damn.

      When they talk about resource intensity, it is necessary to understand, in comparison with what. If we compare with one addition - try / catch is more expensive. If we compare with reading a byte from a file, it is much less expensive.

      Based on this, let's break your program apart.

      1. Ui. When we talk about UI, basically time is wasted waiting for user input / response. This time is several orders of magnitude longer than the throw / handling exception. Therefore, the use of exceptions in the UI code is a normal thing.
      2. The level of business logic, controllers, view models and such. Flow of the program is no more than one new state per second - otherwise the user simply does not have time to figure out what happened. This means that exceptions can be fine for managing flow. The same applies to the code that communicates with the UI.
      3. Models. Here, of course, throwing out exceptions may be disadvantageous. In any case, you need to look at what this model does and how often erroneous situations arise. If this is reading a file, or reading data from the Internet, then again, the overhead of communication with the outside world is so great that it makes no sense to save on matches. But if the bottleneck of your model is processor time (for example, this is the number of the hammer), then the time spent on handling the exception may already be comparable to the typical element processing time, which means you have to carefully plan the error reaction strategy. In this case, however, even if you apply error codes within the model, it makes sense to report the total error to the top with an exception.

      In any case, I would caution you against premature optimization. In the overwhelming majority of cases, the bottleneck will not be exception handling at all. Therefore, write your code with exceptions, and if you are not satisfied with the performance, perform a profiling. Only it can tell you what really needs to be improved. If it turns out that the problem is in the exceptions, only then it makes sense to get rid of them.