JUC下的CompletableFuture详解

news2024/11/19 20:31:42

详细介绍

CompletableFuture是Java 8引入的一个实现Future接口的类,它代表一个异步计算的结果。与传统的Future相比,CompletableFuture提供了更丰富的功能,比如链式调用、组合异步操作、转换结果、异常处理等,极大地增强了Java在处理异步编程的能力。

核心API与方法
  1. 创建实例

    • CompletableFuture<Void/Type> supplyAsync(Supplier<U> supplier):在ForkJoinPool.commonPool()或自定义Executor中异步执行supplier,并返回一个新的CompletableFuture,其结果类型由Supplier决定。
    • CompletableFuture<Void> runAsync(Runnable runnable):同上,但Runnable没有返回值,因此CompletableFuture的类型为Void。
    • 还有非Async版本,如supplyAsync(Supplier<U> supplier, Executor executor),允许指定执行器。
  2. 链式调用与转换结果

    • .thenApply(Function<? super T,? extends U> fn):当前阶段正常完成时,使用给定的函数fn转换结果,并返回一个新的CompletableFuture。
    • .thenAccept(Consumer<? super T> action):当前阶段正常完成时,执行给定的action消费结果,无返回值。
    • .thenCompose(Function<? super T,? extends CompletionStage<U>> fn):当前阶段完成时,使用给定的函数fn将结果转换为另一个CompletionStage,并将其结果作为新的CompletableFuture。
  3. 组合异步操作

    • .thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn):当两个CompletableFuture都完成时,使用BiFunction组合它们的结果。
    • .thenComposeBoth(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends CompletionStage<V>> fn):类似于.thenCombine(),但fn返回的是另一个CompletionStage,而非直接结果。
  4. 异常处理

    • .exceptionally(Function<Throwable,? extends T> fn):如果出现异常,使用提供的函数fn处理异常,并返回一个包含处理结果的新CompletableFuture。
    • .handle(BiFunction<? super T, Throwable, ? extends U> fn):无论正常完成还是异常结束,都会调用fn处理结果或异常,返回一个新的CompletableFuture。
  5. 完成与等待

    • .join():等待计算完成,如有异常直接抛出,适用于不需要区分成功失败的场景。
    • .get():同join,但此方法会抛出具体的ExecutionException或InterruptedException,便于区分错误类型。
  6. 触发动作

    • .whenComplete(BiConsumer<? super T,? super Throwable> action):无论CompletableFuture成功完成还是异常结束,都会执行action,但不改变结果或处理异常。
    • .whenCompleteAsync(BiConsumer<? super T,? super Throwable> action):异步版本的whenComplete。
实现原理浅析

   CompletableFuture基于Java的Fork/Join框架实现,利用工作窃取算法提高线程利用率。每个CompletableFuture对象内部维护了一个状态机,用于跟踪任务的完成状态(初始化、完成、取消、异常)。当一个阶段的任务完成时,它会触发后续阶段的任务开始执行,这一过程通过内部的等待队列和信号机制高效完成,实现了非阻塞的链式调用。

性能与最佳实践
  • 线程池选择:合理选择线程池,避免过度使用ForkJoinPool.commonPool(),尤其是在IO密集型任务中,应考虑使用自定义的固定大小线程池。
  • 避免过度链式:虽然链式调用使代码简洁,但过度使用可能导致逻辑难以理解和维护,适当使用中间变量命名可以帮助理解。
  • 异常传播与日志:确保异常处理逻辑完整,利用日志记录异常信息,便于调试。
  • 资源释放:在涉及资源操作的异步任务中,确保资源能够正确关闭或释放,避免资源泄露。

核心特性

1. 非阻塞式执行

CompletableFuture 允许任务异步执行,而不需要调用线程等待其完成。这意味着主线程可以继续执行其他操作,而不是被阻塞等待结果,提高了程序的响应性和并发性能。

2. 异步回调

它支持链式调用回调函数(如 thenApply, thenAccept, thenCompose 等),允许在异步操作完成时自动执行后续操作,无论是成功还是失败。这种机制使得复杂的异步流程控制变得简单直观。

3. 组合异步任务

CompletableFuture 提供了多种方法来组合多个异步操作,比如 thenCombine, thenCompose,可以将多个独立的异步任务按照依赖关系组织起来,实现任务间的流水线处理,提高程序的并发执行效率。

4. 异步转换结果

通过 thenApply 方法,可以在异步操作完成后,对结果进行转换或进一步处理,而无需等待整个过程完成,这对于构建复杂的异步工作流特别有用。

