Java调优

news2024/11/17 23:31:44

Java调优

Java 性能调优不像是学一门编程语言,无法通过直线式的思维来掌握和应用,它对于工程师的技术广度和深度都有着较高的要求。

互联网时代,一个简单的系统就囊括了应用程序、数据库、容器、操作系统、网络等技术,线上一旦出现性能问题,就可能要你协调多方面组件去进行优化,这就是技术广度;而很多性能问题呢,又隐藏得很深,可能因为一个小小的代码,也可能因为线程池的类型选择错误…可归根结底考验的还是我们对这项技术的了解程度,这就是技术深度。

调优的前提

扎实的计算机基础

我们调优的对象不是单一的应用服务,而是错综复杂的系统。应用服务的性能可能与操作系统、网络、数据库等组件相关,所以我们需要储备计算机组成原理、操作系统、网络协议以及数据库等基础知识。具体的性能问题往往还与传输、计算、存储数据等相关,那我们还需要储备数据结构、算法以及数学等基础知识。

习惯透过源码了解技术本质

学习方式可以通过论坛,博客,官网等。又因为论坛,博客上的大部分内容都是生产者自己吸收消化后总结的知识点,能帮助我们快速获取、快速理解。但是只做到这个程度还不够,因为缺失了自己的判断。这么解决我们需要深入源码,通过分析来学习、总结一项技术的实现原理和优缺点,这样我们就能更客观地去学习一项技术,还能透过源码来学习牛人的思维方式,收获更好的编码实现方式。

善于追问和总结

很多同学在使用一项技术时,只是因为这项技术好用就用了,从来不问自己:为什么这项技术可以提升系统性能?对比其他技术它好在哪儿?实现的原理又是什么呢?事实上,“知其然且知所以然”才是我们积累经验的关键。知道了一项技术背后的实现原理,我们才能在遇到性能问题时,做到触类旁通

优化模块

概述

  • 性能调优标准,告诉你可以通过哪些参数去衡量系统性能;

  • 调优过程标准,带你了解通过哪些严格的调优策略,我们可以排查性能问题,从而解决问题。

Java 编程性能调优

JDK 是 Java 语言的基础库,熟悉 JDK 中各个包中的工具类,可以帮助你编写出高性能代码。这里我会从基础的数据类型讲起,涉及容器在实际应用场景中的调优,还有现在互联网系统架构中比较重要的网络通信调优。

多线程性能调优

目前大部分服务器都是多核处理器,多线程编程的应用广泛。为了保证线程的安全性,通常会用到同步锁,这会为系统埋下很多隐患;除此之外,还有多线程高并发带来的性能问题,这些都会在这个模块重点讲解。

JVM 性能监测及调优

Java 应用程序是运行在 JVM 之上的,对 JVM 进行调优可以提升系统性能。这里重点讲解 Java 对象的创建和回收、内存分配等。

设计模式调优

在架构设计中,我们经常会用到一些设计模式来优化架构设计。这里我将结合一些复杂的应用场景,分享设计优化案例。模块六,数据库性能调优。数据库最容易成为整个系统的性能瓶颈,这里我会重点解析一些数据库的常用调优方法。

实战演练场

以上六个模块的内容,都是基于某个点的调优,现在是时候把你前面所学都调动起来了,这里我将带你进入综合性能问题高频出现的应用场景,学习整体调优方法。

性能调优标准

为什么要做性能调优

一款线上产品如果没有经过性能测试,那它就好比是一颗定时炸弹,不知道它什么时候会出现问题,也不清楚它能承受的极限在哪儿。

有些性能问题是时间累积慢慢产生的,到了一定时间自然就爆炸了;而更多的性能问题是由访问量的波动导致的,例如,活动或者公司产品用户量上升;当然也有可能是一款产品上线后就半死不活,一直没有大访问量,所以还没有引发这颗定时炸弹。

现在假设你的系统要做一次活动,产品经理或者老板告诉你预计有几十万的用户访问量,询问系统能否承受得住这次活动的压力。如果你不清楚自己系统的性能情况,也只能战战兢兢地回答老板,有可能大概没问题吧。

