【Linux】玩转操作系统,深入刨析进程状态与调度机制

news2024/11/16 4:18:49

目录

  • 1. 进程排队
  • 2. 进程状态的表述
    • 2.1. 进程状态
    • 2.2 运行状态
    • 2.3. 阻塞状态
    • 2.4. 挂起状态
  • 3. Linux下具体的进程状态
    • 3.1. 运行状态R
    • 3.2. 可中断睡眠状态S
    • 3.3. 不可中断睡眠状态D
    • 3.4. 停止状态T
    • 3.5. 死亡状态X
    • 3.6. 僵尸状态Z
  • 4. 孤儿进程
  • 5. 优先级
  • 6. Linux的调度与切换
    • 6.1. 四个概念
    • 6.2. 进程切换
    • 6.3. 进程调度

1. 进程排队

  1. 进程排队:指的是操作系统将等待资源的进程组织成队列,以便按照特定的调度策略来决定哪个进程可以获取资源并继续执行,即:将进程放入到等待资源的队列中进行排队。

进程排队,表示进程不是一直在运行的,是在等待某种软硬件"资源"。eg:scanf,等待键盘资源。

即使进程被调度到CPU上执行,它也不会一直运行下去。在多任务操作系统中,进程的执行是分时的,每个进程会分配到一定的时间片来执行,当时间片用完,操作系统会暂停运行当前进程。

  1. 进程排队,一定是进程的task_struct(PCB)进行排队。

  2. 进程的task_struct(PCB)可以放入到多种数据结构中。

进程的PCB既可以被放入到全局的双链表中,又可以被放入到特定的队列中。当进程被放入到全局的双链表中,OS会在进程的每个PCB中创建链表节点的对象;当进程被放入到特定的队列中,OS会在队列的数据结构中创建或复用双链表节点,在PCB中设置队列节点的链接。

image.png

2. 进程状态的表述

前言:教材中描述进程状态的模型和实际操作系统(如:Linux)中实现的进程状态模型可能会有差异。

2.1. 进程状态

  1. 进程状态:本质是一个整形类型的变量,它定义在task_struct结构体中,用来描述进程的不同的不同状态。
  2. 进程状态,决定着进程的后续操作和它在操作系统的行为。

image.png

2.2 运行状态

运行状态:进程已经准备好随时被调度。即:正在CPU上执行以及在运行队列中等待被调度的进程。

💡Tips:一个CPU一个运行队列。
屏幕截图 2024-07-20 104921.png

2.3. 阻塞状态

阻塞状态:进程暂时无法继续执行,在等待某种软硬件"资源"。

💡Tips:每个硬件都有自己的队列!

  1. 当进程在等待软硬件资源的时候,资源没有就绪,操作系统就会先将进程的task_struct设置为阻塞状态、再将task_struct链入到等待资源的等待队列中。

  2. 状态的变迁,引起的是PCB会被操作系统变迁到不同的队列中!
    image.png

  3. 硬件的就绪状态,本质是硬件的资源准备好执行任务的状态,操作系统作为硬件的管理者,负责监控和管理这些硬件资源的状态。

硬件资源就绪,对于键盘的输入,通常是指键盘的中断机制已触发,表明有新的输入数据已经准备好了。

键盘的输入处理流程如下:硬件资源就绪(键盘输入准备完毕)→ OS通过驱动程序将数据从外设(键盘)搬到内存(内核输入缓冲区)→ 用户程序通过系统调用接口(scanf)将数据从内存搬到用户空间。

2.4. 挂起状态

挂起状态:进程被暂时停止执行,它的状态被保存,以便在将来某个时刻恢复。分为内部挂起、外部挂起。

  1. 外部挂起:也称为阻塞挂起。当系统资源紧张,如:内存空间不足,OS会将进程的代码和数据保存到磁盘的swap分区,以释放内存供其他进程使用,此时进程状态为挂起状态。当内存资源变的可用时,OS会将对应的代码和数据重新加载到内存中,并将其状态由挂起变为运行,以便它可以被调度执行。

  2. 唤出过程:当内存资源紧张时,OS会将内存中数据(等待资源的进程的代码和数据)交换到磁盘的swap分区中,以释放内存空间,这个过程称为唤出。

  3. 唤入过程:当需要恢复执行此进程时,就会将磁盘的swap分区保存的内容回到内存中,使进程可以继续执行,这个过程称为唤出。

image.png

问1:创建一个新进程,是先创建进程的PCB,还是先把进程的代码和数据加载到内存中?

