当前位置: 首页 > news >正文

Linux进程 -fork(初识),进程状态和进程优先级

目录

一、通过系统调用创建进程-fork

1.fork的介绍

 2.fork的理解

3.fork常规用法

4.fork的三个问题 

5.创建多个子进程 

二、进程状态 

(1)Linux内核源代码

(2)进程的状态 

R运行状态(运行态)

S 睡眠状态(sleeping)和 D 磁盘休眠状态(disk sleep)

T 停止状态(stopped)

Z 僵尸状态(zombie)-- 僵尸进程 

 孤儿进程

三、进程优先级 

(1)基本概念

 (2)查看进程优先级的命令


一、通过系统调用创建进程-fork

1.fork的介绍

平时创建进程一般是通过 ./myproc 运行某个存储在磁盘上的可执行程序来创建。而我们还可以通过系统调用接口来创建进程。

pid_t是无符号整型。我们先看一段代码。

 1 #include<stdio.h>2 #include <unistd.h>3 int main()4 {5   printf("I am a father: %u\n", getpid());6     fork();7 8     while(1)9     {10         printf("I am a process, pid: %u, ppid: %u\n", getpid(), getppid());11         sleep(1);12     }13 14     return 0;                                                                                      15 }

 pid为31318即为创建的子进程id

当我们查看进程

此时有三个进程:分别为父进程和fork创建的子进程和grep进程

 2.fork的理解

从代码的角度看

父子进程共享用户代码(代码是只读的,不可写),而用户数据各自私有一份(为了不让进程互相干扰),采用写时拷贝技术。

fork 之后子进程会被创建成功,然后父子进程都会继续运行,但谁先运行是不确定的,由系统调度优先级决定。

从内核的角度看 

对于操作系统来说,通过fork后,系统多了一个进程。

具体是,fork后以父进程为模板,操作系统创建新的PCB,把父进程PCB的内容属性拷贝过来,他们共享代码和数据。

3.fork常规用法

我们创建子进程的目的是为了让子进程给我们完成任务,所以 fork 之后通常要用 if 进行分流,让父子进程执行不同的代码,实现一个并行的效果。(比如父进程播放音乐,子进程下载文件)

通过 fork 的两个返回值来进行分流:

  • 如果 fork 执行成功,在父进程中返回子进程的 pid,在子进程中返回 0。
  • 如果 fork 执行失败,在父进程中返回 -1,不创建子进程,并适当地设置 errno。
#include <stdio.h>  
#include <sys/types.h> // getpid, getppid  
#include <unistd.h>    // getpid, getppid, forkint main()  
{  printf("I'm a father: %u\n", getpid());pid_t ret = fork();if (ret == 0){  // child processwhile (1){printf("child process, pid:%u, ppid:%u\n", getpid(), getppid());sleep(1);}}else if (ret > 0){// father processwhile (1){printf("father process, pid:%u, ppid:%u\n", getpid(), getppid());sleep(1);}}else{// failureperror("fork");return 1;}return 0;            
}

  这一份代码为什么会出现父进程和子进程一起循环呢?

这里给大家抛出三个问题

  • fork为什么有两个返回值?
  • 为什么上述代码中,fork 的返回值 ret 有两个值,既等于 0 又大于 0 呢?fork 之后,父子进程如何做到共享用户代码,如何做到用户数据各自私有的呢?
  • 如果 fork 执行成功,为什么在父进程中返回子进程的 pid,在子进程中返回的是 0 呢?

4.fork的三个问题 

(1)两个返回值问题

fork函数一直往下执行

  • 在执行到最后ret之前,子进程已经被创建出来了,在上面我们说父进程和子进程的代码是共享的,那么这个return ret是不是一份代码呢?
  • 答案肯定是的,那么是代码子进程也会执行return ret。
  • 所以这就是为什么有两个返回值

(2)一个变量为什么会存在两个值呢? 

这个在我们后面讲进程地址空间的时候会给大家介绍,暂时不多做解释。

(3) 为什么在父进程中返回子进程的 pid,在子进程中返回的是 0 呢?

举一个例子,一位父亲有很多孩子,那么该怎么辨别这些孩子呢?这就需要给孩子标识并记住它。而每个孩子只有唯一一个父亲,所以能很好的辨别父亲。

所以在父进程中需要返回子进程的 pid,因为得让父进程知道自己的子进程(儿子)是谁。

而子进程只需要知道自己被创建成功了就行,所以在子进程中返回 0 即可。

5.创建多个子进程 

#include <stdlib.h>68 void runchild()69 {70   int cnt=10;71   while(cnt)72   {73     printf("i am a child:%d,ppid:%d",getpid(),getppid());74     sleep(1);75     cnt--;76   }77 }78 int main()79 {80   int i=0;                                                                                         81   for(i=0;i<5;i++)82   {83     pid_t id=fork();84     if(id==0)85     {86       runchild();87       exit(0);88     }89     sleep(100);90   }91 }

二、进程状态 

进程的状态体现一个进程的生命状态。

(1)Linux内核源代码

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):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

