【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【15】异步_线程池


持续学习&持续更新中…

守破离


【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【15】异步_线程池

  • 初始化线程的 4 种方式
  • 开发中为什么使用线程池
  • 线程池七大参数
  • 线程池工作原理
  • 常见的 4 种线程池
  • 生产中如何使用线程池?
  • CompletableFuture 异步编排—简介
    • 业务场景
    • 简介
  • CompletableFuture—创建(run/supply)
  • CompletableFuture—计算完成(whenComplete)
  • CompletableFuture—处理(handle)
  • CompletableFuture—线程串行化方法
  • CompletableFuture—两任务组合—都要完成(Both/Combine)
  • CompletableFuture—两任务组合—一个完成(Either)
  • CompletableFuture—多任务组合
  • 参考

初始化线程的 4 种方式

1)、继承 Thread
2)、实现 Runnable 接口
3)、实现 Callable 接口 + FutureTask (可以拿到返回结果,可以处理异常)
4)、线程池

  • 方式 1 和方式 2:主进程无法获取线程的运算结果。不适合当前场景,也会导致资源耗尽

  • 方式 3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。极大可能导致服务器资源耗尽。

  • 我们以后在业务代码里面,方式123,这三种启动线程的方式都不用。可能会导致资源耗尽【应该将所有的多线程异步任务都交给线程池执行】

  • 方式 4:通过如下两种方式初始化线程池(当前系统中线程池最好只有一两个,每个异步任务,提交给线程池让他自己去执行就行)

    • 1、Executors.newFiexedThreadPool(3);

    • 2、new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit unit, workQueue, threadFactory, handler);

