Proceso de multi-subprocesos Java (Android)
Estoy trabajando en la aplicación ( Matt's traceroute windows versión http://winmtr.net/ ) que crea múltiples subprocesos cada hilo tiene su propio proceso (que ejecutan el comando ping). ThreadPoolExecutor
apagar todos los subprocesos después de algún tiempo (por ejemplo, 10 segundos)
ThreadPoolExecutor
utiliza la cola de bloqueo (las tareas de mantenimiento antes de ejecutarse)
- Acceso al dominio desde un subproceso incorrecto Android
- Emisión de concurrencia para la cancelación del bucle de encuesta larga
- ¿Cómo configurar el nombre del hilo?
- Android: onCreate () se llama varias veces (y no por mí)
- RxJava Android: cargar datos de caché en los subprocesos adecuados
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors(); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor( NUMBER_OF_CORES * 2, NUMBER_OF_CORES * 2 + 2, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() );
PingThread.java
private class PingThread extends Thread { @Override public void run() { long pingStartedAt = System.currentTimeMillis(); // PingRequest is custom object PingRequest request = buildPingRequest(params); if (!isCancelled() && !Thread.currentThread().isInterrupted()) { // PingResponse is custom object // Note: // executePingRequest uses PingRequest to create a command // which than create a runtime process to execute ping command // using string response i am creating PingResponse PingResponse pingResponse = PingUtils.executePingRequest(request); if (pingResponse != null) { pingResponse.setHopLocation(hopLocation); // publish ping response to main GUI/handler publishProgress(pingResponse); } else Logger.error( "PingThread", "PingResponse isNull for " + request.toString() ); } } }
Ahora si creo varios hilos diga más de 500 en un bucle y ejecute dentro del ejecutor de pool
Ejecución de subprocesos
PingThread thread = new PingThread(params); poolExecutor.execute(thread);
Sé que LinkedBlockingQueue
contiene las tareas antes de ejecutarse. El proceso de cada hilo toma un máximo de 200 a 400ms pero generalmente es menos de 10ms
Qué estoy haciendo
for (int iteration = 1; iteration <= 50/*configurable*/; iteration++) { for (int index = 0; index < 10/*configurable*/; index++) { PingThread thread = new PingThread(someParams); poolExecutor.execute(thread); } try { Thread.sleep(500); } catch (InterruptedException e) { Logger.error(false, e); } }
50 iteraciones tomará cerca de 25 segundos, aquí tengo solamente hasta 40 respuestas del silbido de bala considere como pérdida debido al tiempo hacia fuera. Si aumenta la pérdida de iteraciones aumenta también (exponencialmente debido al aumento en el número de hilos)
Observación:
Estoy ejecutando esta aplicación en el Galaxy S6 que tiene 8 núcleos, el tamaño del pool de aplicaciones es de 16 y el tamaño máximo de la piscina es de 16 + 2, sé que el procesador ejecuta sólo un hilo a la vez, que comparte un tiempo cuántico para el procesamiento en paralelo.
Observando ThreadPoolExecutor
en forma oportuna, veo muchas tareas en la cola, después de tiempo de espera todavía hay muchos hilos presentes en la cola debido a LinkedBlockingQueue
Si disminuyo el número de hilos, funciona bien, pero si aumenta, crea problemas
Problema:
- Las respuestas de ping disminuyen cuando uso dispositivos con procesador de doble núcleo.
- ¿Por qué hay muchos hilos presentes en la cola, donde cada hilo toma alrededor de 10 a 50ms (aumentar el tiempo de hilos aumentará uptp 300ms o más)?
- Debe completar con en el tiempo dado, ¿por qué no?
- ¿Cómo superar este problema?
- ¿Debo utilizar
ConcurrentLinkedQueue
pero utiliza el productor / modelo del consumidor, de alguna maneraThreadPoolExecutor
(pienso que es) utiliza este modelo también. -
LinkedBlockingQueue
contiene las tareas antes de ejecutarse (los hilos están inactivos o en cola), ¿cómo superar esto? - Al establecer
Thread.MAX_PRIORITY
para iteraciones posteriores no resuelve el problema (el hilo de iteración posterior está en cola) - La disminución del número de hilos resuelve el problema ¿por qué? Porque hay menos hilos presentes en la cola?
- ¿Hay alguna manera de comprobar, si los hilos presentes en la cola los entretienen entonces ejecuta otros, sin bloquear otros hilos pero dentro del tiempo dado.
- Agregar tiempo extra como 5 segundos no es una solución
- Cambiar
corePoolSize
como en ¿Cómo obtener el ThreadPoolExecutor para aumentar los hilos a máximo antes de hacer cola? No está funcionando en mi caso.
Durante la prueba de memoria y el uso del procesador están en un límite.
Se requiere respuesta / ayuda detallada.
Editar
Cuando la aplicación entra en el fondo no hay pérdida y el uso de la CPU del usuario cae a 0-2%, mientras que en la aplicación de enfoque tuvo un 4-6% de uso de la CPU. ¿Es debido a la interfaz de usuario y otras cosas ralted, traté de eliminar todo el código innecesario también PingThread
cambiado PingThread
a PingTask
PingTask implements Runnable {/*....*/}
Nota: he creado una aplicación basada en java independiente utilizando el mismo código y funciona bien en el escritorio, así que podemos decir que es el problema específico de Android?
- Después de ASyncTask.execute () do x () de Activity
- Los subprocesos WebView nunca se detienen (WebViewCoreThread, CookieSyncManager, http )
- Servicio androide con repetición de hilo en el fondo con el bloqueo parcial de la estela
- Práctica recomendada para gestionar la llamada de error HTTP
- Actualización de la interfaz de usuario con Runnable y postDelayed no funciona con la aplicación de temporizador
- ¿Cómo esperar que todas las tareas en un ThreadPoolExecutor terminen sin apagar el Ejecutor?
- WebViewClient shouldInterceptRequest Congela el WebView
- Manejadores inicializados con Looper.getMainLooper () no responde a callbacks de mensaje
No estoy seguro de si esto es lo que causa todos los problemas, pero está creando una gran cantidad de hilos innecesarios.
Deberías reemplazar
private class PingThread extends Thread {
con :
private class PingThread implements Runnable {
O (usando un nombre más adecuado):
private class PingTask implements Runnable {
Es decir, las tareas enviadas a Executor
s no se supone que son hilo ellos mismos. Funciona, porque un Thread
implementa Runnable
, pero lo está desperdiciando.
Observación:
Después de crear y observar una aplicación java independiente (logs) usando el mismo código, llegué a conocer lo siguiente:
- De alguna manera, la arquitectura y / o procesador del sistema operativo Android está limitando el número de subprocesos.
-
LinkedBlockingQueue
contiene las tareas antes de ejecutarse, por lo que si tenemos una larga cola más tarde los hilos en la cola tendrán que esperar más. - Aumentar / Dynamic
corePoolSize
ymaxPoolSize
está haciendo lo mismo, agregaron subprocesos en la cola - La aplicación utiliza un 4-6% de CPU, por lo que no podemos decir que la CPU está sobrecargando o utilizando recursos completos de la aplicación, pero cuando la aplicación entra en segundo plano (la GUI u otro SO relacionado y / o aplicaciones basadas en hilos pueden detenerse o interrumpirse) -3%.
Solución:
Para 50 iteraciones y 10 internos crea 500 hilos ahora hice dos cosas:
- Aumentar el tiempo
Thread.sleep(millis)
con algunos cálculos implica. - Disminuye el número de subprocesos para cada iteración. Ahora estoy creando 10 hilos
Math.ceil((double) 10 / 3) = 3
por lo que tenemos 3 secuencialesPingUtils.executePingRequest(pingRequest)
para cada hilo es decir3 * 3 = 9
sigue siendo 1 por lo que vamos a crear un hilo separado para el último solicitud. Para cada iteración en lugar de crear 10 hilos ahora estoy creando 4 hilos. - Utilizando este enfoque ahora tengo 200 subprocesos en lugar de 500 que resuelve el problema.
Los subprocesos crean un nuevo objeto único, mientras que runnable permite que todos los subprocesos compartan un objeto. Como tal, no debe extender Thread al intentar multithread, en su lugar utilizar Runnable:
class RunnableDemo implements Runnable { private Thread thread; String threadName="My thread"; public void run() { //do your code from here 'logic' System.out.println("Threading is Running"); try { for(int i = 4; i > 0; i--) { System.out.println("Thread: "+threadName +" "+ i); // Let the thread sleep for a while. Thread.sleep(50); //sleep your content for xx miliseconds } } catch (InterruptedException e) { System.out.println("Thread " + threadName + " interrupted."); } System.out.println("Thread " + threadName + " exiting."); //finish your work here } public void start () { System.out.println("Starting " + threadName ); if (thread == null) { thread = new Thread (this); thread.start (); //This will call your run methods of Runnable } } } //test your thread from here public class TestThread { public static void main(String args[]) { RunnableDemo R1 = new RunnableDemo( "Thread-1"); R1.start(); RunnableDemo R2 = new RunnableDemo( "Thread-2"); R2.start(); } }