In che modo Swift può essere molto più veloce di Objective-C in questi confronti?


115

Apple ha lanciato il suo nuovo linguaggio di programmazione Swift al WWDC14 . Nella presentazione, hanno effettuato alcuni confronti delle prestazioni tra Objective-C e Python. La seguente è una foto di una delle loro diapositive, di un confronto di quelle tre lingue che eseguono un ordinamento di oggetti complessi:

inserisci qui la descrizione dell'immagine

C'era un grafico ancora più incredibile su un confronto delle prestazioni usando l' algoritmo di crittografia RC4 .

Ovviamente questo è un discorso di marketing, e non sono entrati nei dettagli su come questo è stato implementato in ciascuno. Mi lascio chiedermi però:

  1. Come può un nuovo linguaggio di programmazione essere molto più veloce?
  2. I risultati di Objective-C sono causati da un cattivo compilatore o c'è qualcosa di meno efficiente in Objective-C di Swift?
  3. Come spiegheresti un aumento delle prestazioni del 40%? Capisco che la garbage collection / controllo di riferimento automatizzato potrebbe produrre un sovraccarico aggiuntivo, ma così tanto?

13
@MathewFoscarini Obj-C va all'assemblatore, ma ha un costoso meccanismo di invio dei messaggi oggetto. Per la maggior parte del lavoro con la GUI non importa, ma per l'ordinamento è molto importante.
Donal Fellows,

17
Il confronto con Python è il vero grattacapo qui.
asthasr,

9
@syrion marketing, e il linguaggio sembra prendere in prestito dalla sintassi di Python (proprio come il Golang). Stanno cercando di dire "ehi, sviluppatori di Python, puoi scrivere qualcosa di non troppo estraneo sul Mac e farlo essere molto più veloce, persino più veloce dell'Obiettivo C di cui non hai mai

4
@MichaelT Lo capisco, ma è ancora strano. Chiunque sappia qualcosa sui linguaggi capirà che Python, come linguaggio interpretato, semplicemente non si troverà nello stesso campo di gioco di Objective-C o di altri linguaggi compilati (per la maggior parte delle attività). Usarlo come punto di riferimento è strano.
asthasr,

7
Probabilmente significano il tempo necessario per scrivere il codice ...
Lukas Eder

Risposte:


62

Innanzitutto, (IMO) il confronto con Python è quasi privo di significato. È significativo solo il confronto con Objective-C.

  • Come può un nuovo linguaggio di programmazione essere molto più veloce?

Objective-C è un linguaggio lento. (Solo la parte C è veloce, ma è perché è C) Non è mai stato estremamente veloce. Era abbastanza veloce per il loro scopo (di Apple) e più veloce delle loro versioni precedenti. Ed è stato lento perché ...

  • Objective-C risulta da un cattivo compilatore o c'è qualcosa di meno efficiente in Objective-C di Swift?

Objective-C ha garantito la spedizione dinamica di ogni metodo. Nessuna spedizione statica. Ciò ha reso impossibile ottimizzare ulteriormente un programma Objective-C. Bene, forse la tecnologia JIT può essere di aiuto, ma AFAIK, Apple odia davvero le prestazioni imprevedibili e la durata degli oggetti. Non credo che avessero adottato alcun materiale JIT. Swift non ha una tale garanzia di spedizione dinamica a meno che non si inserisca un attributo speciale per la compatibilità Objective-C.

  • Come spiegheresti un aumento delle prestazioni del 40%? Capisco che la garbage collection / controllo di riferimento automatizzato potrebbe produrre un sovraccarico aggiuntivo, ma così tanto?

GC o RC non contano qui. Swift impiega anche RC principalmente. Non c'è GC, e non lo farà a meno che non ci sia un enorme balzo architettonico sulla tecnologia GC. (IMO, è per sempre) Credo che Swift abbia molto più spazio per l'ottimizzazione statica. Algoritmi di crittografia di livello particolarmente basso, poiché di solito si basano su enormi calcoli numerici, e questa è una grande vittoria per i linguaggi di invio statico.

In realtà sono rimasto sorpreso perché il 40% sembra troppo piccolo. Mi aspettavo molto di più. Ad ogni modo, questa è la versione iniziale e penso che l'ottimizzazione non sia stata la preoccupazione principale. Swift non è nemmeno completo di funzionalità! Lo renderanno migliore.

Aggiornare

