Linux - 进程概念
1、冯诺依曼体系结构
我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系;
截至目前,我们所认识的计算机,都是有一个个的硬件组件组成:
- 输入单元:包括键盘,鼠标,扫描仪,写板等;
- 中央处理器(CPU):含有运算器和控制器等;
- 输出单元:显示器,打印机等;
关于冯诺依曼强调几点:
- 这里的存储器指的是内存;
- 不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备);
- 外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取;
- 一句话,所有设备都只能直接和内存打交道;
2、操作系统(Operator System)
2.1、概念
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
- 内核(进程管理,内存管理,文件管理,驱动管理)
- 其他程序(例如函数库,shell程序等等)
2.2、设计OS的目的
- 对下:与硬件交互,管理所有的软硬件资源
- 对上:为用户程序(应用程序)提供一个良好的执行环境
2.3、定位
- 在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件
2.4、如何理解 “ 管理 ”
- 描述被管理对象
- 组织被管理对象
2.5、总结
计算机管理硬件:
- 描述起来,用struct结构体
- 组织起来,用链表或其他高效的数据结构
3、系统调用和库函数概念
- 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用;
- 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发;
4、进程
4.1、基本概念
- 课本概念:程序的一个执行实例,正在执行的程序等;
- 内核观点:担当分配系统资源(CPU时间,内存)的实体;
4.2、描述进程-PCB
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合;
- 课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct;
task_struct-PCB的一种
- 在Linux中描述进程的结构体叫做task_struct;
- task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息;
task_ struct内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程;
- 状态: 任务状态,退出代码,退出信号等;
- 优先级: 相对于其他进程的优先级;
- 程序计数器: 程序中即将被执行的下一条指令的地址;
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针;
- 上下文数据: 进程执行时处理器的寄存器中的数据;
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表;
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等;
- 其他信息
4.3、组织进程
可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里;
4.4、查看进程
进程的信息可以通过 /proc 系统文件夹 查看
- 如:要获取PID为1的进程信息,你需要查看 /proc/1 这个文件夹;
- 大多数进程信息同样可以使用 top 和 ps 这些用户级工具来获取;
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{while(1){sleep(1);}return 0;
}
4.5、通过系统调用获取进程标示符
- 进程id(PID)
- 父进程id(PPID)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{printf("pid: %d\n", getpid());printf("ppid: %d\n", getppid());return 0;
}
4.6、通过系统调用创建进程-fork初识
- 运行 man fork 认识fork
- fork有两个返回值
- 父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{int ret = fork();printf("hello proc : %d!, ret: %d\n", getpid(), ret);sleep(1);return 0;
}
- fork 之后通常要用 if 进行分流
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{int ret = fork();if(ret < 0){perror("fork");return 1;}else if(ret == 0){ //childprintf("I am child : %d!, ret: %d\n", getpid(), ret);}else{ //fatherprintf("I am father : %d!, ret: %d\n", getpid(), ret);}sleep(1);return 0;
}
5、进程状态
5.1、Linux内核源代码的定义
- 为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在 Linux内核里,进程有时候也叫做任务);
- 下面的状态在kernel源代码里定义:
/*
* 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 */
};
- R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里;
- S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep));
- D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束;
- T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程,这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行;
- X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态;
5.2、进程状态查看
ps aux / ps axj 命令
5.3、Z(zombie)-僵尸进程
- 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程;
- 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码;
- 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态;
来一个创建维持30秒的僵死进程例子:
#include <stdio.h>
#include <stdlib.h>
int main()
{pid_t id = fork();if(id < 0){perror("fork");return 1;}else if(id > 0){ //parentprintf("parent[%d] is sleeping...\n", getpid());sleep(30);}else{printf("child[%d] is begin Z...\n", getpid());sleep(5);exit(EXIT_SUCCESS);}return 0;
}
ptrace系统调用追踪进程运行
5.4、僵尸进程危害
- 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态;
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护;
- 那一个父进程创建了很多子进程,就是不回收,就会造成内存资源的浪费!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间;
- 内存泄漏
6、孤儿进程
- 父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
- 父进程先退出,子进程就称之为“孤儿进程”’
- 孤儿进程被1号init进程领养,当然要有init进程回收;
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{pid_t id = fork();if(id < 0){perror("fork");return 1;}else if(id == 0){//childprintf("I am child, pid : %d\n", getpid());sleep(10);}else{//parentprintf("I am parent, pid: %d\n", getpid());sleep(3);exit(0);}return 0;
}
7、进程优先级
7.1、基本概念
- cpu资源分配的先后顺序,就是指进程的优先权(priority);
- 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能;
- 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能;
7.2、查看系统进程
在linux或者unix系统中,用ps –l命令则会类似输出以下几个内容:
容易注意到其中的几个重要信息,有下:
- UID : 代表执行者的身份
- PID : 代表这个进程的代号
- PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
- PRI :代表这个进程可被执行的优先级,其值越小越早被执行
- NI :代表这个进程的nice值
7.3、PRI and NI
- PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小,进程的优先级别越高;
- NI就是所要说的nice值了,其表示进程可被执行的优先级的修正数值;
- PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice;
- 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行;
- 所以,调整进程优先级,在Linux下,就是调整进程nice值;
- nice其取值范围是-20至19,一共40个级别;
7.4、PRI vs NI
- 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化;
- 可以理解nice值是进程优先级的修正修正数据;
7.5、查看进程优先级的命令
用top命令更改已存在进程的nice:
- top;
- 进入top后按“r”–>输入进程PID–>输入nice值;
8、其他概念
- 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级;
- 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰;
- 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行;
- 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发
9、环境变量
9.1、基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找;
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性;
9.2、常见环境变量
- PATH : 指定命令的搜索路径
- HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
- SHELL : 当前Shell,它的值通常是/bin/bash;
9.3、测试PATH
1. 创建hello.c文件;
#include <stdio.h>
int main()
{printf("hello world!\n");return 0;
}
2. 对比./hello执行和之间hello执行;
3. 为什么有些指令可以直接执行,不需要带路径,而我们的二进制程序需要带路径才能执行;
4. 将我们的程序所在路径加入环境变量PATH当中, export PATH=$PATH:hello程序所在路径
5. 对比测试
9.4、测试HOME
1. 用root和普通用户,分别执行 echo $HOME ,对比差异 . 执行 cd ~; pwd ,对应 ~ 和 HOME 的关系
9.5、和环境变量相关的命令
- echo: 显示某个环境变量值
- export: 设置一个新的环境变量
- env: 显示所有环境变量
- unset: 清除环境变量
- set: 显示本地定义的shell变量和环境变量
9.6、环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
9.7、通过代码如何获取环境变量
- 命令行第三个参数
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{int i = 0;for(; env[i]; i++){printf("%s\n", env[i]);}return 0;
}
- 通过第三方变量environ获取
#include <stdio.h>
int main(int argc, char *argv[])
{extern char **environ;int i = 0;for(; environ[i]; i++){printf("%s\n", environ[i]);}return 0;
}
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明;
9.8、通过系统调用获取或设置环境变量
- putenv
- getenv
#include <stdio.h>
#include <stdlib.h>
int main()
{printf("%s\n", getenv("PATH"));return 0;
}
常用getenv和putenv函数来访问特定的环境变量
9.9、环境变量通常是具有全局属性的
- 环境变量通常具有全局属性,可以被子进程继承下去
#include <stdio.h>
#include <stdlib.h>
int main()
{char * env = getenv("MYENV");if(env){printf("%s\n", env);}return 0;
}
直接查看,发现没有结果,说明该环境变量根本不存在
- 导出环境变量 export MYENV="hello world"
- 再次运行程序,发现结果有了!说明:环境变量是可以被子进程继承下去的
实验
- 如果只进行 MYENV=“helloworld” ,不调用export导出,在用我们的程序查看,会有什么结果;
- 普通变量;
10、程序地址空间
10.1、研究背景
- kernel 2.6.32
- 32位平台
10.2、程序地址空间回顾
来段代码感受一下
#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;
}
输出
//与环境相关,观察现象即可
parent[2996]: 0 : 0x80497a9
child[2997]: 0 : 0x80497a9
我们发现,输出出来的变量值和地址是一模一样的,很好理解,因为子进程按照父进程为模版,父子并没有对变量进行进行任何修改;可是将代码稍加改动:
#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;
}
输出结果:
//与环境相关,观察现象即可
child[3056]: 100 : 0x80347f4
parent[3055]: 0 : 0x80347f4
我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:
- 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量;
- 但地址值是一样的,说明,该地址绝对不是物理地址;
- 在Linux地址下,这种地址叫做 虚拟地址
- 在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理OS必须负责将 虚拟地址 转化成 物理地址;
10.3、进程地址空间
所以之前说"程序的地址空间"是不准确的,准确的应该说成 "进程地址空间",那该如何理解?看图:
说明:
- 上面的图就足矣说明问题,同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址;
11、Linux2.6内核进程调度队列
上图是Linux2.6内核中进程队列的数据结构
一个CPU拥有一个runqueue
- 如果有多个CPU就要考虑进程个数的负载均衡问题
优先级
- 普通优先级:100~139(我们都是普通的优先级,想想nice值的取值范围,可与之对应!)
- 实时优先级:0~99(不关心)
活动队列
- 时间片还没有结束的所有进程都按照优先级放在该队列
- nr_active: 总共有多少个运行状态的进程
- queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级;
- 从该结构中,选择一个最合适的进程,过程是怎么的?
- 从0下表开始遍历queue[140];
- 找到第一个非空队列,该队列必定为优先级最高的队列;
- 拿到选中队列的第一个进程,开始运行,调度完成;
- 遍历queue[140]时间复杂度是常数!但还是太低效了;
- bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个 比特位表示队列是否为空,这样,便可以大大提高查找效率;
过期队列
- 过期队列和活动队列结构一模一样;
- 过期队列上放置的进程,都是时间片耗尽的进程;
- 当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算;
active指针和expired指针
- active指针永远指向活动队列;
- expired指针永远指向过期队列;
- 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的;
- 没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程;
总结
- 在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法!
更多文档
相关文章:

