Linux入门:环境变量与进程地址空间

一. 环境变量

1. 概念

1️⃣基本概念

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数

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

2️⃣见一见环境变量:通过指令env 可以看到当前环境下的环境变量表
在这里插入图片描述
3️⃣可以用环境变量回答的诸多疑问

疑问1 :🤔为什么我们平常输入的指令需要直接运行,而我们编译好的可执行文件需要+./指明在当前路径下?

——》💡因为一般我们输入的命令可执行文件,在/usr/bin目录下,并且是PATH这个环境变量告诉OS,要在哪一个目录下查指令的!我们+./ 是为了告诉OS,要在当前目录下寻找!
在这里插入图片描述
——》PATH环境变量是一个由 : 为分隔符的路径集,我们直接输入的命令通常会直接在这几个路径下寻找

疑问2 :🤔如果我也想不输入./就能运行我的程序,改怎么做?

——》💡(1) cp /usr/bin ./程序名将我们的程序拷贝到PATH路径中的其中一个搜索路径!
——》💡(2)在PATH添加一个自己的路径!这样OS就会在自己的路径下寻找!
在这里插入图片描述
—》(2)ps: 在指令中直接输入PATH= …就能添加自己的路径,要注意,这样的写法是覆盖式的,也就是要加上原本环境变量的路径,再以:为分隔符+上需要添加的路径。或者PATH=$PATH:…… 这样的意思就是在原有路径的基础上新增路径

—》像这样在命令行环境变量的修改的生命周期随以你的bash进程的结束而重置的,意思就是说,如果你在以上操作中误改了环境变量也没关系,只需重启一下Xshell,所有的环境变量都会重置,我们的修改只影响当次使用

疑问3 :🤔这些环境变量的内容最开始从哪里来的?
——》💡首先,肯定不是从内存中来的。环境变量的内容最开始都是从系统的配置文件中来的我们登录Xshell—>启动一个shell进程—>进程会读取跟环境变量有关的配置文件—>然后形成自己的环境变量表—>之后再执行命令时生成子进程去执行命令,就可以把环境变量表传给子进程。

——》这也能解释,为什么在疑问2修改环境变量时,我们重启shell,就能重置环境变量表,因为我们根本就没有真正的修改环境变量!我们的修改操作都是内存级的,没有触碰到配置文件,bash进程在启动时只会去读取配置文件的环境变量表!

疑问4 :🤔我们知道,进程会记录是谁启动了自己——》你在启动进程的时候,系统怎么知道你是谁的?并且把你的uid写到进程的PCB结构体里面去?

——》环境变量表早就告诉了你答案
在这里插入图片描述
当前环境变量下,早就记录了你是谁,你在启动进程的时候,bash进程会传入环境变量表到子进程,根据环境变量表也就知道是谁启动了自己。

2. 查看环境变量的方法

2.1 在命令行中

env ——》查看当前进程的环境变量表

在这里插入图片描述

echo $PATH ——》查看一个环境变量,以PATH为例

在这里插入图片描述

2.2 在c语言程序中获取

getenv ——》系统级接口函数,获取一个环境变量的字符串

在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>int main()
{char * arr = getenv("PATH");printf("%s\n",arr);
}

在这里插入图片描述

**extern char environ ——》第三方变量引入
在这里插入图片描述

#include<stdio.h>extern char **environ;
int main()
{for(int i = 0 ; environ[i];i++){printf("%s\n",environ[i]);}
}

在这里插入图片描述

3. 常见的环境变量

  • PATH : 指定命令的搜索路径
    在这里插入图片描述
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录

在这里插入图片描述

  • SHELL : 当前Shell,它的值通常是/bin/bash
    在这里插入图片描述
  • PWD:保存当前进程的工作路径
    在这里插入图片描述

——》PWD:由于这个环境变量的存在,我们创建新文件,删除文件,或者通过./执行命令,系统都可以根据PWD找到当前工作路径执行操作。

4. 命令行参数

4.1 main函数的两个参数

😇其实我们的main函数是可以带参数的,因为他其实也是被别人调用的一个函数,分别是int argc ,char * argv[]