(2)进程的状态 

R运行状态(运行态)

当我们写一段代码,为什么状态时是S+而不是R呢?

  • 因为CPU的运行速度非常快,而进程绝大多数时间都在休眠(sleep(1)),只有极少数的时间在运行 。
  • 因为 printf 是往显示器上打印,涉及到 IO,所以效率比较低,该进程需要等待操作系统把数据刷新到显示器中。

那有一个问题了?如果该进程的状态是R,那它一定在CPU上运行吗?

不一定,在CPU上运行一定是R状态,但一个进程状态是R,也有可能在运行队列中。 

 如果想看到R状态,我们只需要写一个while(1)即可。

S 睡眠状态(sleeping)和 D 磁盘休眠状态(disk sleep)

S:休眠状态(sleeping)(也可以叫阻塞状态

  • 表示进程虽然是一种休眠状态,但随时可以接受外部的信号,处理外部的请求,被唤醒。

当键盘还未输入数据时,却在内存中,如图在等待队列中等待,可以叫做阻塞状态,可以随时接受外接的信号,被唤醒。

当在等待队列中,如果操作系统内部的内存资源严重不足时,在保证正常的情况,队列中只存在PCB,把对应的代码和数据返回到外设中,当存在响应的时候,再把代码和数据换入,再放到运行队列中。这种状态叫做挂起状态 

D:磁盘休眠状态(disk sleep)深度休眠) 

比如:进程 A 想要把一些数据写入磁盘中,因为 IO 需要时间,所以进程 A 需要等待。但因为内存资源不足,在等待期间进程 A 被操作系统 kill 掉了,而此时磁盘因为空间不足,写入这些数据失败了,却不能把情况汇报给进程 A,那这些数据该如何处理呢?很可能导致这些数据被丢失,操作系统 kill 掉进程 A 导致了此次事故的发生。所以诞生了 D 状态,不可以被杀掉,即便是操作系统。只能等待 D 状态自动醒来,或者是关机重启

 S状态和S+状态有什么区别呢?

S+ 状态:表示前台进程。(前台进程一旦运行,bash 就无法进行命令行解释,使用 Ctrl+C 可以终止前台进程)
S 状态:表示后台进程。(后台进程在运行时,bash 可以进行命令行解释,使用 Ctrl+C 无法终止后台进程)

T 停止状态(stopped)

我们可以通过kill命令,让进程进入T状态也就是停止状态,停止运行了。

举个例子:

  • 我们给进程发 19 号信号 SIGSTOP,可以让进程进入 T 停止状态。停止运行。

  • 我们给进程发 18 号信号 SIGCONT,可以让进程停止 T 停止状态。恢复运行。

Z 僵尸状态(zombie)-- 僵尸进程 

我们先看一段代码

#include <stdio.h>
#include <stdlib.h>    // exit
#include <sys/types.h> // getpid, getppid  
#include <unistd.h>    // getpid, getppid, fork, sleepint main()
{// 创建5个子进程for (int i = 0; i < 5; i++){pid_t ret = fork();if (ret == 0){// child processprintf("child%d, pid:%u, ppid:%u\n", i, getpid(), getppid());sleep(1);exit(1); // 子进程退出}}getchar(); // getchar()目的是不让父进程退出,则无法回收子进程。return 0;
}

 成功创建了 5 个子进程。但程序会一直卡在这里,不会自己退出。