所以,要不要做性能调优,这个问题其实很好回答。所有的系统在开发完之后,多多少少都会有性能问题,我们首先要做的就是想办法把问题暴露出来,例如进行压力测试、模拟可能的操作场景等等,再通过性能调优去解决这些问题。

比如,当你在用某一款 App 查询某一条信息时,需要等待十几秒钟;在抢购活动中,无法进入活动页面等等。你看,系统响应就是体现系统性能最直接的一个参考因素。

好的系统性能调优不仅仅可以提高系统的性能,还能为公司节省资源。这也是我们做性能调优的最直接的目的。

什么时候开始调优

如果需要对系统做一次全面的性能监测和优化,从什么时候开始介入性能调优呢?是不是越早介入越好?

在开发初期我们没必要在意性能调优,这样反而会让我们疲于性能优化,不仅不会给系统性能带来提升,还会影响到开发进度,甚至获得相反的效果,给系统带来新的问题。

我们只需要在代码层面保证有效的编码,比如,减少磁盘 I/O 操作、降低竞争锁的使用以及使用高效的算法等等。遇到比较复杂的业务,我们可以充分利用设计模式来优化业务代码。例如,设计商品价格的时候,往往会有很多折扣活动、红包活动,我们可以用装饰模式去设计这个业务。

在系统编码完成之后,我们就可以对系统进行性能测试了。这时候,产品经理一般会提供线上预期数据,我们在提供的参考平台上进行压测,通过性能分析、统计工具来统计各项性能指标,看是否在预期范围之内。

在项目成功上线后,我们还需要根据线上的实际情况,依照日志监控以及性能统计日志,来观测系统性能问题,一旦发现问题,就要对日志进行分析并及时修复问题。

哪些参考因素可以体现系统的性能

CPU

  • 有的应用需要大量计算,他们会长时间、不间断地占用 CPU 资源,导致其他资源无法争夺到 CPU 而响应缓慢,从而带来系统性能问题。例如,代码递归导致的无限循环,正则表达式引起的回溯,JVM 频繁的 FULL GC,以及多线程编程造成的大量上下文切换等,这些都有可能导致 CPU 资源繁忙。

内存

  • Java 程序一般通过 JVM 对内存进行分配管理,主要是用 JVM 中的堆内存来存储
    Java 创建的对象。系统堆内存的读写速度非常快,所以基本不存在读写性能瓶颈。但是由于内存成本要比磁盘高,相比磁盘,内存的存储空间又非常有限。所以当内存空间被占满,对象无法回收时,就会导致内存溢出、内存泄露等问题。

磁盘I/O

  • 磁盘相比内存来说,存储空间要大很多,但磁盘 I/O 读写的速度要比内存慢,
    虽然目前引入的 SSD 固态硬盘已经有所优化,但仍然无法与内存的读写速度相提并论。

网络

  • 网络对于系统性能来说,也起着至关重要的作用。如果你购买过云服务,一定经历过,选择网络带宽大小这一环节。带宽过低的话,对于传输数据比较大,或者是并发量比较大的系统,网络就很容易成为性能瓶颈。

异常

  • Java 应用中,抛出异常需要构建异常栈,对异常进行捕获和处理,这个过程非常消耗系统性能。如果在高并发的情况下引发异常,持续地进行异常处理,那么系统的性能就会明显地受到影响。

数据库

  • 大部分系统都会用到数据库,而数据库的操作往往是涉及到磁盘 I/O 的读写。大量的数据库读写操作,会导致磁盘 I/O 性能瓶颈,进而导致数据库操作的延迟性。对于有大量数据库读写操作的系统来说,数据库的性能优化是整个系统的核心。

锁竞争

  • 在并发编程中,我们经常会需要多个线程,共享读写操作同一个资源,这个时候为了保持数据的原子性(即保证这个共享资源在一个线程写的时候,不被另一个线程修改),我们就会用到锁。锁的使用可能会带来上下文切换,从而给系统带来性能开销。JDK1.6 之后,Java 为了降低锁竞争带来的上下文切换,对 JVM 内部锁已经做了多次优化,例如,新增了偏向锁、自旋锁、轻量级锁、锁粗化、锁消除等。而如何合理地使用锁资源,优化锁资源,就需要你了解更多的操作系统知识、Java 多线程编程基础,积累项目经验,并结合实际场景去处理相关问题。