5. 错误处理

提供了错误处理机制,如 exceptionallyhandle 方法,可以优雅地捕获并处理异步执行过程中发生的异常,增强了程序的健壮性。

6. 自动线程管理

默认情况下,CompletableFuture 会使用 ForkJoinPool.commonPool() 来执行异步任务,但也可以通过 supplyAsync(Supplier<U> supplier, Executor executor) 方法指定自定义的 Executor,从而实现对线程资源的精细控制。

7. 可取消性

如同 FutureCompletableFuture 也支持任务的取消操作,通过 cancel(boolean mayInterruptIfRunning) 方法可以尝试取消一个正在执行或尚未开始的任务。

8. 延迟计算与懒初始化

通过 CompletableFuture.supplyAsync(Supplier<U> supplier) 方法,可以在需要结果时才真正触发计算,这对于资源敏感或计算密集型操作特别有用。

9. 高度可组合性

由于其丰富的API,CompletableFuture 可以轻松地与其他 CompletableFuture 实例组合,形成复杂的异步逻辑,而代码依然保持清晰和可维护。

10. 函数式编程风格

它鼓励使用函数式编程的思维,通过传递函数(Lambda表达式)来定义任务的执行逻辑和结果处理逻辑,使得代码更加简洁、易读且易于推理。

这些特性使 CompletableFuture 成为了Java中处理异步编程的强大工具,尤其是在构建高性能、响应式系统时,能够有效地提升代码的效率和可维护性。

使用场景

微服务架构中的异步通信

在微服务架构中,服务间通常通过HTTP、gRPC或其他协议进行通信。当一个服务需要调用多个下游服务获取数据时,如果采用同步方式,每个调用都会阻塞当前线程直到响应,这会大大增加请求的总耗时。使用CompletableFuture,可以并行发起这些调用,然后通过组合操作处理所有响应,显著减少整体响应时间,提升用户体验。

示例场景:电商平台的订单服务需要在创建订单时,异步调用库存服务检查商品库存、用户服务验证用户信息、支付服务预扣款等多个下游服务,使用CompletableFuture可以高效地并行处理这些任务。

数据库批量操作

对于大量数据的读写操作,如批量插入、更新或查询,直接在主线程中执行可能会导致长时间阻塞。通过CompletableFuture,可以将这些操作分批异步执行,每批操作完成后合并结果,既充分利用了系统资源,又保证了操作的高效性。

示例场景:系统日志收集模块,需要定时从多个来源拉取日志并存储到数据库中。利用CompletableFuture异步处理每个数据源的日志收集和存储任务,最后合并所有操作结果。

文件处理与上传下载

处理大文件的上传、下载或转换操作时,这些操作往往比较耗时,直接在主线程中执行会影响用户体验。使用CompletableFuture可以将这些操作放在后台执行,同时可以提供进度监控、结果通知等功能。

示例场景:云存储服务中,用户上传大文件后,服务端需要异步进行病毒扫描、格式转换等操作,完成后通知用户或进行下一步处理。

定时任务与周期性任务

在实现定时任务或周期性任务时,如定时数据分析、报表生成等,可以利用CompletableFuture配合ScheduledExecutorService进行异步调度,避免阻塞主线程,并且可以方便地控制任务的执行策略(如首次执行延迟、执行间隔等)。

示例场景:每天凌晨自动统计前一天的销售数据并生成报表,通过CompletableFuture安排在低峰时段异步执行,不影响白天的业务操作。

并发限制与资源池管理

在处理大量并发请求时,直接为每个请求分配线程可能会迅速耗尽资源。通过自定义线程池与CompletableFuture结合,可以有效控制并发数量,例如使用Semaphore限制并发数,确保系统稳定运行。

示例场景:在爬虫系统中,需要并发抓取大量网页,但不能无限制地创建线程。通过CompletableFuture结合Semaphore限制并发抓取的数量,既保证了抓取效率,又防止了资源耗尽。

使用示例:

通过一个具体的场景来展示其核心特性的应用:模拟在线购物平台中,用户下单后,系统需要异步执行三个任务——检查库存、验证用户支付能力和发送订单确认邮件,并在所有任务完成后,更新订单状态。

示例场景
  1. 检查库存:确认所购商品是否有足够的库存。
  2. 验证用户支付能力:检查用户的账户余额是否足够支付订单金额。
  3. 发送订单确认邮件:向用户邮箱发送订单确认信息。