开发中为什么使用线程池

  • 降低资源的消耗:通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗

  • 提高响应速度:因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于 等待分配任务 的状态,当任务来时无需创建新的线程就能执行

  • 提高线程的可管理性:线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

    public static void main(String[] args)  throws ExecutionException, InterruptedException {System.out.println("main....start....");/*** 1)、继承Thread*         Thread01 thread = new Thread01();*         thread.start();//启动线程** 2)、实现Runnable接口*         Runable01 runable01 = new Runable01();*         new Thread(runable01).start();* 3)、实现Callable接口 + FutureTask (可以拿到返回结果,可以处理异常)*         FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());*         new Thread(futureTask).start();*         //阻塞等待整个线程执行完成,获取返回结果*         Integer integer = futureTask.get();* 4)、线程池[ExecutorService]*         给线程池直接提交任务。*         service.execute(new Runable01());*     创建:*            1)、Executors*            2)、new ThreadPoolExecutor**      Future:可以获取到异步结果** 区别;*      1、2不能得到返回值。3可以获取返回值*      1、2、3都不能控制资源*      4可以控制资源,性能稳定。*///        new Thread(()-> System.out.println("hello")).start();//我们以后再业务代码里面,以上三种启动线程的方式都不用。可能会导致资源耗尽【应该将所有的多线程异步任务都交给线程池执行】
//        executor.execute(new Runable01());
//        Future<?> submit = executor.submit(new Thread01());
//        Object o = submit.get();
//        System.out.println(o);//当前系统中线程池最好只有一两个,每个异步任务,提交给线程池让他自己去执行就行/*** 七大参数* corePoolSize:核心线程数[一直存在除非设置allowCoreThreadTimeOut]; 线程池创建好以后就会准备就绪这些数量的线程,它们等待接受异步任务去执行。*        5个  Thread thread = new Thread();  thread.start();* maximumPoolSize:[200] 最大线程数量;  控制资源* keepAliveTime:存活时间。如果当前的线程池中的线程数量大于core线程数量。*                          并且只要线程空闲时间大于指定的keepAliveTime,也就是线程在最大多长时间没有接到新任务*                          就会释放(maximumPoolSize-corePoolSize)数量空闲的线程,最终线程池维持在 corePoolSize大小** unit:时间单位* BlockingQueue<Runnable> workQueue:阻塞队列。如果任务有很多,就会将目前多的任务放在队列里面。*              只要有线程空闲,就会去队列里面取出新的任务继续执行。* threadFactory:线程的创建工厂。* RejectedExecutionHandler handler:如果队列满了,按照我们指定的拒绝策略拒绝执行任务**** 工作顺序:* 1)、线程池创建,准备好core数量的核心线程,准备接受任务* 1.1、core满了,就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行* 1.2、阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量* 1.3、max满了就用RejectedExecutionHandler拒绝任务* 1.4、max都执行完成,有很多空闲.在指定的时间keepAliveTime以后,释放max-core这些线程**      new LinkedBlockingDeque<>():默认是Integer的最大值。内存不够** 一个线程池 core 7; max 20 ,queue:50,100并发进来怎么分配的;* 7个会立即得到执行,50个会进入队列,再开13个进行执行。剩下的30个就使用拒绝策略。* 如果不想抛弃还要执行。CallerRunsPolicy;**/ExecutorService executor = new ThreadPoolExecutor(5,200,10,TimeUnit.SECONDS,new LinkedBlockingDeque<>(100000),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
//        Executors.newCachedThreadPool() core是0,所有都可回收
//        Executors.newFixedThreadPool() 固定大小,core=max;都不可回收
//        Executors.newScheduledThreadPool() 定时任务的线程池
//        Executors.newSingleThreadExecutor() 单线程的线程池,后台从队列里面获取任务,挨个执行//System.out.println("main....end....");}

线程池七大参数

在这里插入图片描述

在这里插入图片描述

corePoolSize:

  • the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set
  • 核心线程数[一直存在除非设置allowCoreThreadTimeOut];
  • 线程池创建好以后就会将这些数量的线程准备就绪,它们等待接受异步任务去执行。

maximumPoolSize:

  • the maximum number of threads to allow in the pool
  • 最大线程数量;
  • 可以控制资源

keepAliveTime:

  • when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
  • 存活时间。
  • 如果当前的线程池中的线程数量大于core线程数量。
  • 并且只要这些多余的空闲线程空闲时间大于指定的keepAliveTime,也就是线程在最大多长时间没有接到新任务
  • 就会释放(maximumPoolSize-corePoolSize)数量空闲的线程,最终使得线程池维持在 corePoolSize 大小

unit:

  • the time unit for the keepAliveTime argument
  • 时间单位

workQueue(阻塞队列)

  • the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.
  • 如果任务有很多,就会将目前多的任务放在队列里面。
  • 队列用来存储等待执行的任务,只要有线程空闲,就会去队列里面取出新的任务继续执行。

threadFactory:

  • the factory to use when the executor creates a new thread
  • 线程的创建工厂。

handler:(RejectedExecutionHandler)

  • the handler to use when execution is blocked because the thread bounds and queue capacities are reached
  • 如果队列满了,按照我们指定的拒绝策略拒绝执行任务:
    • AbortPolicy【默认】:直接拒绝策略,也就是不会执行任务,直接抛出RejectedExecutionException,这是默认的拒绝策略。
    • DiscardPolicy:抛弃策略,也就是直接忽略提交的任务(通俗来说就是空实现)。
    • DiscardOldestPolicy:抛弃最老任务策略,也就是通过poll()方法取出任务队列队头的任务抛弃,然后执行当前提交的任务。
    • CallerRunsPolicy:调用者执行策略,也就是当前调用Executor#execute()的线程直接调用任务Runnable.run(),一般不希望任务丢失会选用这种策略,但从实际角度来看,原来的异步调用意图会退化为同步调用。

线程池工作原理

在这里插入图片描述

在这里插入图片描述

文字描述:

  • 在创建了线程池后,开始等待请求。

  • 当调用execute()方法添加一个请求任务时,线程池会做出如下判断:

    • 如果正在运行的线程数量小于corePoolSize,那么马上创建核心线程运行这个任务;
    • 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列;
    • 如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
    • 如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。
  • 当一个线程完成任务时,它会从队列中取下一个任务来执行。

  • 当一个线程无事可做超过一定的时间(keepAliveTime)时,线程会判断:

    • 如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。
    • 所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小。

常见的 4 种线程池

在这里插入图片描述

在这里插入图片描述

点进源码可以去看一看:Executors.newCachedThreadPool() core是0,所有都可回收
Executors.newFixedThreadPool() 固定大小,core=max;都不可回收
Executors.newScheduledThreadPool() 定时任务的线程池
Executors.newSingleThreadExecutor() 单线程的线程池,后台从队列里面获取任务,挨个执行

生产中如何使用线程池?

在工作中 单一的/固定数的/可变的 三种创建线程池的方法哪个用的多?

答案是一个都不用,我们工作中只能使用自定义的

Executors中JDK已经给你提供了,为什么不用?

在这里插入图片描述

一般不要把最大线程数写死:

    final int availableProcessors = Runtime.getRuntime().availableProcessors();int maximumPoolSize = availableProcessors + 1;ExecutorService threadPool = new ThreadPoolExecutor(2,maximumPoolSize,200L,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()//   new ThreadPoolExecutor.CallerRunsPolicy()//   new ThreadPoolExecutor.DiscardPolicy()//    new ThreadPoolExecutor.DiscardOldestPolicy());

CompletableFuture 异步编排—简介

业务场景

通过线程池性能稳定,也可以获取执行结果,并捕获异常。

但是,在业务复杂情况下,一 个异步调用可能会依赖于另一个异步调用的执行结果。

业务场景: 查询商品详情页的逻辑比较复杂(第4/5/6步需要获取到第1步的数据才能去查询),有些数据还需要远程调用,必然需要花费更多的时间。

在这里插入图片描述

假如商品详情页的每个查询,需要以上标注的时间之和才能完成,那么,用户需要 5.5s 后才能看到商品详情页的内容。很显然是不能接受的。

如果有多个线程同时完成这 6 步操作,也许只需要 1.5s(某个最大耗时) 即可完成响应。

简介

  • Future 是 Java 5 添加的类,用来描述一个异步计算的结果。你可以使用isDone方法检查计 算是否完成,或者使用get阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel 方法停止任务的执行。

  • 虽然Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不 方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的 初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果,为 什么不能用观察者设计模式当计算结果完成及时通知监听者呢?

  • 很多语言,比如 Node.js,采用回调的方式实现异步编程。Java 的一些框架,比如 Netty,自 己扩展了 Java 的 Future接口,提供了addListener等多个扩展方法;Google guava 也提供了 通用的扩展 Future;Scala 也提供了简单易用且功能强大的 Future/Promise 异步编程模式。
    作为正统的 Java 类库,是不是应该做点什么,加强一下自身库的功能呢?

  • 在 Java 8 中, 新增加了一个包含 50 个方法左右的类: CompletableFuture,提供了非常强大的 Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以 通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture 的方法。

  • CompletableFuture 类实现了 Future 接口,所以你还是可以像以前一样通过get方法阻塞或 者轮询的方式获得结果,但是这种方式不推荐使用。

  • CompletableFuture 和 FutureTask 同属于 Future 接口的实现类,都可以获取线程的执行结果。

在这里插入图片描述

CompletableFuture—创建(run/supply)

在这里插入图片描述

  • runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的

  • 可以传入自定义的线程池,否则就用默认的线程池;

CompletableFuture—计算完成(whenComplete)

在这里插入图片描述

  • whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况。

  • whenComplete 和 whenCompleteAsync 的区别:

    • whenComplete:是执行当前任务的线程(创建该CompletableFuture的线程)继续执行 whenComplete的任务。
    • whenCompleteAsync:是把 whenCompleteAsync 这个任务继续提交给线程池来执行。
  • 方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程 执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {System.out.println("当前线程:" + Thread.currentThread().getId());int i = 10 / 0;System.out.println("运行结果:" + i);return i;
}, executor).whenComplete((res,excption)->{//虽然能得到异常信息,但是没法修改返回数据。System.out.println("异步任务成功完成了...结果是:"+res+";异常是:"+excption);
}).exceptionally(throwable -> {//可以感知异常,同时返回默认值return 10;
});
    public static void main(String[] args) throws Exception {System.out.println(Thread.currentThread().getName());CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\tfuture");return 1024;});completableFuture.whenComplete((t, u) -> {System.out.println(Thread.currentThread().getName() + "\twhenComplete");}).exceptionally(f -> {return 4444;}).get();Thread.sleep(3000);System.out.println(Thread.currentThread().getName());new Thread(() -> {CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\tfuture");return 1024;});try {future.whenComplete((t, u) -> {System.out.println(Thread.currentThread().getName() + "\twhenComplete");}).exceptionally(f -> {return 4444;}).get();} catch (Exception e) {e.printStackTrace();}}, "线程a").start();