响应时间

响应时间是衡量系统性能的重要指标之一,响应时间越短,性能越好,一般一个接口的响应时间是在毫秒级。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T4obnGab-1687328295657)(Java优化.assets/image-20220913160357287.png)]

  • 数据库响应时间:

    • 数据库操作所消耗的时间,往往是整个请求链中最耗时的;
  • 服务端响应时间:

    • 服务端包括 Nginx 分发的请求所消耗的时间以及服务端程序执行所消
  • 耗的时间;

    • 网络响应时间:这是网络传输时,网络硬件需要对传输的请求进行解析等操作所消耗的时间;
  • 客户端响应时间:

    • 对于普通的 Web、App 客户端来说,消耗时间是可以忽略不计的,但如果你的客户端嵌入了大量的逻辑处理,消耗的时间就有可能变长,从而成为系统的瓶颈。

吞吐量

在测试中,我们往往会比较注重系统接口的 TPS(每秒事务处理量),因为 TPS 体现了接口的性能,TPS 越大,性能越好。在系统中,我们也可以把吞吐量自下而上地分为两种:磁盘吞吐量网络吞吐量

我们先来看磁盘吞吐量,磁盘性能有两个关键衡量指标。

一种是 IOPS(Input/Output Per Second),即每秒的输入输出量(或读写次数),这种是指单位时间内系统能处理的 I/O 请求数量,I/O 请求通常为读或写数据操作请求,关注的是随机读写性能。适应于随机读写频繁的应用,如小文件存储(图片)、OLTP 数据库、邮件服务器。

另一种是数据吞吐量,这种是指单位时间内可以成功传输的数据量。对于大量顺序读写频繁的应用,传输大量连续数据,例如,电视台的视频编辑、视频点播 VOD(Video OnDemand),数据吞吐量则是关键衡量指标。

接下来看网络吞吐量,这个是指网络传输时没有帧丢失的情况下,设备能够接受的最大数据速率。网络吞吐量不仅仅跟带宽有关系,还跟 CPU 的处理能力、网卡、防火墙、外部接口以及 I/O 等紧密关联。而吞吐量的大小主要由网卡的处理能力、内部程序算法以及带宽大小决定。

计算机资源分配使用率

通常由 CPU 占用率、内存使用率、磁盘 I/O、网络 I/O 来表示资源使用率。这几个参数好比一个木桶,如果其中任何一块木板出现短板,任何一项分配不合理,对整个系统性能的影响都是毁灭性的。

负载承受能力

当系统压力上升时,你可以观察,系统响应时间的上升曲线是否平缓。这项指标能直观地反馈给你,系统所能承受的负载压力极限。例如,当你对系统进行压测时,系统的响应时间会随着系统并发数的增加而延长,直到系统无法处理这么多请求,抛出大量错误时,就到了极限。

总结

  • 性能调优可以使系统稳定,用户体验更佳,甚至在比较大的系统中,还能帮公司节约资源。

  • 没有必要过早地介入性能优化,只需在编码的时候保证其优秀、高效,以及良好的程序设计。

  • 在完成项目后,可以进行系统测试,可以将以下性能指标,作为性能调优的标准;

    • 响应时间、
    • 吞吐量、
    • 计算机资源分配使用率、
    • 负载承受能力。

优化策略

优化代码

应用层的问题代码往往会因为耗尽系统资源而暴露出来。例如,我们某段代码导致内存溢出,往往是将 JVM 中的内存用完了,这个时候系统的内存资源消耗殆尽了,同时也会引发JVM 频繁地发生垃圾回收,导致 CPU 100% 以上居高不下,这个时候又消耗了系统的CPU 资源。

还有一些是非问题代码导致的性能问题,这种往往是比较难发现的,需要依靠我们的经验来优化。例如,我们经常使用的 LinkedList 集合,如果使用 for 循环遍历该容器,将大大降低读的效率,但这种效率的降低很难导致系统性能参数异常。