我们发现五个子进程全部变僵尸进程了(Z状态) 

那什么是僵尸状态呢?

要知道,进程退出,一般不是立马就让操作系统回收进程的所有资源。

因为创建进程的目的,是为了让它完成某个任务和工作。当它退出时,我们得知道它把任务完成的怎么样,所以需要知道这个进程是正常还是异常退出的。

如果进程是正常退出的,那么交给进程的任务有没有正常完成呢?
所以,进程退出时,会自动将自己的退出信息,保存到进程的 PCB 中,供 OS 或者父进程来进行读取。

进程退出但父进程还没有读取,进程此时就处于僵尸状态。
读取成功后,该进程才算是真正的死亡,变成 X 死亡状态。

僵尸状态的概念:

  • 僵死状态(Zombies)是一个比较特殊的状态。当子进程退出,并且父进程没有读取到子进程退出时的返回代码时就会产生僵死(尸)进程。(父进程使用系统调用 wait() 让 OS 回收子进程)
  • 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出代码。
  • 所以,只要子进程退出,父进程还在运行,但父进程没有读取到子进程状态,子进程就会进入 Z 状态。
  • 父进程通过调用 getchar() 函数来等待用户输入,这样做可以防止父进程过早退出,在大多数情况下,这也意味着父进程不会立即回收结束的子进程资源,因为没有调用 wait / waitpid 函数来等待子进程结束。 
  • 虽然父进程通过 getchar() 等待,但这并不是处理僵尸进程(已结束但未被父进程回收的子进程)的正确做法。在实际应用中,父进程应该使用 wait / waitpid 函数来等待子进程结束,并回收它们的资源,以避免僵尸进程的产生。
  • 进程处于Z状态,资源会被一直占用,进程相关资源task_struct不能被释放,导致内存泄漏。等后面给大家介绍进程等待能很好的解决内存泄露问题。

 孤儿进程

若子进程先退出,父进程没回收,则子进程为僵尸进程

若父进程先退出,子进程将被1号进程领养(父进程改为1号进程),子进程称作孤儿进程

我们能看到,父进程退出后,子进程的父进程变成了1。 

我们能看到1号进程就是我们的操作系统。

三、进程优先级 

优先级 vs 权限,两者有什么区别呢?

  • 优先级:在资源有限的前提下,确立多个进程中谁先访问资源,谁后访问资源。
  • 权限:决定能不能得到某种资源。

(1)基本概念

在 Linux 或者 Unix 系统中,使用命令 ps -al 查看当前系统进程的信息:

  • PRI:优先级,值越小,优先级越大。
  • NI:nice,进程优先级的修正数据,范围调整[-20,19]。
  • UID:用户的ID名,执行者ID。
  • 进程新的优先级:PRI(new) = PRI(old, 默认都是 80) + nice
  •  优先级不可能一味的高,也不可能一味的低。因为 OS 的调度器也要考虑公平问题。
  • 进程的 nice 值不是进程的优先级,他们不是一个概念,但是进程的 nice 值会影响到进程的优先级变化。

 (2)查看进程优先级的命令

 通过 top 命令(类似于 Windows 的任务管理器)更改已存在进程的 nice:

  • 执行 top 命令后,按 r 键,输入进程的 PID,输入 nice 值。

 

每次输入 nice 值调整进程优先级,都是默认从 PRI = 80 开始调整的。
输入的 nice 值如果超过 [-20, 19] 这个范围,默认是按照最左/最右范围来取的。

为什么每次都要默认从 PRI = 80 开始调整呢?

  • 有一个基准值,方便调整。
  • 在设计上,实现比较简单。

为什么 nice 值的范围是 [-20, 19] 呢?