代码示例:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class CompletableFutureDemo {

    public static void main(String[] args) throws Exception {
        // 创建一个线程池,用于执行异步任务
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 模拟用户下单
        Order order = new Order(1, "Product A", 100);

        // 异步检查库存
        CompletableFuture<Boolean> stockCheckFuture = CompletableFuture.supplyAsync(
                () -> checkStock(order), executor);

        // 异步验证用户支付能力
        CompletableFuture<Boolean> paymentValidationFuture = CompletableFuture.supplyAsync(
                () -> validatePayment(order), executor);

        // 异步发送订单确认邮件
        CompletableFuture<Void> emailSendingFuture = CompletableFuture.runAsync(
                () -> sendConfirmationEmail(order), executor);

        // 当所有任务完成时,更新订单状态
        CompletableFuture<Void> allTasks = CompletableFuture.allOf(
                stockCheckFuture, paymentValidationFuture, emailSendingFuture);

        // 等待所有任务完成
        allTasks.get(); // 注意:在实际生产中应避免使用get()阻塞主线程,这里仅作示例

        // 假设所有任务成功完成,更新订单状态
        updateOrderStatus(order, true);

        executor.shutdown();
    }

    // 检查库存的模拟方法
    private static boolean checkStock(Order order) {
        // ... 实际库存检查逻辑
        System.out.println("Checking stock for order: " + order);
        return true; // 假设库存充足
    }

    // 验证用户支付能力的模拟方法
    private static boolean validatePayment(Order order) {
        // ... 实际支付能力验证逻辑
        System.out.println("Validating payment for order: " + order);
        return true; // 假设支付能力充足
    }

    // 发送订单确认邮件的模拟方法
    private static void sendConfirmationEmail(Order order) {
        // ... 实际邮件发送逻辑
        System.out.println("Sending confirmation email for order: " + order);
    }

    // 更新订单状态的模拟方法
    private static void updateOrderStatus(Order order, boolean isSuccess) {
        if (isSuccess) {
            System.out.println("Order " + order + " processed successfully. Status updated.");
        } else {
            System.out.println("Order processing failed for " + order);
        }
    }

    // 订单类
    static class Order {
        int orderId;
        String productName;
        int amount;

        public Order(int orderId, String productName, int amount) {
            this.orderId = orderId;
            this.productName = productName;
            this.amount = amount;
        }

        @Override
        public String toString() {
            return "Order{" +
                    "orderId=" + orderId +
                    ", productName='" + productName + '\'' +
                    ", amount=" + amount +
                    '}';
        }
    }
}
解释说明
  • 使用CompletableFuture.supplyAsync来启动异步任务,对于有返回值的任务(如库存检查和支付能力验证)。
  • 使用CompletableFuture.runAsync来启动无返回值的任务(如发送邮件)。
  • 利用CompletableFuture.allOf来组合多个CompletableFuture实例,等待所有任务完成。
  • 通过get()方法阻塞等待所有任务完成(实际应用中,应避免在主线程中阻塞等待,可以考虑使用.thenAccept().thenRun()等方法继续异步处理)。
  • 在所有异步任务完成后,调用updateOrderStatus方法更新订单状态。

注意事项

1. 线程池的选择与管理
  • 选择合适的线程池:默认情况下,如果没有显式提供ExecutorCompletableFuture会使用ForkJoinPool.commonPool(),这适合CPU密集型任务。对于IO密集型任务或大量短期任务,考虑自定义单线程或固定大小的线程池。
  • 避免资源耗尽:合理设置线程池大小,避免因创建过多线程而导致资源耗尽或系统崩溃。
  • 及时关闭线程池:使用完毕后,通过shutdownshutdownNow方法关闭线程池,尤其是对于短生命周期的线程池。
2. 异常处理
  • 全面的异常捕捉:确保每个可能抛出异常的异步操作都有相应的异常处理逻辑,如使用exceptionallyhandle方法。
  • 避免异常丢失:如果不恰当处理,异常可能在异步链中被忽略,导致问题难以追踪。
3. 避免过度链式调用
  • 代码可读性:过度的链式调用会使代码变得难以阅读和维护。适时使用局部变量存储中间结果,或拆分为多个方法。
  • 性能考量:链式调用过长可能导致不必要的复杂性,影响性能,尤其是在异常处理和资源管理方面。