Alcuni continuano a infastidirmi per sostenere che la tecnologia GC è superiore. Sebbene le cose di seguito possano essere discutibili, e solo la mia opinione molto parziale, ma penso di dover dire per evitare questa discussione non necessaria.

So cosa sono i GC conservativi / di tracciamento / generazionali / incrementali / paralleli / in tempo reale e come sono diversi. Penso che anche la maggior parte dei lettori lo sappia già. Concordo anche sul fatto che GC sia molto bello in alcuni campi e in alcuni casi mostri un rendimento elevato.

Comunque, sospetto che l'affermazione del throughput GC sia sempre migliore di RC. La maggior parte del sovraccarico di RC proviene dall'operazione di conteggio dei ref e dal blocco per proteggere la variabile del numero di ref-count. E l'implementazione RC di solito fornisce un modo per evitare le operazioni di conteggio. In Objective-C, ci sono __unsafe_unretainede in Swift (anche se per me non è ancora chiaro) cose unowned. Se il costo dell'operazione di conteggio dei ref non è accettabile, puoi provare a disattivarli in modo selettivo utilizzando la meccanica. Teoricamente, possiamo simulare uno scenario di proprietà quasi unica usando i riferimenti non ritenuti in modo molto aggressivo per evitare spese generali di RC. Inoltre mi aspetto che il compilatore possa eliminare automaticamente alcune ovvie operazioni RC inutili.

A differenza del sistema RC, AFAIK, la rinuncia parziale ai tipi di riferimento non è un'opzione sul sistema GC.

So che ci sono molti giochi e grafica rilasciati che utilizzano un sistema basato su GC, e so anche che molti di loro soffrono per la mancanza di determinismo. Non solo per le caratteristiche prestazionali, ma anche per la gestione della durata degli oggetti. Unity è per lo più scritto in C ++, ma la minuscola parte in C # causa tutti gli strani problemi di prestazioni. App ibride HTML e ancora affette da picchi imprevedibili su qualsiasi sistema. Usato ampiamente non significa che sia superiore. Significa solo che è facile e popolare per le persone che non hanno molte opzioni.

Aggiornamento 2

Ancora una volta per evitare discussioni o discussioni inutili, aggiungo alcuni dettagli.

@Asik ha fornito un'opinione interessante sui picchi GC. Ecco perché possiamo considerare l' approccio del tipo di valore ovunque come un modo per rinunciare a cose GC. Questo è piuttosto attraente e persino realizzabile su alcuni sistemi (ad esempio un approccio puramente funzionale). Sono d'accordo che questo è bello in teoria. Ma in pratica ha diversi problemi. Il problema più grande è che l'applicazione parziale di questo trucco non fornisce vere caratteristiche senza picchi.

Perché il problema di latenza è sempre tutto o niente problema. Se hai un picco di frame per 10 secondi (= 600 frame), allora l'intero sistema sta ovviamente fallendo. Non si tratta di quanto meglio o peggio. È solo passare o fallire. (o meno dello 0,0001%) Allora dov'è la fonte del picco GC? Questa è una cattiva distribuzione del carico GC. E questo perché il GC è fondamentalmente indeterministico. Se fai spazzatura, allora attiverà il GC e alla fine si verificherà un picco. Naturalmente, nel mondo ideale in cui il carico GC sarà sempre l'ideale, questo non accadrà, ma vivo nel mondo reale piuttosto che nel mondo ideale immaginario.

Quindi, se si desidera evitare picchi, è necessario rimuovere tutti i ref-type dall'intero sistema. Ma è difficile, folle e persino impossibile a causa di parti inamovibili come il sistema centrale .NET e la libreria. L'uso del sistema non GC è molto più semplice .

A differenza di GC, RC è fondamentalmente deterministico e non è necessario utilizzare questa folle ottimizzazione (solo di tipo puramente di valore) solo per evitare picchi. Quello che devi fare è rintracciare e ottimizzare la parte che causa il picco. Nei sistemi RC, lo spike è un problema di algoritmo locale, ma nei sistemi GC, gli spike sono sempre un problema di sistema globale.

Penso che la mia risposta sia andata troppo fuori tema, e soprattutto solo ripetizione di discussioni esistenti. Se vuoi davvero rivendicare un po 'di superiorità / inferiorità / alternativa o qualcos'altro di materiale GC / RC, ci sono molte discussioni esistenti in questo sito e StackOverflow, e puoi continuare a combattere lì.


4
La raccolta dei rifiuti, in particolare di tipo generazionale, è in genere significativamente più veloce del conteggio dei riferimenti.
Jan Hudec,

