C# System.Timers.Timer. Is there really that much overhead in a winform app vs. console? Example Code

  • Thread starter Thread starter m00n
  • Start date Start date
M

m00n

Guest
Hi all…

I wanted to create a timer that could app where I could monitor how many times a timer will tick per second. This all came about because I wanted to be able to throttle down how many times I was sending things over a network stream and I wanted to find the sweet spot in milliseconds and using a timer. Think FPS.



To do this I used two System.Timers.Timer objects.
_tpsTimer (ticks per second)


  • Ticks on a user input interval so I can test to see how often I’d want to trigger based on FPS.
  • Simply increments a counter variable “_tpsCount” tracking how many times its delegate was fired off

_oneSecondTimer

  • Hard coded to 1000 milliseconds, 1 second.
  • Displays the “_tpsCount” variable showing me how many times the _tpsTimer fired its event in one second.



I wrote a couple versions of the app. The logic behind these two apps are identical except for the fact that one is a winform one is a console. The two versions I’m most interested in posting about are

  • SystemTimers – A Windows form app using System.Timers.Timer
  • SystemTimersConsole – A console app using System.Timers.Timer


I was surprised at how much of a difference there was in ticks per second between a console app and windows form app. Is there REALLY that much overhead in a windows form app? Secondly, am I way off base in using timers for this purpose? Ultimately wanting to create a FPS throttle... How many images I send over a network per second.


The following image shows various tests at different millisecond intervals. The columns are :

  • Milli Sec column : Millisecond interval.
  • Console : At the given milli sec interval, how many times the timer was triggered for the Console application
  • Win Form : At the given milli sec interval, how many times the timer was triggered for the Win Form application


1403147.png


Here is the code for the console app.

using System;

namespace SystemTimersConsole
{
class Program
{

// Ticks on 1 second intervals, Used to write _tpsCount every second
private System.Timers.Timer _oneSecondTimer;

// Ticks on user specified interval, used to update _tpsCount variable
private System.Timers.Timer _tpsTimer;

// Represends how many times in 1 second _tpsTimer is fired off.
private int _tpsCount;

// Since timers run in differnt treads than GUI thread, need a delegate to
// update the GUI
public delegate void DisplayTPS( object source, System.Timers.ElapsedEventArgs e );


static void Main( string[ ] args )
{
Program p = new Program();
p.Reset( );

// Param specifies millisecond frequency for _tpsTimer
p.StartTimers( 19 );
ConsoleKeyInfo i = Console.ReadKey( );
}



/// <summary>
/// _oneSecondTimer tick event.
/// Updates the list box with the TPS count information. Function can be called from either
/// the GUI thread or one one of timer threads.
/// </summary>
/// <param name="state">Not using this state</param>
private void DisplayData( Object source, System.Timers.ElapsedEventArgs e )
{
Console.WriteLine( "TPS COUNT : " + _tpsCount );
_tpsCount = 0;
}



/// <summary>
/// _tpsTimer tick event handler. Increments the TPS counter indicator.
/// </summary>
/// <param name="state"></param>
private void IncTPSCount( Object source, System.Timers.ElapsedEventArgs e )
{
_tpsCount++;
}

/// <summary>
/// Resets all the controls and what not.
/// </summary>
private void Reset( )
{
if( _oneSecondTimer != null )
_oneSecondTimer.Dispose( );
if( _tpsTimer != null )
_tpsTimer.Dispose( );

_oneSecondTimer = null;
_tpsTimer = null;
_tpsCount = 0;
}


/// <summary>
/// Resets controls, timers and restarts timers.
/// </summary>
/// <param name="milli">Specifies in milliseconds how frequent to call IncCount</param>
private void StartTimers( int milli )
{
Reset( );
_oneSecondTimer = new System.Timers.Timer( 1000 );
_tpsTimer = new System.Timers.Timer( milli );

_oneSecondTimer.Elapsed += DisplayData;
_tpsTimer.Elapsed += IncTPSCount;

_oneSecondTimer.Enabled = true;
_tpsTimer.Enabled = true;
}
}
}

Here is the code for the Windows Form app
using System;
using System.Windows.Forms;
using System.Threading;