这时有经验的同学,就会改用 Iterator (迭代器)迭代循环该集合,这是因为LinkedList是链表实现的,如果使用 for 循环获取元素,在每次循环获取元素时,都会去遍历一次List,这样会降低读的效率。

优化设计

面向对象有很多设计模式,可以帮助我们优化业务层以及中间件层的代码设计。优化后,不仅可以精简代码,还能提高整体性能。例如,单例模式在频繁调用创建对象的场景中,可以共享一个创建对象,这样可以减少频繁地创建和销毁对象所带来的性能消耗。

优化算法

好的算法可以帮助我们大大地提升系统性能。例如,在不同的场景中,使用合适的查找算法可以降低时间复杂度。

时间换空间

有时候系统对查询时的速度并没有很高的要求,反而对存储空间要求苛刻,这个时候我们可以考虑用时间来换取空间

空间换时间

这种方法是使用存储空间来提升访问速度。现在很多系统都是使用的 MySQL 数据库,较为常见的分表分库是典型的使用空间换时间的案例。

参数调优

以上都是业务层代码的优化,除此之外,JVM、Web 容器以及操作系统的优化也是非常关键的。

根据自己的业务场景,合理地设置 JVM 的内存空间以及垃圾回收算法可以提升系统性能。例如,如果我们业务中会创建大量的大对象,我们可以通过设置,将这些大对象直接放进老年代。这样可以减少年轻代频繁发生小的垃圾回收(Minor GC),减少 CPU 占用时间,提升系统性能。

Web 容器线程池的设置以及 Linux 操作系统的内核参数设置不合理也有可能导致系统性能
瓶颈,根据自己的业务场景优化这两部分,可以提升系统性能。

兜底策略

上边讲到的所有的性能调优策略,都是提高系统性能的手段,但在互联网飞速发展的时代,产品的用户量是瞬息万变的,无论我们的系统优化得有多好,还是会存在承受极限,所以为了保证系统的稳定性,我们还需要采用一些兜底策略。

什么是兜底策略

第一,限流,对系统的入口设置最大访问限制。这里可以参考性能测试中探底接口的 TPS。同时采取熔断措施,友好地返回没有成功的请求。

第二,实现智能化横向扩容。智能化横向扩容可以保证当访问量超过某一个阈值时,系统可以根据需求自动横向新增服务。

第三,提前扩容。这种方法通常应用于高并发系统,例如,瞬时抢购业务系统。这是因为横向扩容无法满足大量发生在瞬间的请求,即使成功了,抢购也结束了。

目前很多公司使用 Docker 容器来部署应用服务。这是因为 Docker 容器是使用
Kubernetes 作为容器管理系统,而 Kubernetes 可以实现智能化横向扩容和提前扩容
Docker 服务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lbtMUffn-1687328295658)(Java优化.assets/image-20220913161823872.png)]

字符串性能优化

String 对象是我们使用最频繁的一个对象类型,但它的性能问题却是最容易被忽略的。
String 对象作为 Java 语言中重要的数据类型,是内存中占据空间最大的一个对象。高效地使用字符串,可以提升系统的整体性能。

public static void main(String[] args) {
    String str1 = "abc";
    String str2 = new String("abc");
    //具有与此字符串相同内容的字符串,但保证来自唯一字符串池。
    String str3 = str2.intern();

    System.out.println(str1 == str2);
    System.out.println(str2 == str3);
    System.out.println(str1 == str3);
}

当代码中使用第一种方式创建字符串对象时,JVM 首先会检查该对象是否在字符串常量池中,如果在,就返回该对象引用,否则新的字符串将在常量池中被创建。这种方式可以减少同一个值的字符串对象的重复创建,节约内存。

String str = new String(“abc”) 这种方式,首先在编译类文件时,"abc"常量字符串将
会放入到常量结构中,在类加载时,“abc"将会在常量池中创建;其次,在调用 new 时,JVM 命令将会调用 String 的构造函数,同时引用常量池中的"abc” 字符串,在堆内存中创建一个 String 对象;最后,str 将引用 String 对象。

String对象是如何实现的