//Thread.sleep(3000);System.out.println(Thread.currentThread().getName());new Thread(() -> {CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + "\tfuture");return 1024;});try {future.whenCompleteAsync((t, u) -> {System.out.println(Thread.currentThread().getName() + "\twhenCompleteAsync");}).exceptionally(f -> {return 4444;}).get();} catch (Exception e) {e.printStackTrace();}}, "线程b").start();}

CompletableFuture—处理(handle)

在这里插入图片描述

和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。

        /*** 方法执行完成后的处理【无论成功完成还是失败完成】*/CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {System.out.println("当前线程:" + Thread.currentThread().getId());int i = 10 / 4;i = i / 0;System.out.println("运行结果:" + i);return i;}, executor).handle((res, thr) -> {if (res != null) {return res * 2;}if (thr != null) {return 0;}return 0;});
//        R apply(T t, U u);System.out.println(future.get());Thread.sleep(50000);if(1==1) throw new RuntimeException();

CompletableFuture—线程串行化方法

在这里插入图片描述

  • 带有 Async 默认是异步执行的。同之前。

  • thenRun方法:【不接收,不返回】只要上面的任务执行完成,就开始执行thenRun。

  • thenAccept方法:【只接收,无返回】能接收消费上一步处理的结果,无返回结果。

  • thenApply方法:【既接收,又返回】当一个线程依赖另一个线程时,获取上一个任务返回的结果,并且当前任务也有返回值可以传递给下一个异步任务。

