1414
1515package com .google .firebase .firestore .util ;
1616
17- import android .os .AsyncTask ;
17+ import static kotlinx .coroutines .ExecutorsKt .asExecutor ;
18+
1819import com .google .android .gms .tasks .TaskExecutors ;
1920import java .util .concurrent .Executor ;
21+ import kotlinx .coroutines .Dispatchers ;
2022
2123/** Helper class for executors. */
2224public final class Executors {
2325 /**
24- * The maximum number of tasks we submit to AsyncTask.THREAD_POOL_EXECUTOR.
25- *
26- * <p>The limit is based on the number of core threads spun by THREAD_POOL_EXECUTOR and is well
27- * below the queue size limit of 120 pending tasks. Limiting our usage of the THREAD_POOL_EXECUTOR
28- * allows other users to schedule their own operations on the shared THREAD_POOL_EXECUTOR .
26+ * The number of physical CPU cores available for multithreaded execution, or 2, whichever is
27+ * larger.
28+ * <p>
29+ * CPU-bound tasks should never use more than this number of concurrent threads as doing so will
30+ * almost certainly reduce throughput due to the overhead of context switching .
2931 */
30- private static final int ASYNC_THREAD_POOL_MAXIMUM_CONCURRENCY = 4 ;
32+ public static final int HARDWARE_CONCURRENCY =
33+ Math .max (2 , Runtime .getRuntime ().availableProcessors ());
3134
3235 /**
3336 * The default executor for user visible callbacks. It is an executor scheduling callbacks on
@@ -38,10 +41,46 @@ public final class Executors {
3841 /** An executor that executes the provided runnable immediately on the current thread. */
3942 public static final Executor DIRECT_EXECUTOR = Runnable ::run ;
4043
41- /** An executor that runs tasks in parallel on Android's AsyncTask.THREAD_POOL_EXECUTOR. */
42- public static final Executor BACKGROUND_EXECUTOR =
43- new ThrottledForwardingExecutor (
44- ASYNC_THREAD_POOL_MAXIMUM_CONCURRENCY , AsyncTask .THREAD_POOL_EXECUTOR );
44+ /**
45+ * An executor suitable for short tasks that perform little or no blocking.
46+ */
47+ public static final Executor SHORT_WORKLOAD_EXECUTOR =
48+ asExecutor (
49+ Dispatchers .getIO ()
50+ .limitedParallelism (HARDWARE_CONCURRENCY , "firestore.SHORT_WORKLOAD_EXECUTOR" ));
51+
52+ /**
53+ * An executor suitable for IO-bound workloads. New threads are usually created to satisfy demand,
54+ * and, therefore, tasks do not usually wait in a queue for execution.
55+ */
56+ public static final Executor IO_WORKLOAD_EXECUTOR = asExecutor (Dispatchers .getIO ());
57+
58+ /**
59+ * An executor suitable for CPU-bound workloads. No more tasks than available CPU cores will
60+ * execute concurrently, while other tasks line up and wait for a thread to become available, and
61+ * are scheduled in an arbitrary order.
62+ */
63+ public static final Executor CPU_WORKLOAD_EXECUTOR =
64+ asExecutor (
65+ Dispatchers .getIO ()
66+ .limitedParallelism (HARDWARE_CONCURRENCY , "firestore.CPU_WORKLOAD_EXECUTOR" ));
67+
68+ /**
69+ * Creates and returns a new {@link Executor} that executes tasks sequentially.
70+ * <p>
71+ * The implementation guarantees that tasks are executed sequentially and that a happens-before
72+ * relation is established between them. This means that tasks run by this executor do _not_ need
73+ * to synchronize access to shared resources, such as using "synchronized" blocks or "volatile"
74+ * variables. See `kotlinx.coroutines.limitedParallelism` for full details.
75+ * <p>
76+ * Note that there is no guarantee that tasks will all run on the _same thread_.
77+ *
78+ * @param name a brief name to assign to the executor, for debugging purposes.
79+ * @return the newly-created executor.
80+ */
81+ public static Executor newSequentialExecutor (String name ) {
82+ return asExecutor (Dispatchers .getIO ().limitedParallelism (1 , "firestore.seq." + name ));
83+ }
4584
4685 private Executors () {
4786 // Private constructor to prevent initialization
0 commit comments