在 Java 语言中,Sun 公司的工程师们对 String 对象做了大量的优化,来节约内存空间,提升 String 对象在系统中的性能。一起来看看优化过程,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SLGD16Nj-1687328295659)(Java优化.assets/image-20220913163104799.png)]

  • 在Java6以及之前的版本

    • String 对象是对 char 数组进行了封装实现的对象,主要有四个成员变量:char 数组、偏移量 offset、字符数量 count、哈希值 hash。
    • String 对象是通过 offset 和 count 两个属性来定位 char[] 数组,获取字符串。这么做可以高效、快速地共享数组对象,同时节省内存空间,但这种方式很有可能会导致内存泄漏。
  • 从 Java7 版本开始到 Java8 版本

    • String 类中不再有offset 和 count 两个变量了。这样的好处是 String 对象占用的内存稍微少了些,同时,String.substring 方法也不再共享 char[],从而解决了使用该方法可能导致的内存泄漏问题。
  • 从 Java9 版本开始

    • 工程师将 char[] 字段改为了 byte[] 字段,又维护了一个新的属性
      coder,它是一个编码格式的标识。
  • 工程师为什么这样修改呢?

    • 我们知道一个 char 字符占 16 位,2 个字节。这个情况下,存储单字节编码内的字符(占一个字节的字符)就显得非常浪费。JDK1.9 的 String 类为了节约内存空间,于是使用了占8 位,1 个字节的 byte 数组来存放字符串。

    • 而新属性 coder 的作用是,在计算字符串长度或者使用 indexOf()函数时,我们需要根据这个字段,判断如何计算字符串长度。coder 属性默认有 0 和 1 两个值,0 代表 Latin-1(单字节编码),1 代表 UTF-16。如果 String 判断字符串只包含了 Latin-1,则 coder属性值为 0,反之则为 1。

String对象的不可变性

了解了 String 对象的实现后,发现在实现代码中 String 类被 final 关键字修饰了,而且变量 char 数组也被 final 修饰了。

类被 final 修饰代表该类不可继承,而 char[] 被 final+private 修饰,代表了String 对象不可被更改。Java 实现的这个特性叫作 String 对象的不可变性,即 String 对象一旦创建成功,就不能再对它进行改变。

Java这样做的好处

  • 保证 String 对象的安全性。假设 String 对象是可变的,那么 String 对象将可能被
    恶意修改。
  • 保证 hash 属性值不会频繁变更,确保了唯一性,使得类似 HashMap 容器才能实
    现相应的 key-value 缓存功能。
  • 可以实现字符串常量池。在 Java 中,通常有两种创建字符串对象的方式,一种是通
    过字符串常量的方式创建,如 String str=“abc”;另一种是字符串变量通过 new 形式的创建,如 String str = new String(“abc”)。

经典反例

一个 String 对象 str 赋值“hello”,然后又让 str 值为“world”,这个时候 str 的值变成了“world”。那么 str 值确实改变了,那为什么String对象不可改变呢

public static void main(String[] args) {
    String str1 = "hello";
    System.out.println(str1);
    //str1  = "word";
    System.out.println(str1);
    String str2 = "hello";

    System.out.println(str1 == str2);
    System.out.println(str1.equals(str2));

}

在 Java 中要比较两个对象是否相等,往往是用 ==,而要判断两个对象的值是否相等,则需要用 equals 方法来判断。

这是因为 str 只是 String 对象的引用,并不是对象本身。对象在内存中是一块内存地址,str 则是一个指向该内存地址的引用。所以在刚刚我们说的这个例子中,第一次赋值的时候,创建了一个“hello”对象,str 引用指向“hello”地址;第二次赋值的时候,又重新创建了一个对象“world”,str 引用指向了“world”,但“hello”对象依然存在于内存
中。

也就是说 str 并不是对象,而只是一个对象引用。真正的对象依然还在内存中,没有被改变。

String对象的优化

如何构建超大字符串

编程过程中,字符串的拼接很常见。前面我讲过 String 对象是不可变的,如果我们使用String 对象相加,拼接我们想要的字符串,是不是就会产生多个对象呢?例如以下代码:

String str = "ab"+"cd"+"ef";

分析代码可知:首先会生成 ab 对象,再生成 abcd 对象,最后生成 abcdef 对象,从理论上来说,这段代码是低效的。