是一种可控状态,保证了进程的优先级始终在 [60, 99] 这个范围内,保证了 OS 调度器的公平。但公平并不是平均。根据每个进程的特性尽可能公平的去调度它们,而不是指每个进程的调度时间必须完全一样。 

  • 竞争性:系统进程数目众多,而 CPU 的资源很少,甚至只有一个,所以进程之间是具有竞争属性的。为了更高效的完成任务,更合理的竞争相关资源,便有了优先级。
  • 独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。(这也是 OS 设计进程的一个原则)
  • 并发:多个进程在一个 CPU 下采用进程切换的方式,在同一段时间内,让多个进程都得以推进。(描述的时间段)
  • 并行:多个进程在多个 CPU 下同时运行。(描述的是时刻,任何一个时刻,都可能有多个进程在运行)

相关文章:

Linux进程 -fork(初识),进程状态和进程优先级

目录 一、通过系统调用创建进程-fork 1.fork的介绍 2.fork的理解 3.fork常规用法 4.fork的三个问题 5.创建多个子进程 二、进程状态 &#xff08;1&#xff09;Linux内核源代码 &#xff08;2&#xff09;进程的状态 R运行状态(运行态&#xff09; S 睡眠状态&…...

数据从前端传到后端入库过程分析

数据从前端传到后端入库过程分析 概述 积累了一些项目经验&#xff0c;成长为一个老程序员了&#xff0c;自认为对各种业务和技术都能得心应手的应对了&#xff0c;殊不知很多时候我们借助了搜索引擎的能力&#xff0c;当然现在大家都是通过AI来武装自己。 今天要分析的话题是…...

macOS如何进入 Application Support 目录(cd: string not in pwd: Application)

错误信息 cd: string not in pwd: Application 表示在当前目录下找不到名为 Application Support 的目录。可能的原因如下&#xff1a; 拼写错误或路径错误&#xff1a;确保你输入的目录名称正确。目录名称是区分大小写的&#xff0c;因此请确保使用正确的大小写。正确的目录名…...

第38周:猫狗识别 (Tensorflow实战第八周)

目录 前言 一、前期工作 1.1 设置GPU 1.2 导入数据 输出 二、数据预处理 2.1 加载数据 2.2 再次检查数据 2.3 配置数据集 2.4 可视化数据 三、构建VGG-16网络 3.1 VGG-16网络介绍 3.2 搭建VGG-16模型 四、编译 五、训练模型 六、模型评估 七、预测 总结 前言…...

【2024年华为OD机试】 (A卷,200分)- 计算网络信号、信号强度(JavaScriptJava PythonC/C++)

一、问题描述 题目解析 问题描述 我们有一个 m x n 的二维网格地图,每个格子可能是以下几种情况之一: 0:表示该位置是空旷的。x(正整数):表示该位置是信号源,信号强度为 x。-1:表示该位置是阻隔物,信号无法直接穿透。信号源只有一个,阻隔物可能有多个。信号在传播…...

【go语言】数组和切片

一、数组 1.1 什么是数组 数组是一组数&#xff1a;数组需要是相同类型的数据的集合&#xff1b;数组是需要定义大小的&#xff1b;数组一旦定义了大小是不可以改变的。 1.2 数组的声明 数组和其他变量定义没有什么区别&#xff0c;唯一的就是这个是一组数&#xff0c;需要给…...

2025美赛MCM数学建模A题:《石头台阶的“记忆”:如何用数学揭开历史的足迹》(全网最全思路+模型)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ 《石头台阶的“记忆”&#xff1a;如何用数学揭开历史的足迹》 目录 《石头台阶的“记忆”&#xff1a;如何用数学揭开历史的足迹》 ✨摘要✨ ✨引言✨ 1. 引言的结构 2. 撰写步骤 &#xff08;1&#xff09;研究背景 &#…...

使用 Docker Compose 一键启动 Redis、MySQL 和 RabbitMQ

目录 一、Docker Compose 简介 二、服务配置详解 1. Redis 配置 2. MySQL 配置 3. RabbitMQ 配置 三、数据持久化与时间同步 四、部署与管理 五、总结 目录挂载与卷映射的区别 现代软件开发中&#xff0c;微服务架构因其灵活性和可扩展性而备受青睐。为了支持微服务的…...

新增自定义数据功能|UWA Gears V1.0.7

