Posts
103
Comments
238
Trackbacks
4
DataBinding Performance 1.1 vs. 2.0, an update

UPDATE 10/03/2006: Ultimi test con .NET 2.0 e sintassi specifica 2.0

Sulla linea di un post di metà ottobre ho rieseguito un test di performance per evidenziare le differenze tra DataBinding su una TemplateColumn di un DataGrid ASP.NET effettuato con DataBinder.Eval, e quello effettuato con il cast al tipo esatto di contenitore del dato.

Inoltre, dopo l'uscita della RTM del framework 2.0 ho rieseguito il test di comparazione tra 1.1 e 2.0. 

Il DataBinding con DataBinder.Eval è molto comodo perchè non è necessario sapere il tipo di dato che ci arriva e soprattutto il tipo di oggetto che lo contiene, ma per vari motivi (late binding, reflection, bla bla bla...) è anche meno performante.
Le due DataGrid nella nostra pagina si differenziano proprio per questo aspetto: una utilizza DataBinder.Eval, e l'altra il cast esplicito del DataItem del contenitore a DataRowView, perchè sappiamo già che il contenitore dei dati è di tipo DataView (vedi codice successivo).

Quello che vogliamo fare è valutare la differenza di prestazioni tra i due metodi. Ecco il code behind in C#:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DataBindingTest
{
    
public class WebForm1 : Page
    {
        
protected DataGrid DataBinderGrid;
        
protected DataGrid StrongTypeGrid;
        
private DataSet ds;
    
        
private const string m_ConnectionString = @"Database=NorthWind;server=localhost;integrated security=sspi;";

        
private void Page_Load(object sender, EventArgs e)
        {
            
long startTicks;
            
long timeTakenTicks;
            
long[] timeArr = new long[2];
            timeArr[0] = 0;
            timeArr[1] = 0;
          

            BuildDataSet();
            
            
bool bindToggle = true;

            DataGrid dg;

            
for(int i = 0; i < 4; i++)
            {
                startTicks = Environment.TickCount;

                
if(bindToggle)
                    dg = DataBinderGrid;
                
else  
                    
dg = StrongTypeGrid;

                
for(int j = 0; j < 10; j++)
                    BindDataToGrid(dg,ds);
                
                timeTakenTicks = Environment.TickCount - startTicks;

                
if(bindToggle)
                    timeArr[0] += timeTakenTicks;

                
else timeArr[1] += timeTakenTicks;

                bindToggle = !bindToggle;
            }

            
int time1 = (int)(timeArr[0]) / 2;
            Response.Write("DataBinder: " + time1.ToString() + "
");
            
int time2 = (int)(timeArr[1]) / 2;
            Response.Write("StrongType: " + time2.ToString() + "
");

            
long maxTime = Math.Max(time1,time2);
            
long minTime = Math.Min(time1,time2);
            
long diffInt = maxTime - minTime;
            
float percentDiff =( (float)diffInt  * 100) / maxTime ;
            
            Response.Write("Diff: " + percentDiff.ToString() + "%");
        }

        
private void BuildDataSet()
        {
            
string sqlString = @"SELECT * FROM Orders";
            SqlConnection conn = 
new SqlConnection(m_ConnectionString);
            
            conn.Open();

            SqlDataAdapter da = 
new SqlDataAdapter(sqlString, conn);
            
            conn.Close();
            
            ds = 
new DataSet();
            
            da.Fill(ds);
        }

        
private void BindDataToGrid(DataGrid grid, DataSet ds)
        {
            grid.DataSource = ds;
            grid.DataBind();
        }

        
#region Web Form Designer generated code
        override protected void 
OnInit(EventArgs e)
        {
            InitializeComponent();
            
base.OnInit(e);
        }
        
        
private void InitializeComponent()
        {    
            
this.Load += new System.EventHandler(this.Page_Load);
        }
        
#endregion
    
}
}

Senza entrare troppo nei particolari - il codice comunque non è difficile da capire - quello che facciamo è recuperare i dati dal database una volta sola, in modo da limitare l'impatto delle query sul nostro test, e fare il Bind delle due DataGrid per dieci volte, in modo alternato. In "formule":

grid1 (x10) : grid2 (x10) : grid1 (x10) : grid2 (x10)

In questo modo limitiamo l'impatto dell'ordine dei Binding sul test.
Notare che questo test non è stato scritto da me ma da Scott Galloway (ed è scaricabile
qui), sicuramente più affidabile di quanto non possa esserlo io.

Naturalmente durante questi cicli ci memorizziamo il tempo di esecuzione e dopo rielaboriamo i tempi per renderli un pò più presentabili.

Così come constatato anche da Scott Galloway la differenza di prestazioni tra un metodo di Binding e l'altro si attesta sul 20% a favore del Binding con cast esplicito, ed anche io ho ottenuto gli stessi risultati. (con una variabilità dal 10% al 30% circa).

Ecco un esempio di risultati:

DataBinder: 203
StrongType: 164
Diff: 19,21182% 

Tutto questo con il framework 1.1 (1.1.4322)!

Saputo della retrocompatibilità della versione 2.0 (allora in beta2) avevo eseguito il test anche con quella versione, cambiando la versione su cui l'applicazione girava tramite il manager di IIS (click destro sulla directory-applicazione -> scheda ASP.NET), ed avevo notato un notevole deterioramento delle prestazioni assolute dei due metodi (la differenza percentuale si attestava sempre sul 20%).

Dopo i commenti ricevuti da quel post, uno dei quali relativo anche alla mia presunta violazione della licenza del framework, che impediva di "pubblicare" risultati relativi alle prestazioni della beta2, ho atteso con ansia il rilascio della RTM, ed ora eccomi qui, per vedere se quel calo delle prestazioni era DAVVERO dovuto al codice di debug presente nella beta2.

Ora, quindi, con la mia bella 2.0 installata, vado nello snap-in di IIS, click destro sull'applicazione DataBindingTest, schedina ASP.NET, e seleziono la versione 2.0.50727.

Riapro allora la pagina nel browser e leggo un pò di risultati, e questo è quello che ottengo, dopo averla rinfrescata un pò di volte (la prima volta doveva essere ricompilata jit).

DataBinder: 437
StrongType: 344
Diff: 21,28146% 

La differenza percentuale tra i due metodi rimane pressochè la stessa, ma le prestazioni singole, [(2.0 - 1.0)/1.0]*100, sono peggiorate di circa il 100% per ciascuno dei due metodidi Binding.

Nota: il test è stato eseguito senza ricompilare il file .cs della pagina con i due diversi compilatori 1.1 e 2.0, ma soltanto cambiando la versione di ASP.NET su cui farla girare.
Quindi mi è venuto il dubbio che lo scarto di prestazioni fosse dovuto a questo. Di conseguenza mi sono preso i miei bei due compilatori csc.exe (installati assieme al framewrok) e ho ricompilato il code behind della pagina con entrambi. Dopodichè, per non saper nè leggere nè scrivere, ho fatto girare sotto ASP.NET 1.1 (sempre selezionandolo dallo snap-in di IIS) sia l'assembly compilato con csc v.1.1 che quello compilato con csc v.2.0 (ovviamente questo non gira sotto ASP.NET 1.1) e ho fatto la stessa cosa con la versione ASP.NET 2.0 (qui ovviamente invece girano entrambi gli assemply...retrocompatibilità!).
Bene (e per riassumere):

  • l'assembly 1.1 sotto ASP.NET 1.1 gira come prima, veloce (e del resto è lo stesso)
  • l'assembly 2.0 sotto ASP.NET 1.1 (ovviamente) non gira
  • l'assembly 1.1 sotto ASP.NET 2.0 gira pianissimo (è lo stesso valutato prima)
  • ed infine, quello nuovo e che poteva riservarci delle sorprese, l'assembly 2.0 sotto ASP.NET 2.0 gira piano, un pochino meglio che facendolo girare sotto ASP.NET 1.1 ma comunque piano.

Conclusione: ASP.NET 2.0 fa il Binding mooolto più piano che la versione 1.1 (quale altra conclusione se no?).

Sarei contento di sapere cosa ne pensano, tra gli altri, Lorenzo Barbieri e Pierre Greborio.

powered by IMHO 1.3

posted on Tuesday, December 6, 2005 3:13 AM Print
News

Scopri CS2, il mio progetto universitario per l'indicizzazione e la ricerca di codice sorgente personale costruito su Lucene.Net.

Windows Developer Power Tools

Potete trovare il mio progetto BusyBoxDotNet nel libro Windows Developer Power Tools, pubblicato da O'Reilly, per il quale ho scritto l'intero capito dedicato.

Sono stato nominato dVP 2008, un riconoscimento per l'apporto fornito alla comunità del progetto db4o.