/*** 线程串行化* 1)、thenRun:不能获取到上一步的执行结果,无返回值*  .thenRunAsync(() -> {*             System.out.println("任务2启动了...");*         }, executor);* 2)、thenAcceptAsync;能接受上一步结果,但是无返回值* 3)、thenApplyAsync:;能接受上一步结果,有返回值*/CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {System.out.println("当前线程:" + Thread.currentThread().getId());int i = 10 / 4;System.out.println("运行结果:" + i);return i;}, executor).thenApplyAsync(res -> {System.out.println("任务2启动了..." + res);return "Hello " + res;}, executor);future.get() //阻塞方法

CompletableFuture—两任务组合—都要完成(Both/Combine)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 两个任务必须都完成,触发该任务。

  • thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值

  • thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有 返回值。

  • runAfterBoth:组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后, 处理该任务。

        /*** 两个都完成*/CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {System.out.println("任务1线程:" + Thread.currentThread().getId());int i = 10 / 4;System.out.println("任务1结束:");return i;}, executor);CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {System.out.println("任务2线程:" + Thread.currentThread().getId());try {Thread.sleep(3000);System.out.println("任务2结束:");} catch (InterruptedException e) {e.printStackTrace();}return "Hello";}, executor);//        future01.runAfterBothAsync(future02, () -> {
//            System.out.println("任务3开始...runAfterBothAsync");
//        }, executor);
//
//        future01.thenAcceptBothAsync(future02, (f1, f2) -> {
//            System.out.println("任务3开始...之前的结果thenAcceptBothAsync:" + f1 + "--》" + f2);
//        }, executor);CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {return f1 + "  :" + f2 + " -> Haha       thenCombineAsync";}, executor);System.out.println(future.get());

CompletableFuture—两任务组合—一个完成(Either)

在这里插入图片描述
在这里插入图片描述

  • 当两个任务中,任意一个 future 任务完成的时候,执行任务。

  • applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。

  • acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。

  • runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返 回值。

        /*** 两个任务,只要有一个完成,我们就执行任务3* runAfterEitherAsync:不感知结果,自己没有返回值* acceptEitherAsync:感知结果,自己没有返回值* applyToEitherAsync:感知结果,自己有返回值*/
//        future01.runAfterEitherAsync(future02, () -> {
//            System.out.println("任务3开始...没有之前的结果");
//        }, executor);
//        future01.acceptEitherAsync(future02, (res) -> {
//            System.out.println("任务3开始...之前的结果:" + res);
//        }, executor);CompletableFuture<String> future = future01.applyToEitherAsync(future02, res -> {System.out.println("任务3开始...之前的结果:" + res);return res.toString() + "->哈哈";}, executor);System.out.println(future.get());

