Il seguente codice, che associa i valori semplici ai valori booleani, esegue oltre 20 volte più velocemente in Java rispetto a Swift 2 - XCode 7 beta3, "Ottimizzazioni più veloci e aggressive [-Ostast]" e "Ottimizzazioni veloci, intero modulo" attivate. Posso ottenere oltre 280 milioni di ricerche/sec in Java, ma solo circa 10 milioni in Swift.Dizionario rapido lento anche con le ottimizzazioni: esecuzione di mantenimento/rilascio non appropriato?
Quando lo guardo in Strumenti, vedo che la maggior parte del tempo sta entrando in una coppia di chiamate di mantenimento/rilascio associate alla ricerca della mappa. Qualsiasi suggerimento sul perché questo sta accadendo o una soluzione alternativa sarebbe apprezzato.
La struttura del codice è una versione semplificata del mio codice reale, che ha una classe di chiavi più complessa e memorizza anche altri tipi (sebbene Boolean sia un caso reale per me). Inoltre, si noti che sto utilizzando una singola istanza di chiave mutabile per il recupero per evitare di allocare oggetti all'interno del ciclo e secondo i miei test questo è più veloce in Swift di una chiave immutabile.
EDIT: Ho anche provato a passare a NSMutableDictionary ma quando usato con gli oggetti Swift come chiavi sembra essere terribilmente lento.
EDIT2: ho provato attuare il test in objc (che non avrebbe l'overhead scartare opzionale) ed è più veloce, ma ancora più di un ordine di grandezza più lento di Java ... Ho intenzione di porre quell'esempio come un'altra domanda per vedere se qualcuno ha idee.
EDIT3 - Risposta. Ho pubblicato le mie conclusioni e la mia soluzione alternativa in una risposta di seguito.
public final class MyKey : Hashable {
var xi : Int = 0
init(_ xi : Int) { set(xi) }
final func set(xi : Int) { self.xi = xi }
public final var hashValue: Int { return xi }
}
public func == (lhs: MyKey, rhs: MyKey) -> Bool {
if (lhs === rhs) { return true }
return lhs.xi==rhs.xi
}
...
var map = Dictionary<MyKey,Bool>()
let range = 2500
for x in 0...range { map[ MyKey(x) ] = true }
let runs = 10
for _ in 0...runs
{
let time = Time()
let reps = 10000
let key = MyKey(0)
for _ in 0...reps {
for x in 0...range {
key.set(x)
if (map[ key ] == nil) { XCTAssertTrue(false) }
}
}
print("rate=\(time.rate(reps*range)) lookups/s")
}
e qui è il codice Java corrispondente:
public class MyKey {
public int xi;
public MyKey(int xi) { set(xi); }
public void set(int xi) { this.xi = xi; }
@Override public int hashCode() { return xi; }
@Override
public boolean equals(Object o) {
if (o == this) { return true; }
MyKey mk = (MyKey)o;
return mk.xi == this.xi;
}
}
...
Map<MyKey,Boolean> map = new HashMap<>();
int range = 2500;
for(int x=0; x<range; x++) { map.put(new MyKey(x), true); }
int runs = 10;
for(int run=0; run<runs; run++)
{
Time time = new Time();
int reps = 10000;
MyKey buffer = new MyKey(0);
for (int it = 0; it < reps; it++) {
for (int x = 0; x < range; x++) {
buffer.set(x);
if (map.get(buffer) == null) { Assert.assertTrue(false); }
}
}
float rate = reps*range/time.s();
System.out.println("rate = " + rate);
}
Hai provato a cambiare MyKey dalla classe alla struct o usare 'indexForKey (key: Key)' per cercare i dati? Le strutture hanno una gestione della memoria diversa e 'indexForKey' potrebbe essere diverso in quanto non restituisce l'oggetto, solo indice. – MirekE
Sto cercando di eseguire questo e mi mostra errore identificatore non risolto 'Tempo'. – Aks
Nell'interesse di mantenere il codice focalizzato, non ho incluso il mio codice del timer banale. L'ho messo qui (Java e Swift): https://gist.github.com/patniemeyer/bf73e0e6f06a8b6de97e –