Linux进程-2

 一:进程优先级

基本概念

cpu资源分配的先后顺序,就是指进程的优先权(priority)。
优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

查看系统进程 ps -la

ps -la命令用于以长格式列出当前系统中所有进程的信息,包括所有用户的进程。-l 选项提供详细的进程信息,而 -a 则表示显示所有进程,包括没有控制终端的进程。

UID : 代表执行者的身份 (跟该程序的持有者 所属组对比,看是否有对应权限)
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
 PRI = 80+NI 
NI :代表这个进程的nice值 [-20,19]

修改优先级

top -> r(进入修改模式) -> 要修改的进程的PID -> 修改后的NI值

PRI=80+NI

[root@hcss-ecs-178e ~]# ps -la
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0 30838 30810  0  80   0 - 47970 do_wai pts/1    00:00:00 su
4 S  1001 30839 30838  0  80   0 - 28887 do_wai pts/1    00:00:00 bash
0 S  1001 30860 30839  0  80   0 -  1054 hrtime pts/1    00:00:00 myexe
1 S  1001 30861 30860  0  99  19 -  1054 hrtime pts/1    00:00:00 myexe
4 R     0 30894 30862  0  80   0 - 38332 -      pts/2    00:00:00 ps

二:进程切换

1. 什么是进程切换?

进程切换是指 CPU 停止执行当前进程,并将控制权转移到另一个进程的过程。这种机制使得操作系统能够在多任务环境中并发运行多个进程。

2. 进程切换的原因

时间片到期:当某个进程的时间片用完时,调度器会选择其他进程。

I/O 操作:进程请求 I/O 操作时,会被阻塞,操作系统会切换到其他可运行的进程。

3. 如何进行切换的

首先结构体指针current会指向目标task_struct

pc(程序计数器)内数据是下一条指令的地址,ir(指令寄存器)内数据是目前要执行的指令内容。

1.控制器读取PC中的地址。

2.从内存中获取该地址对应的指令,并将其放入IR中。

3.PC自增,指向下一条指令的地址。

4.控制器执行IR内指令。

5.不断循环直到进程结束或停止。

那这些数据哪里来的呢?如果执行到一半,该第二个进程执行,那这些数据怎么办呢?

其实这些相关寄存器的内容会被存入task_struct(PCB)中,等到再执行到它的时候,再把数据拷贝回PCU的寄存器中,就可以继续运行。

三:Linux2.6内核进程调度队列

CPU的调度顺序是按照队列的顺序从头到尾变量一遍吗?那优先级体现在那呢?

runqueue

runqueue调度队列中有两个指针*active *expired,他们各自指向一个结构体struct queue array

,array中有

1.queue[140]: 一个元素就是一个进程队列。

下标0~99是实时优先级(不关心)(实时优先级使用 SCHED_FIFO 和 SCHED_RR 策略,优先级高的实时任务会优先获得 CPU,实时任务可以抢占普通任务。)

下标100~139是普通优先级(我们都是普通的优先级,想想nice值的取值范围,可与之对应!)

task_struct优先级越高,下标越小。优先级相同的串在同一个位置,类似哈希桶那样。

2.int nr_active 代表队列中有多少个进程

3.int bit_map[5] 用来快速查找进程位置

活动队列 过期队列

*active指向的就是活动队列,*expried指向的就是过期队列。

为什么要有两个队列呢?
1.活动队列中就是要将要调度的进程,如果该进程运行退出了/时间片到了,或者又有新的进程出现了,要重新插到活动队列里吗?随便插就不能叫队列了,尾插优先级就体现不出来了。

2.所以我们一般这3种情况的进程按优先级大小插入到过期队列中。

3.当我们活动队列中nr_active==0时说明已经没有进程了,之后swap(&active,&expried),通过交换指针的对象来改变活动队列 过期队列,保证活动队列只出不进,过期队列只进不出。

快速查找队列中进程

int bit_map[5] 用来快速查找进程位置,这是怎么做到的呢?

5 int = 20 字节 = 160 bit 可以满足140个进程