答:先创建进程的PCB,再把进程的代码和数据加载到内存中,确保了OS对进程的创建和管理。

问2:磁盘的swap分区的大小是越大越好吗?

答:不是,会导致性能下降、资源浪费等问题。与内存相比,磁盘速度慢的多,如果swap分区很大,会导致OS过度依赖它,而频繁的唤入唤出操作会显著降低系统的性能,因为磁盘的IO速度远低于内存的读写速度。

  • swap分区不能设置过大,通常大小等于内存大小或内存大小的一半。

3. Linux下具体的进程状态

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

image.png

3.1. 运行状态R

运行状态R:进程正在运行或者准备运行。它可能正在CPU上执行,或者在运行队列中等待被调度。

在这里插入图片描述

  1. grep是单独指令,是程序,只有被运行,变成进程,它才会执行过滤操作,所以它的状态总是运行状态R。

  2. 前台进程(带+),可以被键盘(ctrl + c)终止;后台进程(不带+),不可以被键盘终止,可以通过发信号(kill -9 进程的PID),才可终止后台进程 ;前台进程 -> 后台进程:./程序 & 。

3.2. 可中断睡眠状态S

可中断睡眠S:也称为浅度睡眠或睡眠状态,意味着进程正在等待某个事件的完成,如: I/O操作、定时器到期(sleep函数)等,它可以被信号中断,如:ctrl + c、kill -9终止进程。

💡Tips:可中断睡眠睡眠S == 阻塞状态。

#include<stdio.h>
#include<unistd.h>
 
int main()
{
    while(1)
    {
        printf("I am a process, id: %d\n", getpid());
        sleep(1);
    }
}

在这里插入图片描述
问:为什么这个进程处于睡眠状态?

答:sleep函数会将进程由运行状态变为睡眠状态,等待指定的时间,进程会被OS唤醒。printf函数的执行速度通常是非常快的,因为CPU的执行速度很快,而printf是向显示器打印,需要访问外设,printf可能会等待I/O操作完成时使进程短暂的进入睡眠状态。

3.3. 不可中断睡眠状态D

不可中断睡眠D:也称为深度睡眠或磁盘休眠状态,它通常会等待硬件操作(如:磁盘I/O)完成,不能响应信号,直到它所等待的事件完成。

💡Tips:不可中断睡眠睡眠D == 阻塞状态。

eg:当一个进程发起磁盘的写入操作时,当内存资源十分吃紧,如果此进程处于睡眠状态S,OS就会将此进程杀掉,可能会导致数据丢失,所以此进程的状态被设置于不可中断睡眠状态D,OS不可以杀掉此进程,进程等待磁盘的结果以作出相应的应答。

3.4. 停止状态T

停止状态T:意味着进程已经被暂停或者正在被追踪,通常是因为接受到一个信号,或者是在调试器中被断点所拦截。

💡Tips:停止状态T == 阻塞状态。

  1. 可以通过发送SIGSTOP信号(kill -19)给进程来停止进程,通过发送SIGCONT信号(kill -18)让处于暂停状态的进程继续运行。

image.pngimage.png

3.5. 死亡状态X

死亡状态X:意味着进程已经终止,且资源已经被回收,它只是一个返回状态,不再存在于进程列表中。

3.6. 僵尸状态Z

僵尸状态:进程已经退出,但其父进程尚未调用wait( )来收集其退出信息。即: 进程是已退出但未清理的状态,等待父进程回收资源。

  1. 前提:子进程比父进程先退出。只要子进程退出了,父进程还在运行,但父进程没有读取子进程退出信息,子进程就进入Z状态,当父进程回收了子进程的资源,子进程由Z状态变为X状态。

处于僵尸状态的进程会一直保存在进程列表中。通常情况下,进程先变为Z状态,再变为X状态。

  1. 当一个Shell( bash )会话结束时,如果没有显示的调用wait( )回收子进程的资源,而Shell作为父进程,会自动调用wait( )来清理所有已经终止的子进程的资源,避免留下僵尸进程,后台进程除外。

  2. 当进程退出后,先会释放进程的代码和数据,进程的PCB不能被释放,因为它里面存储着结果数据,只有当父进程完成了资源的回收和状态的读取,PCB才会被释放。

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<wait.h> 