Linux - 进程概念
1、冯诺依曼体系结构 我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系; 截至目前,我们所认识的计算机,都是有一个个的硬件组件组成: 输入单元:…...

H5小游戏,象棋
H5小游戏源码、JS开发网页小游戏开源源码大合集。无需运行环境,解压后浏览器直接打开。有需要的,私信本人,发演示地址,可以后再订阅,发源码,含60+小游戏源码。如五子棋、象棋、植物大战僵尸、开心消消乐、扑鱼达人、飞机大战等等 <!DOCTYPE html PUBLIC "-//W3C/…...

LLM春招准备(1)
llm排序 GPT4V GPT-4V可以很好地理解直接绘制在图像上的视觉指示。它可以直接识别叠加在图像上的不同类型的视觉标记作为指针,例如圆形、方框和手绘(见下图)。虽然GPT-4V能够直接理解坐标,但相比于仅文本坐标,GPT-4V在…...
网络安全知识点总结
1、常见的网络攻击有哪些? 答:(1)口令攻击:也就是窃取用户的账户和密码,普通用户习惯于设置简单的密码,且多个系统用同一套密码,黑客可以使用字典攻击(常用密码库&#…...

服务完善的智能组网系统?
智能组网是现代信息技术的重要组成部分,它通过将各种设备和计算机连接起来,实现高效的数据传输和远程通信。在一个全球化、高度互联的时代背景下,智能组网已经成为了各行各业的必需品。传统的组网方案往往面临着许多问题和挑战。为了解决这些…...

VS2022如何添加行号?(VS2022不显示行号解决方法)
VS2022不显示行号解决方法 VS2022是非常好用的工具,很多同学在初学C/C的时候,都会安装,默认安装好VS2022后,写代码时,在编辑框的窗口左边就有显示行号,如下图所示: 但是有些同学安装好后&#…...

125.验证回文字符串
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s,如果它是 回文串 ,返回 true ;否则&#…...
Spring Boot的启动流程(个人总结,仅供参考)
SpringBoot应用程序的启动流程主要包括初始化SpringApplication和运行SpringApplication两个过程。 1.初始化SpringApplication包括配置基本的环境变量、资源、构造器和监听器,初始化阶段的主要作用是为运行SpringApplication实例对象启动环境变量准备以及进行必要的…...

用BIO实现tomcat
一、前言 本课程的难度较高,需要将Servlet原理和IO课程全部学完。 二、当前项目使用方式 (1).自定义servlet 自定义servlet需要实现WebServlet并且实现name和urlMapping 重启进行访问 http://localhost:8090/myServlet (2).自定义html 重启进行访问 http://loc…...

JS逆向进阶篇【去哪儿旅行登录】【下篇-逆向Bella参数JS加密逻辑Python生成】
目录: 每篇前言:引子——本篇目的1、 代码混淆和还原(1)单独替换:(2)整个js文件替换: 2、算法入口分析3、 深入分析(0)整体分析:(1&am…...

【机器学习】生成对抗网络GAN
概述 生成对抗网络(Generative Adversarial Network,GAN)是一种深度学习模型架构,由生成器(Generator)和判别器(Discriminator)两部分组成,旨在通过对抗训练的方式生成逼…...

centos7安装kafka、zookeeper
安装jdk 安装jdk8 安装zookeeper 在指定目录执行下载命令 我是在/newdisk/zookeeper目录下 wget https://archive.apache.org/dist/zookeeper/zookeeper-3.5.8/apache-zookeeper-3.5.8-bin.tar.gz --no-check-certificate下载好后并解压 tar -zxvf apache-zookeeper-3.5…...

基于 STM32U5 片内温度传感器正确测算温度
目录预览 1、引言 2、问题 3、小结 01 引言 STM32 在内部都集成了一个温度传感器,STM32U5 也不例外。这个位于晶圆上的温度传感器虽然不太适合用来测量外部环境的温度,但是用于监控晶圆上的温度还是挺好的,以防止芯片过温运行。 02 问题…...

【比较mybatis、lazy、sqltoy、mybatis-flex、easy-query操作数据】操作批量新增、分页查询(三)
orm框架使用性能比较 比较mybatis、lazy、sqltoy、mybatis-flex、easy-query操作数据 环境: idea jdk17 spring boot 3.0.7 mysql 8.0测试条件常规对象 orm 框架是否支持xml是否支持 Lambda对比版本mybatis☑️☑️3.5.4sqltoy☑️☑️5.2.98lazy✖️☑️1.2.4…...
Leetcode 3068. Find the Maximum Sum of Node Values
Leetcode 3068. Find the Maximum Sum of Node Values 1. 解题思路2. 代码实现 题目链接:3068. Find the Maximum Sum of Node Values 1. 解题思路 这一题虽然标记为一道hard的题目,但其实就是一个脑筋急转弯的题目。 我们只需要想明白一点即可&…...
用 Dockerfile为镜像添加SSH服务
1、基础镜像ubuntu:18.04 2、替换为国内的安装源 3、安装openssh-server 4、允许root用户远程登陆 5、暴露端口22 6、服务开机自启动 1.创建目录 [rootopenEuler-node1 db]# mkdir sshd_ubuntu 2.创建 Dockerfile、 run.sh 、authorized_keys、vim aliyun.list 文件 [rootop…...
Maven能解决什么问题?为什么要用?
如果没有maven,我们在开发一个应用的时候,需要自己先确定要引入哪些第三方的jar包,并且要去找到这些jar包,把他们导入到项目中,而且最痛苦的时候各个jar包之间的兼容性和冲突的问题。 jar包弄好了之后,我们…...
【Golang星辰图】探索网络和HTTP的奇妙世界:使用Go语言打造高性能应用
提升Web开发效率:学会使用Go语言的网络和HTTP库 前言 随着互联网的快速发展,网络和HTTP成为了现代应用开发中必不可少的部分。Go语言作为一门快速、可靠和高效的编程语言,提供了丰富的网络编程和HTTP处理库,使得构建高性能的网络…...
[C语言]——操作符
目录 一.算术操作符:、-、*、/、% 1. 和 - 2.* 3./ 4.% 二.赋值操作符:和复合赋值 1.连续赋值 2.复合赋值符 三.单目操作符:、--、、- 1.和-- 1.1前置 1.2后置 1.3前置-- 2. 和 - 四.强制类型转换 一.算术操作符:…...

iview碰到的一些问题总结
iview tabs嵌套使用问题 tabs嵌套使用的时候不是直接套用行了,直接套用会出现内层tab都集成到一级tab去,需要设置该属性指向对应 Tabs 的 name 字段(需要版本大于3.3.1) <Tabs name"tab1" ><TabPane label"标签1" tab&qu…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...