缓冲区的奥秘:解析数据交错的魔法

目录

一、理解缓存区的好处

(一)直观性的理解

(二)缓存区的好处

二、经典案例分析体会

(一)文件读写流(File I/O Buffering)

BufferedOutputStream 和 BufferedWriter 可以加快写入的速度

BufferedInputStream 和 BufferedReader 可以加快读取字符的速度

(二)日志缓冲(Logging Buffering)

三、案例回顾和优化方向分析

四、Kafka缓存区优化思考

(一)Kafka 的生产者,有可能会丢数据吗?

(二)Kafka 生产者会影响业务的高可用吗?

参考文章


在计算机科学的广袤世界里,有一项看似简单却又深奥无比的技术,那就是缓冲。缓冲,像是隐藏在代码背后的魔法,它默默地改变着数据的流动,使得看似杂乱无章的操作变得井然有序。然而,它的本质并非只是简单的数据暂存,而是一种艺术,一门科学。

一、理解缓存区的好处

(一)直观性的理解

在Java虚拟机(JVM)中,堆内存扮演了一个重要的角色,用于存储动态分配的对象。当代码执行时,不断地在堆空间中创建新的对象,这些对象会暂时存放在堆中,直到不再需要时才被垃圾回收器回收。这个过程就像是在一个巨大的缓存中存储着各种数据。

垃圾回收器进程则负责在后台默默地进行垃圾回收,清理不再被引用的对象,释放内存空间。这就像是在缓存中进行定期的清理和整理,以保持缓存的有效性和性能。

所以,JVM的堆空间可以被视为一个巨大的缓存,它存储着临时的对象数据,并且由垃圾回收器进程来管理和维护。这个例子很好地展示了缓存的概念,即通过暂存数据来提高系统的效率和性能,同时保持数据的一致性和可用性。

生活化一些的,想象每年过大年你和大家庭的亲人们正在一起包饺子,每个人都有不同的任务。有的人负责擀面皮,有的人负责包馅料,还有的人负责煮饺子。但是,大家的速度并不总是一致的,有时候有人擀好了面皮,但包馅的还没准备好,有时候包馅的准备好了,但煮饺子的还在忙其他的事情。

这时,你们决定在中间放一个大盆子,就像是一个缓冲区一样。每当有人完成了自己的任务,就把成果放进盆子里,而需要下一个任务的人则从盆子里取出材料进行下一步操作。这样一来,即使大家的速度不一致,也不会影响整个过程的进行,每个人都可以按照自己的节奏进行操作,保持了整个包饺子过程的顺畅进行。

(二)缓存区的好处

无论是在生活中还是在程序设计中,缓冲区都扮演着类似的角色,平衡了不同速度之间的数据流动,保证了整个过程的顺畅进行。总结下缓冲区的好处:

好处描述
平衡数据流速度差异缓冲区可以暂时存储数据,平衡生产者和消费者之间的速度差异,防止数据丢失或处理延迟。
降低系统开销通过批量处理数据,减少频繁的数据交互和I/O操作,降低系统的开销,提高系统效率。
提高系统性能缓冲区优化数据处理方式,减少等待时间,提高系统的响应速度,从而提高系统性能。
保护数据一致性缓冲区暂存数据,直到数据传输或处理完成,保护数据的一致性,避免数据丢失或损坏。
优化用户体验在音视频播放或网络通信等应用场景中,提前缓冲数据可以实现流畅的用户体验,提高用户满意度。

二、经典案例分析体会

我们将介绍几个经典的缓冲区应用案例,并分析它们的优势和适用场景:

