Programación de tareas asincrónica

problema

Cuando el cliente envía varias tareas a la capa de servicio al mismo tiempo, con el fin de aprovechar al máximo la potencia de procesamiento y computación del servidor, el hilo único ordinario ya no puede satisfacer nuestras necesidades. Es necesario utilizar varios hilos o tecnología multiproceso para procesar tareas simultáneamente. El servidor debe cumplir los siguientes requisitos al procesar tareas concurrentes:

  • 1. Después de enviar la tarea, espero que el servidor procese y devuelva el resultado lo más rápido posible.
  • 2. No afecta el rendimiento cuando se procesan varias tareas al mismo tiempo.
  • 3. Cuando ocurre un error durante la ejecución de una tarea, se permite reintentar sin obstaculizar el procesamiento de otras tareas.

análisis

  • 1. Envíe varias tareas al mismo tiempo y espere que el servidor procese y devuelva los resultados lo más rápido posible, utilizando tecnología de subprocesos múltiples para lograr, para cada tarea, si se asigna un subproceso para procesar, luego cuando miles de los envíos se envían al mismo tiempo. Las tareas pueden llevar fácilmente al agotamiento de los recursos del sistema del servidor y al tiempo de inactividad del servidor. Al asignar tareas, crear y destruir subprocesos es un desperdicio de recursos. La tecnología de grupo de subprocesos se utiliza para mejorar la eficiencia de ejecución de subprocesos, menos el tiempo para la creación y destrucción de subprocesos durante la ejecución de tareas, lo que mejora en gran medida la eficiencia de ejecución de tareas. A través de la tecnología del grupo de subprocesos, se almacena una cierta cantidad de subprocesos cuando se inicializa el sistema. Una vez que el cliente envía las tareas al servidor, cada tarea se asigna a los subprocesos inactivos existentes para su procesamiento. Sin embargo, cuando se envían muchas tareas, es obvio que los subprocesos en el grupo de subprocesos El número de subprocesos será insuficiente, entonces, ¿cómo resolverlo? Una vez que el cliente envía la tarea al servidor, la tarea ahora se envía a la cola de tareas (TaskQueue). Cuando el sistema ejecuta la tarea, la tarea se extrae de la cola de tareas y luego se asigna al subproceso inactivo en el grupo de subprocesos para ejecutar la tarea.
  • 2. Después de que liberamos la tarea, la tarea se entrega a la capa de servicio para su procesamiento. En el proceso de procesamiento, es inevitable que encontremos algunos problemas especiales, que harán que la tarea falle. Para garantizar que la tarea se puede ejecutar de manera efectiva y lograr las tareas que necesitamos, también es necesario proporcionar un mecanismo de reintento para el procesamiento de la tarea, de modo que cuando el sistema no pueda ejecutar una tarea, el mecanismo de reintento se pueda activar para procesar la tarea enviada nuevamente, aumentando la tasa de éxito de la ejecución de tareas.

 

diseño

 

  • Cliente El
    cliente simula varios clientes. El método submit () se utiliza para enviar tareas. El tipo de tarea enviada es AsyncTask, que es una clase de tarea dedicada, que se describirá a continuación.
  • AsyncExecutorService En
    primer lugar, el propósito de esta clase es crear un ejecutor de grupo de subprocesos para la asignación de recursos. Necesita inicializar algunos parámetros, como el número de subprocesos, el número máximo de subprocesos, el tiempo de supervivencia del subproceso, el número de reintentos, y el tiempo de espera para reintentar, etc. Hay un parámetro oculto -> cola de tareas. Al asignar recursos, las tareas se seleccionan aleatoriamente de la cola de tareas y se asignan. Cuando se ejecutan tareas y hay hilos inactivos, el ejecutor redistribuirá los recursos nuevamente, desde la cola de tareas Seleccione la tarea correspondiente para ejecutar.
    Esta clase también proporciona una interfaz para ejecutar tareas, las tareas pasadas del cliente se reciben en esta clase y se ejecuta la lógica interna.
  • AsyncTask
    AsyncTask es una clase Runnable que rectifica el lugar donde se ejecuta la tarea, la tarea ejecutada se entrega al exterior a través del método abstracto doWork (), para que se puedan realizar diferentes operaciones de la tarea. En esta clase, la lógica del mecanismo de reintento se implementa principalmente.Cuando falla la ejecución de la tarea, se ejecuta el número correspondiente de reintentos para asegurar el éxito de la ejecución de la tarea.

