Edit: Changed Boden Sentinel, wurde ein Fehler behoben
Zunächst nicht die gesamte Karte iterieren eine verfügbare ID zu finden. Du solltest nur konstante Zeit dafür brauchen.
Was Sie tun könnten, um es schnell zu machen ist, dies zu tun:
ein int index = 1;
für Ihren Zähler erstellen. Dies ist technisch die Anzahl der erzeugten IDs + 1 und immer > 0
.
Erstellen Sie eine ArrayDeque<Integer> free = new ArrayDeque<>();
für die freien IDs. Garantierter konstanter Zugriff.
Wenn Sie eine ID zuweisen, wenn die freie ID-Warteschlange leer ist, können Sie den Zähler einfach zurückgeben und inkrementieren (z. B. return index++;
). Ansonsten nimm den Kopf und gib das zurück.
Wenn Sie eine ID freigeben, drücken Sie die zuvor verwendete ID auf die free
Deque.
Denken Sie daran, synchronize
Ihre Methoden.
Dies garantiert O(1)
Zuteilung und Freigabe, und es hält auch Zuweisung recht niedrig (wörtlich einmal pro free
). Obwohl es synchronisiert ist, ist es schnell genug, dass es kein Problem sein sollte.
Eine Implementierung könnte wie folgt aussehen:
import java.util.ArrayDeque;
public class IDPool {
int index = 1;
ArrayDeque<Integer> free = new ArrayDeque<>();
public synchronized int acquire() {
if (free.isEmpty()) return index++;
else return free.pop();
}
public synchronized void release(id) {
free.push(id);
}
}
Wenn Sie darüber hinaus die freie ID-Liste ist einzigartig sicherstellen wollen (wie Sie sollte für etwas Wichtiges) sowie persistent, können Sie tun die folgenden:
Verwenden Sie eine HashMap<Integer id, Integer prev>
, um alle generierten IDs zu halten. Denken Sie daran, es muss nicht bestellt oder sogar iteriert werden.
- Dies ist technisch ein Stapel in einer Hash-Karte codiert werden.
- Hocheffiziente Implementierungen von diesem existieren.
- In der Realität wird jede ungeordnete
int
->int
Karte hier tun.
Verfolgen Sie die top
ID für die freie ID-Set. Denken Sie daran, dass 1 nichts darstellen und null verwendet werden kann, so dass Sie es nicht boxen müssen. (IDs sind immer positiv.) Am Anfang, das ist nur int top = 1;
werden würde, wenn eine ID-Zuweisung, wenn es freie IDs (dh top >= 2
) sind, gehen Sie wie folgt vor:
- Stellen Sie den neuen
top
auf die alt head
Wert in der free
Karte.
- Setzen Sie den alten
top
Wert in der Karte auf 0 und markieren Sie ihn.
- Geben Sie die alte
top
zurück.
Wenn ein altes ID Freigabe, dies zu tun, statt:
- Wenn die alte ID bereits im Pool ist, kehren früh, so dass wir es nicht beschädigt.
- Setzen Sie den Wert der ID in der Karte auf den alten
top
.
- Setzen Sie die neue
top
auf die ID, da sie immer die letzte ist.
Die optimierte Implementierung enden würde wie folgt aussehen:
import java.util.HashMap;
public class IDPool {
int index = 2;
int top = 1;
HashMap<Integer, Integer> pool = new HashMap<>();
public synchronized int acquire() {
int id = top;
if (id == 1) return index++;
top = pool.replace(id, 0);
return id;
}
public synchronized void release(id) {
if (pool.getOrDefault(id, 1) == 0) return;
pool.put(id, top);
top = id;
}
}
Wenn es sein muss, können Sie anstelle der Hash-Karte eine wachstumsfähige Integer-Array verwenden könnte (es ist immer zusammenhängend), und erkennen, deutliche Leistungssteigerungen. Tatsache ist, dass ich das wahrscheinlich umsetzen würde. Es würde nur eine kleine Menge an Bit Twiddling erfordern, da ich die Größe des Arrays beibehalten würde, um auf die nächste Potenz von 2 aufgerundet zu werden.
Ja ... Ich musste tatsächlich einen ähnlichen Pool in JavaScript schreiben, weil ich eigentlich mäßig schnell IDs in Node.js für potenziell Hochfrequenz langlebige IPC Kommunikation benötigt.
Das gute daran ist, dass es im Allgemeinen Zuweisungen vermeidet (im schlimmsten Fall einmal pro erworbene ID, wenn keine freigegeben sind), und es ist sehr anfällig für spätere Optimierung, wo nötig.
Haben Sie eine Kopie Ihres Javascript-Codes in diesem Teil? Ich bin daran interessiert, die Art und Weise zu tun, wie es geht. – newguy
Ich benutze die [naivere Variante] (https://github.com/isiahmeadows/invoke-parallel/blob/master/lib/id-pool.js) in meinem Code (ich brauche es schnell, aber ich nicht müssen CPU-Zyklen dafür zählen) –