#include <stdio.h>
int main(int argc,char * argv[])
{printf("argc:%d\n,argc");for(int i = 0 ; i< argc ; i++){printf("argv[%d]:%s\n",i,argv[i]);}
}
  • argc : 记录命令行参数的个数
  • argv[]:命令行参数表,里面存储就是命令行参数,最后一个成员是null

以上程序运行的例子:
在这里插入图片描述
在这里插入图片描述
——》命令行参数其实就是我们在执行命令时,包括命令在内的以空格为分割的各个选项,argc记录个数,argv[]以字符串数组的形式记录命令行参数

——》为什么需要命令行参数?同一个程序,就可以根据命令行参数中选项的不同,表现出不同的功能了!我们在shell上的指令都是这样的!

4.2 与环境变量相关的参数

👉 其实main函数除了命令行参数的两个参数外,还有一个参数(第三个参数)——》char * env[] ——》它用于记录传入的环境变量表!

#include <stdio.h>int main(int argc,char * argv[],char * env[])
{for(int i = 0 ; env[i];i++){printf(" env[%d] = %s\n",i,env[i]);}
}

在以上的程序中,我们尝试打印出char * env 的内容,执行命令,他打印出了当前所有的环境变量
在这里插入图片描述
——》综上,我们知道了,在程序中有两个重要的表:命令行参数表,环境变量表

4.3 理解环境变量的"全局性"

🤔思考:当我们执行程序时,环境变量是怎么一步一步传到我们的程序的?

——》💡我们登录Xshell 👉 启动一个shell进程 👉 进程会读取跟环境变量有关的配置文件 👉 然后形成自己的环境变量表👉 我们执行一个程序,而我们我们执行程序所启动的进程,本质上bash的子进程,子进程会拷贝父进程的相关变量,即使进行了程序替换👉子进程拿到环境变量表

——》就是因为所有的进程都是bash的亲子进程,而bash已启动时就会获取环境变量——>环境变量可以被所有bash之后的进程全部看到!!所以,环境变量具有“全局属性”
在这里插入图片描述
💭就算其中一个子进程修改了环境变量表,也不会影响全局的环境变量表,子进程修改环境变量表,只会影响他自己的子进程
在这里插入图片描述
💭环境变量的“全局性”是充分运用了进程的继承性质的:子进程在开始时与父进程除了数据是独立的之外完全一样

4.4 环境变量 VS 本地变量

🤔什么是本地变量?

在这里插入图片描述
——》像这样在命令行中直接定义的变量,就是本地变量,它可以通过echo $指令查看

💭本地变量与环境变量相比,只会在bash内部有效,不会被继承

🤔什么情况下需要本地变量呢??

——》就是只希望在bash里面使用但是不希望被子进程继承下去的,比如说我们的命令行提示符,如果是root用户就是# 如果是普通用户就是$

5 总结

💭环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数,它一般具有全局属性。
在这里插入图片描述

💭环境变量表记录这每个环境变量,每个程序都会收到一张环境变量表,它是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串,这个指针数组以NULL结尾

  1. echo: 显示某个环境变量值
  2. export: 设置一个新的环境变量
  3. env: 显示所有环境变量
  4. unset: 清除环境变量
  5. set: 显示本地定义的shell变量和环境变量

二. 虚拟进程地址空间

先来看一个现象:

 #include <stdio.h>#include <unistd.h>#include <stdlib.h>int g_val = 0;int main(){pid_t id = fork();if(id < 0){perror("fork");return 0;}else if(id == 0){ //childprintf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);}else{ //parentprintf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);}sleep(1);return 0;}

在以上的代码中,我们创建了一个子进程,然后让父进程和子进程都打印出全局变量g_val的地址,然后发现:

在这里插入图片描述

——》我们发现,输出出来的变量值和地址是一模一样的,这很好理解呀,因为子进程按照父进程为模版,父子并没有对变量进行进行任何修改。可是将代码稍加改动:

 #include <stdio.h>#include <unistd.h>#include <stdlib.h>int g_val = 0;int main(){pid_t id = fork();if(id < 0){perror("fork");return 0;}else if(id == 0){ //child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取g_val=100;printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);}else{ //parentsleep(3);printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);}sleep(1);return 0;}