每一个bit位代表一个进程,存在1 不存在0。

遍历数组,一次性就可以看32个位置存不存在进程。

1.为0说明没有进程

2.不为0有进程,下面代码可以查一个数的二进制中有几个1

int count_set_bits(int x) {int count = 0;while (x) {count++;x &= (x - 1);}return count;
}

这是因为 x - 1 会将 x 的最低位的“1”变为“0”,并将其右侧的所有位(如果有的话)变为“1”。然后,使用按位与(&)操作符,xx - 1 结合后,最低的“1”位被清除。

举个例子:

假设 x = 12,它的二进制表示为 1100

  1. 计算 x - 1

    • x - 1 = 11,二进制为 1011
  2. 按位与操作

    x = 1100 ;x - 1 = 1011  x &= (x - 1) = 1000

补充:为什么进程可以在不同队列中

一般队列中的元素都是包含 数据data 指向下个元素指针struct node*next,

而在struct task_struct这个结构体中,有多个队列 struct node link struct node queuenode...

里面的成员只有指向下个元素的指针struct node*next,而这个元素是struct task_struct的成员变量。知道成员变量地址,就可以算出该结构体首地址,进而随便访问它的成员变量。

成员变量地址-该成员变量的偏移量=struct task_struct的首地址。

offsetof(结构体名, 成员变量名) 

  • &(((type *)0)->member):通过解引用该指针获取成员的地址。

四:命令行参数

什么是命令行参数

命令行参数是用户在运行程序时通过命令行界面传递给程序的输入值。这些参数通常用于配置程序的行为或提供必要的数据。

eg. ls -l -a 

ls指令后面的-l -a 就是命令行参数

这段代码可以打印出命令行参数

argc代表参数个数,argv[] 里面是以空格分开是字符串

根据参数列表的不同,同一个程序可以实现出不同的功能。

eg.ls -a       ls -l

谁传给main函数参数列表的?

参数是由操作系统在程序启动时传递的,当用户在命令行中运行程序时,操作系统会解析命令行并将参数传递给程序。

五:环境变量

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。

查看环境变量

1.通过main函数第三个参数

env[0]:XDG_SESSION_ID=354
env[1]:HOSTNAME=hcss-ecs-178e
env[2]:SHELL=/bin/bash
env[3]:TERM=xterm
env[4]:HISTSIZE=10000
env[5]:SSH_CLIENT=121.36.59.153 43740 22
env[6]:OLDPWD=/root
env[7]:SSH_TTY=/dev/pts/0
env[8]:USER=wws
env[9]:LD_LIBRARY_PATH=:/home/wws/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
env[10]:LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
env[11]:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
env[12]:MAIL=/var/spool/mail/root
env[13]:PWD=/home/wws
env[14]:LANG=en_US.UTF-8
env[15]:HISTCONTROL=ignoredups
env[16]:HOME=/home/wws
env[17]:SHLVL=2
env[18]:LOGNAME=wws
env[19]:SSH_CONNECTION=121.36.59.153 43740 192.168.15.237 22
env[20]:LESSOPEN=||/usr/bin/lesspipe.sh %s
env[21]:XDG_RUNTIME_DIR=/run/user/0
env[22]:HISTTIMEFORMAT=%F %T wws 
env[23]:_=./myexe

2.env指令

env   查看所有环境变量

3.echo $环境变量名

在 Linux 中,echo $环境变量名 命令用于显示环境变量的值。

[wws@hcss-ecs-178e ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

4.getenv函数

#include <stdio.h>
#include <stdlib.h>int main() {const char *path = getenv("PATH");  // 获取 PATH 环境变量if (path != NULL) {printf("PATH: %s\n", path);} else {printf("环境变量 PATH 不存在。\n");}return 0;
}

头文件#include<stdlib.h> 找到返回指向该变量值的指针,找不到返回NULL

5.environ全局变量

environ 是一个全局变量,其类型通常定义为 char **environ,表示指向字符指针的指针。