但实际运行中,我们发现只有一个对象生成,这是为什么呢?难道我们的理论判断错了?我们再来看编译后的代码,你会发现编译器自动优化了这行代码,如下:

String str = "abcded";

字符串变量的累计

String str = "abcdef";

for(int i = 0 ; i < 100000;i++){
    str = str + i ;
}

上面的代码编译后,你可以看到编译器同样对这段代码进行了优化。不难发现,Java 在进行字符串的拼接时,偏向使用 StringBuilder,这样可以提高程序的效率。

String str1 = "abcdef";
for (int i = 0 ; i<10000000;i++){
    str1 = (new StringBuilder(String.valueOf(str1))).append(i).toString();
}

**综上已知:**即使使用 + 号作为字符串的拼接,也一样可以被编译器优化成 StringBuilder的方式。但再细致些,你会发现在编译器优化的代码中,每次循环都会生成一个新的StringBuilder 实例,同样也会降低系统的性能。

所以平时做字符串拼接的时候,我建议你还是要显示地使用 String Builder 来提升系统性能。

如果在多线程编程中,String 对象的拼接涉及到线程安全,你可以使用 StringBuffer。但是要注意,由于 StringBuffer 是线程安全的,涉及到锁竞争,所以从性能上来说,要比StringBuilder 差一些。

如何使用String.intern节省内存

Twitter 每次发布消息状态的时候,都会产生一个地址信息,以当时 Twitter 用户的规模预估,服务器需要 32G 的内存来存储地址信息。

public class Location{
    private String city;//城市
    private String region;//地区
    private String countryCode;//国家代码
    private double logitude;//经度
    private double latitude;//维度
}

考虑到其中有很多用户在地址信息上是有重合的,比如,国家、省份、城市等,这时就可以将这部分信息单独列出一个类,以减少重复,代码如下:

public class SharedLocation{
    private String city;//城市
    private String region;//地区
    private String countryCode;//国家代码
}

public class Location{
    private SharedLocation sharedLocation;
    private double logitude;//经度
    private double latitude;//维度
}

通过优化,数据存储大小减到了 20G 左右。但对于内存存储这个数据来说,依然很大,怎么办呢?

这个案例来自一位 Twitter 工程师在 QCon 全球软件开发大会上的演讲,他们想到的解决方法,就是使用 String.intern 来节省内存空间,从而优化 String 对象的存储。

具体做法就是,在每次赋值的时候使用 String 的 intern 方法,如果常量池中有相同值,就会重复使用该对象,返回对象引用,这样一开始的对象就可以被回收掉。这种方式可以使重复性非常高的地址信息存储大小从 20G 降到几百兆。

例如

 public static void main(String[] args) {

        String a = new String("abc").intern();
        String b = new String("abc").intern();
        System.out.println(a == b);

    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f6d9OjP4-1687328295659)(Java优化.assets/image-20220913175657742.png)]

为了更好地理解,我们再来通过一个简单的例子,回顾下其中的原理:
输出结果:在字符串常量中,默认会将对象放入常量池;在字符串变量中,对象是会创建在堆内存中,同时也会在常量池中创建一个字符串对象,复制到堆内存对象中,并返回堆内存对象引用。

如果调用 intern 方法,会去查看字符串常量池中是否有等于该对象的字符串,如果没有,就在常量池中新增该对象,并返回该对象引用;如果有,就返回常量池中的字符串引用。堆内存中原有的对象由于没有引用指向它,将会通过垃圾回收器回收。

在一开始创建 a 变量时,会在堆内存中创建一个对象,同时会在加载类时,在常量池中创建一个字符串对象,在调用 intern 方法之后,会去常量池中查找是否有等于该字符串的对象,有就返回引用。

在创建 b 字符串变量时,也会在堆中创建一个对象,此时常量池中有该字符串对象,就不再创建。调用 intern 方法则会去常量池中判断是否有等于该字符串的对象,发现有等于"abc"字符串的对象,就直接返回引用。而在堆内存中的对象,由于没有引用指向它,将会被垃圾回收。所以 a 和 b 引用的是同一个对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IzkBKIwJ-1687328295660)(Java优化.assets/image-20220913175840418.png)]