Codigo del cliente

package com.ngsky.async;
 
/**
 * @Description TODO
 * @Author daxiong
 * @Date 7/7/2018 10:48 AM
 **/
public class AsyncTaskTest {
    public static void main(String[] args){
        AsyncExecutorService executorService = new AsyncExecutorService(5, 10, 30, TimeUnit.SECONDS, 2, 5);
        long beginTime = System.currentTimeMillis();
        for(int i = 0; i < 1000;i++){
            MockTask mockTask = new MockTask();
            mockTask.setName("task" + i);
            mockTask.setRetryTimes(3);
            mockTask.setRetryWaitTime(2000);
            executorService.execute(mockTask);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("The task spend on " + ((endTime - beginTime) / 60L) + " minutes");
    }
 
}
// every task spend 20s, (1000 * 2) / 60 = 33 minutes
class MockTask extends AsyncTask{
    public void doWork() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 Clase AsyncTask.java

package com.ngsky.async;
 
/**
 * @Description TODO
 * @Author daxiong
 * @Date 7/7/2018 10:14 AM
 **/
public abstract class AsyncTask implements Runnable {
 
    private String name;  // task name
    private boolean successDone; // whether the task completed successful
    private int retryTimes;  // if the task was't finished successful, system allow retry to do the task for retrytimes
    private int retryWaitTime;  // system cant't retry to do work immediately, but execute after retryWaitTime
 
