Quanto è più veloce di C ++ di C #?


246

O è ora il contrario?

Da quello che ho sentito ci sono alcune aree in cui C # si rivela più veloce di C ++, ma non ho mai avuto il coraggio di provarlo da solo.

Pensavo che qualcuno di voi potesse spiegare queste differenze in dettaglio o indicarmi il posto giusto per informazioni al riguardo.


7
Protetto, per impedire la pubblicazione di altri benchmark casuali. Se pensi di poter presentare il tuo caso, avrai bisogno di 10 rappresentanti per farlo.
Robert Harvey,

2
In che modo questo non è chiuso come opinione / argomentazione comunque? Non sono ancora su StackOverflow? (Non suggerendo la chiusura, solo curioso. Adoro le domande che stimolano argomentazioni supposte)
Bill K

1
È quasi una domanda controversa, dato che viviamo in un'epoca in cui IL può essere convertito in CPP e ottimizzato da lì: docs.unity3d.com/Manual/IL2CPP.html
pixelpax

Un linguaggio che controlla l'accesso fuori gamma non supererà mai quello che non lo è.
Seva Alekseyev,

@SevaAlekseyev Non è la lingua che lo fa, ma il compilatore. Uno dei motivi per cui C ++ è così veloce (a parte quelli ovvi) è che i compilatori C ++ sono in circolazione da 35 anni (se non di più). Non c'è nulla che impedisce ai compilatori C # di migliorare nel tempo. Per il caso menzionato, leggi questo stackoverflow.com/questions/16713076/…
Trap

Risposte:


343

Non vi è alcun motivo rigoroso per cui un linguaggio basato su bytecode come C # o Java che abbia un JIT non possa essere veloce come il codice C ++. Tuttavia il codice C ++ era significativamente più veloce per molto tempo, e anche oggi lo è ancora in molti casi. Ciò è dovuto principalmente al fatto che le ottimizzazioni JIT più avanzate sono complicate da implementare e quelle davvero interessanti stanno arrivando solo ora.

Quindi il C ++ è più veloce, in molti casi. Ma questa è solo una parte della risposta. I casi in cui C ++ è effettivamente più veloce, sono programmi altamente ottimizzati, in cui programmatori esperti hanno ottimizzato a fondo il codice. Ciò non solo richiede molto tempo (e quindi è costoso), ma spesso porta anche a errori dovuti a ottimizzazioni eccessive.

D'altra parte, il codice nei linguaggi interpretati diventa più veloce nelle versioni successive del runtime (.NET CLR o Java VM), senza che tu faccia nulla. E ci sono molte utili ottimizzazioni che i compilatori JIT possono fare che sono semplicemente impossibili in linguaggi con puntatori. Inoltre, alcuni sostengono che la garbage collection dovrebbe essere generalmente veloce o più veloce della gestione manuale della memoria, e in molti casi lo è. In genere puoi implementare e ottenere tutto ciò in C ++ o C, ma sarà molto più complicato e soggetto a errori.

Come diceva Donald Knuth, "l'ottimizzazione prematura è la radice di tutti i mali". Se sai davvero per certo che la tua applicazione consisterà per lo più in aritmetica critica per le prestazioni, e che sarà il collo di bottiglia, e sicuramente sarà più veloce in C ++, e sei sicuro che C ++ non entrerà in conflitto con l'altra requisiti, andare per C ++. In ogni altro caso, concentrati prima sull'implementazione corretta della tua applicazione in qualunque lingua tu preferisca, poi trova i colli di bottiglia delle prestazioni se funziona troppo lentamente e poi pensa a come ottimizzare il codice. Nel peggiore dei casi, potrebbe essere necessario richiamare il codice C tramite un'interfaccia di funzione esterna, quindi sarà comunque possibile scrivere parti critiche in un linguaggio di livello inferiore.

Tieni presente che è relativamente facile ottimizzare un programma corretto, ma molto più difficile correggere un programma ottimizzato.

Dare percentuali effettive di vantaggi di velocità è impossibile, dipende in gran parte dal codice. In molti casi, l'implementazione del linguaggio di programmazione non è nemmeno il collo di bottiglia. Prendi i parametri di riferimento su http://benchmarksgame.alioth.debian.org/ con grande scetticismo, poiché questi test ampiamente testano il codice aritmetico, che molto probabilmente non è affatto simile al tuo codice.


92
Il <quote> codice nelle lingue interpretate diventa più veloce nelle versioni successive del runtime </quote> Poiché anche il codice compilato da una versione migliore del compilatore diventerà più veloce.
Martin York,

47
In realtà c'è almeno un motivo: JIT deve essere veloce e non può permettersi di dedicare tempo a varie ottimizzazioni avanzate disponibili per un compilatore C ++.
Nemanja Trifunovic,

63
"ma porta anche comunemente a errori dovuti a ottimizzazioni eccessive." [citazione disperatamente necessaria]. Lavoro in un laboratorio nazionale e ottimizziamo al massimo il nostro codice. Questo non provoca comunemente codice errato.
Todd Gamblin,

35
"È relativamente facile ottimizzare un programma corretto, ma molto più difficile correggere un programma ottimizzato".
Gradbot,

20
Inge: non sono sicuro di essere sulla strada giusta lì. Sì, C # è implementato in un'altra lingua, ma il compilatore JIT sta generando codice macchina, quindi non è un linguaggio interpretato. Pertanto non è limitato dalla sua implementazione in C ++. Non sono sicuro del perché pensi che l'aggiunta di un manager a qualcosa intrinsecamente lo renda più veloce.
Martin Probst,

202

C # potrebbe non essere più veloce, ma ti rende più veloce. Questa è la misura più importante per quello che faccio. :)


68
Haha, c'è una buona citazione di Larry Wall sull'argomento. Sta parlando di perl, ma si può pensare a tutte le discussioni che coinvolgono le lingue e le prestazioni: ".. linguaggi di computer precedenti, come Fortran e C, erano progettati per un uso efficiente di hardware costoso. Al contrario, Perl è progettato per fare un uso efficiente di costosi programmatori di computer "
Falaina

60
1. "C # è molto più veloce di C ++" 2. "Non può essere vero" 1. "Sicuro che può" 2. "Di quanto?" 1. "Di solito entro 3-4 mesi"
Dmitry S.

2
per C ++ che dipende davvero dalle librerie che stai usando, C # non è in genere più veloce, .NET lo è, quando parli di produttività
Ion Todirel

È lo stesso motivo per cui potresti usare Python invece di C per scrivere del codice ... ma dopo aver creato alcuni calcoli pesanti puoi sentire la differenza nelle prestazioni.
Ch3shire,

Dipende da cosa sei abituato. Programma in C ++ molto più velocemente di quanto avrei in C #. La conoscenza delle biblioteche è una grande parte di ciò poiché non si desidera reinventare la ruota per le attività di base. Il problema principale di C / C ++ era la gestione dei puntatori che è praticamente risolta con i puntatori intelligenti. Detto questo, in C ++ manca una vasta libreria offerta da .NET e Java e ciò può accelerare notevolmente lo sviluppo. Questo non sarà risolto presto poiché quei ragazzi standard amano passare il loro tempo a migliorare i modelli anziché le estensioni della libreria.
gast128,