使用 intern 方法需要注意的一点是,一定要结合实际场景。因为常量池的实现是类似于一个 HashTable 的实现方式,HashTable 存储的数据越大,遍历的时间复杂度就会增加。如果数据过大,会增加整个字符串常量池的负担。

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

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

相关文章

【深度学习】GPT-1

GPT-1是OpenAI在《Improving Language Understanding by Generative Pre-Training》中于2018年提出的生成式预训练语言模型。 1.GPT-1 简介 在自然语言处理任务中&#xff0c;存在大量无标签的语料数据&#xff0c;而有标签的语料数据相对较少&#xff0c;因此基于有监督训练的…

[建议收藏] Mysql+ETLCloud CDC+Doris实时数仓同步实战

一、业务需求及其痛点 随着数字化转型&#xff0c;企业需要对各种销售及营销数据进行实时同步分析&#xff0c;例如销售订单信息&#xff0c;库存信息&#xff0c;会员信息&#xff0c;设备状态信息等等&#xff0c;这些统计分析信息可以实时同步到 Doris中进行分析和统计&…

搜索跳出率:了解并优化用户体验

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言什么是搜索跳出率&…

【Linux编辑器-vim使用】

目录 Linux编辑器-vim使用1.vim的基本概念2.vim的基本操作3.vim正常模式命令集4.vim末行模式命令集 Linux编辑器-vim使用 1.vim的基本概念 目前了解的vim有三种模式&#xff08;其实有好多模式&#xff09;&#xff0c;分别是命令模式、插入模式和底行模式&#xff0c;各模式…

Midjourney如何用参考图/垫图来绘画图

大家都知道AI绘画工具每次生成的效果都是随机的&#xff0c;但是现在很多AI绘图工具都提供了利用参考图/垫图的方式出图&#xff0c;这样就可以让让AI画作生成自己想要的布局、场景、色彩等等。 国内的AI绘图工具一般都好操作&#xff0c;国外主流的Midjourney也可以添加参考图…

ChatGPT/GPT-4 或将从根本上改变软件工程

文章目录 一、前言二、主要内容 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、前言 编程也可能是最容易被 AI 技术取代的工作之一&#xff0c;软件的构建方式将产生根本性的转变。 今年以来&#xff0c;相信大家都听说过 ChatGPT、New Bing 和…

8.5 字节序及IP地址转换

目录 主机字节序和网络字节序 什么是字节序&#xff1f; 字节序转换函数 IP地址字节序转换函数 主机字节序和网络字节序 什么是字节序&#xff1f; 字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序&#xff0c;分为&#xff1a; 大端字节序 (Big …

药物 3D 打印新突破:圣地亚哥大学用机器学习筛选喷墨打印生物墨水,准确率高达 97.22%

内容一览&#xff1a;药物喷墨打印是一种高度灵活和智能化的制药方式。据相关报告统计&#xff0c;该领域市场规模将在不久的未来呈现指数级增长。过往&#xff0c;筛选合适生物墨水的方法费时且费力&#xff0c;因此也成为药物喷墨打印领域面临的主要挑战之一。为解决这一问题…

开启你的时间序列分析之旅:一步步教你学会HyperTS

目录 前言一、HyperTS介绍二、HyperTS安装、使用2-1、安装2-2、HyperTS使用 三、案例3-0、通用工作流程3-1、时间序列预测3-2、时间序列分类3-3、时间序列异常检测 四、高级应用4-1、模型的保存和加载 总结 前言 HyperTS是一个开源的时间序列分析库&#xff0c;主要用于处理和分…

K8S 云集群安装纯享版 - 傻瓜式一键教程 全自动脚本文件

引言&#xff1a; 用的云服务器&#xff0c;整个过程读者还是需要准备些软妹币的… 另外众所周知&#xff0c;K8S最难的部分是什么&#xff1f;——是安装。。。 目录 0. 技术选型( :bell: 重要&#xff01;)0.0 version0.1 云服务器 1. 容器运行时2. k8s 安装前准备2.0 网络连…