/* ==============================================================================================
* Shows how to use two the System.Timers.Timer class instances to create a to display how many
* times a timer will trigger in one second.
*
* _tpsTimer triggers on a user specified value in the GUI. It will update _tpsCount which
* holds the number of times _tpsTimer was triggered.
*
* _oneSecondTimer will trigger every 1 second and will display the _tpsTimer value in the
* list box showing how many times _tpsTimer was triggered in 1 second.
*
* These methods can be used to try and control how fast something happens within 1 second. This
* is not SCIENTIFICALLY accurate, but it might be good enough to throttle down something like
* Frames Per Second to prevent flooding the network with too much streaming media.
*
* Because the timers run in a separate thread, the DisplayData function must use multithreading
* techniques to allow cross threaded data to be used in the GUI.
============================================================================================= */


namespace FPSTimer
{
public partial class FormSystemTimers : Form
{
// Ticks on 1 second intervals, used to trigger list box updates
private System.Timers.Timer _oneSecondTimer;

// Ticks on user specified interval, used to update _tpsCount variable
private System.Timers.Timer _tpsTimer;

// Represends how many times in 1 second _tpsTimer is fired off.
private int _tpsCount;

// Since timers run in differnt treads than GUI thread, need a delegate to
// update the GUI
public delegate void DisplayTPS( object source, System.Timers.ElapsedEventArgs e );


public FormSystemTimers( )
{
InitializeComponent( );

// Set initial state
Reset( );
}

/// <summary>
/// _oneSecondTimer tick event.
/// Updates the list box with the TPS count information. Function can be called from either
/// the GUI thread or one one of timer threads.
/// </summary>
/// <param name="state">Not using this state</param>
private void DisplayData( Object source, System.Timers.ElapsedEventArgs e )
{

if( this.lb1.InvokeRequired )
{
// Create the delegate and specify which function to call.
DisplayTPS d = new DisplayTPS( DisplayData );
this.Invoke( d, new object[ ] { source, e } );
}
else
lb1.Items.Add( "TPS COUNT : " + _tpsCount );

_tpsCount = 0;
}



/// <summary>
/// _tpsTimer tick event handler. Increments the TPS counter indicator.
/// </summary>
/// <param name="state"></param>
private void IncTPSCount( Object source, System.Timers.ElapsedEventArgs e )
{
_tpsCount++;
Console.WriteLine( _tpsCount );
}


/// <summary>
/// Resets all the controls and what not.
/// </summary>
private void Reset( )
{
if( _oneSecondTimer != null )
_oneSecondTimer.Dispose( );
if( _tpsTimer != null )
_tpsTimer.Dispose( );

_oneSecondTimer = null;
_tpsTimer = null;

lb1.Items.Clear( );
_tpsCount = 0;

if( tbMilli.Text == "" )
tbMilli.Text = "30";
}


/// <summary>
/// Resets controls, timers and restarts timers.
/// </summary>
/// <param name="milli">Specifies in milliseconds how frequent to call IncCount</param>
private void StartTimers( int milli )
{
Reset( );
_oneSecondTimer = new System.Timers.Timer( 1000 );
_tpsTimer = new System.Timers.Timer( milli );

_oneSecondTimer.Elapsed += DisplayData;
_tpsTimer.Elapsed += IncTPSCount;

_oneSecondTimer.Enabled = true;
_tpsTimer.Enabled = true;
}

/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStart_Click( object sender, EventArgs e )
{
if( tbMilli.Text == "" )
return;

int milli = Int32.Parse( tbMilli.Text );

if( milli > 0 && milli < 1001 )
StartTimers( milli );
}


/// <summary>
/// Calling this to kill the timers. If you don't do this, they continue to run after the
/// form starts to shut down which causes an exception. This is because the timer will still
/// try to call their tick handlers (updating the list), but the form controls have been killed,
/// so an exception happens. So, kill everyting BEFORE allowing the form to close.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_FormClosing( object sender, FormClosingEventArgs e )
{
Reset( );
}
}
}


Any feedback is greatly appreciated!

Thanks
Rick


Rick

Continue reading...
 
Back
Top