案例前提描述描述
文件读写流(File I/O Buffering)当需要进行大量文件读写操作时,可以使用缓冲区来提高性能。在文件读写操作中使用缓冲区来提高性能。将文件内容暂存到内存缓冲区中,减少对磁盘的频繁访问。写入数据时,也可以暂存到缓冲区,减少磁盘I/O操作次数。
网络数据传输缓冲(Network Data Transfer Buffering)在进行网络数据传输时,为了提高效率和稳定性,可以使用缓冲区来缓存发送和接收的数据。在网络通信中使用缓冲区来缓存发送和接收的数据,提高网络数据传输的效率和稳定性。发送端和接收端都可以利用缓冲区来优化数据传输。
日志缓冲(Logging Buffering)当系统需要进行日志记录,并且对系统性能有一定要求时,可以使用日志缓冲区来优化日志写入操作。在软件系统中使用日志缓冲区来减少对系统性能的影响。将待写入的日志信息暂存到缓冲区中,定期批量写入日志文件,减少磁盘I/O操作,提高系统性能。
内存缓存(Memory Caching)当系统需要频繁访问某些数据,并且对数据访问速度有较高要求时,可以使用内存缓存来提高数据访问速度。使用内存缓存来暂存频繁访问的数据,提高数据访问速度和效率。比如,Web服务器可以将经常访问的网页内容暂存到内存中,减少磁盘访问,提高网页访问速度。

选取其中的两个可以展开进行分析体会。

(一)文件读写流(File I/O Buffering)

缓冲在 Java 语言中被广泛应用,在 IDEA 中搜索*buffer,可以看到长长的类列表,其中最典型的就是文件读取和写入字符流。

Java 的 I/O 流设计,采用的是装饰器模式,当需要给类添加新的功能时,就可以将被装饰者通过参数传递到装饰者,封装成新的功能方法。

Java的I/O库中提供了许多装饰器类,如BufferedInputStream和BufferedOutputStream,它们通过装饰器模式来给输入流和输出流添加额外的功能,比如缓冲功能。

一般情况下,在读取和写入流的 API 中,BufferedInputStream 和 BufferedReader 可以加快读取字符的速度,BufferedOutputStream 和 BufferedWriter 可以加快写入的速度。

BufferedOutputStream 和 BufferedWriter 可以加快写入的速度

以BufferedWriter为例分析,当需要写入字符时,使用BufferedWriter相对于直接使用FileWriter可以提供更高的写入速度,因为BufferedWriter内部使用了缓冲区,能够一次写入多个字符,减少了频繁的系统调用和磁盘访问次数。我们可以通过对比使用BufferedWriter和直接使用FileWriter的写入速度:

package org.zyf.javabasic.io;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

/**
 * @program: zyfboot-javabasic
 * @description: 使用BufferedWriter相对于直接使用FileWriter可以提供更高的写入速度
 * @author: zhangyanfeng
 * @create: 2024-05-26 17:28
 **/
public class BufferedWriterIOExample {
    private static final String FILE_PATH = "example.txt";
    private static final String CONTENT = "This is a test content. ";