以上代码多了在子进程对g_val对象进行修改,输出现象:

在这里插入图片描述

——》父进程与子进程,输出地址是一致的,但是变量内容不一样!?!!😧这好像不对啊!我们知道,进程之间具有独立性,父进程与子进程的数据是相互独立一份的,子进程的g_val进行修改,那他们的g_val数据也应该是不一样的,但是这二者的地址又相等,这是怎么回事🤔?难道是不同的数据存到同一份地址上😯?那就更不可能了😰!

——》所以在此,可以输出结论👉 :(1)变量内容不一样,所以父子进程输出的变量绝对不是同一个变量(2)这个地址绝对不是物理地址!(3)在Linux地址下,这种地址叫做虚拟地址,或称线性地址(4)我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理。

1.1 什么是进程地址空间(是什么)

1.1.1 理解地址空间

在这里插入图片描述
——》在之前的学习中,我们知道这张图被称为程序地址空间,但其实这个说法并不准确,实际上应该叫做进程地址空间,上面的编制(0x000000&&0xFFFFFFF)也全都是虚拟的地址。

——例子引入:
——》有一个大富翁,他不仅100亿的资产,而且还有很多的私生子,私生子与私生子之间互相不知道对方的存在。私生子知道自己的老爸是富翁,所以要钱是大把大把的要,只有一个私生子还好说,但是他有数不清的私生子,他这资产怎么遭得住?所以,他给每一个私生子都画了个大饼:自己死后,会把自己的100亿资产继承给你。有了这个承诺,私生子都不急着要钱了,所以向富翁要钱花的时候,需要多少,才取多少,这样,富翁就实现了保持和每一个私生子的友好关系,又能不被私生子们发现其他私生子的存在。

——》回到话题,这里的大富翁就是操作系统100亿是实际的物理内存而每一个私生子就是进程,大富翁给他们的大饼就是进程地址空间!OS向每一个进程都许诺了它们有4G(如上图所示结构的)的进程地址空间,每一个进程真的有占这么大的内存吗?并不是!实际上是进程要多少空间,才会向OS申请多少空间。OS让每一个进程都认为自己独占了系统的物理内存大小,进程之间彼此不知道,不关心对方的存在,从而实现一定程度的隔离。

——》饼画多了,OS也要对它们进行管理!先描述,再组织!所谓的进程地址空间,在上图是他的逻辑结构,在内存中,本质是一个内核数据结构对象!OS描述为mm_struct
在这里插入图片描述

1.1.2 理解区域划分

我们在上面了解到,os描述进程地址空间的结构体叫做mm_struct——》🤔这样的成员构成是做到进程地址空间的区域划分的?

💡👇
在这里插入图片描述

一个区域只用两个整形进行管理:一个记录着begin的地址,一个记录着end的地址,是这样的实现区域划分!

1.1.3 理解地址空间上的地址

在这里插入图片描述

从0x0000 0000到0xFFFF FFFF,一共有多少地址?答案是 4GB = 2^10 X 2^10 X 2^10 X 2^2 X 1字节 =2^32 个地址,这些地址的线性的,连续的——》这样设置地址的方式叫做内存编址

其实我们可以观察到,地址本质就是一个数字,可以被unsignal long 类型的变量保存着——》这就是区域划分的变量内容,只有一个begin,一个end——》我们不需要记录一个区域中除了begin和end之外其他的地址,就能知道一个地址值是否在这一个区域内了——》所以空间范围内的地址,我们可以随便用,甚至不用记录他,只用知道一个区域的begin和end就行了。

1.1.4 页表

程序在运行时,所用的是虚拟进程地址空间的虚拟地址,这个虚拟地址是怎么和物理地址产生关联的🤔(怎么通过虚拟地址找到物理地址)?

💡进程中维护一个表,用来一个一个记录虚拟地址和物理地址的映射关系,叫做页表

在这里插入图片描述