UWA Gears 是UWA最新发布的无SDK性能分析工具。针对移动平台&#xff0c;提供了实时监测和截帧分析功能&#xff0c;帮助您精准定位性能热点&#xff0c;提升应用的整体表现。 本次版本更新新增了自定义数据功能&#xff0c;支持灵活定义和捕获关键性能指标&#xff0c;满足特…...

docker 简要笔记

文章目录 一、前提内容1、docker 环境准备2、docker-compose 环境准备3、流程说明 二、打包 docker 镜像1、基础镜像2、国内镜像源3、基础的dockerfile4、打包镜像 四、构建运行1、docker 部分2、docker-compose 部分2.1、构建docker-compose.yml2.1.1、同目录构建2.1.2、利用镜…...

在Ubuntu上使用Apache+MariaDB安装部署Nextcloud并修改默认存储路径

一、前言 Nextcloud 是一款开源的私有云存储解决方案&#xff0c;允许用户轻松搭建自己的云服务。它不仅支持文件存储和共享&#xff0c;还提供了日历、联系人、任务管理、笔记等丰富的功能。本文将详细介绍如何在 Ubuntu 22.04 LTS 上使用 Apache 和 MariaDB 安装部署 Nextcl…...

【JavaEE】-- 计算机是如何工作的

文章目录 1. 冯诺依曼体系&#xff08;VonNeumann Architecture)2. CPU 基本工作流程2.1 寄存器(Register)和 内存(RAM)2.2 控制单元 CU(ControlUnit)2.3 指令&#xff08;Instruction) 3. 操作系统&#xff08;OperatingSystem)3.1 操作系统的定位3.2 什么是进程/任务(Process…...

政安晨的AI大模型训练实践三:熟悉一下LF训练模型的WebUI

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 目录 启动WebUI 微调模型 LLaMA-Factory 支持通过 WebUI 零代码微调大语言模型。 启动Web…...

基于微信小程序的网上订餐管理系统

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

科技快讯 | 理想官宣:正式收费!WeChat 港币钱包拓宽商户网络;百川智能发布深度思考模型Baichuan-M1-preview

理想官宣&#xff1a;正式收费&#xff01; 1月23日&#xff0c;理想汽车宣布&#xff0c;理想超充站超时占用费正式运营。触发超时占用费的条件为充电结束后15分钟内未将充电枪插回充电桩&#xff0c;收费标准为2元/分钟&#xff0c;单次封顶200元。理想汽车将在充电结束的四个…...

【java数据结构】map和set

【java数据结构】map和set 一、Map和Set的概念以及背景1.1 概念1.2 背景1.3 模型 二、Map2.1 Map说明2.2 Map的常用方法 三、Set3.1 Set说明3.2 Set的常用方法 四、Set和Map的关系 博客最后附有整篇博客的全部代码&#xff01;&#xff01;&#xff01; 一、Map和Set的概念以及…...

飞牛NAS安装过程中的docker源问题

采用CloudFlare进行飞牛NAS的远程访问 【安全免费】无需公网IP、端口号&#xff0c;NAS外网访问新方法_网络存储_什么值得买 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<EOF {"registry-mirrors": ["https://docker.1panel.dev&quo…...

Linux(Centos 7.6)命令详解:dos2unix

1.命令安装 dos2unix 命令默认情况下是没有安装的&#xff0c;如配置yum源&#xff0c;可通过yum安装命令如下&#xff1a; yum install dos2unix dos2unix 有一个对立的命令unix2dos&#xff0c;也需要yum安装&#xff0c;一般使用不到这里不做过多解释&#xff0c;具体参数…...

Linux MySQL离线安装

一、准备工作 1. 下载MySQL安装包 访问MySQL官方网站&#xff0c;选择适合您Linux系统的MySQL版本进行下载。通常推荐下载Generic Linux (glibc 2.12)版本的.tar.gz压缩包&#xff0c;例如mysql-8.0.33-linux-glibc2.12-x86_64.tar.xz。将下载好的安装包拷贝到Linux服务器的某…...

声明,这些内容和我无关

声明&#xff0c;下面这些内容和我无关&#xff0c;不是我写的&#xff0c;买了我不负责答疑&#xff0c;也不负责其他相关。 一下内容都不是我写的&#xff0c;系统自己加上去的&#xff0c;和我无关&#xff0c;我不负责答疑也不负责其他。...

