Writing Mobile Code Essential Software Engineering for Building Mobile Applications [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Writing Mobile Code Essential Software Engineering for Building Mobile Applications [Electronic resources] - نسخه متنی

Ivo Salmre

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید











The Cost of Runtime Exceptions


Modern runtime environments offer structured exception handling that allows code to deal with exceptional circumstances robustly. Programmers can catch exceptions thrown by lower-level framework code and can also throw and catch their own exceptions. Structured exception handling is a great robustness feature that allows managed-code frameworks, components, and applications to clean up after unforeseen failures and resume normal execution. When an exception is raised, the runtime takes control and starts walking the stack upward looking for an appropriate handler to catch the exception being thrown. It is more important that things unwind properly than that the exception gets handled as quickly as normally executing code. The common result of this is that throwing and handling exceptions is moderately expensive from a performance perspective.

For good application performance, your code should avoid conditions where exceptions are being frequently thrown in the normal course of an application's execution. Rather than writing code that causes exceptions to be thrown and caught during the normal execution of your algorithms, your mobile application code should aggressively seek to avoid circumstances that would cause an exception to be raised during normal code execution. When designing your own algorithms for maximum performance, avoid writing code that causes exceptions to be raised unless truly exceptional circumstances occur. It should normally be possible to run your entire application without a single exception being raised.

If you are finding that your application's code is commonly handling framework-raised exceptions or raising and handling its own exceptions, examine and redesign your code to avoid these exceptional circumstances.

Structured exception handling is a powerful capability of object-oriented programming but must be used properly. Along with things such as object allocation and garbage collection, structured exceptions can make programming simpler and robust when used properly, but can cause significant performance problems when misused.

An Example Comparing Equivalent Algorithms That Do and Do Not Throw Exceptions


Listing 7.4 is a sample application that compares two algorithms performing equivalent work but with significantly different performance characteristics. One algorithm adds two numbers together and returns the sum as well as a Boolean value that specifies whether the result is positive or negative. The other algorithm also adds two numbers together and returns the result but raises an exception if the result is negative. As you might expect, the algorithm that throws an exception as part of its normal execution runs drastically slower in comparison to the nonexception-throwing loop. Although in an absolute sense both algorithms run quite quickly and perform 10,000 iterations in fewer than 2.5 seconds, one algorithm performs more than 350 times faster than the other algorithm; for tight loop computations, this difference can be crucial.

Table 7.1 shows the results of running the test on a physical Pocket PC device without the debugger hooked up. As you can see, the algorithm that runs without throwing and catching exceptions runs several hundred times faster. Our example used a very simple algorithm along with a simple mechanism for throwing and catching exceptions; relatively little cleanup and unwinding was required by the runtime to deal with the exception. Because of the simplicity of the work being done, the effects of throwing an exception are very pronounced. Results for different kinds of algorithms will vary depending on the complexity of the algorithm as well as the work required to handle thrown exceptions; however, one thing should be clear: Frequently thrown exceptions can be expensive, and their unnecessary use should be avoided under normal code-execution conditions.

Table 7.1. Comparative Performance of a Simple Algorithm with and without Exceptions

# Iterations

No Exception Thrown (sec)

Exception Thrown (sec)

x Times Faster Without Exception

10,000

0.006

2.202

367 times faster

10,000

0.006

2.201

367 times faster

100,000

0.061

22.716

372 times faster

100,000

0.055

22.834

415 times faster

100,000

0.055

22.995

418 times faster

Figure 7.2 shows the sample application running in a Pocket PC emulator.

Figure 7.2. Sample application comparing exception and nonexception algorithms.

Note

It is worth noting that because exception handling is a core runtime and debugging feature of the .NET Compact Framework and Visual Studio .NET, the application's performance can vary greatly under two conditions:

The performance of code that throws exceptions can be vastly impeded if the debugger is attached to the program while it is running. This is because the development environment is made aware of exceptions that are thrown even if they are caught by the application's code. This means that running algorithms that throw lots of exceptions will be very slow if the debugger is attached! Something to think about in your design and development; throwing lots of exceptions can slow down development. The behavior of the development environment should generally not force you to change the way you write code; but in this case, it should be an added incentive to avoid having lots of exceptions thrown inside loops of frequently run code.

The performance of handling exceptions will vary significantly between emulators and physical devices. For the most accurate measurements of how throwing and handling exceptions will affect your application, it is recommended that you run the tests on a physical device without the debugger attached to measure the effects accurately.

The code in Listing 7.4 belongs inside a Form in a Pocket PC project. Do the following to build and run the application:


1.

Start Visual Studio .NET (2003 or later) and create a C# Smart Device Application.

2.

Choose Pocket PC as the target platform. (A project will be created for you and Pocket PC Form designer will appear.)

3.

Add the following controls to the form. See Listing 7.1.

8.

Run the application on a physical device or an emulator using F5. Use Ctrl+F5 if you want to run the sample without the debugger attachedthis is recommended for this sample because exceptions are handled much more slowly with the debugger attached.


Listing 7.4. Performance Comparison Between Exception-Throwing Algorithm and NonException-Throwing Algorithm



//===========================================================
//Note: This sample uses the PerformanceSampling class
// defined earlier in this chapter. Make sure this
// class is included in your project.
//===========================================================
//TEST FUNCTION:
//
//Attempt to add 'n1' and 'n2' together and return the result
// in 'n3'
//
// return:
// TRUE: If the result is positive
// FALSE: If the result is negative
//===========================================================
bool returnFalseIfLessThanZero_Add2Numbers(int n1, int n2,
out int n3)
{
n3 = n1 + n2;
//Is the item less than 0?
if(n3 < 0)
{
return false;
}
return true;
}
//===========================================================
//TEST FUNCTION:
//
//Attempt to add 'n1' and 'n2' together and return the result
// in 'n3'
//
//This function THROWS AN EXCEPTION if 'n3' is less than 0.
//Otherwise TRUE is returned
//===========================================================
bool exceptionIfLessThanZero_Add2Numbers(int n1, int n2,
out int n3)
{
n3 = n1 + n2;
//Is the item less than 0?
if(n3 < 0)
{
throw new Exception("Less than 0!");
}
return true;
}
//===========================================================
//Calls a simple function a large number of times and
//measures the total execution time.
//
//The function called DOES NOT raise an exception
//===========================================================
private void buttonRunNoExceptionCode_Click(object sender,
System.EventArgs e)
{
const int TEST_NUMBER = 0;
int numberIterations;
numberIterations =
System.Convert.ToInt32(textBoxNumberAttempts.Text);
//Show the number of iterations we are going to perform
listBox1.Items.Add("=>" + numberIterations.ToString() +
" Iterations");
int count_SumLessThanZero;
int dataOut;
//-----------------------------------------------------------
//Start the performance timer
//-----------------------------------------------------------
PerformanceSampling.StartSample(TEST_NUMBER, "No Exception");
//-----------------------------------------------------------
//Run the loop that calls the function
//-----------------------------------------------------------
count_SumLessThanZero = 0;
bool sumGreaterThanZero;
for(int i = 0; i < numberIterations; i++)
{
//=======================
//Call the test function!
//=======================
sumGreaterThanZero =
returnFalseIfLessThanZero_Add2Numbers(-2, -3, out dataOut);
if(sumGreaterThanZero == false)
{
count_SumLessThanZero++;
}
} //end of loop
//-----------------------------------------------------------
//Stop the performance timer
//-----------------------------------------------------------
PerformanceSampling.StopSample(TEST_NUMBER);
//-----------------------------------------------------------
//Output the results to the user
//-----------------------------------------------------------
if(count_SumLessThanZero == numberIterations)
{
System.Windows.Forms.MessageBox.Show("Test Passed");
listBox1.Items.Add(
PerformanceSampling.GetSampleDurationText(TEST_NUMBER));
}
else
{
System.Windows.Forms.MessageBox.Show(
"Something is wrong with the test");
}
} //end of function
//===========================================================
//Calls a simple function a large number of times and
//measures the total execution time.
//
//The function called DOES raise an exception
//===========================================================
private void buttonRunExceptionCode_Click(object sender,
System.EventArgs e)
{
const int TEST_NUMBER = 1;
//Get the # of iterations
int numberIterations;
numberIterations =
System.Convert.ToInt32(textBoxNumberAttempts.Text);
//Show the number of iterations we are going to perform
listBox1.Items.Add("=>" + numberIterations.ToString() +
" Iterations");
int count_SumLessThanZero;
int dataOut;
//-----------------------------------------------------------
//Start the performance timer
//-----------------------------------------------------------
PerformanceSampling.StartSample(TEST_NUMBER ,
"Catch Exception");
//-----------------------------------------------------------
//Run the loop that calls the function
//-----------------------------------------------------------
count_SumLessThanZero = 0;
bool sumGreaterThanZero;
for(int i = 0; i < numberIterations; i++)
{
try
{
//=======================
//Call the test function!
//=======================
sumGreaterThanZero =
exceptionIfLessThanZero_Add2Numbers(-2, -3, out dataOut);
}
catch
{
count_SumLessThanZero++;
}
} //end of loop
//-----------------------------------------------------------
//Stop the performance timer
//-----------------------------------------------------------
PerformanceSampling.StopSample(TEST_NUMBER);
//-----------------------------------------------------------
//Output the results to the user
//-----------------------------------------------------------
if(count_SumLessThanZero == numberIterations)
{
System.Windows.Forms.MessageBox.Show("Test Passed");
listBox1.Items.Add(
PerformanceSampling.GetSampleDurationText(TEST_NUMBER));
}
else
{
System.Windows.Forms.MessageBox.Show(
"Something is wrong with the test");
}
} //End of function


/ 159