Improve search performance.

This commit is contained in:
Greyson Parrelli
2021-06-10 15:47:12 -04:00
committed by GitHub
parent 53ffca964d
commit c274ed6a96
18 changed files with 413 additions and 219 deletions

View File

@@ -0,0 +1,87 @@
package org.signal.core.util.concurrent;
import androidx.annotation.NonNull;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
/**
* A serial executor that will order pending tasks by a specified priority, and will only keep a single task of a given priority, preferring the latest.
*
* So imagine a world where the following tasks were all enqueued (meaning they're all waiting to be executed):
*
* execute(0, runnableA);
* execute(3, runnableC1);
* execute(3, runnableC2);
* execute(2, runnableB);
*
* You'd expect the execution order to be:
* - runnableC2
* - runnableB
* - runnableA
*
* (We order by priority, and C1 was replaced by C2)
*/
public final class LatestPrioritizedSerialExecutor {
private final Queue<PriorityRunnable> tasks;
private final Executor executor;
private Runnable active;
public LatestPrioritizedSerialExecutor(@NonNull Executor executor) {
this.executor = executor;
this.tasks = new PriorityQueue<>();
}
/**
* Execute with a priority. Higher priorities are executed first.
*/
public synchronized void execute(int priority, @NonNull Runnable r) {
Iterator<PriorityRunnable> iterator = tasks.iterator();
while (iterator.hasNext()) {
if (iterator.next().getPriority() == priority) {
iterator.remove();
}
}
tasks.offer(new PriorityRunnable(priority) {
@Override
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
}
private synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
private abstract static class PriorityRunnable implements Runnable, Comparable<PriorityRunnable> {
private final int priority;
public PriorityRunnable(int priority) {
this.priority = priority;
}
public int getPriority() {
return priority;
}
@Override
public final int compareTo(PriorityRunnable other) {
return other.getPriority() - this.getPriority();
}
}
}