CompletableFuture—多任务组合

在这里插入图片描述

  • allOf:等待所有任务完成

  • anyOf:只要有一个任务完成

        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {System.out.println("查询商品的图片信息" + Thread.currentThread().getName());return "hello.jpg";}, executor);CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("查询商品的属性");return "黑色+256G";}, executor);CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);System.out.println("查询商品介绍");} catch (InterruptedException e) {e.printStackTrace();}return "华为";}, executor);CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);allOf.get();//等待所有结果完成System.out.println("main....end....");System.out.println(futureImg.get() + "=>" + futureAttr.get() + "=>" + futureDesc.get()); //直接拿来future的结果来用//        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
//        anyOf.get();//等待任意一个结果完成
//        System.out.println("main....end....");
//        System.out.println(anyOf.get());

参考

雷丰阳: Java项目《谷粒商城》Java架构师 | 微服务 | 大型电商项目.

Throwable: 硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理.

话唠扇贝: 线程池 ThreadPoolExecutor 详解.


本文完,感谢您的关注支持!


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

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

相关文章

selenium4如何指定chrome和firefox的驱动(driver)路径

pythonpytestselenium框架的自动化测试脚本。 原本用的chrome&#xff0c;很久没用了&#xff0c;今天执行&#xff0c;发现chrome偷偷升级&#xff0c;我的chromedriver版本不对了。。。鉴于访问chrome相关网站太艰难&#xff0c;决定弃用chrome&#xff0c;改用firefox。因为…

2.SQL注入-字符型

SQL注入-字符型(get) 输入kobe查询出现id和邮箱 猜测语句,字符在数据库中需要用到单引号或者双引号 select 字段1,字段2 from 表名 where usernamekobe;在数据库中查询对应的kobe&#xff0c;根据上图对应上。 select id,email from member where usernamekobe;编写payload语…

JAVA期末速成库(10)第十一章

一、习题介绍 Check Point&#xff1a;P416 11.1&#xff0c;11.6&#xff0c;11.7&#xff0c;11.8&#xff0c;11.12&#xff0c;11.17&#xff0c;11.24 Programming Exercise&#xff1a;11.1 二、习题及答案 Check Point&#xff1a; 11.1 True or false? A subcl…

CST--如何在PCB三维模型中自由创建离散端口

在使用CST电磁仿真软件进行PCB的三维建模时&#xff0c;经常会遇到不能自动创建离散端口的问题&#xff0c;原因有很多&#xff0c;比如&#xff1a;缺少元器件封装、开路端口、多端子模型等等&#xff0c;这个时候&#xff0c;很多人会选择手动进行端口创建&#xff0c;但是&a…

【redis】Redis AOF

1、AOF的基本概念 AOF持久化方式是通过保存Redis所执行的写命令来记录数据库状态的。AOF以日志的形式来记录每个写操作&#xff08;增量保存&#xff09;&#xff0c;将Redis执行过的所有写指令记录下来&#xff08;读操作不记录&#xff09;。AOF文件是一个只追加的文件&…

已解决javax.security.auth.login.LoginException:登录失败的正确解决方法,亲测有效!!!

已解决javax.security.auth.login.LoginException&#xff1a;登录失败的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 出现问题的场景 报错原因 解决思路 解决方法 1. 检查用户名和密码 用户名和密码验证 2. 验证配置文件 …

Spark基于DPU的Native引擎算子卸载方案

1.背景介绍 Apache Spark&#xff08;以下简称Spark&#xff09;是一个开源的分布式计算框架&#xff0c;由UC Berkeley AMP Lab开发&#xff0c;可用于批处理、交互式查询&#xff08;Spark SQL&#xff09;、实时流处理&#xff08;Spark Streaming&#xff09;、机器学习&a…

昇思25天学习打卡营第5天|MindSpore-ResNet50图像分类