4. 合理使用组合方法
  • 并行与串行:理解.thenCompose.thenCombine.thenApply等方法的区别,合理安排任务的执行顺序和依赖关系。
  • allOf与anyOf:使用.allOf等待所有任务完成,或.anyOf等待任一任务完成,根据需求选择合适的方法。
5. 避免阻塞操作
  • 非阻塞性质:尽量避免在使用CompletableFuture时调用阻塞方法,如.get(),除非确实需要阻塞等待结果。考虑使用.join()或异步处理结果。
  • 超时处理:如果必须使用.get(),考虑设置超时参数,防止无限等待。
6. 资源泄漏预防
  • 外部资源管理:在异步任务中使用外部资源(如数据库连接、文件句柄)时,确保资源被正确关闭,即使任务异常终止也要清理资源。
7. 测试与调试
  • 测试难度:异步代码的测试通常比同步代码更复杂。确保为异步流程编写充分的单元测试和集成测试。
  • 日志记录:适当添加日志记录,特别是关键路径和异常处理部分,有助于调试和问题定位。
8. 并发控制与限流
  • 并发控制:对于需要限制并发度的操作,如数据库写入,可以使用Semaphore等工具控制并发访问。
  • 限流保护:对于高负载场景,考虑在入口处实施限流策略,避免因并发度过高导致的服务不稳定。

优缺点

优点
  1. 提高并发性与响应性:通过非阻塞的异步执行,CompletableFuture允许程序在等待某个操作完成的同时执行其他任务,显著提高了系统的并发处理能力和响应速度。

  2. 链式编程与易于组合:丰富的API支持链式调用,使得异步任务的组织和逻辑流转清晰明了,易于构建复杂的异步流程。同时,提供了多种组合操作,如.thenCompose().thenCombine(),使得任务间的协作和依赖管理变得简单。

  3. 强大的异常处理机制:通过.exceptionally().handle()等方法,CompletableFuture允许开发者优雅地处理异步执行过程中的异常,确保程序的健壮性。

  4. 灵活性与可定制性:开发者可以根据需要选择不同的线程池执行异步任务,或者利用.supplyAsync().runAsync()的重载方法指定特定的Executor,提供了高度的灵活性和对资源的控制能力。

  5. 易于测试与调试:虽然异步编程通常比同步编程更难测试,但通过明确的链式调用和异常处理逻辑,CompletableFuture的代码结构相对清晰,有助于单元测试和调试。

缺点
  1. 代码可读性与维护性:虽然链式调用提高了编码效率,但在处理复杂逻辑时,过度的链式可能会导致代码变得冗长且难以阅读,特别是当涉及到多个条件分支和异常处理时。

  2. 潜在的资源管理问题:如果不小心管理,尤其是在大量使用CompletableFuture时,可能会导致线程池资源耗尽,或因忘记关闭资源(如数据库连接)而引发资源泄漏。

  3. 调试难度:异步编程的调试相较于同步编程更为复杂。异常的传播和处理路径可能跨越多个异步阶段,使得定位问题变得更加困难。

  4. 潜在的性能开销:虽然异步执行可以提升整体性能,但如果任务本身非常轻量级,创建和管理CompletableFuture实例以及线程上下文切换的开销可能会抵消异步带来的好处。

  5. 阻塞风险:尽管鼓励非阻塞使用,但在某些场景下,如直接使用.get()方法等待结果,可能会导致线程阻塞,影响程序的响应性。

可能遇到的问题及解决方案

1. 死锁问题

问题描述:在使用CompletableFuture时,如果存在相互等待的情况,可能导致死锁。例如,一个任务的完成依赖于另一个任务的结果,而后者又反过来等待前者的完成。

解决方案:仔细设计任务之间的依赖关系,避免循环等待。使用正确的组合方法,如.thenCompose()而不是.thenApply()来避免不必要的阻塞等待。

2. 资源泄漏

问题描述:未正确管理外部资源(如数据库连接、文件句柄)可能导致资源泄漏,尤其是在异步任务异常终止时。

解决方案:确保使用try-with-resources语句或finally块来确保资源被正确关闭。对于异步操作中的资源,考虑使用自定义的CompletableFuture,以便在任务完成或异常时清理资源。

3. 异常处理不当

问题描述:异常信息可能在异步链中丢失,尤其是当使用.thenApply().thenCompose()等方法时,异常不会自动传递到链的下一个阶段。

解决方案:积极使用.exceptionally().handle()方法来捕获和处理异常,确保异常信息被妥善处理并记录。

4. 性能瓶颈

