Presentamos los escenarios de aplicación reales de subprocesos múltiples Spring Boot y cómo optimizar el rendimiento de subprocesos múltiples

Spring Boot es un marco Java popular que le permite crear y ejecutar rápidamente aplicaciones basadas en Spring. Al desarrollar en Spring Boot, existen algunos escenarios de aplicación prácticos, así como algunas técnicas que pueden optimizar el rendimiento de subprocesos múltiples. En este blog, presentaré algunos escenarios y técnicas comunes que espero que le resulten útiles.

Escenarios prácticos de aplicación.

Al desarrollar en Spring Boot, a veces necesitamos manejar algunas tareas que requieren mucho tiempo, como llamar a API externas, realizar cálculos complejos o procesar grandes cantidades de datos. Estas tareas pueden bloquear el hilo principal, lo que hace que la aplicación tenga menos capacidad de respuesta o incluso provoque tiempos de espera o desbordamientos de memoria. Para resolver estos problemas, podemos utilizar subprocesos múltiples para realizar estas tareas simultáneamente y mejorar la eficiencia y el rendimiento de la aplicación.

Llamar API externa

Supongamos que necesitamos llamar a una API externa en una aplicación Spring Boot, obtener algunos datos y guardarlos en la base de datos. Si llamamos a la API directamente en el hilo principal, entonces debemos esperar la respuesta de la API antes de poder continuar ejecutando la lógica posterior. Esto desperdiciará los recursos del hilo principal y también afectará la experiencia del usuario. Para evitar esto, podemos usar @Asyncanotaciones para marcar un método asincrónico para que se ejecute en un hilo separado. Por ejemplo:

@Service
public class ApiService {
    
    

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DataRepository dataRepository;

    @Async
    public void callApiAndSaveData() {
    
    
        // 调用外部的API
        Data data = restTemplate.getForObject("https://example.com/api", Data.class);
        // 保存数据到数据库
        dataRepository.save(data);
    }
}

En el código anterior, usamos @Serviceanotaciones para definir una clase de servicio e ApiServiceinyectar dos componentes. Es una clase de herramienta utilizada para enviar solicitudes HTTP y una interfaz utilizada para operar la base de datos. Luego definimos un método y usamos anotaciones para marcarlo como un método asincrónico. De esta forma, cuando llamemos a este método, se ejecutará en un nuevo hilo sin bloquear el hilo principal.RestTemplateDataRepositoryRestTemplateDataRepositorycallApiAndSaveData()@Async

Para usar @Asyncanotaciones, también necesitamos habilitar la compatibilidad asíncrona en la aplicación Spring Boot. Podemos agregar anotaciones a la clase de configuración @EnableAsyncpara lograr esto. Por ejemplo:

@Configuration
@EnableAsync
public class AsyncConfig {
    
    
}

Realizar cálculos complejos

Supongamos que necesitamos realizar algunos cálculos complejos en una aplicación Spring Boot, como calcular el factorial de un número grande. Si realizamos cálculos directamente en el hilo principal, debemos esperar los resultados del cálculo antes de continuar ejecutando la lógica posterior. Esto ocupará los recursos de CPU del hilo principal y también afectará la experiencia del usuario. Para evitar esto, podemos usar CompletableFutureuna clase para crear una tarea asincrónica y devolver un resultado futuro. Por ejemplo:

@Service
public class MathService {
    
    

    public CompletableFuture<BigInteger> factorial(BigInteger n) {
    
    
        // 创建一个异步任务
        return CompletableFuture.supplyAsync(() -> {
    
    
            // 执行复杂的计算
            BigInteger result = BigInteger.ONE;
            for (BigInteger i = BigInteger.ONE; i.compareTo(n) <= 0; i = i.add(BigInteger.ONE)) {
    
    
                result = result.multiply(i);
            }
            return result;
        });
    }
}