87

Sono cinque arance più veloci. O meglio: non ci può essere una risposta (corretta) coperta. C ++ è un linguaggio compilato staticamente (ma poi c'è anche l'ottimizzazione guidata dal profilo), C # viene aiutato da un compilatore JIT. Ci sono così tante differenze che non è possibile rispondere a domande come "quanto più velocemente", nemmeno dando ordini di grandezza.


177
Hai qualche prova a sostegno della tua scandalosa affermazione sulle cinque arance? I miei esperimenti puntano tutti al massimo a 2 arance, con un miglioramento di 3 mango durante la metaprogrammazione dei modelli.
Alex

42
Al lievito non sta chiedendo a gran voce che gli antipasti di grandezza siano più veloci.
Chris,

11
Dalla mia esperienza sono piuttosto 5,2 arance. Ma questo dipende dal misuratore di frutta che usi.
Dio F,

4
Aggiornamento, StackOverflow stesso ha incasinato e gestisce i commenti inefficienti, quindi meno banane (300 banane peggio di quanto dovrebbe essere): meta.stackexchange.com/questions/254534/…
KeksArmee

87

Inizierò in disaccordo con una parte della risposta accettata (e ben votata) a questa domanda affermando:

In realtà ci sono molte ragioni per cui il codice JITted verrà eseguito più lentamente di un programma C ++ (o altra lingua senza sovraccarico di runtime) correttamente ottimizzato, tra cui:

  • i cicli di calcolo spesi sul codice JITting in fase di esecuzione non sono per definizione disponibili per l'uso nell'esecuzione del programma.

  • eventuali percorsi caldi in JITter saranno in concorrenza con il codice per istruzioni e cache di dati nella CPU. Sappiamo che la cache domina quando si tratta di prestazioni e che i linguaggi nativi come il C ++ non hanno questo tipo di contesa, per definizione.

  • il budget temporale di un ottimizzatore di runtime è necessariamente molto più limitato di quello di un ottimizzatore di compilazione (come sottolineato da un altro commentatore)

Linea di fondo: In definitiva, si sarà quasi certamente in grado di creare una più rapida attuazione in C ++ di quanto si potrebbe in C # .

Ora, detto questo, quanto più velocemente non è davvero quantificabile, poiché ci sono troppe variabili: l'attività, il dominio del problema, l'hardware, la qualità delle implementazioni e molti altri fattori. Avrai eseguito dei test sul tuo scenario per determinare la differenza nelle prestazioni e quindi decidere se valga la pena lo sforzo e la complessità aggiuntivi.

Questo è un argomento molto lungo e complesso, ma penso che valga la pena menzionare per completezza che l'ottimizzatore di runtime di C # è eccellente ed è in grado di eseguire determinate ottimizzazioni dinamiche in fase di runtime che non sono semplicemente disponibili per C ++ con il suo tempo di compilazione ( statico) ottimizzatore. Anche con questo, il vantaggio è ancora in genere profondamente nella corte dell'applicazione nativa, ma l'ottimizzatore dinamico è la ragione del " quasi qualificatore certamente" di cui sopra.

-

In termini di prestazioni relative, sono stato anche disturbato dalle cifre e dalle discussioni che ho visto in alcune altre risposte, quindi ho pensato di intervenire e allo stesso tempo fornire supporto alle dichiarazioni che ho fatto sopra.

Una grande parte del problema con questi benchmark è che non puoi scrivere codice C ++ come se stessi scrivendo C # e ti aspetti di ottenere risultati rappresentativi (es. Eseguire migliaia di allocazioni di memoria in C ++ ti darà numeri terribili).

Invece, ho scritto un codice C ++ leggermente più idiomatico e confrontato con il codice C # fornito da @Wiory. Le due principali modifiche che ho apportato al codice C ++ sono state:

1) vettore utilizzato :: reserve ()

2) appiattito l'array 2d a 1d per ottenere una migliore localizzazione della cache (blocco contiguo)

C # (.NET 4.6.1)

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);
}

Tempo di esecuzione (Rilascio): Init: 124ms, Fill: 165ms

C ++ 14 (Clang v3.8 / C2)

#include <iostream>
#include <vector>

auto TestSuite::ColMajorArray()
{
    constexpr size_t ROWS = 5000;
    constexpr size_t COLS = 9000;

    auto initStart = std::chrono::steady_clock::now();

    auto arr = std::vector<double>();
    arr.reserve(ROWS * COLS);

    auto initFinish = std::chrono::steady_clock::now();
    auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);

    auto fillStart = std::chrono::steady_clock::now();

    for(auto i = 0, r = 0; r < ROWS; ++r)
    {
        for (auto c = 0; c < COLS; ++c)
        {
            arr[i++] = static_cast<double>(r * c);
        }
    }

    auto fillFinish = std::chrono::steady_clock::now();
    auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);

    return std::make_pair(initTime, fillTime);
}

Tempo di esecuzione (Release): Init: 398µs (sì, sono microsecondi), Fill: 152ms

Totale tempi di esecuzione: C #: 289ms, C ++ 152ms (circa il 90% più veloce)

osservazioni

  • La modifica dell'implementazione C # nella stessa implementazione di array 1d ha prodotto Init: 40ms, Fill: 171ms, Total: 211ms (il C ++ era ancora quasi il 40% più veloce ).

  • È molto più difficile progettare e scrivere codice "veloce" in C ++ che scrivere codice "normale" in entrambe le lingue.

  • È (forse) sorprendentemente facile ottenere scarse prestazioni in C ++; lo abbiamo visto con prestazioni di vettori senza prenotazione. E ci sono molte insidie ​​come questa.

  • Le prestazioni di C # sono piuttosto sorprendenti se si considera tutto ciò che accade in fase di esecuzione. E quella performance è relativamente facile da accedere.

  • Ulteriori dati aneddotici che confrontano le prestazioni di C ++ e C #: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore

La linea di fondo è che C ++ ti dà molto più controllo sulle prestazioni. Vuoi usare un puntatore? Un riferimento? Stack memoria? Mucchio? Polimorfismo dinamico o eliminare l'overhead di runtime di una tabella con polimorfismo statico (tramite modelli / CRTP)? In C ++ devi ... er, arrivare a fare tutte queste (e di più) te stesso, idealmente in modo che la tua soluzione affronti al meglio il problema che stai affrontando.

Chiediti se in realtà desideri o hai bisogno di quel controllo, perché anche per l'esempio banale sopra, puoi vedere che sebbene ci sia un miglioramento significativo delle prestazioni, per accedere è necessario un investimento più profondo.


16
@Quonux grazie per il commento. Naturalmente questo non è un "vero programma". Il punto di riferimento è stato il refactoring di un benchmark C # offerto altrove in questa pagina come prova che il codice JITted è in qualche modo più veloce di quello nativo - non lo è, e il benchmark era potenzialmente fuorviante per le nuove persone.
U007D