上图中,管理进程的结构体为task_struct,在task_struct中,有一个mm_struct的结构体指针成员管理者进程地址空间。在其中,g_val变量在进程地址空间中使用的是虚拟地址0x601054,他在实际的物理地址是0x11223344,页表就将g_val的虚拟地址和物理地址记录下来,让他们一一对应

从理解的角度,页表的结构可以看作一个我们曾经学过的一个数据结构——》map(当然,真实的结构还要复杂很多),由虚拟地址作为key,找到对应的物理地址这个value——》很像一张表,所以叫页表。
在这里插入图片描述

父进程创建子进程后,子进程会拷贝父进程PCB中的大部分属性,其中当然包括进程地址空间和页表!页表的内容及映射关系全部都拷贝一份——》在这个时候,父进程的g_val通过页表映射到物理内存的数据和子进程是一样的!父进程的g_val和子进程是同一份!——》类别到其他的数据,比如说,代码区,父子映射到同一份代码区,所以一般来说,父子进程代码共享!

——》有没有一点奇怪?对呀,之前我们说过进程之间具有独立性,他们的代码是共享的,但是数据是独一份的,但是这里的g_val为什么是同一份?原因是,OS具有写实拷贝机制!
在这里插入图片描述

——》当不修改变量的时候,父子进程的数据确实的同一份,但是,一旦子进程或者父进程要对数据进行写入(修改),那么这个时候就会出发写实拷贝机制:子进程对父进程的数据空间进行一次拷贝,修改页表中物理地址的部分,重新建立映射关系,再对数据进行写入。——》这样的机制由OS自主完成——》默认不分开,只有在你需要的时候再分开——》这样好处非常大!既节省了内存空间,避免资源的浪费,又保证了进程之间的独立性

在这里插入图片描述
——》最终,我们终于能够解释我们一开始举例的现象了!🤔为什么同一个地址,能看到不同的内容因为这个地址的虚拟地址!在底层,父子进程使用相同的虚拟地址,但是他们的页表不同,映射到的物理地址也不相同——》所以同一个虚拟地址,在不同的进程,通过同一个页表,就可以看到不同的内容!!!

1.1.5 补充

1️⃣关于变量和地址:
——》在汇编底层中,变量名其实不存在了,转而变成了地址,地址变成了变量的唯一标识符,对变量进行操作,其实也就是对地址的值进行操作。

2️⃣重新理解进程和进程的独立性
——》究其原因,进程为什么具有独立性?我们知道,进程 = 内核数据结构(task_struct/进程地址空间mm_struct/页表/…)+自己的代码和数据代码和数据是独立的,从前文中我们也可以得知,像进程地址空间mm_struct这样的内核数据结构也是独立的,task_struct是独立的——>右式都具有独立性,左式也就具有相同的性质,所以进程就是独立的。

3️⃣关于页表
上文提到页表的数据结构可以看作一个map,一个虚拟地址对应一个物理地址——>但其实没有谈完,每一个对应关系还存在标记位,用来记录映射关系的相关信息,这里谈两个标记位

  1. rwx有一个标记位记录着物理地址的rwx权限,如果有对应的权限,就可以通过映射关系拿到对应的物理地址

——》比如代码区的数据,我们知道它是只读的,读取代码时先拿着虚拟地址,通过页表检查权限,有r权限,就成功拿到物理内存的代码区数据;但如果我要修改代码区数据时,流程在页表时检查没有w权限,虚拟地址无法转化为物理地址(这个时候在cpu一般直接报错,os直接把进程杀了),也就改不了代码区的数据了

——》以前学习C语言的时候我们知道,像char * str = “hello world”,我们通过 * str = “abc”,程序就会直接崩溃——》为什么?原因就是"hello world"这样的数据在内存中是只读的,不可写入,一旦写入,cpu通过页表拿不到对应的物理内存,就会出错(缺页中断),os检查原因认为,你的程序对只读的区域进行写入,是你的代码出了问题,所以就直接杀掉进程,我们的程序也就直接崩溃了。

——》针对上面的问题,C语言就有了const,const是在编译阶段就告诉编译器,我这个变量不可修改,所以一旦对const修饰的变量进行修改,程序就会在编译阶段就给你拦截了。

提个小问题const char * str = “hello world”char * str = “hello world”如果都对* str进行修改而发送报错,区别在哪

