This question already has answers here:
Testing for Dictionary KeyNotFoundException
(4 answers)
Closed 5 years ago.
I'm building a project where the config file will be load as a dictionary. To prevent from invalid config, I simply added an try catch frame. But I noticed that when exceptions throw, there will be a dramatic performance dropping. So I made a test:
var temp = new Dictionary<string, string> {["hello"] = "world"};
var tempj = new JObject() {["hello"]="world"};
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 100; i++)
{
try
{
var value = temp["error"];
}
catch
{
// ignored
}
}
sw.Stop();
Console.WriteLine("Time cost on Exception:"+sw.ElapsedMilliseconds +"ms");
sw.Restart();
for (int i = 0; i < 100; i++)
{
var value = tempj["error"]; //equivalent to value=null
}
Console.WriteLine("Time cost without Exception:" + sw.ElapsedMilliseconds + "ms");
Console.ReadLine();
And the result is:
Time cost on Exception:1789ms
Time cost without Exception:0ms
The JObject here is taken from Newtownsoft.Json, which does not throw an exception when no key is found ,as opposed to Dictionary.
So my question is:
Does exception throwing really slow down the program that much?
How do I guarantee the performance when multiple exceptions may occur?
Anyway work around if I really want to use Dictionary in this case?(shut down the KeyNotFoundException?)
Thank you!
Use Dictionary.TryGetValue to avoid exceptions in your example code at all. The most expensive part is the try .. catch.
If you cannot get away from exceptions then you should use a different pattern to perform actions inside a loop.
Instead of
for ( i = 0; i < 100; i++ )
try
{
DoSomethingThatMaybeThrowException();
}
catch (Exception)
{
// igrnore or handle
}
which will set up the try .. catch for every step whether an exception has raised or not, use
int i = 0;
while ( i < 100 )
try
{
while( i < 100 )
{
DoSomethingThatMaybeThrowException();
i++;
}
}
catch ( Exception )
{
// ignore or handle
i++;
}
which will only set up a new try .. catch when an exception was thrown.
BTW
I cannot reproduce that massive slowdown of your code as you describe. .net fiddle
Related
I wonder what happens if I catch an exception and pass it to some other threads.
try
{
//...
}
catch (Exception e)
{
for (int i = 0; i < 100; i++)
{
int currIndex = i;
Task.Run(() => e.Data[currIndex] = currIndex);
}
throw;
}
Given these other threads alter the contents of the exception's Data property (that holds an internal dictionary, see Reference Source), will the Datadictionary get corrupted?
Looking into the source code of Exception reveals that this dictionary is not thread-safe.
If my suspicion is true, what are the consequences? I would think that you should never alter the contents of the Data property after throwing the exception, right?
here is the error I am getting :
System.ExecutionEngineException was unhandled
HResult=-2146233082
Message=Exception of type 'System.ExecutionEngineException' was thrown.
InnerException:
code Update:
here is my code
void WriteGraph(int[] vData)
{
string tempWrite = "";
try
{
for (int y = 0; y < vData.Length;)
{
for (int i = 0; i < 20; i++)
{
tempWrite = tempWrite + vData[i] + ",";
y++;
}
File.AppendAllText(name2, tempWrite);
}
File.AppendAllText(name2, Environment.NewLine);
}
catch ( Exception e)
{
AppendTextBox(e.Message.ToString());
}
}
it fails at tempWrite = tempWrite + vData[i] + ",".
not that is in a loop so it does write some values to the file.
I open the file in Excel and it goes from A to LW
before it died ...
the question is why ?
here is the loop :
void PlotSpectrum(int []vData)
{
ArrayList listDataSource = new ArrayList();
// Populate the list with records.
for (int i = 0; i < vData.Length; i++)
{
WriteGraph(Convert.ToString(vData[i]));
listDataSource.Add(new Graph_Class(i, vData[i]));
}
// Bind the chart to the list.
ChartControl myChart = chartControl1;
myChart.DataSource = listDataSource;
// Create a series, and add it to the chart.
Series series1 = new Series("Spectrum", ViewType.Line);
myChart.Series.Add(series1);
// Adjust the series data members.
series1.ArgumentDataMember = "X";
series1.ValueDataMembers.AddRange(new string[] { "Y" });
// Access the view-type-specific options of the series.
((LineSeriesView)series1.View).ColorEach = true;
series1.LegendTextPattern = "{A}";
try
{
//myChart.Update();
// myChart.Refresh();
}catch(Exception err)
{
AppendTextBox(err.Message.ToString());
print("Error in Graph: ", DateTime.Now.ToString(), err.Message.ToString());
}
}
The same thing is happening for me, but it only throws this exception when a yarn rebuild finishes (front-end is React). I am using IIS Express to run locally. I wonder if it doesn't like that the files are changing while the app is running.
This seems to fix it:
Go to Tools, Options, Projects and Solutions, Web Projects; and check "Use the 64 bit version of IIS Express for web sites and projects".
In my case this happened in Service Fabric startup before it has a chance to begin running. The exception shows up in the Event Viewer rather than VS.
This problem happens because something failed before throw ExecutionEngineException.
I faced this issue (typing Japanese characters in TextBox on WPF app), I solved activating Common Language Runtime Exceptions in Exceptions Settings in VS
and checking the values of each runtime exception(before get crash) and I found a null value in one of the variables in a previous method but the crash was thrown many seconds after that.
You can find a deep explanation here: Why this code throws System.ExecutionEngineException
I have this piece of code, I want to know do they work likewise and only their speed is different or they act totally different?
try
{
for (int i = Start; i < End; i++)
{
src.Samples[i].x = i;
src.Samples[i].y = HR[i];
}
}
catch{}
or
for (int i = Start; i < End; i++)
{
try
{
src.Samples[i].x = i;
src.Samples[i].y = HR[i];
}
catch
{
break;
}
}
Just don't do that to start with - it's an abuse of exceptions, IMO. Write the code so it's safe without try/catch. If you don't know whether HR is long enough, use:
int cappedEnd = Math.Min(HR.Length, End);
for (int i = Start; i < cappedEnd; i++)
{
src.Samples[i].x = i;
src.Samples[i].y = HR[i];
}
(Use similar logic for Start if that might be invalid.)
If you feel you absolutely have to use try/catch for some reason, I'd catch the exact type you're expecting to be thrown, and put it on the outside of the loop - catching just to break feels even worse to me. And no, I wouldn't expect any significant performance difference either way.
The main difference would be that encapsulating your logic in a try statement would enable you to catch any errors/exceptions that might occur.
In your second listed example your could get an exception because of Start and or End being invalid values for some reason or the other causing a crash that you wouldn't catch.
Note that most code of that level is usually very simple and not very error prone.
Writing code that is free of exceptions is often the better approach though.
As stated in the comments you would need a catch block in your first example for it to work though.
I hopes you are a beginer(like me), so you expects an answer like this
I will tell another example.
first code
try{
foreach(file in files)
{
upload(file);
}
}
catch(Exception ex)
{
handleException(ex);
}
second code
foreach(file in files)
{
try{
upload(file);
}
catch(Exception ex)
{
handleException(ex);
}
}
on first code all file upload will stop when first one fails. In second if one failes handles exception there itself and code continues for next execution.
So in the example you given both seems like works in same way(since you are giving in break in catch block. Other wise both are differnet). So use try catch where it really requires handling.
My code:
public void CPUStats()
{
var cpuCounter = new PerformanceCounter("Processor", "% Processor Time",
"_Total");
var ramCounter = new PerformanceCounter("Memory", "Available MBytes");
ramCounter.NextValue();
cpuCounter.NextValue();
System.Threading.Thread.Sleep(1000);
string cpusage = cpuCounter.NextValue().ToString();
string ramusage = ramCounter.NextValue().ToString();
//Occurs here v
try
{
//exception thrown here v
cpuLabel.Invoke((MethodInvoker)(() => cpuLabel.Text = "CPU: " +
cpusage.Remove(cpusage.IndexOf('.')) + "%"));
}
catch(ArgumentOutOfRangeException)
{
cpuLabel.Invoke((MethodInvoker)(() => cpuLabel.Text = "CPU: " +
cpusage + "%"));
}
ramLabel.Invoke((MethodInvoker)(() => ramLabel.Text = "Free RAM: " +
ramusage + "mb"));
}
At times my application will stop at the cpuLabel invoke and throw an "ArgumentOutOfRangeException" when it was handled and fixed in my code. I tried increasing the timer that activates the thread that activates CPUStats(), but to no avail.
Why would this happen?
Update:
Sorry, I should read your code more carefully. Your try-catch wrapped the delegate invocation which may not in the current context of thread. I think what you want to do should be:
public void CPUStats() {
var cpuCounter= ..
...
MethodInvoker m=() => {
try {
cpuLabel.Text="CPU: "+cpusage.Remove(cpusage.IndexOf('.'))+"%";
}
catch(ArgumentOutOfRangeException) {
cpuLabel.Text="CPU: "+cpusage+"%";
}
};
cpuLabel.Invoke(m);
...
}
Have a look of SynchronizationContext and also Control.InvokeRequired.
Again, avoid try-catch if there's a better way to check for possible errors.
#competent_tech's answer is good, but I'd like to add a little bit.
There are some cases that a try-catch block would still throw:
You did not catch the exact exception it thrown
The handler rethrows the original exception
The handler causes another exception
In your case, it hits the catch block and did not rethrow the original one, that is, it met the third circumstance: the handler causes another exception.
If you can address the problem causes the exception and avoid it , then don't design it in this way.
Mr. Lippert wrote a good article about the exceptions, you might want to have a look at:
http://ericlippert.com/2008/09/10/vexing-exceptions/
The issue is being caused by this code:
cpusage.Remove(cpusage.IndexOf('.')
You need to ensure that cpusage has length and contains a '.' before attempting to call .Remove.
You can prove this by running a simple app test:
var cpuusage = "0";
System.Diagnostics.Debug.WriteLine(cpuusage.Remove(cpuusage.IndexOf('.')));
This will throw the ArgumentOutOfRangeException exception.
If you modify the code to be:
var cpuusageforlabel = "CPU: ";
if (!string.IsNullOrEmpty(cpuusage)) {
var index = cpuusage.IndexOf('.');
if (index != -1) {
cpuusageforlabel += cpuusage.Remove(index);
} else {
cpuusageforlabel += cpuusage;
}
} else {
cpuusageforlabel += "0";
}
cpuusageforlabel += "%";
cpuLabel.Invoke((MethodInvoker)(() => cpuLabel.Text = cpuusageforlabel));
You address the exception and won't have to catch the argument out of range exception.
Most probable reason is that cpusage is null or empty or without .. So when you get exception and try to use same variable again, you get the second exception.
Check cpusage before using it and don't use catch the way you are using.
I need to find ways to add retry mechanism to my DB calls in case of timeouts, LINQ to SQL is used to call some sprocs in my code...
using (MyDataContext dc = new MyDataContext())
{
int result = -1; //denote failure
int count = 0;
while ((result < 0) && (count < MAX_RETRIES))
{
result = dc.myStoredProc1(...);
count++;
}
result = -1;
count = 0;
while ((result < 0) && (count < MAX_RETRIES))
{
result = dc.myStoredProc2(...);
count++;
}
...
...
}
Not sure if the code above is right or posed any complications.
It'll be nice to throw an exception after MAX_RETRIES has reached, but I dunno how and where to throw them appropriately :-)
Any helps appreciated.
If you get a timeout from your database, it's not very likely that it's going to respond in a timely fashion a few miliseconds later.
Retrying in a tight loop as you suggest is likely to make a bad situation worse because you would be placing an undue burden on the database server, as well as tying up a thread in the calling code. It would be safer to introduce a wait time between each retry.
For more advanced scenarios, you could consider a progressive wait pattern where you retry more frequently in the beginning and then with longer and longer intervals if you still get timeouts.
You may also want to look into the Circuit Breaker design pattern from the book Release It!, as well as many of the other patterns and anti-patterns described in that book.
The State pattern is a good fit for implementing Circuit Breaker.
Personally, I would use recursion here. It makes for cleaner code since the only "extra code" you have is a parameter into a function. For example:
private MyResult Foo(MyParameters mp, int repeatCall)
{
var result = null;
try
{
result = mp.dc.myStoredProc(...);
}
catch (MyException err)
{
if (repeatCall > 0)
{
result = Foo(mp, repeatCall - 1);
}
else
{
throw;
}
}
return result;
}
This is an ideal example for recursion, I think. Whatever is calling this need not be concerned with the looping and it makes MUCH cleaner code.
As Mark Seemann corrrectly mentioned, it's not a good idea to use a retry policy to deal with with timeouts. However, given a delay this might be a good idea after all. To implement it, you can use a custom action invoker that executes your action method and takes care of retries in case of an SQL exception. This way you don't have to take care of the retry policy in each and every action method's code.
We don't have database timeout in our system, but I am using the same technique to handle sql read deadlocks in a generic way.
We use something like this (prefer that a new EF Context is instantiated for each retry):
Sorry but the code for SqlExceptionUtil.IsSqlServerErrorType() could not be included (overly custom and many layers).
static public T ExecuteRetryable<T>(
Func<T> function,
out int actualAttempts,
string actionDescriptionForException = "SQL",
int maxTries = 3,
int pauseMaxMillis = 1000,
int pauseMinMillis = 0,
bool alsoPauseBeforeFirstAttempt = false,
bool allowRetryOnTimeout = false)
{
Exception mostRecentException = null;
for (int i = 0; i < maxTries; i++)
{
// Pause at the beginning of the loop rather than end to catch the case when many servers
// start due to inrush of requests (likely). Use a random factor to try and avoid deadlock
// in the first place.
//
if (i > 0 || alsoPauseBeforeFirstAttempt)
Thread.Sleep(new Random
(
// Default Initializer was just based on time, help the random to differ when called at same instant in different threads.
(Int32)((DateTime.Now.Ticks + Thread.CurrentThread.GetHashCode() + Thread.CurrentThread.ManagedThreadId) % Int32.MaxValue)
)
.Next(pauseMinMillis, pauseMaxMillis));
actualAttempts = i + 1;
try
{
T returnValue = function();
return returnValue;
}
catch (Exception ex)
{
// The exception hierarchy may not be consistent so search all inner exceptions.
// Currently it is DbUpdateException -> UpdateException -> SqlException
//
if (!SqlExceptionUtil.IsSqlServerErrorType(ex, SqlServerErrorType.Deadlock) &&
(!allowRetryOnTimeout || !SqlExceptionUtil.IsSqlServerErrorType(ex, SqlServerErrorType.Timeout)))
throw;
mostRecentException = ex;
}
}
throw new Exception(
"Unable to perform action '" + actionDescriptionForException + "' after " + maxTries +
" tries with pauses of [" + pauseMinMillis + "," + pauseMaxMillis + "]ms due to multiple exceptions.",
mostRecentException);
}
Usage:
List<SomeTableEntity> result = DatabaseHelpers.ExecuteRetryable<List<SomeTableEntity>>(() =>
{
using (EfCtx ctx = new EfCtx())
{
return ctx.SomeTable.Where(...).ToList()
}
}, out int actualAttempts, allowRetryOnTimeout: true);
It would be nice if someone would show how to disguise the wrapping code behind a custom Linq construct like: WithRetry(...).