9
@Quonux perché devi scrivere così? Sono persone come te che non mi fanno impilare StackOverflow.
Markus Knappen Johansson,

5
@MarkusKnappenJohansson Ho avuto una brutta giornata;), sono solo un essere umano, ho rimosso il mio voto negativo, ma la mia opinione è ancora valida. Oh, per favore, non disprezzare SO solo perché ci sono alcune persone "stupide" :). Buona.
Quonux,

9
BENCHMARK COMPLETAMENTE MISLEADING. Nella versione C ++ stai semplicemente riservando parte della memoria (e poi ti stupisci di come l'esecuzione di tale operazione richiede microsecondi). Nella versione C # si stanno creando 5000 ARRAY (istanza di oggetti in memoria). Il C ++ è più veloce del C # ... ma la differenza non è affatto vicina al 40% ... in questo momento è più nell'intervallo <10%. Ciò che illustra il tuo esempio è che i programmatori dovrebbero attenersi al linguaggio di loro scelta (e dal tuo profilo è ovvio che sei un programmatore di carriera C ++). In C # puoi fare un array 2D int[,]... seguendo l'esempio.
nikib3ro,

3
Da quello che posso dire, il codice nell'esempio in C ++ sta letteralmente allocando la memoria in anticipo. L'implementazione PROPER C # scriverà semplicemente 'Elenco <doppio> arrs = nuovo Elenco <doppio> (ROWS * COLS)' che alloca la memoria richiesta per indicizzare un array 2 dimensionale in formato 1 dimensionale (ad esempio, cosa hai fatto in C ++). Non c'è assolutamente alcun motivo per allocare un array bidimensionale e appiattirlo manualmente: l'enorme quantità di iterazioni nel pre-test è la causa delle prestazioni di merda. Immagino che il sovraccarico sarebbe ancora maggiore in C #, ma non in misura considerevole.
JDSweetBeat

62

Nella mia esperienza (e ho lavorato molto con entrambe le lingue), il problema principale con C # rispetto a C ++ è il consumo elevato di memoria e non ho trovato un buon modo per controllarlo. Era il consumo di memoria che alla fine avrebbe rallentato il software .NET.

Un altro fattore è che il compilatore JIT non può permettersi troppo tempo per eseguire ottimizzazioni avanzate, poiché viene eseguito in fase di esecuzione e l'utente finale lo noterà se impiega troppo tempo. D'altro canto, un compilatore C ++ ha tutto il tempo necessario per eseguire ottimizzazioni in fase di compilazione. Questo fattore è molto meno significativo del consumo di memoria, IMHO.


6
In un progetto al lavoro dovevamo estrarre quantità gigantesche di dati, incluso tenere molti GB contemporaneamente in memoria ed eseguire costosi calcoli su tutto questo - questo richiedeva un controllo preciso di tutte le allocazioni, il C ++ era praticamente l'unica scelta. +1 per C ++. D'altra parte, quello era solo un progetto, abbiamo trascorso la maggior parte del nostro tempo a scrivere sistemi che interagivano con simulatori lenti e il debug poteva essere un incubo, quindi avrei voluto poter usare un linguaggio di ottimizzazione del tempo del programmatore per tutto ciò che cose.
Bogatyr,

7
@IngeHenriksen: sono ben consapevole del modello Dispose, ma non aiuta affatto con la memoria gestita.
Nemanja Trifunovic,

10
La disposizione di @IngeHenriksen assicura solo che sia stato chiamato il metodo Dispose. Lo smaltimento non libera mai la memoria raccolta rifiuti. Il metodo Dispose è destinato esclusivamente alla pulizia di risorse non gestite come handle di file e non ha nulla a che fare con la gestione della memoria.
doug65536,

1
@NemanjaTrifunovic: "Il compilatore JIT non può permettersi troppo tempo per eseguire ottimizzazioni avanzate". Puoi citare alcune ottimizzazioni che non vengono fatte dalle squadre investigative comuni perché richiederebbero troppo tempo?
Jon Harrop,

5
@ user3800527: Anche se l'aggiunta di RAM era sempre fattibile (e non lo è - immagina che Microsoft abbia aggiunto RAM a ciascun utente di MS Office) che non risolvesse il problema. La memoria è gerarchica e un programma C # avrà molti più errori di cache rispetto a uno C ++.
Nemanja Trifunovic,

35

Uno scenario particolare in cui il C ++ ha ancora il sopravvento (e lo sarà, per gli anni a venire) si verifica quando le decisioni polimorfiche possono essere predeterminate al momento della compilazione.

In generale, l'incapsulamento e il processo decisionale differito sono una buona cosa perché rendono il codice più dinamico, più facile da adattare ai mutevoli requisiti e più facile da usare come framework. Questo è il motivo per cui la programmazione orientata agli oggetti in C # è molto produttiva e può essere generalizzata con il termine "generalizzazione". Sfortunatamente, questo particolare tipo di generalizzazione ha un costo in fase di esecuzione.

Di solito, questo costo non è sostanziale, ma ci sono applicazioni in cui l'overhead delle chiamate ai metodi virtuali e la creazione di oggetti possono fare la differenza (soprattutto perché i metodi virtuali impediscono altre ottimizzazioni come l'inserimento delle chiamate ai metodi). Questo è dove C ++ ha un enorme vantaggio perché puoi usare i template per ottenere un diverso tipo di generalizzazione che non ha impatto sul runtime ma non è necessariamente meno polimorfico di OOP. In effetti, tutti i meccanismi che costituiscono OOP possono essere modellati usando solo tecniche di template e risoluzione in fase di compilazione.

In questi casi (e, certamente, sono spesso limitati a domini con problemi speciali), C ++ vince contro C # e linguaggi simili.


6
In realtà, le VM Java (e probabilmente .NET) fanno di tutto per evitare l'invio dinamico. Fondamentalmente, se c'è un modo per evitare i polimorfismi, puoi essere abbastanza sicuro che la tua VM lo farà.
Martin Probst,

3
+1 Ho sempre problemi a spiegarlo ai miei colleghi C # che conoscono poco C ++ in un modo che consentirebbe loro di apprezzarne il significato. L'hai spiegato abbastanza bene.
Roman Starkov,

9
@crtracy: stai scommettendo senza applicazioni di elaborazione ad alte prestazioni. Prendi in considerazione previsioni meteorologiche, bioinformatica e simulazioni numeriche. Il vantaggio prestazionale del C ++ in queste aree non si ridurrà, poiché nessun altro codice può raggiungere prestazioni comparabili allo stesso livello di elevata astrazione.
Konrad Rudolph,