ISO:摄影中的光线敏感度密码

目录 一、ISO 究竟是什么 二、ISO 与光线的关系 &#xff08;一&#xff09;低 ISO 在充足光线下的表现 &#xff08;二&#xff09;高 ISO 在光线不足时的作用 三、ISO 对画质的影响 &#xff08;一&#xff09;低 ISO 带来的优质画质 &#xff08;二&#xff09;高 IS…...

长短期记忆网络LSTM

视频链接 1.LSTM与RNN的区别 RNN想把所有信息都记住&#xff0c;不管是有用的信息还是没用的信息&#xff0c;并且有梯度爆炸或者梯度消失的问题 而LSTM设计了一个记忆细胞&#xff0c;具备选择记忆功能&#xff0c;可以选择记忆重要信息&#xff0c;过滤掉噪声信息&#xff0…...

2. 握手问题python解法——2024年省赛蓝桥杯真题

原题传送门&#xff1a;1.握手问题 - 蓝桥云课 问题描述 小蓝组织了一场算法交流会议&#xff0c;总共有 50人参加了本次会议。在会议上&#xff0c;大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手 (且仅有一次)。但有 7 个人&#xff0c;…...

poi在word中打开本地文件

poi版本 5.2.0 方法1&#xff1a;使用XWPFFieldRun&#xff08;推荐&#xff09; 比如打开当前相对路径的aaaaa.docx XWPFFieldRun run paragraph.createFieldRun();CTRPr ctrPr run.getCTR().addNewRPr();CTFonts font ctrPr.addNewRFonts();// 设置字体font.setAscii(&quo…...

国产编辑器EverEdit - 输出窗口

1 输出窗口 1.1 应用场景 输出窗口可以显示用户执行某些操作的结果&#xff0c;主要包括&#xff1a; 查找类&#xff1a;查找全部&#xff0c;筛选等待操作&#xff0c;可以把查找结果打印到输出窗口中&#xff1b; 程序类&#xff1a;在执行外部程序时(如&#xff1a;命令窗…...

整数的个数(信息学奥赛一本通-1067)

【题目描述】 给定k(1<k<100)个正整数&#xff0c;其中每个数都是大于等于1&#xff0c;小于等于10的数。写程序计算给定的k个正整数中&#xff0c;1&#xff0c;5和10出现的次数。 【输入】 输入有两行&#xff1a;第一行包含一个正整数k&#xff0c;第二行包含k个正整数…...

ios swift画中画技术尝试

继上篇&#xff1a;iOS swift 后台运行应用尝试失败-CSDN博客 为什么想到画中画&#xff0c;起初是看到后台模式里有一个picture in picture&#xff0c;去了解了后发现这个就是小窗口视频播放&#xff0c;方便用户执行多任务。看小窗口视频的同时&#xff0c;可以作其他的事情…...

MyBatis 写法

MyBatis 高效使用技巧 常见 MyBatis 使用技巧&#xff0c;这些技巧有助于简化数据库操作&#xff0c;提高开发效率&#xff0c;并增强系统的性能。 1. 动态 SQL 动态 SQL 让开发者能够依据参数灵活地构建 SQL 语句&#xff0c;避免了手动拼接字符串带来的复杂性和错误风险。…...

Three城市引擎地图插件Geo-3d

一、简介 基于Three开发&#xff0c;为Three 3D场景提供GIS能力和城市底座渲染能力。支持Web墨卡托、WGS84、GCJ02等坐标系&#xff0c;支持坐标转换&#xff0c;支持影像、地形、geojson建筑、道路&#xff0c;植被等渲染。支持自定义主题。 二、效果 三、代码 //插件初始化…...

【贪心算法】洛谷P1106 - 删数问题

2025 - 01 - 22 - 第 46 篇 【洛谷】贪心算法题单 - 【贪心算法】 - 【学习笔记】 作者(Author): 郑龙浩 / 仟濹(CSND账号名) 目录 文章目录 目录P1106 删数问题题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示思路代码 P1106 删数问题 题目描述 键盘输入一个高…...