En el código anterior, usamos @Serviceanotaciones para definir una clase de servicio MathService. Luego definimos un método factorial()que acepta un número grande como parámetro y devuelve un resultado futuro. Usamos CompletableFuture.supplyAsync()el método para crear una tarea asincrónica y le pasamos una expresión lambda para definir la lógica de cálculo. De esta manera, cuando llamemos a este método, devolverá un CompletableFutureobjeto inmediatamente sin bloquear el hilo principal. Podemos usar los métodos de este objeto en otros lugares para obtener los resultados del cálculo o agregar funciones de devolución de llamada para manejar los resultados del cálculo. Por ejemplo:

@Controller
public class MathController {
    
    

    @Autowired
    private MathService mathService;

    @GetMapping("/factorial")
    public String factorial(@RequestParam("n") BigInteger n, Model model) {
    
    
        // 调用异步方法
        CompletableFuture<BigInteger> future = mathService.factorial(n);
        // 添加回调函数
        future.thenAccept(result -> {
    
    
            // 将计算结果添加到模型中
            model.addAttribute("result", result);
        });
        // 返回视图名称
        return "factorial";
    }
}

En el código anterior, usamos @Controlleranotaciones para definir una clase de controlador MathControllere inyectar MathServiceel componente. Luego definimos un método factorial()que acepta un parámetro de solicitud ny devuelve un nombre de vista. Usamos @GetMappinganotaciones para asignar una solicitud GET a este método. En el método, llamamos MathServiceal método asincrónico factorial()y obtuvimos un resultado futuro. Luego usamos CompletableFuture.thenAccept()métodos para agregar una función de devolución de llamada que acepta una expresión lambda para definir la lógica de procesamiento. En esta lógica, agregamos los resultados del cálculo al modelo para mostrarlos en la vista.

Procesar grandes cantidades de datos

Supongamos que necesitamos procesar grandes cantidades de datos en una aplicación Spring Boot, como leer datos de un archivo y realizar algunos análisis y transformaciones. Si procesamos datos directamente en el hilo principal, debemos esperar a que se complete el procesamiento de datos antes de poder continuar ejecutando la lógica posterior. Esto ocupará los recursos de memoria del hilo principal y también afectará la experiencia del usuario. Para evitar esto, podemos utilizar Stream APIla creación de un flujo paralelo y aprovechar las CPU multinúcleo para acelerar el procesamiento de datos. Por ejemplo:

@Service
public class DataService {
    
    

    public void processData(String fileName) {
    
    
        // 创建一个并行流
        try (Stream<String> lines = Files.lines(Paths.get(fileName)).parallel()) {
    
    
            // 对每一行数据进行分析和转换
            lines.map(line -> analyzeAndTransform(line))
                // 对转换后的数据进行汇总和输出
                .collect(Collectors.groupingBy(data -> data.getType(), Collectors.counting()))
                .forEach((type, count) -> System.out.println(type + ": " + count));
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

    private Data analyzeAndTransform(String line) {
    
    
        // 省略具体的分析和转换逻辑
        return new Data();
    }
}

En el código anterior, usamos @Serviceanotaciones para definir una clase de servicio DataService. Luego definimos un método processData()que acepta un nombre de archivo como parámetro. En el método, utilizamos Files.lines()el método para crear una secuencia que pueda leer los datos del archivo línea por línea. Luego utilizamos Stream.parallel()métodos para convertir la secuencia en una secuencia paralela, lo que permite que varios subprocesos procesen elementos en la secuencia al mismo tiempo. A continuación, utilizamos una serie de operaciones de flujo para analizar y transformar cada fila de datos, y resumir y generar los datos transformados.

Cómo optimizar el rendimiento de subprocesos múltiples

Al desarrollar en Spring Boot, el uso de subprocesos múltiples puede mejorar la eficiencia y el rendimiento de su aplicación, pero también existen algunos problemas y riesgos que debe tener en cuenta. Si el subproceso múltiple se usa incorrectamente, puede causar algunos problemas, como interbloqueos, condiciones de carrera, pérdidas de memoria, etc. Para evitar estos problemas y optimizar el rendimiento de subprocesos múltiples, podemos seguir algunos principios y técnicas.

Supongo que te gusta

Origin blog.csdn.net/m0_61581389/article/details/132595539
Recomendado
Clasificación