5
@Jon Mele e arance. La tua richiesta specifica era "C # è ordini di grandezza più veloci di C ++ nel contesto della metaprogrammazione", non "usare il codice precompilato è ordini di grandezza più veloci del codice interpretato". Mentre ci siamo, la tua affermazione che la generazione del codice di runtime è "più generale" rispetto alla generazione del codice in fase di compilazione è anche chiaramente sbagliata - entrambi hanno punti di forza e di debolezza. La generazione del codice in fase di compilazione utilizza il sistema di tipi per fornire sicurezza di tipo statico - la generazione di codice di runtime non può farlo ( può fornire una sicurezza di tipo forte, ma non una sicurezza di tipo statico ).
Konrad Rudolph,

5
@ user3800527 Penso che ti manchi l'intero punto di questa risposta. Ovviamente puoi aggirare questo problema rompendo l'incapsulamento e scendendo a strutture di basso livello: puoi scrivere assembly in (quasi) qualsiasi lingua. La cosa che rende C ++ (quasi) unico e adatto in modo univoco alla programmazione ad alte prestazioni, è che puoi costruire astrazioni di alto livello che non comportano costi di runtime. Quindi non è necessario scrivere codice simile a assembly in C ++ per ottenere prestazioni eccezionali: un testo ben scritto sort(arr, generic_comparer)sarà efficiente come un ciclo scritto a mano in C ++. Non sarà mai in C #.
Konrad Rudolph,

20

C ++ (o C del resto) ti offre un controllo approfondito sulle tue strutture di dati. Se vuoi fare il bit-twiddle hai questa opzione. Le grandi app Java o .NET gestite (OWB, Visual Studio 2005 ) che utilizzano le strutture di dati interne delle librerie Java / .NET portano con sé il bagaglio. Ho visto sessioni di progettazione di OWB che utilizzano oltre 400 MB di RAM e BIDS per la progettazione di cubi o ETL che arrivano anche ai 100 di MB.

Su un carico di lavoro prevedibile (come la maggior parte dei benchmark che ripetono un processo più volte), un JIT può ottenere un codice ottimizzato abbastanza bene da non avere differenze pratiche.

IMO su applicazioni di grandi dimensioni la differenza non è tanto nella JIT quanto nelle strutture di dati utilizzate dal codice stesso. Laddove un'applicazione è ricca di memoria, si otterrà un utilizzo della cache meno efficiente. I cache mancati nelle CPU moderne sono piuttosto costosi. Dove C o C ++ vincono davvero è dove puoi ottimizzare l'utilizzo delle strutture dati per giocare bene con la cache della CPU.


19

Per la grafica, la classe grafica standard C # è molto più lenta di quella GDI a cui si accede tramite C / C ++. So che questo non ha nulla a che fare con il linguaggio in sé, più con la piattaforma .NET totale, ma la grafica è ciò che viene offerto allo sviluppatore in sostituzione di GDI e le sue prestazioni sono così pessime che non oserei nemmeno fare la grafica con esso.

Abbiamo un semplice benchmark che usiamo per vedere quanto è veloce una libreria grafica e che è semplicemente disegnare linee casuali in una finestra. C ++ / GDI è ancora veloce con 10000 linee mentre C # / Graphics ha difficoltà a fare 1000 in tempo reale.


5
Sono stato incuriosito dalla tua risposta. Hai testato lo stesso benchmark con codice non sicuro e lockbits e disegnando tu stesso le linee casuali? Ora che sarebbe una cosa interessante da guardare.
Pedery,

2
@Pedery no, non l'ho fatto. semplicemente usando GDI e .NET.Graphics nel modo più semplice. cosa intendi con "disegnando tu stesso le linee casuali"?
QBziZ,

1
Quindi dovresti forse considerare di testarlo per ottenere metriche più realistiche su quanto veloce può essere C #. Ecco una bella panoramica della tecnica: bobpowell.net/lockingbits.htm
Pedery

6
Non è quello che vogliamo fare, inserendo noi stessi pixel separati in un frame buffer. Se devi implementare tutto da solo, qual è il punto di avere un'API / una piattaforma per codificare? Per me questo non è un argomento. Non abbiamo mai avuto bisogno di mettere pixel separati in un framebuffer in GDI per disegnare linee, e non abbiamo intenzione di farlo nemmeno in .NET. A mio avviso, abbiamo utilizzato una metrica realistica e .NET si è rivelato lento.
QBziZ,

1
Bene, ho solo una leggera idea di cosa sia il rilevamento dei BLOB, ma affermare semplicemente che un tempismo non prova affatto nulla. Ne hai scritto uno in C ++? In JavaScript? E confrontati con quelli in C #? Inoltre, non credo che il rilevamento BLOB stia utilizzando molte primitive grafiche. Correggimi se sbaglio, ma suppongo che siano algoritmi statistici che eseguono operazioni sui pixel.
QBziZ,

13

La garbage collection è il motivo principale per cui Java # NON PU be essere utilizzato per i sistemi in tempo reale.

  1. Quando accadrà il GC?

  2. Quanto tempo ci vorrà?

Questo non è deterministico.


5
Non sono un grande fan di Java ma non c'è nulla che dica che Java non può usare un GC amichevole in tempo reale.
Zan Lynx,

5
Ci sono molte implementazioni GC in tempo reale se ti interessa guardare. (GC è un'area traboccante di documenti di ricerca)
Arafangion,

FWIW, Richard Jones ha appena pubblicato una versione aggiornata del suo libro sulla raccolta dei rifiuti che copre, tra le altre cose, i progetti GC in tempo reale all'avanguardia.
Jon Harrop,

11
Questo è un argomento senza senso, Windows (e Linux) non sono sistemi operativi in ​​tempo reale. Il tuo codice C ++ può essere sostituito anche per un numero di slot di 18 ms in qualsiasi momento.
Henk Holterman,

2
@HenkHolterman Vero, ma potresti sempre scrivere un bootloader in assembly, legarlo in un bootstrap del kernel per la tua applicazione ed eseguire le tue app C ++ direttamente sull'hardware (in RT btw). Non puoi farlo in C # e tutti gli sforzi che ho visto imitano solo l'assemblaggio precompilato in C # e usano una tonnellata di codice C, il che rende inutile usare C #. Leggere tutto ciò è piuttosto divertente, perché C # è veramente inutile senza il framework .NET.
zackery.fix,

11

Abbiamo dovuto determinare se C # era paragonabile a C ++ nelle prestazioni e ho scritto alcuni programmi di test per questo (usando Visual Studio 2005 per entrambi i linguaggi). Si è scoperto che senza garbage collection e considerando solo il linguaggio (non il framework) C # ha sostanzialmente le stesse prestazioni del C ++. L'allocazione della memoria è molto più veloce in C # che in C ++ e C # ha un leggero vantaggio nel determinismo quando le dimensioni dei dati vengono aumentate oltre i limiti delle linee della cache. Tuttavia, tutto ciò alla fine ha dovuto essere pagato e c'è un costo enorme sotto forma di hit di prestazioni non deterministiche per C # a causa della garbage collection.


1
In C ++, hai la possibilità di utilizzare diversi metodi di allocazione, quindi a seconda di come è stata allocata la memoria (AOT?) In C #, potrebbe essere fatta allo stesso modo (ma molto più veloce) in C ++.
zackery.fix,

5
@ zackery.fix .NET ha un vantaggio interessante nell'allocazione dell'heap, perché deve solo spostare un puntatore per allocare un nuovo oggetto. Ciò è possibile solo grazie al contenitore di raccolta rifiuti compatto. Ovviamente puoi fare la stessa cosa in C ++, ma C ++ non lo fa. È divertente come usi lo stesso argomento per dire "C # potrebbe ma non lo fa, quindi è spazzatura" e "C ++ no, ma potrebbe, quindi è fantastico" :)
Luaan,

