Multi Threaded Calculations in C#
Introduction
This C# .NET test harness configures easilycomparing throughput results of multi-threaded and single threadedcalculations using ADO .NET datasets. This simple multi-threadedexample performs calculation and database updates three times fasterthan a single threaded approach.
Creating the Workspace
To start the test harness, open a MicrosoftVisual Studio 2005, .NET Framework Version 2.0 development environmentand create two Console Applications. The first application performscalculations using a scheduler and worker threads. The secondapplication performs calculations in a single thread.
Code
Both applications create an ADO .NET datasetof inventory from a fictitious database table called INVENTORYcontaining fields for the ID, COST, PRICE and PROFIT. The sample codeincludes database SQL scripts containing the ID and COST for samplesizes up to 10000 data points. The test harness calculates the PRICEand PROFIT for each data point and updates the database.
The multi-threaded test harness starts a worker thread for each calculation and database update.
public class CalculatorScheduler
{
private DataSet m_invDataSet;
public void Init()
{
try
{
m_invDataSet = (new InventoryData()).GetDataSet();
foreach (DataRow row in m_invDataSet.Tables[Properties.Settings.Default.TABLE_DS].Rows)
{
Thread t = new Thread(new ParameterizedThreadStart(ProcessCalculations));
t.Start(row);
}
}
catch (Exception exc)
{
exc.Message.ToString();
}
}
private void ProcessCalculations(object row)
{
new CalculatorWorker().Calc((DataRow) row);
}
}
public class CalculatorWorker
{
private static Decimal MARGIN = Convert.ToDecimal(1.1);
private static object item = new object();
public void Calc(DataRow row)
{
try
{
row.BeginEdit();
row[Properties.Settings.Default.PRICE] = Convert.ToDecimal(row[Properties.Settings.Default.COST]) * MARGIN;
row[Properties.Settings.Default.PROFIT] = Convert.ToDecimal(row[Properties.Settings.Default.PRICE]) – Convert.ToDecimal(row[Properties.Settings.Default.COST]);
row.EndEdit();
row.AcceptChanges();
UpdateInventory(row);
}
catch (Exception exc)
{
exc.Message.ToString();
}
}
private void UpdateInventory(DataRow row)
{
try
{
OdbcCommand m_UpdateRatingsCmd = new OdbcCommand(Properties.Settings.Default.UPDATE, DBWrapper.Instance.InitializeConnection());
m_UpdateRatingsCmd.Parameters.AddWithValue("@PRICE", Convert.ToDouble(row[Properties.Settings.Default.PRICE]));
m_UpdateRatingsCmd.Parameters.AddWithValue("@PROFIT", Convert.ToDouble(row[Properties.Settings.Default.PROFIT]));
m_UpdateRatingsCmd.Parameters.AddWithValue("@ID", Convert.ToInt32(row[Properties.Settings.Default.ID]));
m_UpdateRatingsCmd.ExecuteNonQuery();
DBWrapper.Instance.CloseConnection();
}
catch (Exception exc)
{
exc.Message.ToString();
}
}
}
Whereas the single threaded test harness performs the calculations linearly.
m_invDataSet = (new InventoryData()).GetDataSet();
foreach (DataRow row in m_invDataSet.Tables[Properties.Settings.Default.TABLE_DS].Rows)
{
try
{
row.BeginEdit();
row[Properties.Settings.Default.PRICE] = Convert.ToDecimal(row[Properties.Settings.Default.COST]) * MARGIN;
row[Properties.Settings.Default.PROFIT] = Convert.ToDecimal(row[Properties.Settings.Default.PRICE]) – Convert.ToDecimal(row[Properties.Settings.Default.COST]);
row.EndEdit();
row.AcceptChanges();
OdbcCommand m_UpdateRatingsCmd = new OdbcCommand(Properties.Settings.Default.UPDATE, DBWrapper.Instance.InitializeConnection());
m_UpdateRatingsCmd.Parameters.AddWithValue("@PRICE", Convert.ToDouble(row[Properties.Settings.Default.PRICE]));
m_UpdateRatingsCmd.Parameters.AddWithValue("@PROFIT", Convert.ToDouble(row[Properties.Settings.Default.PROFIT]));
m_UpdateRatingsCmd.Parameters.AddWithValue("@ID", Convert.ToInt32(row[Properties.Settings.Default.ID]));
m_UpdateRatingsCmd.ExecuteNonQuery();
DBWrapper.Instance.CloseConnection();
}
}
Tests of different sample sizes showsignificantly faster results from the multi-threaded solution comparedto the single threaded solution. All Start Time and End Time values arein seconds. In this simple example the multi-threaded test harnessachieves an average of 1000 calculation and database updates per secondfor a dataset of 5000 records more than three times the rate of thesingle threaded approach. The test harnesses could be modified toperform more complex calculations for larger datasets; however, thissimple example presents the benefits of multi-threaded calculations.
Multi-Threaded Test Harness for Data Set of 1000333 calculation and db updates per second
Start Time : 27
End Time : 30
Single Threaded Test Harness For Data Set of 1000
200 calculation and db updates per second
Start Time : 23
End Time : 32
Multi-Threaded Test Harness for Data Set of 5000
1000 calculation and db updates per second
Start Time : 10
End Time : 15
Single Threaded Test Harness for Data Set of 5000
333 calculation and db updates per second
Start Time : 19
End Time : 34
Download Source & SQL












No comments yet... Be the first to leave a reply!