int main()
{
    pid_t id = fork();
    if(id < 0) return 1;
    else if(id == 0)
    {
        //子进程
        int cnt = 5;
        while(cnt--)
        {
            printf("I am child process, pid: %d, ppid:%d\n",getpid(    ),getppid()); 
            sleep(1);
        }
        exit(0);
    }
    else
    {
        //父进程
        int cnt = 10;
        while(cnt--)
        {
            printf("I am father process, pid: %d, ppid:%d\n",getpid    (),getppid());
            sleep(1);
        }
    }
    wait(NULL);
                                                                     
    printf("father wait child done...\n");
    sleep(5);
}
//现象:父子进程同时运行5s, 5s后子进程退出(变Z状态), 父进程在运行5s, 5s后父进程回收子进程资源(子进程由Z->X状态), 5s后父进程退出

a. 为什么要有僵尸状态Z?

  • 创建进程是希望这个进程执行特定任务,子进程在完成工作后,往往需要向父进程报告结果或者状态信息(子进程必须由结果数据保存在自己的PCB中) , 从而使父进程能够根据子进程的执行结果作出适当的响应。

b. 什么是僵尸状态Z?

  • 进程已经退出,但是当前进程的状态需要自己维持住,供父进程读取。

c. 如果父进程不读取子进程的退出数据呢?

  • 僵尸状态的进程会一直存在,而维护退出状态本质是用数据维护,存储在进程的PCB,所以task_struct对象也要一直存在,而数据结构对象本身就要占用内存,会造成内存泄漏。

4. 孤儿进程

孤儿进程:父进程比子进程先退出,子进程就称为"孤儿进程"。

  • 孤儿进程被PID为1的进程(操作系统)领养,由OS回收其资源。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>

int main()
{
    pid_t id = fork();
    if(id < 0) return 1;
    else if(id == 0)
    {
        //子进程
        int cnt = 10;
        while(cnt--)
        {
            printf("I am child process, pid: %d, ppid:%d\n",getpid(    ),getppid()); 
            sleep(1);
        }
        exit(0);
    }
    else
    {
        //父进程
        int cnt = 5;
        while(cnt--)
        {
            printf("I am father process, pid: %d, ppid:%d\n",getpid    (),getppid());
            sleep(1);
        }
    }                                                       
}

5. 优先级

优先级:CPU资源分配的先后顺序。

  1. 前提:进程要访问某种资源,进程通过一定的方式(排队),确认享受资源的先后顺序。

  2. 为什么要存在优先级?因为资源相对过少。

  3. 优先级本质是一个整数类型的变量,数值越小,优先级越高,具有优先执行的权力。

  4. 优先级PRI(new) = 优先级PRI(old) + nice。

Linux系统允许用户调整进程的优先级,但不能直接修改pri,而是修改进程的nice值。

nice值:是进程优先级的修正数据,!=进程优先级;优先级PRI(old)为默认优先级(值为80)。

  1. Linux优先级默认值为80,优先级的范围为[60 , 99],nice值的范围为[-20,19],一共40个。

Linux为什么调整优先级是要受限制的?

答:如果不受限制,则用户能够随意提高自己的进程优先级调整的非常高,那么很可能他们会过度提升自己的进程,使其始终处于高优先级的状态,导致常规进程难以得到CPU资源,产生进程饥饿现象。

💡Tips:任何分时系统(基于时间片进行轮转执行),确保了进程调度的公平性和系统的稳定性!

ps -l

  • 功能:显示当前登录用户的所有进程的信息。