9

Come al solito, dipende dall'applicazione. Ci sono casi in cui C # è probabilmente trascurabilmente più lento, e altri casi in cui C ++ è 5 o 10 volte più veloce, specialmente nei casi in cui le operazioni possono essere facilmente SIMD.


Il caso migliore per le macchine virtuali sarà la compilazione in fase di esecuzione del codice generato (ad es. Per abbinare un'espressione regolare letta in fase di esecuzione) perché i programmi C ++ vanilla compilati staticamente possono usare l'interpretazione solo perché non hanno un compilatore JIT incorporato.
Jon Harrop

Nota per il futuro: .NET supporta SIMD e amici dal 2014, sebbene non sia ampiamente utilizzato.
Luaan,

9

So che non è quello che stavi chiedendo, ma C # è spesso più veloce da scrivere rispetto a C ++, che è un grande vantaggio in un contesto commerciale.


2
Direi che è più veloce il più delle volte :)
Trap il

8

C / C ++ può funzionare molto meglio nei programmi in cui vi sono o array di grandi dimensioni o loop / iterazioni pesanti su array (di qualsiasi dimensione). Questo è il motivo per cui la grafica è generalmente molto più veloce in C / C ++, poiché le operazioni di array pesanti sono alla base di quasi tutte le operazioni di grafica. .NET è notoriamente lento nelle operazioni di indicizzazione degli array a causa di tutti i controlli di sicurezza, e questo è particolarmente vero per gli array multidimensionali (e, sì, gli array C # rettangolari sono persino più lenti degli array C # frastagliati).

I bonus di C / C ++ sono più pronunciati se si attacca direttamente con i puntatori ed evita Boost std::vectore altri contenitori di alto livello, nonché inlineogni piccola funzione possibile. Utilizzare array di vecchia scuola ogni volta che è possibile. Sì, avrai bisogno di più righe di codice per realizzare la stessa cosa che hai fatto in Java o C # evitando i container di alto livello. Se hai bisogno di un array di dimensioni dinamiche, dovrai solo ricordare di accoppiare il tuo new T[]con un corrispondentedelete[] un'istruzione (o usarestd::unique_ptr): Il prezzo per la velocità extra è che devi codificare più attentamente. Ma in cambio, ti sbarazzerai del sovraccarico di memoria gestita / garbage collector, che può facilmente essere il 20% o più del tempo di esecuzione di programmi fortemente orientati agli oggetti in Java e .NET, nonché di quelli gestiti in modo massiccio costi di indicizzazione dell'array di memoria. Le app C ++ possono anche beneficiare di alcuni switch di compilazione eleganti in alcuni casi specifici.

Sono un programmatore esperto in C, C ++, Java e C #. Di recente ho avuto la rara occasione di implementare esattamente lo stesso programma algoritmico nelle ultime 3 lingue. Il programma aveva molte operazioni matematiche e di array multidimensionali. Ho fortemente ottimizzato questo in tutte e 3 le lingue. I risultati erano tipici di ciò che normalmente vedo in confronti meno rigorosi: Java era circa 1,3 volte più veloce di C # (la maggior parte delle JVM sono più ottimizzate rispetto al CLR) e la versione del puntatore raw C ++ era di circa 2,1 volte più veloce di C #. Nota che il programma C # utilizzava solo un codice sicuro: è mia opinione che potresti anche codificarlo in C ++ prima di usare la unsafeparola chiave.

Per timore che qualcuno pensi di avere qualcosa contro C #, chiuderò dicendo che C # è probabilmente la mia lingua preferita. È il linguaggio di sviluppo più logico, intuitivo e rapido che abbia mai incontrato finora. Faccio tutta la mia prototipazione in C #. Il linguaggio C # ha molti piccoli e sottili vantaggi rispetto a Java (sì, so che Microsoft ha avuto la possibilità di correggere molte delle carenze di Java entrando nel gioco in ritardo e probabilmente copiando Java). Brindare alla Calendarclasse di Java qualcuno? Se Microsoft dovesse mai spendere molto per ottimizzare CLR e .NET JITter, C # potrebbe prendere seriamente il controllo. Sono sinceramente sorpreso che non lo abbiano già fatto: hanno fatto così tante cose nel linguaggio C #, perché non seguirlo con ottimizzazioni del compilatore di grande impatto? Forse se tutti preghiamo.


3
"dovrai solo ricordarti di accoppiare il tuo new T[]con un corrispondente delete[]" - No, non lo fai. C'è std::unique_ptrda fare per te.
emlai

supponendo di aver scritto qualcosa in grafica perché scrivere un codice sicuro in c #, hai preso in considerazione l'idea di utilizzare un codice non sicuro e confrontarlo di nuovo?
user3800527,

7

> Da quello che ho sentito ...

La tua difficoltà sembra essere nel decidere se ciò che hai ascoltato sia credibile e tale difficoltà si ripeterà solo quando proverai a valutare le risposte su questo sito.

Come deciderai se le cose che la gente dice qui sono più o meno credibili di quanto hai sentito in origine?

Un modo sarebbe chiedere prove .

Quando qualcuno afferma "ci sono alcune aree in cui C # si rivela più veloce di C ++" chiedi loro perché lo dicono , chiedi loro di mostrarti le misure, chiedi loro di mostrarti i programmi. A volte avranno semplicemente fatto un errore. A volte scoprirai che stanno solo esprimendo un'opinione piuttosto che condividere qualcosa che possono mostrare come veri.

Spesso le informazioni e l'opinione saranno confuse in ciò che la gente afferma e dovrai cercare di capire quale è quale. Ad esempio, dalle risposte in questo forum:

  • "Prendi i parametri di riferimento su http://shootout.alioth.debian.org/ con grande scetticismo, poiché questi test ampiamente testano il codice aritmetico, che molto probabilmente non è affatto simile al tuo codice."

    Chiediti se capisci veramente cosa significa "questi codici aritmetici in gran parte testati" , e poi chiediti se l'autore ti ha effettivamente mostrato che la sua affermazione è vera.

  • "Questo è un test piuttosto inutile, dal momento che dipende davvero da quanto bene i singoli programmi sono stati ottimizzati; sono riuscito a velocizzarne alcuni di 4-6 volte o più, chiarendo che il confronto tra programmi non ottimizzati è piuttosto sciocco."

    Chiediti se l'autore ti ha effettivamente mostrato che è riuscito a "accelerarne alcuni di 4-6 volte o più" - è una richiesta facile da fare!


Non potrei essere più d'accordo con te ed è per questo che l'ho chiesto in questo forum ... Dopo tutto, le risposte devono essere da qualche parte, no? :)
Trap il