——》综上所述,一个是编译器在编译阶段就拦截了,一个是进程运行时cpu报错被OS杀掉了

  1. isexists这个标记位记录着这个映射关系是否有效,说白了就是在页表中填写的这个物理地址是否存在对应的数据

——》数据是从磁盘加载到内存的,有时候你在程序中定义了一个数据,但是你程序并没有使用这个数据,那么这个数据虽然有在页表中有映射关系,但这份数据不一定加载到内存了isexists这个标志位就表示它是否加载。如果后面的代码中使用了,才会从磁盘中加载数据进来。

——》由这个标志位支持分配加载,挂起等操作

4️⃣关于mm_struct
mm_struct他们是进程管理进程地址空间的结构体,在内存中是一个结构体变量,是结构体变量就要初始化啊!进程地址空间相关的信息(比如栈区,代码区,未初始化变量区…各个区域的大小要设置多少)由哪里得到的呢?

——》答案是从可执行程序中来的!编译器在编译程序形成可执行程序后,各个区域的大小信息就已经有了,OS只需要访问特定区域读取可执行文件的相关区域,就能设置好进程地址空间了。——》页表的相关信息包括标记位,映射关系也是一样的!该物理地址是可读可写不是OS规定的,是可执行文件设置的!

——》从这里我们可以窥见一二:操作系统(的进程管理)与(编译器形成的)可执行程序并不是相互独立的关系,二者是息息相关的

——》堆区申请空间的本质——》改变区域划分,给堆区划分更多的虚拟地址——》再由页表中建立映射关系——》在使用时在申请物理内存。
在这里插入图片描述

1.2 进程地址空间存在的原因(为什么)

  1. 虚拟进程地址空间与页表相互配合,可以有效保护内存

——》意思就是可以有效解决野指针问题。什么是野指针?我们程序为什么使用了野指针就会崩溃?野指针有两种情况,第一是指向了未被在页表建立映射的虚拟地址,第二是指向了不该被指向区域的地址(比如代码区)当你通过野指针进行写入时,页表会找不到对应的映射条目,或者检查标记位发现你没有该虚拟地址的权限,虚拟地址到物理地址的转化不成功,cpu报错,OS就会把你的进程杀掉——》这样就有效避免会出现野指针问题胡乱修改物理内存,也就保护了物理内存。
在这里插入图片描述

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

——》OS在内存管理中,不需要知道进程在物理内存申请一片空间是为了做什么。而在进程管理中,也不需要知道物理内存申请有没有成功,如果没有成功,就没有映射关系,程序再怎么折腾也只是导致自己的进程崩溃。

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

——》可执行程序的代码和数据记载到内存时,不一定是连续的,可能是物理内存的任意位置,或者说连续的虚拟地址在经过页表映射时,物理地址不一定是连续的:
在这里插入图片描述
——》进程不需要关心物理内存是否是连续的,在进程中有页表,使用连续的虚拟进程地址空间。页表和虚拟进程地址空间将地址从“无序”(物理地址)变为“有序”(虚拟地址)

1.3 OS如何管理进程地址空间(怎么做)

进程地址空间在内存中本质是一个结构体:mm_struct,是task_struct结构体(管理进程的结构体)的一个成员,OS只需要把进程(task_struct)管理好,进程地址空间本身就已经管理好了

——》理解全局变量的全局性:今天我们就知道,在代码中具有全局性的变量,不放在栈上,而放在初始化数据区:
在这里插入图片描述
——》而该区域的生命周期的跟随进程的,只有进程被销毁,进程地址空间才会被销毁,该区域的数据才会被销毁,全局变量的虚拟地址一直被整个进程看到,所以,全局变量才具有全局性。

本文就到这里,感谢你看到这里❤️❤️! 我知道一些人看文章喜欢静静看,不评论🤔,但是他会点赞😍,这样的人,帅气低调有内涵😎,美丽大方很优雅😊,明人不说暗话,要你手上的一个点赞😘!

希望你能从我的文章学到一点点的东西❤️❤️

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

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

相关文章

【优选算法 — 滑动窗口】水果成篮 找到字符串中所有字母异位词