MindSpore-ResNet50图像分类 CIFAR-10数据集 CIFAR-10数据集是一个广泛使用的图像分类数据集,它包含了60,000张32x32的RGB彩色图像,分为10个类别,每个类别有6,000张图像。这些类别包括飞机(airplane)、汽车(automobile)、鸟类(bird)、猫(cat)、鹿(deer)、狗(dog…

Echarts地图实现:山东省报考人数

Echarts地图实现&#xff1a;山东省报考人数 效果预览 设计思路 数据可视化&#xff1a;选择地图作为数据展示的方式&#xff0c;可以直观地展示山东省不同城市的报考人数分布。交互性&#xff1a;通过ECharts的交互功能&#xff0c;如提示框&#xff08;tooltip&#xff09;…

《晨集》开源软件平台的创新与发展

一、引言 在数字化浪潮的推动下&#xff0c;开源软件平台已成为推动软件创新、促进知识共享的重要力量。《晨集》作为新兴的开源软件平台&#xff0c;其上线标志着开源生态圈的又一重要里程碑。本文旨在探讨《晨集》开源软件平台的创新特点、对开发者社区的影响以及未来发展趋…

JavaWeb系列十七: jQuery选择器 上

jQuery选择器 jQuery基本选择器jquery层次选择器基础过滤选择器内容过滤选择器可见度过滤选择器 选择器是jQuery的核心, 在jQuery中, 对事件处理, 遍历 DOM和Ajax 操作都依赖于选择器jQuery选择器的优点 $(“#id”) 等价于 document.getElementById(“id”);$(“tagName”) 等价…

【数据可视化技术】1、如何使用Matplotlib和Seaborn库在Python中绘制热力图

热力图是一种数据可视化技术&#xff0c;可以显示变量之间的相关性。这个代码段是数据分析和可视化的常用方法&#xff0c;特别适合于展示变量之间的相关性&#xff0c;对于数据科学和机器学习项目非常有帮助。 1、 导入必要的库 首先&#xff0c;确保你已经安装了matplotlib…

收银系统源码-千呼新零售【分销商城】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

水位自动监测摄像机

随着科技的不断进步&#xff0c;水位自动监测摄像机作为现代智能监控技术的重要应用&#xff0c;正在广泛应用于水利工程、防洪管理和环境监测等领域&#xff0c;显著提升了监测效率和数据准确性。水位自动监测摄像机利用高精度摄像头和先进的图像处理技术&#xff0c;能够实时…

鸿蒙系统——强大的分布式系统

鸿蒙相比较于传统安卓最最最主要的优势是微内核分布式操作系统&#xff0c;具有面向未来&#xff0c;跨设备无缝协作&#xff0c;数据共享的全场景体验。下面简单来感受一下鸿蒙系统的多端自由流转。 自由流转概述 场景介绍 随着全场景多设备的生活方式不断深入&#xff0c;…

解释什么是lambda函数?它有什么好处?

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

深度解密Spark性能优化之道

课程介绍 课程通过实战案例解析和性能调优技巧的讲解&#xff0c;帮助学员提升大数据处理系统的性能和效率。课程内容涵盖了Spark性能调优的各个方面&#xff0c;包括内存管理、并行度设置、数据倾斜处理、Shuffle调优、资源配置等关键技术和策略。学员将通过实际案例的演示和…

线性代数知识点搜刮

求你别考太细... 目录 异乘变零定理 行列式转置 值不变 重要关系 中间相等&#xff0c;取两头 特征值公式 向量正交 点积为0 拉普拉斯定理 矩阵的秩 特征值和特征向量 |A|特征值的乘积 & tr(A)特征值的和 要记要背 增广矩阵 异乘变零定理 某行&#xff08;…

【面试干货】Object 类中的公共方法详解

【面试干货】Object 类中的公共方法详解 1、clone() 方法2、equals(Object obj) 方法3、hashCode() 方法4、getClass() 方法5、wait() 方法6、notify() 和 notifyAll() 方法 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在 Java 中&#…

报工计件工资核算h5开源版开发

报工计件工资核算h5开源版开发 小型计件工资管理系统&#xff0c;支持后台制定工价&#xff0c;核算工资。支持员工H5端报工&#xff0c;和查看工资情况。 H5手机端 支持在线报工&#xff0c;支持查看我的工资。 自定义费用项 在基础计件工资基础上增加扣除和增加项&#xff…