1
Sì. La risposta è, dipende.".
user49117

6

Per problemi 'imbarazzantemente paralleli', usando Intel TBB e OpenMP su C ++ ho osservato un aumento delle prestazioni di circa 10 volte rispetto a problemi simili (matematica pura) fatti con C # e TPL. SIMD è un'area in cui C # non può competere, ma ho anche avuto l'impressione che TPL abbia un notevole sovraccarico.

Detto questo, utilizzo C ++ solo per attività critiche in termini di prestazioni in cui so che sarò in grado di eseguire il multithread e ottenere risultati rapidamente. Per tutto il resto, C # (e occasionalmente F #) va bene.


5

È una domanda estremamente vaga senza vere risposte definitive.

Per esempio; Preferirei giocare a giochi 3D creati in C ++ piuttosto che in C #, perché le prestazioni sono sicuramente molto migliori. (E conosco XNA, ecc., Ma non si avvicina affatto alla cosa reale).

D'altra parte, come precedentemente menzionato; dovresti sviluppare in un linguaggio che ti consenta di fare ciò che desideri rapidamente e, se necessario, ottimizzare.


4
Potresti citare alcuni esempi? Giochi scritti in C # quello che hai trovato lento
Karl,

1
Anche le applicazioni di esempio fornite con l'installazione sembravano lente.
David The Man,

9
Il garbage collector è una grande responsabilità nel fare giochi con C #, in quanto può calciare in qualsiasi momento, causando pause importanti. La gestione esplicita della memoria diventa più semplice per lo sviluppo del gioco.
postfuturista il

3
La maggior parte dei giochi moderni sono limitati dalla GPU. Per tali giochi non importa se la logica (eseguita su CPU) è più lenta del 10%, sono ancora limitate dalla GPU, non dalla CPU. Il Garbage Collector è un vero problema e causa brevi blocchi casuali se le allocazioni di memoria non sono ottimizzate.
Michael Entin,

2
@postfuturist: Questo non è vero su PC; il garbage collector fa un ottimo lavoro per entrare e uscire, non ho mai avuto problemi con esso. Tuttavia, su Xbox 360 e Zune / Windows-7-Phone, il garbage collector non è quasi intelligente come su PC; Non ho mai scritto neanche per me , ma le persone che mi hanno detto che il garbage collector è un grosso problema.
BlueRaja - Danny Pflughoeft,

5

I linguaggi .NET possono essere veloci come il codice C ++ o anche più veloci, ma il codice C ++ avrà un throughput più costante poiché il runtime .NET deve mettere in pausa per GC , anche se è molto intelligente sulle sue pause.

Quindi, se si dispone di un codice che deve essere eseguito in modo coerente e veloce senza alcuna pausa, .NET introdurrà la latenza a un certo punto , anche se si è molto attenti con il GC di runtime.


6
-1: questo è in realtà un mito. In primo luogo, la latenza del C ++ idiomatico è in realtà terribile e spesso molto peggio di .NET perché RAII provoca valanghe di distruttori quando le grandi strutture di dati non rientrano nell'ambito mentre i moderni GC sono incrementali e .NET è persino concorrente. In secondo luogo, puoi effettivamente rimuovere completamente le pause GC su .NET non allocando.
Jon Harrop,

2
In tal caso, è necessario rinunciare a utilizzare BCL poiché la maggior parte dei metodi crea oggetti transitori.
Florian Doyon,

5
Questo è abbastanza vero, non è stato fino a .net 4 che il GC è stato reso incrementale. Abbiamo una grande app C # che si interrompe per secondi alla volta per GC. Per le app critiche per le prestazioni questo è un killer.
Giustino,

5
C'è un motivo per cui i programmi che tendono a spingere l'hardware tendono a usare il C ++. Hai un controllo più preciso quando ne hai bisogno. Le prestazioni sono fondamentali solo quando si spinge il sistema, altrimenti utilizzare C # o Java per risparmiare tempo.
VoronoiPotato,

4
se non riesci a gestire il comportamento della cache, non puoi battere il codice c ++ ottimizzato. Una mancata cache da L1 alla memoria principale potrebbe rallentare l'operazione 100 volte.
DAG,

4

In teoria, per un'applicazione di tipo server di lunga durata, un linguaggio compilato JIT può diventare molto più veloce di una controparte compilata nativamente. Poiché il linguaggio compilato JIT viene generalmente compilato per la prima volta in un linguaggio intermedio di livello piuttosto basso, è comunque possibile eseguire molte ottimizzazioni di alto livello in fase di compilazione. Il grande vantaggio deriva dal fatto che JIT può continuare a ricompilare sezioni di codice al volo man mano che ottiene sempre più dati su come viene utilizzata l'applicazione. Può organizzare i percorsi di codice più comuni per consentire il successo della previsione delle filiali il più spesso possibile. Può riorganizzare blocchi di codice separati che vengono spesso chiamati insieme per tenerli entrambi nella cache. Può spendere più sforzi per ottimizzare i circuiti interni.

Dubito che ciò sia stato fatto da .NET o da qualsiasi JRE, ma era in fase di ricerca quando ero all'università, quindi non è irragionevole pensare che questo tipo di cose possano trovare la loro strada nel mondo reale ad un certo punto presto .


4

Applicazioni che richiedono un accesso intensivo alla memoria, ad es. la manipolazione delle immagini è in genere meglio scritta in ambiente non gestito (C ++) che gestita (C #). I loop interni ottimizzati con aritmetica del puntatore sono molto più facili da controllare in C ++. In C # potresti dover ricorrere a codice non sicuro per avvicinarti alle stesse prestazioni.


4

Ho testato vectorin C ++ e C # equivalenti Liste semplici array 2d.

Sto usando le versioni Visual C # / C ++ 2010 Express. Entrambi i progetti sono semplici applicazioni console, le ho testate in versione standard (senza impostazioni personalizzate) e modalità debug. Gli elenchi C # funzionano più velocemente sul mio PC, l'inizializzazione dell'array è anche più veloce in C #, le operazioni matematiche sono più lente.

Sto usando Intel Core2Duo P8600@2.4GHz, C # - .NET 4.0.

So che l'implementazione vettoriale è diversa dall'elenco C #, ma volevo solo testare le raccolte che avrei usato per archiviare i miei oggetti (e poter usare il programma di accesso all'indice).

Ovviamente è necessario cancellare la memoria (diciamo per ogni uso di new), ma volevo mantenere il codice semplice.

Test vettoriale C ++ :

static void TestVector()
{
    clock_t start,finish;
    start=clock();
    vector<vector<double>> myList=vector<vector<double>>();
    int i=0;
    for( i=0; i<500; i++)
    {
        myList.push_back(vector<double>());
        for(int j=0;j<50000;j++)
            myList[i].push_back(j+i);
    }
    finish=clock();
    cout<<(finish-start)<<endl;
    cout<<(double(finish - start)/CLOCKS_PER_SEC);
}

Test elenco C #:

private static void TestVector()
{

    DateTime t1 = System.DateTime.Now;
    List<List<double>> myList = new List<List<double>>();
    int i = 0;
    for (i = 0; i < 500; i++)
    {
        myList.Add(new List<double>());
        for (int j = 0; j < 50000; j++)
            myList[i].Add(j *i);
    }
    DateTime t2 = System.DateTime.Now;
    Console.WriteLine(t2 - t1);
}

C ++ - array:

static void TestArray()
{
    cout << "Normal array test:" << endl;
    const int rows = 5000;
    const int columns = 9000;
    clock_t start, finish;

    start = clock();
    double** arr = new double*[rows];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    finish = clock();

    cout << (finish - start) << endl;

    start = clock();
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    finish = clock();

    cout << (finish - start) << endl;
}

C # - array:

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

}