水果成篮 水果成篮 题目描述 因为只有两个篮子&#xff0c;每个篮子装的水果种类相同&#xff0c;如果从 0 开始摘&#xff0c;则只能摘 0 和 1 两个种类 &#xff1b; 因为当我们在两个果篮都装有水果的情况下&#xff0c;如果再走到下一颗果树&#xff0c;果树的水果种类…

Java 中使用Mockito 模拟对象的单元测试的快速示例

Mockito是一个流行的Java模拟框架&#xff0c;它允许你在单元测试中创建和配置模拟对象&#xff0c;以便在测试过程中替换那些不容易构造或获取的对象。 Mockito可以与JUnit无缝集成&#xff0c;下面的示例演示 Mockito JUnit实现模拟对象的单元测试。 依赖导入 这里使用Mav…

STM32 创建一个工程文件(寄存器、标准库)

首先到官网下载对应型号的固件包&#xff1a; 像我的STM32F103C8T6的就下载这个&#xff1a; 依次打开&#xff1a; .\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm 可以看到&#xff1a; 这…

vue-h5:在h5中实现相机拍照加上身份证人相框和国徽框

方案1&#xff1a;排出来照片太糊了&#xff0c;效果不好 1.基础功能 参考&#xff1a; https://blog.csdn.net/weixin_45148022/article/details/135696629 https://juejin.cn/post/7327353533618978842?searchId20241101133433B2BB37A081FD6A02DA60 https://www.freesio…

初识GIS

文章目录 一、什么叫地理信息1、定义2、主要特点3、分类 二、什么叫GIS1、定义2、GIS对空间信息的储存2.1、矢量数据模型2.2、栅格数据模型 3、离散栅格和连续栅格的区别 三、坐标系统1、为什么要存在坐标系统&#xff1f;2、地理坐标系2.1、定义与特点2.2、分类 3、投影坐标系…

Android 开发指南:初学者入门

Android 是全球最受欢迎的移动操作系统之一&#xff0c;为开发者提供了丰富的工具和资源来创建各种类型的应用程序。本文将为你提供一个全面的入门指南&#xff0c;帮助你从零开始学习 Android 开发。 目录 1. 了解 Android 平台[1]2. 设置开发环境[2]3. 学习基础知识[3]4. 创…

【QML】QML多线程应用(WorkerScript)

1. 实现功能 QML项目中&#xff0c;点击一个按键后&#xff0c;运行一段比较耗时的程序&#xff0c;此时ui线程会卡住。如何避免ui线程卡住。 2. 单线程&#xff08;会卡住&#xff09; 2.1 界面 2.2 现象 点击delay btn后&#xff0c;执行耗时函数&#xff08;TestJs.func…

MFC1(note)

引言 在学习SDK后我们发现&#xff0c;写消息好麻烦&#xff0c;处理消息更麻烦 处理消息效率低发送消息效率低 所以把SDK中这些消息全部封装好 MFC封装了windows 的大部分API 这里说一下QT架构跨平台 MFC用得如何取决于你SDK的水平 创建 如果打开没有MFC 一般勾选以下…

封装一个省市区的筛选组件

筛选功能&#xff1a;只能单选&#xff08;如需多选需要添加show-checkbox多选框属性&#xff09;&#xff0c;选中省传递省的ID&#xff0c;选中市传递省、市的ID&#xff0c; 选中区传递省市区的ID 父组件&#xff1a; <el-form-item><div style"width: 240px;…

大模型在蓝鲸运维体系应用——蓝鲸运维开发智能助手

本文来自腾讯蓝鲸智云社区用户: CanWay 背景 1、运维转型背景 蓝鲸平台从诞生之初&#xff0c;就一直在不遗余力地推动运维转型&#xff0c;让运维团队可以通过一体化PaaS平台&#xff0c;快速编写脚本&#xff0c;编排流程&#xff0c;开发运维工具&#xff0c;从被动地提供…

独家|京东上线自营秒送,拿出二十年底牌和美团竞争

