Yo quería saber si el allOf
método CompletableFuture
hace de votación o entra en un estado de espera hasta que todo el CompletableFutures
pasado en el método de completar su ejecución. Miré el código del allOf
método IntelliJ
y lo está haciendo algún tipo de búsqueda binaria.
Por favor, ayudarme a averiguar cuál es el allOf
método de la CompletableFuture
que realmente hace.
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
return andTree(cfs, 0, cfs.length - 1);
}
/** Recursively constructs a tree of completions. */
static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs, int lo, int hi) {
CompletableFuture<Void> d = new CompletableFuture<Void>();
if (lo > hi) // empty
d.result = NIL;
else {
CompletableFuture<?> a, b;
int mid = (lo + hi) >>> 1;
if ((a = (lo == mid ? cfs[lo] :
andTree(cfs, lo, mid))) == null ||
(b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
andTree(cfs, mid+1, hi))) == null)
throw new NullPointerException();
if (!d.biRelay(a, b)) {
BiRelay<?,?> c = new BiRelay<>(d, a, b);
a.bipush(b, c);
c.tryFire(SYNC);
}
}
return d;
}
/** Pushes completion to this and b unless both done. */
final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
if (c != null) {
Object r;
while ((r = result) == null && !tryPushStack(c))
lazySetNext(c, null); // clear on failure
if (b != null && b != this && b.result == null) {
Completion q = (r != null) ? c : new CoCompletion(c);
while (b.result == null && !b.tryPushStack(q))
lazySetNext(q, null); // clear on failure
}
}
}
final CompletableFuture<V> tryFire(int mode) {
CompletableFuture<V> d;
CompletableFuture<T> a;
CompletableFuture<U> b;
if ((d = dep) == null ||
!d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
return null;
dep = null; src = null; snd = null; fn = null;
return d.postFire(a, b, mode);
}
No hace una búsqueda binaria - es la construcción de un árbol binario balanceado con los futuros de entrada en las hojas, y los nodos internos que cada uno completa cuando sus dos hijos han completado tanto.
Por alguna razón que no es evidente a partir del código, el autor del código debe haber decidido que era más eficiente considerar allOf(_,_)
entre exactamente dos futuros a ser su operación primitiva, y si se le pregunta a una allOf(...)
entre más de dos futuros, que está fabricarlo como una cascada de estas primitivas binarios.
El árbol debe ser equilibrado para tal de que no importa lo que la última futuro para completar es decir, no sólo será un pequeño número de niveles de izquierda a colapsar antes de que el futuro en la parte superior se puede completar. Esto mejora el rendimiento en algunas situaciones, ya que asegura que tanto trabajo como sea posible puede ser manejado antes de que estamos completamente hecho, en un punto donde (si tenemos suerte) la CPU podría ser simplemente sentados sin hacer nada, esperando que algo asíncrono a completar.
Equilibrar el árbol está hecho por tener la más alta nodo interno tiene casi tantas hojas bajo su hijo izquierdo como derecho en virtud de su hijo - por lo tanto los niños reciben aproximadamente la mitad de la matriz original, y luego el código de forma recursiva construye un árbol de cada mitad del la matriz. La división en dos mitades puede parecer un poco como los cálculos del índice para una búsqueda binaria.
La estructura básica se oscurece ligeramente en casos especiales que parecen estar diseñados para
- utilizar una ruta de código optimizadas con menos asignaciones cuando algunos de los futuros originales ya se han completado, y
- asegurarse de que el resultado de
allOf(_)
exactamente un elemento devolverá un frescoCompleteableFuture
. Para la mayoría de los propósitos que funcionaría sólo devolver ese solo elemento, pero el autor debe haber querido garantizar que los usuarios de la biblioteca pueden contar con el objeto de ser fresco, si los están utilizando como claves en los mapas de patata, u otra lógica que depende en ser capaz de decirle a la salida de los insumos y - tener un solo
throw new NullPointerException();
mediante el uso?:
y las asignaciones en línea en lugar de honestosif
declaraciones. Esto probablemente produce código de bytes ligeramente más pequeño a expensas de la legibilidad. No puede recomendarse como un estilo de aprender de, a menos que pagar personalmente por el costo de almacenamiento del código de bytes que resulta ...