Time: (Release / Debug)

C ++

  • 600/606 ms array array,
  • 200/270 ms riempimento array,
  • 1sec / 13sec vector init & fill.

(Sì, 13 secondi, ho sempre problemi con elenchi / vettori in modalità debug.)

C #:

  • 20/20 ms array array,
  • 403/440 ms riempimento array,
  • 710/742 ms elenco inizio e riempimento.

1
Mi piacerebbe vedere il programma di accesso all'indice nella lista std ::. Ad ogni modo, ci vogliono 37 secondi con la lista, la modalità di rilascio. Rilascio senza debug: elenco 3s, vettore 0,3 s. Probabilmente problema di dereferenziazione o sth. Campione: nopaste.pl/12fb
Wiory il

2
Per misurazioni più precise non dovresti usare System.DateTime.Now, ma piuttosto la classe Cronometro .
Sam,

4
Parte del motivo per cui stai ottenendo tempi di riempimento così lenti per il vettore in C ++ è che stai usando push_back. Ciò è stato dimostrato su numerosi post più lento rispetto all'uso del metodo at o dell'operatore []. Per utilizzare uno di questi metodi è necessario utilizzare il metodo di ridimensionamento o di riserva. Inoltre, il motivo per cui l'inizializzazione impiega così tanto tempo per il caso c ++ vector è che stai forzando un operatore di copia o assegnazione (non sono sicuro di quale in questo caso) inizializzi il tuo vettore c ++. Per l'array in c ++ esiste un algoritmo che utilizza 2 nuove chiamate anziché 5001 ed è anche iterante più veloce.
Zachary Kraus,

5
Penso che non hai fatto c ++ in modo appropriato. Solo uno sguardo e ho trovato così tanti problemi. Ad esempio vector <vector <double>> myList = vector <vector <double>> ()
DAG

2
Wow. Non sono sicuro di quali conclusioni si possano trarre dal confronto tra Elenchi e array ridimensionabili, ma se si utilizzano vettori come questo, è necessario conoscere di riserva (), amico mio, di riserva ().
U007D,

3

Beh, dipende. Se il codice byte viene tradotto in codice macchina (e non solo JIT) (intendo se esegui il programma) e se il tuo programma utilizza molte allocazioni / deallocazioni, potrebbe essere più veloce perché l' algoritmo GC necessita solo di un passaggio (teoricamente) attraverso l'intera memoria una volta, ma le normali chiamate malloc / realloc / free C / C ++ causano un overhead su ogni chiamata (overhead di chiamata, overhead della struttura dei dati, mancate cache;)).

Quindi è teoricamente possibile (anche per altri linguaggi GC).

Non vedo davvero l'estremo svantaggio di non poter usare la metaprogrammazione con C # per la maggior parte delle applicazioni, perché la maggior parte dei programmatori non la usa comunque.

Un altro grande vantaggio è che SQL, come l ' "estensione" LINQ , offre al compilatore l'opportunità di ottimizzare le chiamate ai database (in altre parole, il compilatore potrebbe compilare l'intero LINQ in un binario "BLOB" in cui le funzioni chiamate sono incorporate o per il tuo uso ottimizzato, ma sto speculando qui).


1
Qualsiasi sviluppatore C ++ appropriato non si imbatterà nei problemi descritti. Solo i cattivi programmatori C che hanno deciso di schiaffeggiare le classi sui loro programmi e chiamarlo C ++ hanno questi problemi.
Più chiaro

1
per amore degli dei, 8 anni, OMFGz
Quonux,

sentiti libero di dare una risposta migliore e più aggiornata
Quonux

2

Suppongo che ci siano applicazioni scritte in C # in esecuzione veloce, così come ci sono più app scritte in C ++ in esecuzione veloce (bene C ++ solo più vecchio ... e prendere anche UNIX ...)
- la domanda è davvero - che cos'è quella cosa, gli utenti e gli sviluppatori si lamentano ...
Beh, IMHO, in caso di C # abbiamo un'interfaccia utente molto comoda, una bella gerarchia di librerie e l'intero sistema di interfaccia della CLI. Nel caso di C ++ abbiamo modelli, ATL, COM, MFC e un'intera serie di codici scritti ed in esecuzione alreadyc come OpenGL, DirectX e così via ... Gli sviluppatori si lamentano di chiamate GC indeterminatamente aumentate in caso di C # (significa che il programma funziona veloce e in un secondo - botto! è bloccato).
Scrivere codice in C # molto semplice e veloce (per non dimenticare che aumenta anche la possibilità di errori. In caso di C ++, gli sviluppatori si lamentano di perdite di memoria, - significa schiacciamenti, chiamate tra DLL, nonché di "DLL hell" - problema con librerie di supporto e sostituzione con nuove ...
Penso che più abilità avrai nel linguaggio di programmazione, più qualità (e velocità) caratterizzeranno il tuo software.


2

La metterei così: i programmatori che scrivono codice più veloce, sono quelli che sono i più informati su ciò che rende veloci le macchine attuali, e per inciso sono anche quelli che usano uno strumento appropriato che consente un preciso livello basso e deterministico tecniche di ottimizzazione. Per questi motivi, queste persone sono quelle che usano C / C ++ anziché C #. Andrei fino a dichiarare questo come un dato di fatto.


Notch ha codificato Minecraft per essere abbastanza veloce considerando la quantità di dati che sta manipolando. Inoltre, lo ha codificato per lo più da solo in un tempo relativamente breve, qualcosa che sarebbe stato praticamente impossibile in C ++. Sono comunque d'accordo con le tecniche di ottimizzazione: se hai il tempo di sviluppo aggiuntivo di 10x da spendere, quindi il tuo codice viene eseguito due volte più velocemente, probabilmente ne vale la pena.
Bill K

2

Se non sbaglio, i modelli C # sono determinati in fase di esecuzione. Questo deve essere più lento dei modelli di compilazione di C ++.

E quando prendi in considerazione tutte le altre ottimizzazioni in fase di compilazione menzionate da così tanti altri, così come la mancanza di sicurezza che, in effetti, significa più velocità ...

Direi che C ++ è la scelta ovvia in termini di velocità raw e consumo minimo di memoria. Ma ciò si traduce anche in più tempo nello sviluppo del codice e nell'assicurarsi che non si stia perdendo memoria o causando eccezioni al puntatore null.

Verdetto:

  • C #: sviluppo più veloce, corsa più lenta

  • C ++: sviluppo lento, corsa più veloce.


1

Dipende davvero da cosa stai cercando di realizzare nel tuo codice. Ho sentito che è solo una questione di leggenda urbana che ci sia qualche differenza di prestazioni tra VB.NET, C # e C ++ gestito. Tuttavia, ho scoperto, almeno nei confronti di stringhe, che il C ++ gestito batte i pantaloni di C #, che a sua volta batte i pantaloni di VB.NET.

Non ho mai fatto alcun confronto esaustivo nella complessità algoritmica tra le lingue. Sto anche solo usando le impostazioni predefinite in ciascuna delle lingue. In VB.NET sto usando le impostazioni per richiedere la dichiarazione di variabili, ecc. Ecco il codice che sto usando per C ++ gestito: (Come puoi vedere, questo codice è abbastanza semplice). Sto eseguendo lo stesso nelle altre lingue in Visual Studio 2013 con .NET 4.6.2.

#include "stdafx.h"

using namespace System;
using namespace System::Diagnostics;

bool EqualMe(String^ first, String^ second)
{
    return first->Equals(second);
}
int main(array<String ^> ^args)
{
    Stopwatch^ sw = gcnew Stopwatch();
    sw->Start();
    for (int i = 0; i < 100000; i++)
    {
        EqualMe(L"one", L"two");
    }
    sw->Stop();
    Console::WriteLine(sw->ElapsedTicks);
    return 0;
}

1

Ci sono alcune differenze importanti tra C # e C ++ sull'aspetto delle prestazioni:

  • C # è basato su GC / heap. L'allocazione e lo stesso GC sono spese generali come non località dell'accesso alla memoria
  • Gli ottimizzatori C ++ sono diventati molto buoni nel corso degli anni. I compilatori JIT non possono raggiungere lo stesso livello poiché hanno solo un tempo di compilazione limitato e non vedono l'ambito globale

Oltre a ciò la competenza del programmatore gioca anche un ruolo. Ho visto un cattivo codice C ++ in cui le classi venivano passate per valore come argomento dappertutto. Puoi effettivamente peggiorare le prestazioni in C ++ se non sai cosa stai facendo.


0

> Dopo tutto, le risposte devono essere da qualche parte, no? :)