XQO_I_HJQOJ~HJ{N96`XFI5.png
UID:代表执行者的身份、PID:进程的唯一标识符、PPID:子进程的父进程的唯一标识符、PRI:进程的优先级、NI:进程优先级的修正数据。

top -> r -> 输入进程的PID -> 输入nice值

  • 功能:用top命令更改已存在进程的nice值,从而调整进程的优先级。

优先级.gif

renice nice 进程的PID

  • 功能:更改已存在进程的nice值,从而调整进程的优先级。

6. Linux的调度与切换

6.1. 四个概念

现代操作系统可以分成不同类别,分时操作系统和实时操作系统是两种重要的类型。

对于分时OS,进程都是基于时间片进行轮转执行的。每个就绪进程在轮到自己时,将会获得一个时间片来执行,如果一个进程在时间片结束时还没有执行完,它就会立即被暂停,CPU将被分配给下个进程,造成多个进程在"同时"运行的假象。

对于实时OS,采用的是优先级驱动的调度策略,要求OS对用户有超高响应,其中一旦高优先级的进程一旦就绪,将立即抢占CPU执行,如:车载系统。

  1. 竞争性:系统中进程的数量多、而CPU资源少量,所以进程之间对于共享资源是具有竞争属性的。

  2. 独立性:多进程在运行期间互不影响。每个进程在执行时都有自己的私有执行环境,包括代码、数据等资源,它们各自独享自己的执行资源。

  3. 并行:多个进程在多个CPU下,分别同时进行运行。

  4. 并发:多个进程在一个CPU下采用进程切换的方式,在一段时间内,多个进程看起来同时执行。

6.2. 进程切换

进程切换 = 保护进程的硬件上下文 + 进程的硬件上下文恢复。是OS在多任务环境中实现进程间公平调度和并发执行的关键机制。

  1. 进程在运行的过程中,会产生大量的临时数据,小部分被存储在CPU的寄存器中,大部分被存储在内存中。

  2. 进程的硬件上下文:在某一时刻,CPU执行进程时,所有硬件状态信息的集合。如:CPU内部的寄存器中存储的所有临时数据等。

  3. 保存进程的硬件上下文:当一个进程的时间片结束、主动放弃CPU(等待某种资源scanf)、有更高优先级的进程就绪需要暂时停止执行,OS会保存该进程的硬件上下文到进程的PCB中。

  4. 进程的硬件上下文恢复:在保存完当前进程的上下文后,OS会选择下一个要运行的进程,如果该进程是第二次被调度,就会将该进程的PCB中上下文重新加载到CPU上,CPU会从上次的运行位置继续运行。

💡Tips:所有的保存都是为了最终的恢复,所有的恢复都是为了继续上次的运行位置继续执行。

  1. CPU中的寄存器从物理上是被所有进程共享,在任意时刻,CPU的寄存器由当前正在执行的进程独占使用,而寄存器内部保存的数据,是被该进程私有的。即:CPU中的寄存器只能有一套,寄存器内部保存的数据可以有多套。

💡Tips:寄存器 != 寄存器的内容。

6.3. 进程调度

在这里插入图片描述
背景:Linux的进程调度O(1)算法,需要考虑优先级、进程饥饿、以及效率等问题,这主要是通过是特定的数据结构和算法设计来实现的。

一、####数据结构

  1. queue[140]

这是个优先级数组(prio_array),它是一个长度为140的指针数组,每个元素包含一个链表头,该链表包含具有相同优先级的所有就绪进程,即:每个元素对应一个优先级队列,每个队列中的进程具有相同的优先级,它维护了140个优先级队列。

实时优先级:0~99,用于实时进程,以确保它们能够及时响应并完成任务。

普通优先级:100~139,通过nice值[-20,19]可以调整进程在该范围内的优先级,用于非实时进程,遵循时间片轮转调度策略,确保进程公平的共享CPU资源。image.png

  1. bitmap[5]

这是一个位图(prio_map),用于快速检测哪些优先级队列是非空的。它是一个5个整数的数组,每个整数有32个比特位,共有5*32=160个比特位 > 140,位图操作都是在比特级别进行的,时间复杂度为O(1),非常高效。

位图中的每个比特位的位置,对应着一个优先级队列;每个比特位的内容,表示这个队列是否为空。即:检测某个优先级队列中是否有进程,转为为检测对应比特位是否为1。

  1. nr_active

这是一个计数器,用于记录当前活跃进程队列中进程的总数。

struct q
{
    int nr_active;
    int bitmap[5];
    task_struct queue[140];
}

二、####算法实现

  1. 优先级

通过优先级数组和位图,调度器,可快速定位到最高优先级的非空队列。当需要调度下一个进程时,调度器首先会遍历位图,直到找到’第n位’为1才会停下,再访问queue数组中的下标值为’第n位’的元素,取出该队列中第一个进程进行运行。

  1. 避免进程饥饿

OS会将时间片耗尽的进程放到过期队列中,不让他们一直占用活跃队列的位置,确保其他进程被调度到CPU上执行;新增进程也会被加入到过期队列,不论这个新进程的优先级高低,避免了较高优先级的进程抢占CPU资源。而CPU只会执行活跃队列中的进程,当活跃队列上的进程都被执行完毕,两队列交换。

  1. 效率

因为bitmap[5]数组的存在,调度器只需要遍历bitmap[5]数组,而不是整个queue[140]数组,大大减少了遍历的次数。位图的查询操作时间复杂度为O(1),意味着无论多少个优先级队列,调度器只需要遍历bitmap[5],就可以快速找到非空优先级队列,大大提高了查找效率。

三、活跃进程队列、过期进程队列

  1. 活跃进程队列:包含了当前准备就绪,可以立即被执行的进程。

  2. 过期进程队列:包含了时间片耗尽,但未执行完毕的进程。

四、active指针、expired指针

  1. active指针永远指向活跃队列、expired指针永远指向过期队列。

  2. 进程的时间片一直存在,就会使活跃队列的进程一直在减少、过期队列的进程一直在增多。

struct q  
{
    int nr_active;
    int bitmap[5];
    task_struct queue[140];
}

struct q array[2]; 

struct q* active = &array[0];    //活跃队列
struct q* expired = &array[1];  //过期队列

swap(&active, &expired); //更改的只是指针变量的内容,队列内容并未改变

image.png

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

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

相关文章

[代码审计]记一次简单的java代码审计

如果觉得该文章有帮助的&#xff0c;麻烦师傅们可以搜索下微信公众号&#xff1a;良月安全。点个关注&#xff0c;感谢师傅们的支持。 免责声明 本博客所发布的所有内容&#xff0c;包括但不限于信息、工具、项目以及文章&#xff0c;均旨在提供学习与研究之用。所有工具安全…

《代码大全》读书笔记-第Ⅰ部分 奠定基础

0.欢迎来到软件构建世界 什么是软件构件&#xff1a; 对于非正式及项目&#xff0c;会觉得罗列出来的这些活动太过于繁复。但是这些对于正式项目都是很有必要的(大部分人都没经历过&#xff0c;比如说我)。一般一些小公司主要也就是需求分析、编码、开发人员自测、集成测试这几…

数据库第五次作业

1. 触发器 建立触发器&#xff0c;订单表中增加订单数量后&#xff0c;商品表商品数量同步减少对应的商品订单出数量,并测试 建立触发器&#xff0c;实现功能:客户取消订单&#xff0c;恢复商品表对应商品的数量 建立触发器&#xff0c;实现功能:客户修改订单&#xff0c;商品…

步入新时代,使用区块链服务API打造创新应用

随着区块链技术的兴起&#xff0c;我们正步入一个全新的数据时代——一个由透明性、安全性和去中心化定义的时代。Blockchain公司的区块链API&#xff0c;作为连接现实世界与区块链世界的桥梁&#xff0c;为全球开发者和企业提供了一种前所未有的方式&#xff0c;以访问、交互并…

文件共享功能无法使用提示错误代码0x80004005【笔记】

环境情况&#xff1a; 其他电脑可以正常访问共享端&#xff0c;但有一台电脑访问提示错误代码0x80004005。 处理检查&#xff1a; 搜索里输入“启用或关闭Windows功能”按回车键&#xff0c;在“启用或关闭Windows功能”里将“SMB 1.0/CIFS文件共享支持”勾选后&#xff08;故…

屏幕管控——保护文档内容安全

屏幕管控是保护文档内容安全的重要手段之一&#xff0c;它涉及到对终端屏幕的使用、访问权限、内容展示以及操作行为的监控和管理。专业的企业级防泄密系统&#xff0c;如金刚钻信息&#xff0c;会有一些专业功能针对屏幕这块有对应的防护措施。 一、屏幕水印设置 屏幕水印是…

外卖霸王餐系统推荐,哪家的系统比较稳定呢?

以下是一些较为稳定且有一定用户基础的外卖霸王餐系统&#xff0c;你可以根据自身需求进一步考察和选择&#xff1a; - **饭否霸王餐**&#xff1a;有专门的APP&#xff0c;如在应用宝上其开发商为南京有惠鲸选电子商务有限公司。它覆盖了多个城市&#xff0c;提供美团、饿了么…

从0到1,AI我来了- (1)从AI手写数字识别开始

前两篇我们我们把控制台、Python环境Anaconda 搞定了&#xff0c;接下来&#xff0c;我们快速进入主题&#xff0c;把AI 界的“Hello World” 实现一下&#xff0c;有个感觉&#xff0c;再逐步了解一些AI的概念。 1、Pytorch 安装 1) 什么是Pytorch? 一个深度学习框架&#…

C语言常见字符函数和字符串函数精讲

目录 引言 一、字符函数 1.字符分类函数 2.字符转换函数 二、字符串函数 1.gets、puts 2.strlen 3.strcpy 4.strncpy 5.strcat 6.strncat 7.strcmp 8.strncmp 9.strstr 10.strchr 11.strtok 12.strlwr 13.strupr 引言 在C语言编程中&#xff0c;字符函数…

第二证券:股票交易费用有哪些?

出资者生意股票是需求付出生意费用的&#xff0c;一般来说股票的生意费用主要有以下几种&#xff1a; 1、证券公司佣金。这是证券公司收取的一种服务费&#xff0c;用于供给股票生意的途径和服务。证券公司佣金的份额由证券公司自行拟定&#xff0c;但最高不得超越成交金额的0…

elasticsearch8.14.1集群安装部署

elasticsearch安装部署&#xff0c;首先需要准备至少三台服务器&#xff0c;本例再windows11下安装三台vmware虚拟机&#xff0c;利用centOS7系统模拟服务器环境。 本例假设你已经安装了三台vmware和centOS7&#xff0c;且centOS7运行正常。接下来我们直接讲解elasticsearch下载…

通过IEC104转MQTT网关轻松接入阿里云平台

随着智能电网和物联网技术的飞速发展&#xff0c;电力系统中的传统IEC 104协议设备正面临向现代化、智能化转型的迫切需求。阿里云作为全球领先的云计算服务提供商&#xff0c;其强大的物联网平台为IEC 104设备的接入与数据处理提供了强大的支持。本文将深入探讨钡铼网关在MQTT…

Python seaborn超级细节篇-使用配色palette

本文分享Python seaborn中通过配色palette美化图形。配色(palette),用于设置color palette,例如,Set1、#a1c9f4、red等。 内容很多,快速浏览一下,节选自👉Python可视化-seaborn篇 这里展示部分, 5.3 palette设置图形配色 设置图形配色palette目的在于有效地展示数…

【ffmpeg命令入门】视频剪切,倍速与倒放

文章目录 前言1. 视频剪切2. 视频倍速公式说明例子 3. 视频倒放总结 前言 在视频编辑中&#xff0c;剪切、倍速和倒放是常见的操作&#xff0c;能够帮助我们调整视频的长度、播放速度以及播放顺序。掌握 FFmpeg 命令中的相关参数和用法将使视频处理变得更加高效。在这篇文章中…

vLLM——使用PagedAttention加速推理

参考自https://blog.vllm.ai/2023/06/20/vllm.html 介绍 vLLM是一个用于快速LLM推理和服务的开源库。vLLM 利用PagedAttention&#xff0c;可以有效地管理注意力键和值。PagedAttention 的 vLLM 重新定义了 LLM 服务的最新水平&#xff1a;它提供了比 HuggingFace Transforme…

jdk的major version和minor version是啥意思?

写在前面 1&#xff1a;正文 major version是大版本号&#xff0c;minor version是小版本号&#xff0c;但目前minor version都是0&#xff08;也可能是我没有发现&#x1f605;&#xff09;&#xff0c;如jdk8就是52&#xff0c;如下表&#xff1a; 可以看到jdk版本号和ma…

【Java】随机值设置

&#x1f389;欢迎大家收看&#xff0c;请多多支持&#x1f339; &#x1f970;关注小哇&#xff0c;和我一起成长&#x1f680;个人主页&#x1f680; 在Java中设置随机值通常涉及到java.util.Random类或Math.random()方法。 使用Math.random()方法 Math.random()生成的随机…

AI在Facebook的应用:预见智能化社交的新前景

在数字化时代&#xff0c;社交媒体平台已成为我们生活的重要组成部分&#xff0c;而人工智能&#xff08;AI&#xff09;的快速发展正推动着这些平台向更智能、更个性化的方向发展。Facebook&#xff0c;作为全球最大的社交网络平台之一&#xff0c;正不断探索和应用AI技术&…

leetcode日记(54)加一

很简单 class Solution { public:vector<int> plusOne(vector<int>& digits) {int ndigits.size();for(int in-1;i>0;i--){if(digits[i]<9){digits[i];break;}else if(i0){digits[i]0;digits.insert(digits.begin(),1);}else digits[i]0;}return digits…

【React】JSX 实现列表渲染

文章目录 一、基础语法1. 使用 map() 方法2. key 属性的使用 二、常见错误和注意事项1. 忘记使用 key 属性2. key 属性的选择 三、列表渲染的高级用法1. 渲染嵌套列表2. 条件渲染列表项3. 动态生成组件 四、最佳实践 在 React 开发中&#xff0c;列表渲染是一个非常常见的需求。…