#include <stdio.h>
#include <stdlib.h>extern char **environ;  // 声明 environint main() {// 打印所有环境变量for (char **env = environ; *env != 0; env++) {printf("%s\n", *env);}
}

常见的环境变量

1.PATH 

PATH是一个环境变量,它指定了系统查找可执行文件的目录。

如果我们运行程序时没有加路径就会在PATH的路径下查找。eg. ls

通常是由多个路径组成,以冒号为分隔符。

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

如果我们自己写的程序不想加路径就运行,1.可以把程序move到默认路径下。

2.可以在PATH中添加我们程序所处的路径。PATH=$PATH:新增路径

                                                                      $PATH是原本的路径

[wws@hcss-ecs-178e ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[wws@hcss-ecs-178e ~]$ pwd
/home/wws
[wws@hcss-ecs-178e ~]$ PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[wws@hcss-ecs-178e ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

但当我们重新登录的时候却发现PATH中没有我们新增的路径,这是为什么?
我们要知道PATH等环境变量的内容是从系统的配置文件中获取的,在家目录下找到.bash_profile文件(用于设置环境变量、启动程序及其他一次性配置。)在里面添加自己的路径就可以保存下来。

source ~/.bashrc命令让它立即生效。

2.HOME

HOME的内容代表家目录路径,也就是用户一开始登录的路径。

[wws@hcss-ecs-178e ~]$ echo $HOME
/home/wws
[wws@hcss-ecs-178e ~]$ su -
Password: 
Last login: Thu Sep 26 19:25:10 CST 2024 from 121.36.59.153 on pts/0
[root@hcss-ecs-178e ~]# echo $HOME
/root

根据用户的不同,系统设定的HOME也不同,所以用户就能根据自己的HOME找到自己的家目录。

3.SHELL

 查看当前使用的 shell:

[wws@hcss-ecs-178e ~]$ echo $SHELL
/bin/bash

4.PWD

获取当前工作目录

[wws@hcss-ecs-178e ~]$ echo $PWD
/home/wws

5.USER

当前用户

[wws@hcss-ecs-178e ~]$ echo $USER
wws

根据比对USER是否相同,程序就可以实现让特定用户来执行。

6.OLDPWD

上一次所处的路径

[wws@hcss-ecs-178e ~]$ echo $OLDPWD
/root

cd ~

本地变量

set

[wws@hcss-ecs-178e ~]$ a=1
[wws@hcss-ecs-178e ~]$ b=2
[wws@hcss-ecs-178e ~]$ echo $a
1
[wws@hcss-ecs-178e ~]$ echo $b
2

定义的本地变量用env是查不到的,可以用set查看所有环境变量+本地变量

export

将本地变量变为环境变量。

也可以直接设置环境变量 export a=1

bash中有环境变量表 本地变量表,但只有环境变量表可以传给子进程,本地变量表不能,可以把本地变量变为环境变量再传给子进程。所以环境变量有全局属性(环境变量可以在父进程和子进程之间传递信息)

unset

可以删除环境/本地变量

[wws@hcss-ecs-178e ~]$ unset a
[wws@hcss-ecs-178e ~]$ echo $a

六:进程地址空间

上图是进程的地址空间的划分,这和我们之前C++内存区域划分是不是有点像呢?它们间有什么联系吗?

什么是进程地址空间

#include<stdio.h>
#include<unistd.h>
int g_val = 0;
int main()
{printf("begin.....%d\n",g_val);pid_t id = fork();if(id==0){//childint count = 0;while(1){printf("child: pid: %d,ppid: %d, g_val:%d, &g_val: %p\n",getpid(),getppid(),g_val,&g_val);sleep(1);g_val++;}}else if(id>0){//fatherwhile(1){printf("father: pod: %d,ppid: %d, g_val:%d, &g_val: %p\n",getpid(),getppid(),g_val,&g_val);sleep(1);}}return 0;
}

上面代码子进程对全局变量++,父进程不改变全局变量。

可以看到子进程读取g_val时它的值一直变化,而父进程读取g-val永远是0,但是父子进程取得g_val的地址都是一样。这个地址是物理地址吗?
不是,它是一种虚拟地址。是进程空间地址

进程空间地址的本质是一种结构体struct mm_struct,里面包含了不同区域的范围。

记住堆区的开始和结束地址,中间的都是可以用的。

struct mm_struct
{unsigned long code_start;//代码区unsigned long code_end;unsigned long init_start;//初始化区unsigned long init_end;unsigned long uninit_start;//未初始化区unsigned long uninit_end;unsigned long heap_start;//堆区unsigned long heap_end;unsigned long stack_start;//栈区unsigned long stack_end;//...等等
}

每一个进程都有一个虚拟地址,struct_task中成员变量有指向mm_struct的指针。

在内存中不止存有一个程序的资源,每个进程都有自己的虚拟地址,而虚拟地址的作用就是让每一个进程认为自己可以独享所有内存空间。

比如说进程申请空间,在虚拟地址中标记0x1111~0x2222的空间被申请,实际上在物理地址不一定是0x1111~0x2222,可能是在其它地方。虚拟地址栈区中有4G空间,但实际在物理地址中可能只有2G,这样进程申请3G空间,就会被系统拒绝。

页表

上述虚拟地址和物理地址中间是怎么联系的?
其实是根据页表产生联系的,页表是操作系统中用于管理虚拟内存的一种数据结构,它负责维护虚拟地址与物理地址之间的映射关系。

当进程访问某个变量,它在、的虚拟地址是0x1111,而物理地址是0x2222,页表的作用就是将进程使用的虚拟地址转换为物理地址。

fork()创建子进程,子进程的task_struct mm_struct 页表都是以父进程为模板创建的,所以指向同一段代码,如果子进程对数据进行修改g_val++ ,内存就会再开辟一块空间存放子进程的g_val,子进程页表映射就指向新开辟的空间。也就是写时拷贝

printf打印的就是虚拟地址,而系统真正访问的是物理地址,所以值会不一样。

标志位

在页表中处理了虚拟地址和物理地址外,还有一些标识符,那标志位有什么用?

1.读/写位(Read/Write Bit):

指示该页面是可读的还是可写的。如果该位为0,表示该页面为只读;如果为1,表示可以进行读写操作。

当我们对一个变量进行修改时,先看在页表中是否有对应的映射关系,如果有看是否有写权限,有就修改,反之终止进程。

就像char*str="111" *str="222",对它进行修改编译时不会进行权限检查,所以不会报错,运行时就会终止。也因此出现了const

2.存在位(Present Bit)

页面是否在物理内存中。如果该位为0,表示该页面不在内存中,可能需要从磁盘加载。

当程序从磁盘加载到内存中,不是一次性加载而是分批加载,访问时在页表中有映射关系并且存在位为1,才能访问。如果为0,要等数据从磁盘中加载到内存把存在位变1.

进程地址空间区域范围划分

每个程序都有自己的进程空间,大小不一样,进程空间的代码区等范围也是不一样的。mm_struct本质就是结构体变量,也需要初始化。那么它是根据什么进行初始化划分代码区,栈区 堆区等的范围的呢?

1.首先可执行程序除了代码和数据还包含属性,里面就有代码区范围的大小,变量权限是否可读写。

mm_struct的代码区范围就是从可执行程序的属性中读取。

2.栈区 堆区 命令行参数环境变量 这些程序编译的时候并不会创建,他们是由操作系统动态生成并管理的。当进程被创建时,操作系统会为其分配一个默认的栈/堆大小,函数开辟栈帧改变栈区大小,malloc/free会改变堆区大小

此时改变的mm_struct中堆区范围大小,在物理内存上并没有进行开辟,当对申请的空间使用时,才会在物理内存上开辟。确保物理内存中开辟的空间都在使用

为什么要有进程空间地址

1. 内存隔离

个进程都有独立的地址空间,这样可以防止一个进程访问或修改另一个进程的内存数据。

对内存进行修改时,要查看是否有对应权限才能修改。防止野指针随便修改内容

2.进程管理和内存管理在系统层面上解耦合

创建进程时可以先在进程空间上进行操作,等真正使用数据时再写入内存空间中。

3.让进程以统一的视角看待物理内存

每个进程在操作系统中都有自己独立的虚拟地址空间。这意味着每个进程都可以以统一且一致的方式访问其内存,而不必担心其他进程的内存内容。通过页表映射即使在物理内存中无序放置数据,也可以快速找到

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

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

相关文章

Mysql数据库相关操作总结

目录 1.背景知识 2.创建数据库 2.1创建指令 2.2字符集 3.查看数据库 3.选中数据库 4.删除数据库 5.数据表的操作 5.1基本数据类型 5.2创建表 5.3查看所有的表 5.4查看表的结构 5.5删除表 6.CRUD增删查改 6.1新增和效果查看 6.3删除 6.4查找 1.背景知识 数据库就…

哈希知识点总结:哈希、哈希表、位图、布隆过滤器

目录 哈希 哈希表 哈希常用方法 1、直接定址法 2、存留余数法 哈希冲突 哈希冲突的解决办法 1、闭散列&#xff1a;开放定址法 &#xff08;1&#xff09;线性探测法 &#xff08;2&#xff09;二次探测法 2、开散列 哈希桶 / 拉链法 哈希的运用 位图 set操作 …

3-3 AUTOSAR RTE 对SR Port的作用

返回总目录->返回总目录<- 一、前言 RTE作为SWC和BSW之间的通信机构,支持Sender-Receiver方式实现ECU内及ECU间的通信。 对于Sender-Receiver Port支持三种模式: 显式访问:若运行实体采用显示模式的S/R通信方式,数据读写是即时的;隐式访问:当多个运行实体需要读取…

Docker安装与应用

前言 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言开发。Docker 可以让开发者打包他们的应用以及依赖包到一个轻 量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互 之间…

关于Fake Location定位,运动世界校园问题

不好意思&#xff0c;之前那个文章其实是很早之前的&#xff0c;不知道为什么审核了很久一直没有通过&#xff0c;然后前几周莫名其妙点了一下重新发布&#xff0c;竟然发布成功了&#xff0c;这个方法已经失效了&#xff0c;要可以稳定&#xff0c;我建议是买一台root的手机&a…

鸿蒙开发(NEXT/API 12)【硬件(传感器开发)】传感器服务

使用场景 Sensor Service Kit&#xff08;传感器服务&#xff09;使应用程序能够从传感器获取原始数据&#xff0c;并提供振感控制能力。 Sensor&#xff08;传感器&#xff09;模块是应用访问底层硬件传感器的一种设备抽象概念。开发者可根据传感器提供的相关接口订阅传感器…

Docker容器的使用

前提条件 Linux环境安装好Docker&#xff0c;可参考Rocky Linux9下安装Docker和卸载Docker Docker命令图 帮助命令 帮助命令&#xff0c;查看有哪些命令可以用 [rootlocalhost ~]# docker --help ​ 查看某个命令的帮助&#xff0c;例如&#xff1a;run [rootlocalhost ~]# …

深入探索机器学习中的目标分类算法

在当今数据驱动的世界中&#xff0c;机器学习&#xff08;Machine Learning, ML&#xff09;正逐渐成为解决问题的重要工具。在众多机器学习任务中&#xff0c;目标分类&#xff08;Classification&#xff09;算法尤其受到关注。本文将深入探讨目标分类算法的基本概念、常见类…

【刷点笔试面试题试试水】 i++与++i哪个效率更高?

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: 都应该知道,i是先增加再参与计算. i是先计算再增加. 原理是i,是直接返…

免费的录屏软件有哪些?可以试试这4款。

录屏软件已经被用于很多的领域和场景当中&#xff0c;能够帮助我们进行在线教学&#xff0c;线上培训&#xff0c;游戏直播与分享&#xff0c;视频记录等等。并且很多的录屏软件都有免费的功能&#xff0c;它们让大家的录屏变得更加的方便。如果大家需要录屏工具的话&#xff0…

认知杂谈92《菜鸟的自我修炼:守住存款,识别诱惑》

内容摘要&#xff1a; “快速致富"的口号在网络和广告中无处不在&#xff0c;它们吸引着渴望改变生活的人。然而&#xff0c;这些诱惑常常是精心设计的骗局&#xff0c;利用人的贪婪本性。成功学导师们宣扬的"成功秘诀"和"快速通道”&#xff0c;让人陷入不…

【MATLAB代码】三维空间上的RSS(信号强度)定位,n个锚点自适应(锚点数>3即可)(源代码下载链接)

文章目录 代码概况源代码运行结果RSS定位原理讲解1.基本概念2.信号强度与距离关系3. 定位原理 其他情况 代码概况 基于MATLAB的定位程序&#xff0c;使用RSS&#xff08;接收信号强度&#xff09;来估计距离&#xff0c;再由距离计算位置&#xff0c;用于三维空间上的定位。调…

一行代码,AI大模型训练成本再降30%,混合精度训练再升级

FP8通过其独特的数值表示方式&#xff0c;能够在保持一定精度的同时&#xff0c;在大模型训练中提高训练速度、节省内存占用&#xff0c;最终降低训练成本。 AI大模型开发系统Colossal-AI的混合精度训练再度升级&#xff0c;支持主流的BF16(O2) FP8(O1)的新一代混合精度训练方…

基于php的民宿预订管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

SpringCloud入门(九)Feign实战应用和性能优化

一、Feign实战应用 Feign的客户端与服务提供者的controller代码非常相似&#xff1a; 有没有一种办法简化这种重复的代码编写呢&#xff1f; 方式一&#xff1a;继承 优点&#xff1a; 简单。实现了代码共享。 缺点&#xff1a;服务提供方、服务消费方紧耦合。参数列表中的注解…

25维谛技术面试最常见问题面试经验分享总结(包含一二三面题目+答案)

开头附上工作招聘面试必备问题噢~~包括综合面试题、无领导小组面试题资源文件免费&#xff01;全文干货。 【免费】25维谛技术面试最常见问题面试经验分享总结&#xff08;包含一二三面题目答案&#xff09;资源-CSDN文库https://download.csdn.net/download/m0_72216164/8979…

TDSQL-C电商可视化,重塑电商决策新纪元

前言&#xff1a; 在数字化浪潮席卷全球的今天&#xff0c;电子商务行业以其独特的魅力和无限潜力&#xff0c;成为了推动全球经济增长的重要引擎。然而&#xff0c;随着业务规模的急剧扩张&#xff0c;海量数据的涌现给电商企业带来了前所未有的挑战与机遇。如何高效地处理、…

02-ZYNQ linux开发环境安装,基于Petalinux2022.2和Vitis2022.2

petalinux安装 Petalinux 工具是 Xilinx 公司推出的嵌入式 Linux 开发套件&#xff0c;包括了 u-boot、Linux Kernel、device-tree、rootfs 等源码和库&#xff0c;以及 Yocto recipes&#xff0c;可以让客户很方便的生成、配置、编译及自定义 Linux 系统。Petalinux 支持 Ver…

秦巴山区SHP格式矢量范围

‌秦巴山区的shp范围包括河南、湖北、重庆、四川、陕西、甘肃六省市的80个县(市、区)。‌这一区域不仅地理范围广泛&#xff0c;而且生态多样性丰富&#xff0c;是国家重要的生物多样性和水源涵养生态功能区。秦巴山区的地貌类型以山地丘陵为主&#xff0c;间有汉中、安康、商丹…

告别背锅侠!29个空场景及测试方法的实战指南

想必大家在日常的测试工作中&#xff0c;经常会碰到以下这些场景&#xff1a; 场景一&#xff1a; 测试人员&#xff1a;有一个数据为空的场景还没有验证。 研发人员&#xff1a;这个场景不会出现&#xff0c;因为没有删除逻辑。 场景二&#xff1a; 研发人员&#xff1a;…