Umm, no.

Come indicato da diverse risposte, la domanda è sotto-specificata in modi che invitano domande in risposta, non risposte. Per prendere solo un modo:

E poi quali programmi? Quale macchina? Quale sistema operativo? Quale set di dati?


Sono completamente d'accordo. Mi chiedo perché le persone si aspettino una risposta precisa (63,5%), quando fanno una domanda generale. Non credo che non ci sia una risposta generale a questo tipo di domanda.
Chiamami Steve

@callmesteve: so cosa intendi, ma la tua ultima frase dovrebbe sembrare un chiodo su una lavagna per qualsiasi programmatore.
Wouter van Nifterick,

1
Questo non sembra rispondere alla domanda e legge di più come commento o rant.
Tas,

-13

Ispirato da questo, ho fatto un rapido test con il 60 percento delle istruzioni comuni necessarie nella maggior parte dei programmi.

Ecco il codice C #:

for (int i=0; i<1000; i++)
{
    StreamReader str = new StreamReader("file.csv");
    StreamWriter stw = new StreamWriter("examp.csv");
    string strL = "";
    while((strL = str.ReadLine()) != null)
    {
        ArrayList al = new ArrayList();
        string[] strline = strL.Split(',');
        al.AddRange(strline);
        foreach(string str1 in strline)
        {
            stw.Write(str1 + ",");
        }
        stw.Write("\n");
    }
    str.Close();
    stw.Close();
}

L'array di stringhe e l'arraylist sono usati di proposito per includere quelle istruzioni.

Ecco il codice c ++:

for (int i = 0; i<1000; i++)
{
    std::fstream file("file.csv", ios::in);
    if (!file.is_open())
    {
        std::cout << "File not found!\n";
        return 1;
    }

    ofstream myfile;
    myfile.open ("example.txt");
    std::string csvLine;

    while (std::getline(file, csvLine))
    {
        std::istringstream csvStream(csvLine);
        std::vector csvColumn;
        std::string csvElement;

        while( std::getline(csvStream, csvElement, ‘,’) )
        {
            csvColumn.push_back(csvElement);
        }

        for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
        {
            myfile << *j << ", ";
        }

        csvColumn.clear();
        csvElement.clear();
        csvLine.clear();
        myfile << "\n";
    }
    myfile.close();
    file.close();
}

La dimensione del file di input che ho usato era 40 KB.

Ed ecco il risultato -

  • Il codice C ++ è stato eseguito in 9 secondi.
  • Codice C #: 4 secondi !!!

Oh, ma questo era su Linux ... Con C # in esecuzione su Mono ... E C ++ con g ++.

OK, questo è quello che ho ottenuto su Windows - Visual Studio 2003 :

  • Il codice C # è stato eseguito in 9 secondi.
  • Codice C ++ - orribili 370 secondi !!!

7
Stai usando diverse strutture di dati e codice di libreria lì, anche se "370 secondi" indica qualcosa di orribile - non lo stai eseguendo nel debugger per caso, vero? Sospetto che le prestazioni della libreria CSV che stai utilizzando siano più interessanti delle prestazioni della lingua che stai utilizzando. Metterei in dubbio l'uso di un vettore in quel contesto e quali ottimizzazioni hai usato. Inoltre, è risaputo che gli iostreams (in particolare "myfile << * j <<", ";") sono molto più lenti di altri metodi di scrittura nel file, almeno per alcune implementazioni comuni.
Arafangion,

6
Infine, stai facendo più lavoro nella versione C ++. (Perché stai cancellando csvColumn, csvElement e csvLines?)
Arafangion,

2
Ogni iterazione del ciclo while distruggerà e ricostruirà uno std :: istream e uno std :: vector e uno std :: string. Il corpo while esce dall'ambito di ogni iterazione, tutte quelle variabili all'interno dell'ambito while verranno distrutte e costruite su ogni iterazione.
doug65536,

1
dall'aspetto della lettura del codice c ++ che si sta tentando di copiare da un file a un altro file. Invece di utilizzare le complesse interazioni tra flussi di file, stringhe, vettori e flussi di stringhe, avresti potuto semplicemente copiare il flusso del file di input nel flusso del file di output. Ciò avrebbe risparmiato molto tempo e memoria.
Zachary Kraus,

2
per eseguire test di velocità, testare le cose nella memoria non arrivare al disco IO, a meno che i test sugli ultimi SSD e siano dedicati alla tua app per le prestazioni. Poiché i computer scrivono costantemente su disco, anche se non si tocca la tastiera.
user3800527,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.