问题描述:不合理的线程池配置或过度使用CompletableFuture可能导致线程创建过多,消耗过多系统资源,甚至引起OutOfMemoryError。

解决方案:根据任务特性合理配置线程池,例如,对于IO密集型任务,使用较大的线程池;对于CPU密集型任务,线程池大小应接近可用处理器的数量。避免过度创建CompletableFuture实例,必要时复用已完成的实例。

5. 代码可读性差

问题描述:过度的链式调用和复杂的异步逻辑可能会降低代码的可读性和可维护性。

解决方案:适度分解复杂逻辑,将长链式调用分解为多个小方法或使用中间变量存储结果。对于复杂的流程控制,考虑使用设计模式(如状态模式、责任链模式)来简化逻辑。

6. 调试困难

问题描述:异步执行的非线性特性使得通过日志或调试器跟踪程序流程变得困难。

解决方案:利用日志记录关键步骤和异常信息,使用条件断点和线程Dump分析工具来辅助调试。在设计阶段,尽量使异步逻辑清晰有序,便于追踪问题。

7. 过度阻塞

问题描述:虽然CompletableFuture鼓励非阻塞使用,但不当使用.get().join()方法可能导致主线程或工作线程阻塞。

解决方案:尽量使用.thenApply().thenAccept()等非阻塞方法处理结果。若需等待多个任务完成,优先使用.allOf().anyOf()结合.thenRun(),而非直接阻塞等待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1661876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣HOT100 - 739. 每日温度

解题思路&#xff1a; 单调栈 class Solution {public int[] dailyTemperatures(int[] temperatures) {int length temperatures.length;int[] ans new int[length];Deque<Integer> stack new LinkedList<>();for (int i 0; i < length; i) {int temperatu…

TCP超时重传机制

一、TCP超时重传机制简介 TCP超时重传机制是指当发送端发送数据后&#xff0c;如果在一定时间内未收到接收端的确认应答&#xff0c;则会认为数据丢失或损坏&#xff0c;从而触发重传机制。发送端会重新发送数据&#xff0c;并等待确认应答。如果在多次重传后仍未收到确认应答&…

VMware Workstation 17 Player 创建虚拟机教程

本教程是以windows server 2012物理机服务器安装好的VMware Workstation 17 Player为例进行演示&#xff0c;安装VMware Workstation 17 Player大家可以自行网上搜索安装。 1、新建虚拟机 双击安装好的VMvare图标&#xff0c;点击创建虚拟机。 2、选择是否安装系统 本步骤选…

复习了好久的软考中项,现在上半年不考了,该怎么办?

如果有更多学习时间的话&#xff0c;可以考虑报考高级职称&#xff0c;因为高级和中级职称的很多知识点有重叠&#xff0c;只需要再复习一下相关论文就可以了。 从2024年下半年开始&#xff0c;集成考试将采用最新版教材和大纲&#xff0c;与高级职称的新版教材内容相似度很高…

Spring框架学习笔记(二):Spring IOC容器配置 Bean,分别基于XML配置bean 和 基于注解配置 bean

1 Spring 配置/管理 bean 介绍 Bean 管理包括两方面 &#xff1a;创建 bean 对象&#xff1b;给 bean 注入属性 Bean 配置方式&#xff1a;基于 xml 文件配置方式&#xff1b;基于注解方式 2 基于 XML 配置 bean 2.1 通过类型来获取 bean 方法&#xff1a;给getBean传入一…

新型AI Stable Artisan横空出世?

StabilityAI宣布推出Stable Artisan 前言 就在今天&#xff0c;Stability AI宣布推出 Stable Artisan&#xff0c;让更广泛的受众能够使用 Stability AI 的 Developer Platform API 功能。Stable Artisan 具有他们的高级型号&#xff0c;例如 Stable Diffusion 3、Stable Video…

4000字超详解Linux权限

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 在Linux当中权限的体现主要有两种 普通用户 超…

ARIMA模型在河流水质预测中的应用_含代码

#水质模型 #时间序列 #python应用 ARIMA 时间序列模型简介 时间序列是研究数据随时间变化而变化的一种算法&#xff0c;是一种预测性分析算法。它的基本出发点就是事物发展都有连续性&#xff0c;按照它本身固有的规律进行。ARIMA(p,d,q)模型全称为差分自回归移动平均模型 (A…

动态IP避坑指南:如何挑选合适的动态代理IP?