【计算机视觉】CVPR 2023 上的分割论文真的是神仙打架(介绍前12篇,图像分割,全景分割,语义分割,实例分割)

文章目录 一、图像分割类1.1 AutoFocusFormer: Image Segmentation off the Grid1.2 FreeSeg: Unified, Universal and Open-Vocabulary Image Segmentation1.3 Parameter Efficient Local Implicit Image Function Network for Face Segmentation 二、全景分割类2.1 You Only …

CUDA介绍

CUDA introduction 文章目录 CUDA introduction异构计算架构典型的CUDA程序的执行流程函数类型限定词Kernel 线程层次结构线程ID号计算&#xff1a; Example加法实例托管内存乘法 性能分析工具 Nsight System功能用法 Reference欢迎关注公众号【三戒纪元】 异构计算架构 GPU并…

SIFT算法简介

参考资料 SIFT文献-David-UBC&#xff1a; 《Distinctive Image Features from Scale-Invariant Keypoints》SIFT算法介绍&#xff1a; SIFT特征详解 - Brook_icv - 博客园 (cnblogs.com) 简介 Scale-invariant feature transform 尺度不变特征变换 SIFT算法不仅只有尺度不…

腾讯安全杨光夫:企业需改变“头痛医头”现状,构建持续进化的安全免疫力

6月13日&#xff0c;腾讯安全联合IDC发布“数字安全免疫力”模型框架&#xff0c;主张将守护企业数据和数字业务两大资产作为企业安全建设的核心目标。腾讯安全副总裁杨光夫在《助力企业持续进化安全免疫力》的主题演讲中表示&#xff0c;在新业态、新威胁、新场景、强监管下&a…

【MySQL】MVCC是如何解决快照读下的幻读问题的

文章目录 LBCC当前读 MVCC隐藏列undo logRead View 总结 我们从上文中了解到InnoDB默认的事务隔离级别是repeatable read&#xff08;后文中用简称RR&#xff09;&#xff0c;它为了解决该隔离级别下的幻读的并发问题&#xff0c;提出了LBCC和MVCC两种方案。其中LBCC解决的是当…

StarRocks 统一 OLAP 引擎在滴滴的探索实践

作者&#xff1a;余辉&#xff0c;滴滴出行 OLAP 团队负责人/专家工程师&#xff1b;李明皇&#xff0c;滴滴出行高级软件开发工程师 发展历程 滴滴的 OLAP 系统早期由用于实时监控系统的 Apache Druid &#xff08;以下简称 Druid&#xff09;和离线加速使用的 Apache Kylin&a…

随风摇曳的她——美蕨(matlab实现)

目录 1 随风摇曳的她 2 摇曳带来的哲思 3 Matlab代码实现 1 随风摇曳的她 梦幻的场景、浪漫的气息&#xff0c;带上心爱的人&#xff0c;拥抱在这片花海之下&#xff0c;便有了电影男女主角的氛围感&#xff1b; 就算阅尽了世间风貌&#xff0c;也抵不上和她在一起时锦短情长&a…

Idea批量删除空行

1.在编辑框中使用快捷键ctrl f 打开替换框 2.勾选正则模式 Regex 3.在条件框中输入正则^\s*\n 正则解释&#xff0c;匹配以0个或n个\s空白符起首的换行\n 输入正则后可以看到效果&#xff0c;可以看到单行和多行都被选中了 。 如果想只删除连续多行的空行&#xff0c;就需要…

fl studio for window 21.0.3.3517 官方中文版免费下载及新功能介绍

FL Studio 21 for Mac官方中文版免费下载是一款功能强大的音乐编曲制作软件。尽管你可能没有接触过音乐制作&#xff0c;也能通过fl Studio 21&#xff0c;撰写&#xff0c;整理&#xff0c;录制&#xff0c;编辑&#xff0c;混合&#xff0c;掌握和制作出专业的品质音乐。 fl…

每隔一段时间重试,重试n次 java 工具类

需求&#xff1a; 若代码出现异常&#xff0c;则每隔一段时间重试一下&#xff0c;重试n次 import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.util.function.Supplier;public class RetryUtils {private static final Logger log LoggerFactory.getLogg…