京东自营秒送开启招商&#xff0c;即时零售也要全托管&#xff1f; 作者|王迟 编辑|杨舟 据「市象」独家获悉&#xff0c;京东将在近期上线自营秒送业务&#xff0c;目前已经开始邀约制招商。「市象」获得的招商资料显示&#xff0c;和5月刚升级上线的京东秒送以POP模式不同&…

GEE 数据集——美国gNATSGO(网格化国家土壤调查地理数据库)完整覆盖了美国所有地区和岛屿领土的最佳可用土壤信息

目录 简介 代码 引用 网址推荐 知识星球 机器学习 gNATSGO&#xff08;网格化国家土壤调查地理数据库&#xff09; 简介 gNATSGO&#xff08;网格化国家土壤调查地理数据库&#xff09;数据库是一个综合数据库&#xff0c;完整覆盖了美国所有地区和岛屿领土的最佳可用土…

JavaSE常用API-日期(计算两个日期时间差-高考倒计时)

计算两个日期时间差&#xff08;高考倒计时&#xff09; JDK8之前日期、时间 Date SimpleDateFormat Calender JDK8开始日期、时间 LocalDate/LocalTime/LocalDateTime ZoneId/ZoneDateTIme Instant-时间毫秒值 DateTimeFormatter Duration/Period

15分钟学 Go 第 53 天 :社区资源与学习材料

第53天&#xff1a;社区资源与学习材料 目标 了解Go语言官方资源掌握社区重要学习平台学会利用开源项目学习构建个人知识体系 一、Go语言官方资源汇总 资源类型网址说明Go官网golang.org官方文档、下载、教程Go Blogblog.golang.org技术博客、最新特性介绍Go Playgroundpla…

删库跑路,启动!

起因&#xff1a;这是一个悲伤的故事&#xff0c;在抓logcat时 device待机自动回根目录了&#xff0c;而题主对当前路径的印象还停留在文件夹下&#xff0c;不小心在根目录执行了rm -rf * … 所以&#xff0c;这是个悲伤的故事&#xff0c;东西全没了…device也黑屏了&#xff…

如何优化Kafka消费者的性能

要优化 Kafka 消费者性能&#xff0c;你可以考虑以下策略&#xff1a; 并行消费&#xff1a;通过增加消费者组中的消费者数量来并行处理更多的消息&#xff0c;从而提升消费速度。 批量消费&#xff1a;配置 fetch.min.bytes 和 fetch.max.wait.ms 参数来控制批量消费的大小和…

开始使用 Elastic AI Assistant 进行可观察性和 Microsoft Azure OpenAI

作者&#xff1a;Jonathan Simon 按照此分步过程开始使用 Elastic AI Assistant for Observability 和 Microsoft Azure OpenAI。 最近&#xff0c;Elastic 宣布&#xff0c;AI Assistant for Observability 现已面向所有 Elastic 用户开放。AI Assistant 为 Elastic Observabi…

vue2项目启用tailwindcss - 开启class=“w-[190px] mr-[20px]“ - 修复tailwindcss无效的问题

效果图 步骤 停止编译"npm run dev"安装依赖 npm install -D tailwindcssnpm:tailwindcss/postcss7-compat postcss^7 autoprefixer^9 创建文件/src/assets/tailwindcss.css&#xff0c;写入内容&#xff1a; tailwind base; tailwind components; tailwind utiliti…

深度学习——AE、VAE

&#x1f33a;历史文章列表&#x1f33a; 机器学习——损失函数、代价函数、KL散度机器学习——特征工程、正则化、强化学习机器学习——常见算法汇总机器学习——感知机、MLP、SVM机器学习——KNN机器学习——贝叶斯机器学习——决策树机器学习——随机森林、Bagging、Boostin…

【数字图像处理+MATLAB】基于 Sobel 算子计算图像梯度并进行边缘增强:使用 imgradientxy 函数

引言 在图像处理中&#xff0c;边缘通常是图像中像素强度变化最大的地方&#xff0c;这种变化可以通过计算图像的梯度来量化。梯度是一个向量&#xff0c;它的方向指向像素强度增加最快的方向&#xff0c;它的大小&#xff08;或者说幅度&#xff09;表示像素强度增加的速度。…