Sono uno sviluppatore C ++ e C #. Ho sviluppato applicazioni C # sin dalla prima beta del framework .NET e ho più di 20 anni di esperienza nello sviluppo di applicazioni C ++. In primo luogo, il codice C # non sarà MAI più veloce di un'applicazione C ++, ma non affronterò una lunga discussione sul codice gestito, su come funziona, sul livello di interoperabilità, sugli interni di gestione della memoria, sul sistema di tipi dinamici e sul garbage collector. Tuttavia, permettetemi di continuare dicendo che i benchmark qui elencati producono tutti risultati SCORRETTI.
Mi spiego meglio: la prima cosa che dobbiamo considerare è il compilatore JIT per C # (.NET Framework 4). Ora JIT produce codice nativo per la CPU utilizzando vari algoritmi di ottimizzazione (che tendono ad essere più aggressivi dell'ottimizzatore C ++ predefinito fornito con Visual Studio) e il set di istruzioni utilizzato dal compilatore .NET JIT riflette più da vicino la CPU effettiva sulla macchina in modo che alcune sostituzioni nel codice macchina possano essere effettuate per ridurre i cicli di clock e migliorare la frequenza di riscontro nella cache della pipeline della CPU e produrre ulteriori ottimizzazioni hyper-threading come riordino delle istruzioni e miglioramenti relativi alla previsione dei rami.
Ciò significa che, a meno che non si compili l'applicazione C ++ utilizzando i parametri corretti per la build RELEASE (non la build DEBUG), l'applicazione C ++ potrebbe funzionare più lentamente rispetto alla corrispondente applicazione basata su C # o .NET. Quando si specificano le proprietà del progetto sulla propria applicazione C ++, assicurarsi di abilitare "l'ottimizzazione completa" e "favorire il codice veloce". Se hai una macchina a 64 bit, DEVI specificare di generare x64 come piattaforma di destinazione, altrimenti il tuo codice verrà eseguito attraverso un sottolivello di conversione (WOW64) che ridurrà sostanzialmente le prestazioni.
Dopo aver eseguito le ottimizzazioni corrette nel compilatore, ottengo 0,72 secondi per l'applicazione C ++ e 1,16 secondi per l'applicazione C # (entrambi in versione build). Poiché l'applicazione C # è molto semplice e alloca la memoria utilizzata nel ciclo sullo stack e non sull'heap, in realtà funziona molto meglio di un'applicazione reale coinvolta in oggetti, calcoli pesanti e con set di dati più grandi. Quindi le cifre fornite sono cifre ottimistiche orientate verso C # e il framework .NET. Anche con questo pregiudizio, l'applicazione C ++ viene completata in poco più della metà del tempo rispetto all'applicazione C # equivalente. Tieni presente che il compilatore Microsoft C ++ che ho usato non aveva la pipeline corretta e le ottimizzazioni hyperthreading (utilizzando WinDBG per visualizzare le istruzioni di assemblaggio).
Ora, se utilizziamo il compilatore Intel (che tra l'altro è un segreto del settore per la generazione di applicazioni ad alte prestazioni su processori AMD / Intel), lo stesso codice viene eseguito in 0,54 secondi per l'eseguibile C ++ rispetto a .72 secondi utilizzando Microsoft Visual Studio 2010 Quindi, alla fine, i risultati finali sono 0,54 secondi per C ++ e 1,16 secondi per C #. Quindi il codice prodotto dal compilatore .NET JIT impiega il 214% di volte in più rispetto all'eseguibile C ++. La maggior parte del tempo speso nei 0,54 secondi era per ottenere il tempo dal sistema e non all'interno del ciclo stesso!
Ciò che manca nelle statistiche sono i tempi di avvio e pulizia che non sono inclusi nei tempi. Le applicazioni C # tendono a dedicare molto più tempo all'avvio e alla chiusura rispetto alle applicazioni C ++. Il motivo alla base di ciò è complicato e ha a che fare con le routine di convalida del codice runtime .NET e il sottosistema di gestione della memoria che esegue molto lavoro all'inizio (e di conseguenza, alla fine) del programma per ottimizzare le allocazioni di memoria e la spazzatura collettore.
Quando si misurano le prestazioni di C ++ e .NET IL, è importante esaminare il codice dell'assembly per assicurarsi che TUTTI i calcoli siano presenti. Quello che ho scoperto è che senza inserire del codice aggiuntivo in C #, la maggior parte del codice negli esempi precedenti è stata effettivamente rimossa dal file binario. Questo era anche il caso di C ++ quando si utilizzava un ottimizzatore più aggressivo come quello fornito con il compilatore Intel C ++. I risultati che ho fornito sopra sono corretti al 100% e convalidati a livello di assemblaggio.
Il problema principale con molti forum su Internet è che molti principianti ascoltano la propaganda di marketing di Microsoft senza comprendere la tecnologia e fanno false affermazioni che C # è più veloce di C ++. L'affermazione è che in teoria C # è più veloce di C ++ perché il compilatore JIT può ottimizzare il codice per la CPU. Il problema con questa teoria è che nel framework .NET esistono molte tubature che rallentano le prestazioni; impianto idraulico che non esiste nell'applicazione C ++. Inoltre, uno sviluppatore esperto conoscerà il compilatore giusto da utilizzare per la piattaforma data e utilizzerà i flag appropriati durante la compilazione dell'applicazione. Sulle piattaforme Linux o open source, questo non è un problema perché potresti distribuire il tuo sorgente e creare script di installazione che compilano il codice utilizzando l'ottimizzazione appropriata. Su Windows o piattaforma closed source, dovrai distribuire più eseguibili, ciascuno con ottimizzazioni specifiche. I file binari di Windows che verranno distribuiti sono basati sulla CPU rilevata dal programma di installazione msi (utilizzando azioni personalizzate).