在如今的网络环境中&#xff0c;使用动态IP代理成为实现隐私保护、访问受限内容和提高网络效率的一种常见方式&#xff0c;选择合适的国外动态IP代理可以让我们的业务处理事半功倍。面对市面上琳琅满目的选择&#xff0c;如何挑选购买适合自己的动态IP代理服务呢&#xff1f;在…

数字化转型失败率80%!盘点国内数字化转型“失败案例”有哪些

尤记得几年前&#xff0c;那桩轰动一时的《国外某巨额投入的数字化转型项目失败所引起的法律纠纷案》。 当时&#xff0c;业界人士几乎都在热议这件事。 我也在了解整件事情的原委后&#xff0c;发表一些感想。 当时我就觉得&#xff0c;作为行业从业人员&#xff0c;不要幸…

动态表名 的使用方法

动态表名插件的底层是 拦截器 1&#xff0c;创建一个拦截器 Configuration public class MybatisConfiguration {Beanpublic DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {// 准备一个Map&#xff0c;用于存储TableNameHandlerMap<String, Table…

3d gaussian-splatting源码运行及结果展示

笔者是在windows下配置的环境 源码地址及官方教程 github gaussian-splatting 官网给出了详细的配置教程和视频解说 记录一下个人的部署过程 环境需求 硬件需求 具有计算能力 7.0 的带有CUDA的GPU 24G显存 软件需求 python版本我没注意到明确说明&#xff0c;3.7以上应…

用世界语言讲好中国故事 英孚青少儿“中华文化少年说”广州佛山展演开启

秉持“用世界语言&#xff0c;讲好中国故事”的初心&#xff0c;着眼于培养中国青少儿文化素养&#xff0c;提升青少儿文化自信&#xff0c;英孚教育青少儿近日在广州海珠乐峰广场举办了“中华文化少年说”10周年国宝季广佛展演。学员们在舞台上自信表达&#xff0c;用丰富的动…

机器学习算法应用——时间序列分析(4-5)

时间序列分析&#xff08;4-5&#xff09; 时间序列分析&#xff08;Time-Series Analysis&#xff09;是一种对按时间顺序排列的数据序列进行统计分析和预测的方法。这种方法通常用于研究某个现象随时间的变化规律&#xff0c;并据此预测未来的发展趋势。以下是时间序列分析的…

EasyExcel处理Mysql百万数据的导入导出案例,秒级效率,拿来即用!

一、写在开头 今天终于更新新专栏 《EfficientFarm》 的第二篇博文啦&#xff0c;本文主要来记录一下对于EasyExcel的高效应用&#xff0c;包括对MySQL数据库百万级数据量的导入与导出操作&#xff0c;以及性能的优化&#xff08;争取做到秒级性能&#xff01;&#xff09;。 …

【甲辰雜俎】世界上最不可靠的就是人

"世界上最不可靠的就是人" 人是一個多元的複變函數, 今天經受住考驗, 明天你就有可能叛變。 過去是戰場上的仇敵, 明天就有可能成為政治上的盟友。 —— 擷取自電視劇《黑冰》 人的不可預測性, 的確是一個普遍的現象。 每個人都是一個獨特的個體, 受到不同的…

Linux添加IP地址的方法

1.nmcli&#xff1a;命令式的添加IP地址 [rootlocalhost ~]#nmcli connection modify eno16777736 ipv4.addresses 192.168.126.100/24 ipv4.gateway 192.168.126.1 ipv4.method manual connection.autoconnect yes [rootlocalhost ~]# nmcli connection modify eno16777736 i…

第十三届蓝桥杯决赛(国赛)真题 Java C 组【原卷】

文章目录 发现宝藏试题 A: 斐波那契与 7试题 B: 小蓝做实验试题 C: 取模试题 D: 内存空间试题 E \mathrm{E} E : 斐波那契数组试题 F: 最大公约数试题 G: 交通信号试题 I: 打折试题 J: 宝石收集 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#x…

WPF之绑定属性值转换

1&#xff0c;使用Binding.Format属性简易设置绑定的属性数据显示格式。 <TextBox Grid.Row"2" Grid.Column"1"><TextBox.Text><Binding Path"UnitCost" StringFormat"{}{0:C3}" > …

深入理解Django:中间件与信号处理的艺术

title: 深入理解Django&#xff1a;中间件与信号处理的艺术 date: 2024/5/9 18:41:21 updated: 2024/5/9 18:41:21 categories: 后端开发 tags: Django中间件信号异步性能缓存多语言 引言 在当今的Web开发领域&#xff0c;Django以其强大的功能、简洁的代码结构和高度的可扩…