I was working on a project the other day in MFC/C++ 6 and had to put 180,000 items into a ComboBox. Every Windows programmer that reads this Blog just collectively groaned, but there was a reason for it – honest. On a whim I thought I would see what would happen if I did the same test using C#, Windows Forms, and the .NET Framework; the results were surprising, given all of the “Why .NET Framework?” grief I’ve gotten over the couple of years.
Obviously this is a very pointed test and should be taken as such. The only thing I’m pointing out are the test results themselves, so read them with that in mind. First thing to talk about: the machine in question is a Pentium III 800MHz. Yes, that just caused another collective moan, but suck it up – it’s what I was working on so that’ll have to do. Also has 512MB RAM, so at least it’s not a complete retro-system.
The MFC Test: Created a CStringArray object and then looped through 180,000 times, adding a new CString with each pass. Each CString is set to “Value: %d” with the array index. The results were collected by grabbing CTime::GetCurrentTime() before and after the load of both the array and the ComboBox. It took 9 seconds to load the CStringArray in the object constructor. With a button click, it took 5 minutes and 57 seconds to load the ComboBox.
The C# Test: Created a String[] array with 180,000 items and then looped through 180,000 times, setting each String to “Value: ” + i.ToString() with i being the array index. The results were collected by grabbing DateTime.Now before and after the load of both the array and the ComboBox. It took 22 seconds to create and set the array in the Load event. With a button click, it took 1 minute and 1 second to load the ComboBox.
After this run I said, “No way!” and figured that the fixed-length array versus a dynamic array wasn’t a fair test. So I changed the application to use an ArrayList and filled it with Strings. Rebooted the test machine, just to make sure Framework was in the same “place” as the first test and that nothing was pre-loaded. This time through it took 1 second to load the array; it took 23 seconds to load the ComboBox.
Say what you want about C# and the .NET Framework, but in this instance, the “tried and true” C++ application was “tired and truly awful” by comparison.
Felt I should share it, given the results…
Can you post the code?
I’d like to see how you added the items.
Basically, as described – I’ll see about posting some code samples in a little bit – in the middle of a coding frensy right now :D
You should try it with a virtual list view. instantaneous.
I knew I’d get you to post on this one. :D
Yeah, some other parts of the project are using virtual listboxs (yes, I know how retro that is) but I was stuck with the ComboBox… I was curious to see if the managed code app would be faster and lo! Zipped right along.
Oh yeah – the C# code:
private ArrayList StringArray = new ArrayList();
private void Form1_Load(object sender, System.EventArgs e) {
DateTime dtStart = DateTime.Now;
for (int i=0;i180000;i++) {
StringArray.Add(“Value: ” + i.ToString());
}
MessageBox.Show(“Start: ” + dtStart.ToLongTimeString() + “\n\nEnd: ” + DateTime.Now.ToLongTimeString());
}
private void button1_Click(object sender, System.EventArgs e) {
DateTime dtStart = DateTime.Now;
for (int i=0;iStringArray.Count;i++) {
comboBox1.Items.Add(StringArray[i]);
}
MessageBox.Show(“Start: ” + dtStart.ToLongTimeString() + “\n\nEnd: ” + DateTime.Now.ToLongTimeString());
}
And the MFC code:
// OnInitDialog:
CTime dt = CTime::GetCurrentTime();
TRACE(“Load Start: ” + dt.Format(“%H:%M:%S”) + “\n”);
for (int i=0;i180000;i++) {
CString str;
str.Format(“Value: %d”, i);
ma_strVal.Add(str);
}
dt = CTime::GetCurrentTime();
TRACE(“Load End: ” + dt.Format(“%H:%M:%S”) + “\n”);
void CTestingLoaderDlg::OnButton1()
{
int n = ma_strVal.GetSize();
CTime dt = CTime::GetCurrentTime();
TRACE(“ComboBox Start: ” + dt.Format(“%H:%M:%S”) + “\n”);
for (int i=0; i n; i++) {
m_cbDrop.AddString(ma_strVal[i]);
}
dt = CTime::GetCurrentTime();
TRACE(“ComboBox End: ” + dt.Format(“%H:%M:%S”) + “\n”);
}
Like I said: basic stuff.
This only took 10 seconds to run on my box;
private void button1_Click(object sender, System.EventArgs e)
{
object[] strings = StringArray.ToArray();
comboBox1.BeginUpdate();
dtStart = DateTime.Now;
ComboBox.ObjectCollection objCol= new System.Windows.Forms.ComboBox.ObjectCollection(comboBox1);
objCol.AddRange(strings);
comboBox1.EndUpdate();
MessageBox.Show(“Start: ” + dtStart.ToLongTimeString() + “\n\nEnd: ” + DateTime.Now.ToLongTimeString());
}
Yeah, the code posted was 11 seconds on the Pentium-M 1.6GHz box – didn’t bother to try it ont he P4-2.53GHz box… I was more curious to see how the retro-hardware dealt with it, because that’s an on going debate: “I could run Linux on a 286 and it will run fine!” type crap.
I tried AddRange too, at one point, but I wanted a “similar” comparison between the languages, once I figured I would post the findings…
If you wanted similar, then i’d code the combobox *correctly* on both instances.
You should be using sending the combobox CBEM_SETITEM with the text value set to LPSTR_TEXTCALLBACK in C++.. Would be MUCH faster than the way you’re doing it.
Um, except isn’t the argument always C++ is faster than C#? The Foundation Classes are in C++; .NET Framework is using C#. The CBEN_SETITEM message would bypass MFC and call the Win32 API using C or C++, and I couldn’t care less about that :) Besides, the whole thing was started because of the MFC example and some curiousity to see how .NET would perform… All of that doesn’t change the fact that MFC is 5 minutes slower than the Framework in this instance.
Sigh. Do I have to fly out there and hit you?
USE CComboBoxEx.SetItem() then. Geez.
I do wonder though, use C# to thunk to the CBEN_SETITEM how fast you could get it..
Bah. I’m going out in the sun because this is the first weekend with nice weather all year :P
LOL who cares if using the .NET framework isn’t quite as fast?
.NET programs still get compiled to native at runtime by the JIT compiler.
Plus learning to use the .NET framework is 100 fold easier than learning Win32 or MFC.
If you’re not sold on .NET (and WinFX) yet it’s because you haven’t been keeping up.
Just my $0.02.
Nice blog.
filles
Well that was compelling.