9
@JanHudec Il tuo significativamente più veloce è semplicemente insignificante nel campo grafico in tempo reale. Questo è il motivo per cui menziono un grande balzo è richiesto su GC. Generational GC non è nemmeno vicino per essere privo di picchi sia in teoria che in pratica.
Eonil,

5
Più veloci e senza picchi sono categorie completamente ortogonali. I raccoglitori di rifiuti generazionali sono più veloci . Non sono senza picchi.
Jan Hudec,

4
Quello di cui stai parlando è il throughput . Più veloce è sempre stato un termine vago e può significare qualsiasi cosa dal contesto. Se vuoi discutere del significato dei termini, dovresti usare termini più precisi piuttosto che più veloci, specialmente considerando il contesto attuale - la grafica in tempo reale.
Eonil,

11
@JanHudec: Sui dispositivi mobili o su qualsiasi dispositivo con risorse limitate, GC non è significativamente più veloce e in effetti è una parte importante del problema.
Mason Wheeler,

72

Essendo 3,9 volte più veloce di Python, il linguaggio che perde costantemente la maggior parte dei parametri di riferimento con un margine considerevole (ok, è alla pari con Perl, Ruby e PHP; ma perde a tutto ciò che è tipicamente statico), non c'è nulla di cui vantarsi.

Il gioco dei benchmark mostra programmi C ++ che sono più che dell'ordine di grandezza più veloci dei programmi Python nella maggior parte dei casi. Non è molto meglio se paragonato a Java, C # (su Mono), OCaml, Haskell e persino Clojure, che non è tipizzato staticamente.

Quindi la vera domanda è come è Objective-C solo 2,8 volte più veloce di Python. Apparentemente hanno scelto con cura il benchmark in cui la spedizione lenta e completamente dinamica di ObjC fa molto male. Qualsiasi linguaggio tipizzato staticamente dovrebbe essere in grado di fare meglio. Nell'ordinamento di oggetti complessi ci sono molte chiamate di metodo per confrontare gli oggetti e il confronto reale probabilmente non era molto complesso. Quindi, se Swift sfrutta almeno un po 'delle informazioni sul tipo, può facilmente fare meglio sulle chiamate del metodo e non ci sono abbastanza altre operazioni in cui ObjC potrebbe essere migliore.

Ovviamente, come dimostra chiaramente il gioco dei benchmark , le prestazioni relative a compiti diversi variano in modo selvaggio, quindi un benchmark non è realmente rappresentativo. Se avessero un benchmark in cui aveva un vantaggio maggiore, ci avrebbero mostrato quello, quindi su altri compiti probabilmente non è migliore o non così tanto.


13
Non capisco bene il punto di questa risposta. Stai rispondendo "com'è veloce più veloce" dicendo "i parametri sono difettosi"? È questo il punto che stai facendo? Non vedo come questo risponda a ciò che è stato chiesto.
Bryan Oakley,

15
@BryanOakley: non credo che i parametri di riferimento siano imperfetti, ma la possibilità che abbiano scelto l'unico punto di riferimento in cui Swift era più veloce certamente deve essere considerata.
Jan Hudec,

23
È possibile che la risposta a "Come è più veloce Swift?" potrebbe essere "In realtà non è", @BryanOakley; questo è l'essenza che ottengo dalla risposta di Jan. "Bugie, maledette bugie e statistiche", dopo tutto.
Josh Caswell,

4
Qualche tempo fa abbiamo confrontato Codename One in esecuzione su iOS e la nostra implementazione Java era molto più veloce di Objective-C codenameone.com/blog/… Jan è corretto, l'invio dinamico è molto lento, se li migliorassero anche un po ', alcuni benchmark mostra un enorme miglioramento. Se migliorano ARC anche di una frazione (grazie a una migliore analisi del codice) possono sbarazzarsi di una quantità ridicola di complessità. Più la lingua è limitata, più il compilatore può fare per ottimizzare (vedi Java) e Swift aggiunge restrizioni.
Shai Almog,

7
La risposta di Jan è una risposta perfetta al Q1 e probabilmente al Q2. Quando ho visto i benchmark su un evento di marketing come il keynote, ho pensato: "Caspita, solo 1,3x nel caso migliore selezionato. Quale sarà il risultato medio? 0,3x?"
Amin Negm-Awad,

5

Objective-C invia dinamicamente ogni chiamata di metodo.