    public void run() {
        System.out.println("(task) " + getName() + " beginning execute....");
        long beginTime = System.currentTimeMillis();
        int currentRetryTimes = 1;
        try {
            doWork();
            System.out.println("(task) " + getName() + " completed successful!");
            this.setSuccessDone(true);
        } catch (Exception e) {
            System.out.println("(task) " + " execute filed..., message " + e);
            this.setSuccessDone(false);
        }
        if (getRetryTimes() <= 0) return;
        while (!isSuccessDone() && currentRetryTimes <= getRetryTimes()) {
            System.out.println("(task) " + "Executing retry " + currentRetryTimes + "th!" );
            if (getRetryWaitTime() > 0) {
                try {
                    Thread.sleep(getRetryWaitTime());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                doWork();
                System.out.println("(task) " + getName() + " completed successful!");
                this.setSuccessDone(true);
            } catch (Exception e) {
                System.out.println("(task) " + getName() + " was failed, unknown reason! Please try again!");
                this.setSuccessDone(false);
                currentRetryTimes++;
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("(task) " + " spend on " + (endTime - beginTime) + "ms and result is " + (this.isSuccessDone() ? "successful!" : "failed,Please check your task!"));
    }
 
    public abstract void doWork() throws Exception;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public boolean isSuccessDone() {
        return successDone;
    }
 
    public void setSuccessDone(boolean successDone) {
        this.successDone = successDone;
    }
 
    public int getRetryTimes() {
        return retryTimes;
    }
 
    public void setRetryTimes(int retryTimes) {
        this.retryTimes = retryTimes;
    }
 
    public int getRetryWaitTime() {
        return retryWaitTime;
    }
 
    public void setRetryWaitTime(int retryWaitTime) {
        this.retryWaitTime = retryWaitTime;
    }
}
 

AsyncExecutorService.java

package com.ngsky.async;
 
import java.util.concurrent.*;
 
/**
 * @Description async service interface
 * @Author daxiong
 * @Date 7/7/2018 9:16 AM
 **/
public class AsyncExecutorService {
 
    private int corePoolSize;
    private int maximumPoolSize;
    private long keepLiveTime;
    private TimeUnit timeUnit;
    private int retryTimes;
    private int retryWaitTime;
    private LinkedBlockingQueue<Runnable> blockingQueue;
    private ThreadPoolExecutor executor;
 
    public AsyncExecutorService(int corePoolSize, int maximumPoolSize, long keepLiveTimes,
                                TimeUnit timeUnit, int retryTimes, int retryWaitTimes){
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.keepLiveTime = keepLiveTimes;
        this.timeUnit = timeUnit;
        this.retryTimes = retryTimes;
        this.retryWaitTime = retryWaitTimes;
        init();
    }
 
    private void init(){
        System.out.println("Async executor initializing...");
        blockingQueue = new LinkedBlockingQueue<Runnable>();
        executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepLiveTime, timeUnit, blockingQueue);
    }
 
    // init task information
    private AsyncTask initTask(AsyncTask task){
        System.out.println("(task) " + task.getName() + " initializing...");
        if(retryTimes > 0) task.setRetryTimes(retryTimes);
        if(retryWaitTime > 0) task.setRetryWaitTime(retryWaitTime);
        return task;
    }
 
    public void execute(AsyncTask task){
        task = initTask(task);
        executor.execute(task);
    }
 
    public <T> Future<T> submit(Callable<T> job){
        return executor.submit(job);
    }
 
    public void shutdown(){
        if(executor != null)
            executor.shutdown();
    }
 
    public int getCorePoolSize() {
        return corePoolSize;
    }
 
    public void setCorePoolSize(int corePoolSize) {
        this.corePoolSize = corePoolSize;
    }
 
    public int getMaximumPoolSize() {
        return maximumPoolSize;
    }
 
    public void setMaximumPoolSize(int maximumPoolSize) {
        this.maximumPoolSize = maximumPoolSize;
    }
 
    public long getKeepLiveTime() {
        return keepLiveTime;
    }
 
    public void setKeepLiveTime(long keepLiveTime) {
        this.keepLiveTime = keepLiveTime;
    }
 
    public TimeUnit getTimeUnit() {
        return timeUnit;
    }
 
    public void setTimeUnit(TimeUnit timeUnit) {
        this.timeUnit = timeUnit;
    }
 
    public int getRetryTimes() {
        return retryTimes;
    }
 
    public void setRetryTimes(int retryTimes) {
        this.retryTimes = retryTimes;
    }
 
    public int getRetryWaitTime() {
        return retryWaitTime;
    }
 
    public void setRetryWaitTime(int retryWaitTime) {
        this.retryWaitTime = retryWaitTime;
    }
 
    public LinkedBlockingQueue<Runnable> getBlockingQueue() {
        return blockingQueue;
    }
 
    public void setBlockingQueue(LinkedBlockingQueue<Runnable> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }
 
    public ThreadPoolExecutor getExecutor() {
        return executor;
    }
 
    public void setExecutor(ThreadPoolExecutor executor) {
        this.executor = executor;
    }
}
 

para resumir

Hay muchos lugares que no están involucrados en teorías e implementaciones relacionadas con la programación de tareas asincrónicas. A continuación, se incluye una introducción, como la operación de interceptación durante la ejecución de la tarea, cómo elegir el tamaño del grupo de subprocesos durante la inicialización, etc.

La programación de tareas está dirigida a un gran número de solicitudes de tareas simultáneas y es necesaria para garantizar el rendimiento del sistema, procesar las tareas a la velocidad más rápida y mejorar la eficiencia del procesamiento y la tasa de éxito.

Tecnología seleccionada: subprocesos múltiples, grupo de subprocesos, procesamiento concurrente, programación de tareas, asignación de recursos, mecanismo de reintento.

 

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/suixinsuoyu12519/article/details/108624028
Recomendado
Clasificación