    public static void main(String[] args) {
        long startTime, endTime;

        // 测试直接使用FileWriter写入字符
        startTime = System.currentTimeMillis();
        try (FileWriter fileWriter = new FileWriter(FILE_PATH)) {
            for (int i = 0; i < 100000; i++) {
                fileWriter.write(CONTENT);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        endTime = System.currentTimeMillis();
        System.out.println("直接使用FileWriter写入字符耗时:" + (endTime - startTime) + " 毫秒");

        // 测试使用BufferedWriter写入字符
        startTime = System.currentTimeMillis();
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(FILE_PATH))) {
            for (int i = 0; i < 1000000; i++) {
                bufferedWriter.write(CONTENT);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        endTime = System.currentTimeMillis();
        System.out.println("使用BufferedWriter写入字符耗时:" + (endTime - startTime) + " 毫秒");
    }
}

通过运行测试

可以观察到使用BufferedWriter的写入速度明显要快,在BufferedWriter的源码中,可以看到它内部维护了一个字符数组作为缓冲区,数据会先被写入到这个缓冲区中,然后再一次性地将缓冲区中的数据写入到底层的Writer中。简化版本BufferedWriter

import java.io.*;

public class BufferedWriter extends Writer {
    // 缓冲区大小,默认为 8192
    private static final int DEFAULT_BUFFER_SIZE = 8192;
    
    // 缓冲区字符数组
    private char[] buffer;
    
    // 缓冲区中的数据索引
    private int index;
    
    // 底层的 Writer 对象
    private Writer out;

    // 构造方法
    public BufferedWriter(Writer out) {
        this(out, DEFAULT_BUFFER_SIZE);
    }

    // 带缓冲区大小的构造方法
    public BufferedWriter(Writer out, int bufferSize) {
        this.out = out;
        buffer = new char[bufferSize];
        index = 0;
    }

    // 写入一个字符到缓冲区
    @Override
    public void write(int c) throws IOException {
        if (index >= buffer.length) {
            flushBuffer(); // 如果缓冲区已满,先将缓冲区中的数据写入到底层 Writer 中
        }
        buffer[index++] = (char) c;
    }

    // 写入字符数组到缓冲区
    @Override
    public void write(char[] cbuf, int off, int len) throws IOException {
        for (int i = off; i < off + len; i++) {
            write(cbuf[i]); // 循环调用写入一个字符到缓冲区的方法
        }
    }

    // 刷新缓冲区,将缓冲区中的数据写入到底层 Writer 中
    @Override
    public void flush() throws IOException {
        flushBuffer();
        out.flush();
    }

    // 关闭 BufferedWriter,先刷新缓冲区,再关闭底层的 Writer
    @Override
    public void close() throws IOException {
        flush();
        out.close();
    }

    // 刷新缓冲区
    private void flushBuffer() throws IOException {
        if (index > 0) {
            out.write(buffer, 0, index); // 将缓冲区中的数据写入到底层 Writer 中
            index = 0; // 重置索引
        }
    }
}

通过这段代码,我们可以直接看到BufferedWriter内部使用了缓冲区,数据会先暂时存储在缓冲区中,等到需要刷新缓冲区或关闭BufferedWriter时,才会将缓冲区中的数据一次性写入到底层的Writer中。

BufferedInputStream 和 BufferedReader 可以加快读取字符的速度

同样以BufferedReader为例,当需要读取字符时,使用BufferedReader相对于直接使用FileReader可以提供更高的读取速度,因为BufferedReader内部使用了缓冲区,能够一次读取多个字符,减少了频繁的系统调用和磁盘访问次数。我们通过对比使用BufferedReader和直接使用FileReader的读取速度:

package org.zyf.javabasic.io;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

/**
 * @program: zyfboot-javabasic
 * @description: 使用BufferedReader相对于直接使用FileReader可以提供更高的读取速度
 * @author: zhangyanfeng
 * @create: 2024-05-26 17:40
 **/
public class BufferedReaderIOExample {
    private static final String FILE_PATH = "example.txt";

    public static void main(String[] args) {
        long startTime, endTime;

        // 测试直接使用FileReader读取字符
        startTime = System.currentTimeMillis();
        try (FileReader fileReader = new FileReader(FILE_PATH)) {
            int data;
            while ((data = fileReader.read()) != -1) {
                // 模拟处理读取的字符
                // System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        endTime = System.currentTimeMillis();
        System.out.println("直接使用FileReader读取字符耗时:" + (endTime - startTime) + " 毫秒");

        // 测试使用BufferedReader读取字符
        startTime = System.currentTimeMillis();
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(FILE_PATH))) {
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                // 模拟处理读取的字符
                // System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        endTime = System.currentTimeMillis();
        System.out.println("使用BufferedReader读取字符耗时:" + (endTime - startTime) + " 毫秒");
    }
}

通过运行测试

可以观察到使用BufferedReader的读取速度会明显快于直接使用FileReader,这是因为BufferedReader内部使用了缓冲区,能够一次读取多个字符,减少了频繁的系统调用和磁盘访问次数,从而提高了读取的效率,其源码上的处理这里就不在展示了。

(二)日志缓冲(Logging Buffering)

在Java开发中,日志记录是一个至关重要的方面。 无论是开发过程中的调试和追踪问题,还是生产环境中的监控和排错,日志都是程序员们必不可少的工具之一。然而,在高并发和大规模的应用中,日志记录往往会带来一些挑战。 随着应用程序的规模和用户量的增长,日志消息的数量也会急剧增加,可能会导致大量的磁盘 I/O 操作和系统开销,从而影响应用程序的性能和稳定性。

为了解决这些挑战,我们需要一种高效且可靠的日志记录框架。 这就是Logback发挥作用的地方。作为SLF4J的一种实现,Logback不仅提供了简洁易用的API,还具有出色的性能和可靠性。

其中一个Logback的特点就是异步日志记录。 异步日志记录机制使得Logback可以将日志消息先放入缓冲队列中,而不是立即写入到日志文件中,从而减少了对磁盘的频繁访问,提高了日志记录的效率。以下图实现为了:

Logback的异步日志输出流程中应用程序生成日志消息,并调用Logback的日志记录接口进行记录。Logback将生成的日志消息放入一个ArrayBlockingQueue队列中,这是一个线程安全的有界队列。这个队列充当了生产者-消费者模式中的缓冲区,用于临时存储待写入的日志消息。

也就是说,Logback启动一个后台Worker线程,该线程负责从队列中获取日志消息,并将其写入到磁盘中。后台Worker线程不断地从队列中取出日志消息,然后将这些消息写入到指定的日志文件中。在写入磁盘时,Logback可以通过一些优化手段,比如批量写入和异步IO,来提高写入性能。

一旦后台Worker线程将队列中的日志消息全部写入磁盘后,整个日志记录流程就完成了。总的来说,异步日志输出之后,日志信息将暂存在 ArrayBlockingQueue 列表中,后台会有一个 Worker 线程不断地获取缓冲区内容,然后写入磁盘中。

上图中提及的三个关键参数说明如下:

  1. queueSize(队列大小):这个参数定义了异步日志队列的最大容量,即可以存放的日志消息数量上限。默认值为256。如果队列大小设置得太小,在高并发情况下,日志消息产生速度超过了写入速度,可能会导致队列溢出,从而丢失一部分日志消息。因此,应根据系统的实际情况和性能需求合理设置队列大小。但要注意,如果将队列大小设置得太大,在突发断电等异常情况下,会导致大量的日志消息被丢失。

  2. maxFlushTime(最大刷新时间):这个参数定义了在关闭日志上下文后,继续执行写任务的时间。Logback会在关闭日志上下文时调用Thread的join方法,等待后台Worker线程执行完剩余的写任务。默认情况下,maxFlushTime未设置,即等待所有写任务执行完毕才关闭日志上下文。如果系统中有一些耗时较长的写任务,可能会导致日志上下文无法及时关闭,影响系统的正常关闭和资源释放。因此,可以通过设置maxFlushTime来限制等待的最大时间,保证日志上下文能够及时关闭。

  3. discardingThreshold(丢弃阈值):这个参数定义了当队列快要达到最大容量时,是否丢弃一些级别较低的日志消息。默认值为队列长度的80%。在高负载情况下,如果不及时处理日志消息,队列可能会溢出,从而导致丢失重要的日志信息。通过设置discardingThreshold,可以在队列快要达到上限时,丢弃一些级别较低的日志消息,保证队列不会溢出。如果你担心可能会丢失业务关键的日志,可以将这个值设置为0,表示不丢弃任何日志消息,所有日志都会被记录。

这些关键参数在配置异步日志记录时非常重要。

三、案例回顾和优化方向分析

针对文件读写流和Logback的两个例子,我们可以看到:

  • 文件读写流:当使用文件写入流(如BufferedOutputStream)时,写入的数据首先被放入缓冲区中,而不是直接写入到文件中。这意味着在写入操作完成之前,数据实际上并没有真正地写入到文件中,而是先存储在缓冲区中。为了确保数据被及时写入文件,我们需要手动调用flush()方法来刷新缓冲区,将数据立即写入文件中。这样可以避免因为程序崩溃而导致的数据丢失问题。
  • Logback:Logback的异步日志记录机制使用了缓冲区,将日志消息暂存于缓冲队列中,然后由后台Worker线程负责将日志消息写入磁盘中。通过配置参数来控制缓冲队列的大小、最大刷新时间等,以及是否在队列快满时丢弃日志消息。通过合理配置这些参数,可以平衡性能和可靠性之间的关系,确保日志记录的效率和稳定性。

在处理缓冲区设计的常规操作时,需要注意及时刷新缓冲区,以确保数据被正确地写入到目标资源中,同时要考虑到异步操作可能引入的时序问题,保证程序的正确性和稳定性。

根据不同的资源和应用场景,选择适当的缓存优化设计是非常常见的做法。

  1. 同步操作:适用于对数据完整性要求较高,可以容忍一定程度的性能损失的场景。同步操作会阻塞当前线程,直到操作完成,确保数据的及时写入或处理。这种方式通常适用于对数据一致性要求较高、对性能要求相对较低的场景。

  2. 异步操作:适用于对性能要求较高,可以容忍一定程度的数据丢失或时序不一致的场景。异步操作将数据暂存于缓冲区中,并由后台线程异步处理,从而提高了系统的响应性能和并发能力。这种方式通常适用于高并发、大规模的应用场景,可以显著提升系统的吞吐量和性能。

有时候,甚至可以结合同步和异步操作,针对不同的场景采用不同的缓存优化方案,以达到最佳的性能和可靠性。日常的开发中我们需要不断的思考引入缓存来解决我们的一些业务诉求,同时需要思考对应的优化手段。

四、Kafka缓存区优化思考

在 Kafka 中,消息是通过分区存储的,并且每个分区都有一个存储日志文件(log file)来持久化消息。这些日志文件是以分段(segment)的方式组织的,每个分段包含一定数量的消息。而消息的写入和读取都是通过分段来进行的。

Kafka 同样利用了缓存区的思想来优化消息的写入和读取过程,具体我们通过分析两个基本问题来说明。

(一)Kafka 的生产者,有可能会丢数据吗?

Kafka 生产者会将发送到同一个分区的多条消息封装在一个缓冲区(batch)中。这个缓冲区有两种触发条件:一是缓冲区满了,即达到了指定的大小(batch.size);二是消息在缓冲区中等待的时间超过了指定的超时时间(linger.ms)。一旦满足了其中一个条件,缓冲区中的消息就会被发送到 Kafka Broker 上。

在默认情况下,Kafka 的缓冲区大小为 16KB。如果生产者的业务突然断电或发生故障,尚未发送到 Broker 的 16KB 数据将会丢失,因为它们没有机会被发送出去。这种情况下,消息丢失是有可能发生的。

为了避免这种情况的发生,我们有两种解决办法都是可行的:

  1. 缓冲区大小设置较小:将缓冲区大小设置得非常小,以确保在生产者发生故障时,待发送的数据量较小,从而减少了可能丢失的数据量。但是,将缓冲区大小设置得太小可能会导致性能下降,因为每条消息都需要单独发送,增加了网络开销和系统负载。

  2. 消息发送日志记录:在消息发送前记录一条日志,标记消息发送的开始,然后在消息成功发送后通过回调再记录一条日志,标记消息发送的结束。通过扫描生成的日志,可以判断哪些消息丢失了。这种方法可以有效地追踪和识别丢失的消息,但需要额外的日志记录和扫描操作,可能会增加系统的复杂性和开销。

对于如何处理生产者发生故障时可能丢失的数据,需要根据具体的业务需求和性能要求来选择合适的解决方案。在权衡性能和可靠性的基础上,可以选择合适的缓冲区大小,并结合消息发送日志记录等技术手段来确保消息的可靠传输和处理。

(二)Kafka 生产者会影响业务的高可用吗?

Kafka 生产者的设计确实可能会影响业务的高可用性,特别是与生产者的缓冲区大小和超时参数相关的配置。

  1. 缓冲区大小限制:生产者的缓冲区是有限的,如果消息产生得过快或者生产者与 Broker 节点之间存在网络问题,缓冲区可能会一直处于满载状态。在这种情况下,有新的消息到达时,可能会导致阻塞。

  2. 超时参数设置:通过配置生产者的超时参数和重试次数,可以控制生产者在缓冲区满载时的行为。一般来说,将超时参数设置得较小可以让新的消息不会一直阻塞在业务方。然而,有些情况下,如果将超时参数设置得过大,可能会导致生产者线程被阻塞,无法继续处理新的请求,从而影响了业务的高可用性。

为了确保 Kafka 生产者与业务的高可用性,需要合理配置生产者的缓冲区大小、超时参数以及重试策略,以及针对可能的异常情况进行监控和调优。同时,也需要在系统设计时考虑消息传输的可靠性和容错性,以应对可能发生的各种问题,从而保障业务的稳定运行。

参考文章

《Java 性能优化与面试 21 讲》,李国

https://www.cnblogs.com/zhzhlong/p/11420084.html

【深入浅出C#】章节 7: 文件和输入输出操作:文件读写和流操作-腾讯云开发者社区-腾讯云

Azure HPC 缓存使用情况模型 | Microsoft Learn

专为流式数据设计的另一种缓存:流式缓存技术解读_语言 & 开发_Andrei Paduroiu_InfoQ精选文章

https://zhuanlan.zhihu.com/p/641984395

https://zhuanlan.zhihu.com/p/475320277

IO流中的设计模式_io流用到的设计模式-CSDN博客

https://www.cnblogs.com/LoveShare/p/17029000.html

概念,原理,到例子,全解析logback ,学会日志系统-腾讯云开发者社区-腾讯云

logback配置详解 & 原理介绍_logback 配置原理-CSDN博客

logback之 AsyncAppender 的原理、源码及避坑建议-阿里云开发者社区

快速了解常用日志技术(JCL、Slf4j、JUL、Log4j、Logback、Log4j2)-阿里云开发者社区

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

四川古力未来科技抖音小店打造品质生活,可靠之选引领潮流

在当今数字化快速发展的时代&#xff0c;电商平台如雨后春笋般涌现&#xff0c;抖音小店作为其中的佼佼者&#xff0c;凭借其独特的短视频电商模式&#xff0c;迅速吸引了大批年轻消费者的目光。而在众多的抖音小店中&#xff0c;四川古力未来科技抖音小店凭借其卓越的品质和专…

数字时代网络安全即服务的兴起

在日益数字化的世界里&#xff0c;威胁形势不断演变&#xff0c;网络攻击变得越来越复杂和频繁。当组织努力保护敏感数据并保持运营完整性时&#xff0c;传统的网络安全措施往往不够。 这为更具动态性和可扩展性的解决方案铺平了道路&#xff1a;网络安全即服务 (CSaaS)。网络…

数据结构---排序算法

个人介绍 hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的…

【短剧看剧系统之投流版】短剧看剧系统功能更新,前端uniapp搭建开发

目录 一、常规款短剧系统和投流版的区别&#xff1f; 二、后端体系 1.管理端&#xff1a; 2.代理投流端 三、功能区别 总结&#xff1a; 前言&#xff1a; 短剧看剧系统目前在抖音端是比较热门的&#xff0c;最重要的功能就是可以接入第三方cps&#xff0c;包含类目报白…

如何将JPG/PNG位图免费快速一键转换成SVG格式的矢量图

环境&#xff1a; JPG/PNG位图 问题描述&#xff1a; 如何将JPG/PNG位图快速一键转换成SVG格式的矢量图 解决方案&#xff1a; 是一个人工智能驱动的图片转换工具&#xff0c;可以帮助用户将」JPG/PNG位图快速转换成SVG格式的矢量图&#xff0c;方便设计人员对图片进行二次…

AIGC提示词---如何写提示词?

你真的了解你的AI助手吗&#xff1f; 想象一下&#xff0c;你和别人使用相同的AI工具&#xff0c;但为何他的工作效率总是高出一截&#xff1f;秘诀可能就藏在那些看似简单的提示词里。精准的提示词是解锁AI潜能的关键&#xff0c;它们能让AI更好地理解你的需求&#xff0c;从…

【AI大模型】Transformers大模型库(八):大模型微调之LoraConfig

目录 一、引言 二、LoraConfig配置参数 2.1 概述 2.2 LoraConfig参数说明 2.3 代码示例 三、总结 一、引言 这里的Transformers指的是huggingface开发的大模型库&#xff0c;为huggingface上数以万计的预训练大模型提供预测、训练等服务。 &#x1f917; Transformers …

Spring中事务的隔离级别和传播机制

上一篇博客中讲解了关于事务的两种使用方式包括Transactional的详解。 Transactional 注解当中的三个常⻅属性: 1. rollbackFor: 异常回滚属性. 指定能够触发事务回滚的异常类型. 可以指定多个异常类型 2. Isolation: 事务的隔离级别. 默认值为 Isolation.DEFAULT 3. propagat…

原腾讯云副总裁张纾翔加入矩阵起源,共筑人工智能新篇章

近日&#xff0c;原腾讯云副总裁张纾翔先生正式加入矩阵起源&#xff0c;担任合伙人兼高级副总裁&#xff0c;全面负责矩阵起源商业化工作。 矩阵起源成立于2021年。公司创始团队来自腾讯云、Snowflake等国内外一流的互联网企业、软件公司、数字化企业和开源社区&#xff0c;核…

什么是PMP,含金量高吗?

01PMP是什么&#xff1f; PMP(Project Management Professional)是项目管理领域的高级认证&#xff0c;它被PMI在全球200多个国家和地区广泛推广&#xff0c;被视为项目管理领域内最具含金量的认证之一。持有PMP证书的项目经理不仅能提升其项目管理能力&#xff0c;同时也显著…

数据结构---力扣225.用队列实现栈(C

1.链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;【点击即可跳转】 思路&#xff1a; 栈 是 后进先出 队列 是 先进先出 &#xff08;始终保持一个队列为空的思路&#xff09; 入数据&#xff1a; 往 不为空的队列 中入 出数据&#xff1a; 把不为空的队列数…

C#完整服务器

控件&#xff1a;三个按钮&#xff0c;输入框&#xff0c;文件框(richTextBox) 打开服务器按钮方法 Socket socket;// 服务器对象Dictionary<string,Socket> dic new Dictionary<string,Socket>();// 存储客户端对象// 打开服务器private void button1_Click(obje…

uniapp自定义tabbar——中间特殊按钮放大

在APP.vue里面 .uni-tabbar__item:nth-child(4) .uni-tabbar__icon {width: 50px !important;height: 50px !important;position: relative;bottom: 30rpx;}.uni-tabbar__item:nth-child(4) .uni-tabbar__label {position: relative;bottom: 25rpx;}

uniapp地图选择位置

直接上代码 通过一个点击事件调用官方api即可调用 点击调用成功后显示如下 然后选择自己所需要的位置即可

23种设计模式之代理模式

代理模式 1、概念 代理模式&#xff1a;给某一个对象提供一个代理或占位符&#xff0c;并由代理对象来控制对原对象的访问 代理模式是常用的结构型设计模式之一&#xff0c;在Java RMI、Web Service、Spring AOP等技术和框架中都使用了代理模式 2、代理模式结构 Subject&a…

【学习笔记】Linux

Linux 1、 介绍 1.1、概述 1.2、特点 1.3、Linux的发行版2、 基础篇 —— 文件系统 2.1、文件系统 2.2、目录结构3、 基础篇 —— VI/VIM 编辑器 3.1、概述 3.2、编辑器模式及常用命令4、 基础篇 —— 网络配置 4.1、VMware NetWork …

公司面试题总结(二)

7. 说说 JavaScript 中的数据类型&#xff1f;存储上的差别&#xff1f; • 基本类型&#xff1a; o Number o String o Boolean o Undefined o null o symbol • 引用类型 o Object o Array o Function • 声明变量时不同的内存地址分配&#xff1a; o 简单类型的…

leetcode刷题记录37-2476. 二叉搜索树最近节点查询

问题描述 给你一个 二叉搜索树 的根节点 root &#xff0c;和一个由正整数组成、长度为 n 的数组 queries 。 请你找出一个长度为 n 的 二维 答案数组 answer &#xff0c;其中 answer[i] [mini, maxi] &#xff1a; mini 是树中小于等于 queries[i] 的 最大值 。如果不存在这…

机器学习实验------PCA

目录 一、介绍 二、算法流程 &#xff08;1&#xff09;数据中心化 &#xff08;2&#xff09;计算协方差矩阵 &#xff08;3&#xff09;特征值分解 &#xff08;4&#xff09;选择特征 三、运行结果展示 四、实验中遇到的问题 五、PCA的优缺点 优点&#xff1a; 缺点…

macbook本地部署 pyhive环境连接 hive用例

前言 公司的测试和生产环境中尚未提供基于Hive的客户端。若希望尝试操作Hive表&#xff0c;目前一个可行的方案是使用Python语言&#xff0c;通过借助pyhive库&#xff0c;您可以对Hive表进行各种操作。以下是一些示例记录供您参考。 一、pyhive是什么&#xff1f; PyHive是一…