Ipotesi: il benchmark utilizza la tipizzazione statica per consentire al compilatore Swift di sollevare compareil sortciclo dalla ricerca del metodo . Ciò richiede una restrizione di tipo stretto che consente solo oggetti complessi nell'array, non sottoclassi di complesso.

(In Objective-C potresti sollevare manualmente la ricerca del metodo se lo desideri davvero, chiamando il supporto del runtime della lingua per cercare il puntatore del metodo. Faresti meglio a essere sicuro che tutte le istanze nell'array siano della stessa classe .)

Ipotesi: Swift ottimizza le chiamate di conteggio dei riferimenti fuori dal ciclo.

Ipotesi: il benchmark Swift utilizza una struttura complessa al posto di un oggetto Objective-C, quindi i confronti di ordinamento non necessitano di invii di metodi dinamici (poiché non possono essere sottoclassati) o di conteggio dei riferimenti (poiché è un tipo di valore).

(In Objective-C è possibile ricorrere a C / C ++ per le prestazioni purché non coinvolga oggetti Objective-C, ad esempio ordinare una matrice C di strutture.)


3

Onestamente, a meno che non rilascino la fonte ai test che stanno utilizzando, non mi fiderei di ciò che Apple ha da dire sull'argomento. Ricorda, questa è la società che è passata da PPC a Intel in base a problemi di alimentazione quando 6 mesi prima dicevano che Intel ha succhiato e effettivamente dato alle fiamme il coniglio Intel in una pubblicità. Mi piacerebbe vedere prove inconfutabili che Swift è più veloce di ObjC in più categorie rispetto al semplice ordinamento.

Inoltre, devi mettere in discussione tutte le statistiche rilasciate al WWDC poiché hanno l'odore del marketing dappertutto.

Detto questo, non ho eseguito alcun test tra swift e ObjC da solo, ma da quello che so swift ha le sue estensioni IR LLVM ed è possibile che al momento della compilazione venga eseguita più ottimizzazione rispetto a ObjC.

Full Disclosure: sto scrivendo un compilatore Swift open source che si trova su https://ind.ie/phoenix/

Se qualcuno desidera contribuire a verificare che Swift non sia disponibile solo sull'hardware Apple, fammelo sapere e sarei felice di includervi.


2
questo sembra più un commento ranty, vedi Come rispondere
moscerino

2
Va meglio adesso? :)
greg.casamento

0

Ho lottato con il tutorial di Swift, e mi sembra che Swift sia più diretto (mi fa pensare a Visual Basic) con meno "ificazione degli oggetti" rispetto a Objective-C. Se avessero preso in considerazione il C o il C ++, presumo che quest'ultimo avrebbe vinto, dato che sono ancora più tempo di compilazione.

In questo caso, presumo che Objective-C sia vittima della sua purezza orientata agli oggetti (e ambientale).


13
Fare un benchmark di "ordinamento di oggetti complessi" sarebbe un po 'difficile in un linguaggio come C che non ha un'implementazione nativa di oggetti. Dato che il pubblico di questo discorso era probabilmente programmatore Objective-C al 100%, anche il confronto con un linguaggio come C ++ non ha molto senso. Il punto di vista rapido non è "hey, questa è la più grande lingua di sempre!" ma piuttosto "ehi, questo è più veloce della lingua che stai usando ora per lo sviluppo OSX / iOS".
Bryan Oakley,

10
C ha una fine perfettamente qsortche consentirà l'ordinamento di oggetti complessi; utilizza solo un callback che comprende gli oggetti a portata di mano. Sospetto che manchi C ++ perché std::sortmetterebbe in imbarazzo Swift. (Dal momento che è un modello, un compilatore C ++ può ottimizzarlo pesantemente, fino allo
svolgersi del

@MSalters: sono pienamente d'accordo con te. Sia C che C ++ hanno capacità di superare Swift. Sarebbe possibile ottenere il test eseguito. Sono più che disposto a eseguire lo stesso benchmark con Swift, Objective-C, C ++ e C.
Painted Black

@BryanOakley anche, "Questa lingua richiede meno parentesi quadre!"
Nick Bedford,

1
Questa risposta non trattiene affatto l'acqua ed è terribilmente fuorviante. OO non è molto lento, infatti i sistemi più veloci che troverai in giro saranno C ++, Java e C # e lo stile (pesantemente OO o meno) della programmazione avrà molto poco a che fare con le velocità risultanti a meno che tu non abbia davvero codice errato.
Bill K,
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.