运维笔记.Docker镜像分层原理

news2024/12/23 0:18:14
运维专题
Docker镜像原理

- 文章信息 - Author: 李俊才 (jcLee95)
Visit me at CSDN: https://jclee95.blog.csdn.net
My WebSitehttp://thispage.tech/
Email: 291148484@163.com.
Shenzhen China
Address of this article:https://blog.csdn.net/qq_28550263/article/details/139248460
HuaWei:https://bbs.huaweicloud.com/blogs/428123

【介绍】:Docker镜像是由只读层组成,每层代表一个指令,这些层是堆叠的,每一层都是前一层的增量。本文关于Docker镜像分层相关原理和话题。

在这里插入图片描述


1. Docker中镜像与容器简要回顾

1.1 镜像(Image)

Docker镜像是一个轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,包括代码、运行时环境、库、环境变量和配置文件。

镜像是静态的,即在创建后内容不会改变,它们是构建容器的基础。

1.2 容器(Container)

容器是镜像的运行实例。当镜像被启动时,它在隔离的环境中运行,成为一个或多个正在运行的容器。

容器隔离并运行单独的应用,保证应用运行在快速、可重复的环境中。

2. 镜像的分层原理

2.1 分层存储

2.1.1 分层存储的工作原理

Docker镜像是由一系列只读的层(layer)组成的。这些层按照从下到上的顺序堆叠,每一层都是基于下面一层的变化。当我们创建或更新一个镜像时,只有被改变的部分会被添加为一个新层,其他部分保持不变。

这种分层存储的机制使得Docker镜像可以被高效地构建、传输和存储。

2.1.2 层的创建过程

通常,我们使用Dockerfile来定义和创建Docker镜像。Dockerfile中的每一条指令(如FROMRUNCOPY等)都会创建一个新的层。

例如,考虑以下Dockerfile

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3
COPY app.py /app/
CMD ["python3", "/app/app.py"]

这个Dockerfile会创建四个层:

  1. 基础层:从ubuntu:22.04镜像开始。

  2. 第二层:运行apt-get update && apt-get install -y python3,安装Python3

  3. 第三层:将app.py文件复制到镜像的/app/目录。

  4. 第四层:指定容器启动时运行的命令python3 /app/app.py

2.1.3 层的存储与复用

这些层都是只读的,并且每一层只存储与前一层的差异部分。当我们构建一个新镜像时,Docker会检查每一层的内容是否已经存在。如果一个层与现有的层完全相同,Docker会直接复用这个层,而不是重新创建。

这种机制大大提高了构建和存储效率。例如,如果你有多个Dockerfile都基于ubuntu:22.04,那么这个基础层只需要存储一次,所有的镜像都可以共享它。

2.1.4 容器的可写层

当一个容器从镜像启动时,Docker会在镜像的顶部添加一个新的可写层。容器对文件系统的所有改变,如创建新文件,修改现有文件,删除文件等,都会被记录在这个可写层中。

这个可写层允许多个容器共享同一个镜像,同时又保持各自的状态。当容器被删除时,可写层也会被删除,而底层的镜像保持不变。

通过详细解释分层存储的工作原理、层的创建过程、层的存储与复用,以及容器的可写层,我们可以更深入地理解Docker如何利用分层存储来优化镜像的构建、存储和运行效率。

2.2 重用与共享

2.2.1 共享机制的优点

Docker的分层存储机制不仅优化了镜像的存储,还促进了镜像层的 重用和共享。这种共享机制有以下优点:

  1. 节省存储空间:多个镜像可以共享相同的层,而无需重复存储,大大节省了存储空间。

  2. 加速镜像构建:当构建一个新镜像时,如果所需的层已经存在,Docker会直接使用现有的层,而不是重新创建,从而加速了构建过程。

  3. 加速镜像分发:当从Docker仓库拉取镜像时,如果某些层已经存在于本地,只需拉取缺失的层,减少了网络传输的数据量,加速了镜像分发。

2.2.2 共享的实现方式

Docker通过以下方式实现层的共享:

  1. 内容寻址:每个层都有一个唯一的哈希值,这个哈希值是根据层的内容计算出来的。如果两个层的内容完全相同,它们的哈希值也相同。Docker使用这个哈希值来判断两个层是否相同。

  2. 层的复用:当构建一个新镜像时,Docker会检查每一层的哈希值。如果一个层的哈希值与现有的层相同,Docker会直接使用现有的层,而不是重新创建。

  3. 共享层的存储:所有的镜像层都存储在Docker主机的文件系统中。如果多个镜像共享一个层,这个层在文件系统中只存储一次,所有的镜像都引用这个共享的层。

2.2.3 共享的示例

现在考虑一个具体的例子来说明Docker层共享是如何工作的。假设我们有两个Dockerfile,它们都基于ubuntu:22.04镜像:

Dockerfile1

FROM python:3.11
RUN pip install django
COPY app1/ /app/
WORKDIR /app
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

Dockerfile2

FROM python:3.11
RUN pip install django pillow
COPY app2/ /app/
WORKDIR /app
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

当我们构建这两个镜像时,Docker会创建以下层:

  1. 基础层(python:3.11)
  2. Django层(RUN pip install django)
  3. Pillow层(RUN pip install django pillow)
  4. 应用1层(COPY app1/ /app/)
  5. 应用2层(COPY app2/ /app/)

其中,基础层和Django层是共享的,因为它们在两个Dockerfile中是相同的。Pillow层、应用1层和应用2层是独立的,因为它们在每个Dockerfile中是不同的。

当这两个镜像都构建完成后,Docker只需在文件系统中存储一次基础层和Django层,而不是两次。这样就节省了存储空间,并且加速了镜像的构建和分发过程。

3. 镜像大小问题

Docker镜像的大小是一个重要的考量因素,因为它直接影响到镜像的存储、传输和部署效率。镜像越大,占用的存储空间越多,传输和部署的时间也越长。因此,优化镜像大小是Docker使用中的一个重要课题。

3.1 基础镜像的大小

基础镜像是构建其他镜像的起点,它通常包含操作系统的核心文件和一些常用的库。基础镜像的大小会直接影响到所有基于它构建的镜像的大小

例如,如果你选择了一个 包含完整操作系统的基础镜像 ,如ubuntu:22.04,那么你的镜像大小会比选择一个 最小化的基础镜像 ,如alpine要大很多

因此,在选择基础镜像时,我们需要权衡功能完整性和镜像大小。如果你的应用不需要完整的操作系统,选择一个最小化的基础镜像可以显著减小最终镜像的大小。

3.2 软件依赖

除了基础镜像,应用运行所需的软件库和其他依赖也会增加镜像的大小。每个 RUN 指令安装的软件包,每个COPYADD指令添加的文件,都会增加镜像的大小。

为了减小镜像大小,我们可以采取以下措施:

  1. 只安装必要的软件包:仔细评估每个软件包的必要性,只安装运行应用所必需的包。

  2. 清理安装缓存:在安装软件包后,删除下载的软件包缓存,如/var/cache/apt/archives/

  3. 合并RUN指令:尽可能将多个RUN指令合并为一个,这样可以减少镜像的层数,从而减小镜像大小。

  4. 使用.dockerignore文件:在COPYADD文件时,使用.dockerignore文件排除不必要的文件和目录,减小镜像大小。

3.3 多阶段构建

多阶段构建是Docker提供的一个功能,它允许我们在一个Dockerfile中使用多个FROM语句,每个FROM语句都可以使用不同的基础镜像,并且每个阶段都可以从前一个阶段复制文件。

这个功能对于需要构建依赖项但最终镜像不需要这些依赖项的情况非常有用。通过多阶段构建,我们可以在一个阶段安装所有必要的依赖项并构建应用,然后在另一个阶段只复制构建好的应用,而不复制构建依赖项。这样可以显著减小最终镜像的大小。

以下是一个使用多阶段构建例子:

# 构建阶段
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 运行阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --only=production
CMD ["node", "dist/main.js"]

在这个例子中:

  1. 第一阶段使用node:18镜像作为构建环境。它复制package.jsonpackage-lock.json,运行npm ci安装所有依赖项(包括开发依赖项),然后复制其余的应用代码并运行npm run build构建应用。

  2. 第二阶段使用node:18-alpine镜像作为基础,这是一个更小的Node.js镜像。它从第一阶段复制构建好的应用代码(在dist目录中),复制package.json和package-lock.json,然后运行npm ci --only=production只安装生产依赖项。最后,它指定了容器启动时运行的命令。

这样,最终的镜像就只包含运行应用所需的代码和生产依赖项,而不包含用于构建的代码和开发依赖项,从而大大减小了镜像的大小。

再看一个例子:

# 构建阶段
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
COPY . .

# 运行阶段
FROM python:3.11-alpine
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "main.py"]

在这个例子中:

  • 第一阶段安装所有的依赖项(包括开发依赖项);
  • 第二阶段只复制安装好的依赖项和应用代码,使用更小的python:3.11-alpine镜像。

4. 联合文件系统

联合文件系统(Union File System,简称 UnionFS)是 Docker 镜像的基石。它是一种分层、轻量级并且高性能的文件系统,支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。

4.1 工作原理

UnionFS 的工作原理是将多个不同的目录(也叫分支)内容联合挂载到同一个目录下,并呈现为单个一致的文件系统。这些分支可以是只读的,也可以是可读写的。当对这个虚拟文件系统进行修改时,实际上是在可写的分支上进行操作,而原始的文件并没有被修改。

Docker 中,镜像就是由多个只读层组成的。当我们启动一个容器时,Docker 会在这些只读层之上添加一个可读写层。当容器修改现有的文件时,该文件将被复制到可读写层,并在那里被修改。这种机制被称为写时复制Copy-on-Write)。

4.2 UnionFS的优点

使用 UnionFS 有以下几个优点:

  • 节省存储空间:多个镜像可以共享相同的只读层,从而减少磁盘占用。

  • 加速镜像构建和部署:当构建一个新镜像时,只需要构建与现有镜像不同的层,相同的层可以直接复用。这大大加速了镜像的构建和部署过程。

  • 促进镜像的分发:由于镜像是分层存储的,当我们下载一个镜像时,实际上只需要下载我们本地没有的层。这减少了网络传输的数据量,加速了镜像的分发。

4.3 加载过程

当启动一个容器时,Docker 会从镜像的底层开始,依次加载每一层文件系统,直到最顶层的可读写层。这个过程可以看作是一个 UnionFS 的加载过程。

假设我们有一个包含三个层的镜像:一个基础层,一个中间层,和一个顶层。当我们基于这个镜像启动一个容器时,Docker 会:

  1. 加载基础层,这通常是一个操作系统的文件系统,如 Ubuntu 的文件系统。

  2. 加载中间层,这可能包含一些基本的工具和库,如 Python 解释器。

  3. 加载顶层,这通常包含我们的应用代码和配置。

  4. 添加一个可读写层,用于存储容器运行时的修改。

这四层被 UnionFS 挂载到同一个目录下,呈现为一个完整的文件系统给容器使用。当容器修改文件时,修改会被写入可读写层。

5. 镜像构建过程

Docker 镜像是通过 Dockerfile 文件来定义和构建的。Dockerfile 是一个文本文件,其中包含了一系列指令,告诉 Docker 如何构建镜像。在构建过程中,Docker 会读取 Dockerfile 中的指令,并按照指令的顺序逐步执行,最终生成一个新的镜像。

5.1 分层构建

Docker 的镜像构建过程是分层的。每执行一条 Dockerfile 指令,都会在当前镜像的顶部创建一个新的层。这种分层构建的机制有以下优点:

复用层:不同的镜像可以共享相同的层,减少磁盘占用和加速构建过程。

缓存:如果 Dockerfile 的指令和上下文没有改变,Docker 可以使用缓存的层,无需重新执行指令。

最小化变更:由于每个层都是独立的,对镜像的修改可以仅限于某些层,而不影响其他层。

举个例子,假设我们有以下的 Dockerfile

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3
COPY app.py /app/
CMD ["python3", "/app/app.py"]

当我们构建这个镜像时,Docker 会:

  1. ubuntu:22.04 镜像开始,这是第一层。
  2. 执行 RUN 指令,在第一层的基础上创建第二层,该层包含了更新的软件包列表和安装的 Python3
  3. 执行 COPY 指令,在第二层的基础上创建第三层,该层包含了复制到镜像中的 app.py 文件。
  4. 执行 CMD 指令,在第三层的基础上创建第四层,该层指定了容器启动时运行的默认命令。

每一层都只包含了与前一层的差异部分,而不是完整的文件系统。这种分层构建的方式大大提高了构建和存储的效率。

5.2 缓存利用

为了加速构建过程,Docker 会尽可能地利用缓存。当我们重新构建一个镜像时,Docker 会检查每个指令的缓存情况:

  • 如果该指令和上下文没有改变,且存在可用的缓存层,Docker 会直接使用缓存层,而不会重新执行该指令。

  • 如果该指令或上下文发生了改变,Docker 会重新执行该指令,并为后续的指令invalidate缓存。

这意味着,如果我们修改了 Dockerfile 中的一条指令,该指令之后的所有指令都会被重新执行,而该指令之前的指令如果有缓存则会直接使用缓存。

=> 因此,为了最大限度地利用缓存,我们应该:

将最不“likely to change”的指令放在 Dockerfile 的前面,如 FROMLABEL 等。

将最likely to change的指令放在 Dockerfile 的后面,如 COPYADD 等。

合并 RUN 指令,以减少层数和利用缓存。

例如,不要这样写:

RUN apt-get update
RUN apt-get install -y python3

而应该这样写:

RUN apt-get update && apt-get install -y python3

这样,如果 apt-get update 的结果没有变化,apt-get install 就可以直接使用缓存,而不需要重新执行。

5.3 构建上下文

当我们执行 docker build 命令时,当前目录被称为构建上下文(build context)。Docker 会将构建上下文中的文件发送到 Docker daemon,daemon 根据 Dockerfile 中的指令构建镜像。

这意味着,Dockerfile 中的 COPYADD 指令只能复制构建上下文中的文件。如果我们试图复制上下文之外的文件,会得到一个错误。

为了减小构建上下文的大小,提高构建效率,我们应该:

Dockerfile 放在一个空目录或者项目根目录中。

使用 .dockerignore 文件排除不需要的文件和目录,如 .gitnode_modules 等。

避免使用 ADD 指令自动解压缩归档文件,而是在 RUN 指令中显式地解压缩。

例如,假设我们有以下的项目结构:

.
├── .git
├── .dockerignore
├── Dockerfile
├── app.py
└── README.md

我们可以在 .dockerignore 文件中添加以下内容:

.git
README.md

然后,我们的 Dockerfile 可以这样写:

FROM python:3.9
COPY app.py /app/
CMD ["python", "/app/app.py"]

这样,当我们执行 docker build 命令时,只有 app.py 文件会被发送到 Docker daemon,而 .git 目录和 README.md 文件会被排除在构建上下文之外,从而减小了构建上下文的大小,提高了构建效率。

6. 基础镜像与依赖

Docker 的镜像存储和复用机制是其高效性和灵活性的关键所在。通过巧妙的设计,Docker 在存储和运行镜像时,最大限度地节省了存储空间,提高了运行效率。

6.1 存储优化

得益于 Docker 的分层存储机制,相同的镜像层只需在磁盘上存储一次,不同的镜像可以共享这些层,从而大大节省了存储空间。

假设我们有两个镜像:镜像A和镜像B,它们都基于相同的基础镜像,如 Ubuntu

在此基础上,镜像A安装了 Python,而镜像B安装了 Python 和 Node.js。在 Docker 的存储中,这两个镜像的层结构可能如下:

镜像A:

Layer 3: Python
Layer 2: Ubuntu 基础镜像
Layer 1: Boot FS

镜像B:

Layer 4: Node.js
Layer 3: Python
Layer 2: Ubuntu 基础镜像
Layer 1: Boot FS

可以看到,Layer 1Layer 2 (即 Boot FSUbuntu 基础镜像) 在两个镜像中是完全相同的。Docker 在存储时,只需在磁盘上存储一份这两个层的数据,两个镜像都可以引用这两个层。这样,无论我们有多少个基于 Ubuntu 的镜像,Ubuntu 基础镜像层只需存储一次。

这种存储优化机制使得 Docker 镜像的存储非常高效。即使我们有大量的镜像,只要它们共享一些相同的层,实际占用的磁盘空间就会大大减少。

6.2 运行效率

Docker 的分层存储机制不仅优化了存储,也提高了镜像的运行效率。当我们从一个镜像启动容器时,Docker 只需要在镜像的顶部添加一个可写层,而镜像的其他层都是只读的,可以被多个容器共享。

这意味着,当我们启动多个基于相同镜像的容器时,这些容器可以共享镜像的只读层。这些只读层已经存在于本地磁盘上,无需重新下载或创建。Docker 只需为每个容器创建一个新的可写层。

这种机制大大加速了容器的启动过程。因为大部分数据都已经在本地镜像中准备好了,Docker 不需要在每次启动容器时都去下载或复制这些数据。

此外,由于容器共享镜像的只读层,启动多个容器并不会显著增加内存占用。每个容器只需要一些内存来维护自己的状态和可写层。

7. 基础镜像与依赖

Docker 的镜像构建过程中,基础镜像和软件依赖扮演着至关重要的角色。它们共同构成了应用运行所需的完整环境。

7.1 基础镜像(Base Image)

基础镜像是构建其他镜像的起点。它通常包含以下内容:

  • 操作系统的核心文件,如 Linux 的文件系统层次结构、基本命令和工具等。

  • 常用的系统库,如 glibcOpenSSL 等。

  • 包管理工具,如 apt、yum、apk 等,用于安装其他软件包。

常见的基础镜像如:

  • Ubuntu、Debian、CentOS 等通用操作系统镜像。

  • Alpine,一个面向安全的轻型 Linux 发行版,常用于构建最小化的镜像。

  • Busybox,一个集成了数百个 Unix 工具的单个可执行文件,常用于构建极小的镜像。

选择合适的基础镜像需要考虑以下因素:

  • 应用的兼容性:应用需要哪些特定版本的库和工具。

  • 镜像大小:选择最小化的基础镜像有助于减小最终镜像的大小。

  • 安全性:及时更新基础镜像,以包含最新的安全补丁。

7.2 软件依赖层

在基础镜像之上,我们需要安装应用运行所需的特定软件包和工具,如编程语言解释器、数据库、Web服务器等。这些软件依赖构成了镜像的上层。

管理软件依赖时应该注意:

  • 显式指定版本:在安装软件包时,明确指定所需的版本,以确保构建的可重复性。

  • 使用官方源:从官方源或可信的第三方源安装软件包,以确保软件包的完整性和安全性。

  • 清理缓存:安装完软件包后,删除下载的软件包缓存,以减小镜像的大小。

  • 合并层:尽可能将多个相关的操作合并到一个层中,以减少层数和镜像大小。

FROM python:3.11

ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1

RUN pip install --upgrade pip
RUN pip install django==4.2.1

# 应用代码将在后续层中添加

在这个例子中,我们选择 python:3.11 作为基础镜像,它已经包含了 Python 3.11 解释器和 pip 包管理器。

  • 我们设置了两个环境变量:PYTHONUNBUFFEREDPYTHONDONTWRITEBYTECODE,以优化 Python 的运行表现。

  • 然后,我们使用 pip 升级了 pip 自身,并安装了指定版本(4.2.1)的 Django

  • 应用代码将在后续的层中通过 COPY 指令添加。

这个例子展示了如何在 Python 3.11 的基础镜像上,通过明确指定版本号的方式安装 Django 依赖,构建一个适用于 Django 应用的 Docker 镜像。

通过合理地组织基础镜像和软件依赖层,我们可以构建出结构清晰、易于维护、安全高效的 Docker 镜像,为运行 Django 应用提供一个稳定的环境。

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

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

相关文章

陈丽:人工智能赋能教育创新发展

5月20日,在顾明远先生莅临科大讯飞考察指导高端咨询会暨“人工智能与未来教育”的主题研讨会上,北京师范大学原副校长、中国教育技术协会副会长陈丽教授作了题为《人工智能赋能教育创新发展》的主旨报告。 (以下内容根据陈丽教授在研讨会上的…

Python | Leetcode Python题解之第116题填充每个节点的下一个右侧节点指针

题目: 题解: class Solution:def connect(self, root: Node) -> Node:if not root:return root# 从根节点开始leftmost rootwhile leftmost.left:# 遍历这一层节点组织成的链表,为下一层的节点更新 next 指针head leftmostwhile head:#…

C++习题(1)

一、题目描述&#xff1a; 二、代码展示&#xff1a; #include <iostream> #include <iomanip> using namespace std; struct Student{char name[20];int id;int age;float score; }; int main() {int n;cin>>n;Student student[n];float sum0.0;for(int i0…

Ubuntu22.04之扩展并挂载4T硬盘(二百三十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

第18章-综合以上功能 基于stm32的智能小车(远程控制、避障、循迹) 基于stm32f103c8t6/HAL库/CubeMX/超详细,包含代码讲解和原理图

这个是全网最详细的STM32项目教学视频。 第一篇在这里: 视频在这里 STM32智能小车V3-STM32入门教程-openmv与STM32循迹小车-stm32f103c8t6-电赛 嵌入式学习 PID控制算法 编码器电机 跟随 第18章-综合以上功能 18-按键和app按钮切换功能 根据上面介绍&#xff0c;我们的模式可…

ADS基础教程15 - 设计加密保护IP

设计加密保护IP 一、引言二、IP的生成与调用1.IP生成2.IP的调用 一、引言 介绍如何ADS中如何对设计好的原理图进行加密形成IP&#xff0c;然偶进行调用的过程。 二、IP的生成与调用 1.IP生成 (1)选择一个已经调试好的原理图&#xff0c;在菜单栏中选择Tools–>Encode De…

Aws CodeCommit代码仓储库

1 创建IAM用户 IAM创建admin用户&#xff0c;增加AWSCodeCommitFullAccess权限 2 创建存储库 CodePipeline -> CodeCommit -> 存储库 创建存储库 3 SSH 1) window环境 3.1.1 上载SSH公有秘钥 生成SSH秘钥ID 3.1.2 编辑本地 ~/.ssh 目录中名为“config”的 SSH 配置文…

从零学爬虫:使用比如说说解析网页结构

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、网页结构概述 示例&#xff1a;查看网页结构 三、使用比如说说解析网页 1.…

ThingsBoard网关在燃气泄漏监测中的应用

据不完全统计&#xff0c;全国城市燃气企业的供销差率大约在3%~4%&#xff0c;也就意味着越多的天然气销量就有越多的天然气损失。城市燃气企业计量管理已经接近最不利的状态&#xff0c;开展有效的计量管理势在必行。 智慧燃气综合管理系统 在燃气管网中部署智能传感器、数据采…

2024年03月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,共50分) 第1题 在Python中,hex(2023)的功能是?( ) A:将十进制数2023转化成十六进制数 B:将十进制数2023转化成八进制数 C:将十六进制数2023转化成十进制数 D:将八进制数2023转化成十进制数 答案:A …

C语言 | Leetcode C语言题解之第116题填充每个节点的下一个右侧节点指针

题目&#xff1a; 题解&#xff1a; struct Node* connect(struct Node* root) {if (root NULL) {return root;}// 从根节点开始struct Node* leftmost root;while (leftmost->left ! NULL) {// 遍历这一层节点组织成的链表&#xff0c;为下一层的节点更新 next 指针stru…

【Linux-RTC】

Linux-RTC ■ rtc_device 结构体■ RTC 时间查看与设置■ 1、时间 RTC 查看■ 2、设置 RTC 时间 ■ rtc_device 结构体 Linux 内核将 RTC 设备抽象为 rtc_device 结构体 rtc_device 结构体&#xff0c;此结构体定义在 include/linux/rtc.h 文件中 ■ RTC 时间查看与设置 ■ 1…

超市信息管理系统(java+swing+jdbc+msyql)

商品管理模块 进货管理&#xff1a;记录进货信息&#xff0c;包括商品条码、价格设定、数量等。 库存管理&#xff1a;管理商品的库存情况&#xff0c;提供库存量查询和更新功能。 商品信息管理&#xff1a;商品的基本信息管理&#xff0c;如商品名、规格、生产厂商等。 销…

基于stm32和HC_SR04超声波模块的测距和报警

基于stm32和HC_SR04超声波模块的测距和报警 目录 **基于stm32和HC_SR04超声波模块的测距和报警****一.工作原理****二.功能实现****HC_SR04初始化和读取距离****使用呼吸灯表示距离远近****主函数编写** **三.效果****四.关于modbus和串口RS485****五.总结** 一.工作原理 (1)采…

设计模式 20 中介者模式 Mediator Pattern

设计模式 20 中介者模式 Mediator Pattern 1.定义 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型设计模式&#xff0c;它通过封装对象之间的交互&#xff0c;促进对象之间的解耦合。中介者模式的核心思想是引入一个中介者对象&#xff0c;将系统中对象之间…

【IC】良率模型-yield model

缺陷密度Default Density&#xff08;D0&#xff09;&#xff0c;表示单位面积的缺陷数D。 单位面积有M个部件&#xff0c;一个部件的平均失效率为&#xff1a; 一个面积为A的系统&#xff08;芯片&#xff09;良率&#xff1a; Possion模型&#xff1a; 当M趋于无穷时&…

秋招突击——算法打卡——5/27——复习{寻找特定中位数}——新做:{最长回文字串、Z 字形变换}

文章目录 复习——寻找特定中位数新作——最长回文子串个人思路分析实现代码参考学习和上述思路相同&#xff0c;枚举中心点字符串哈希二分 新作——Z 字形变换个人做法思路分析实现代码 参考解法分析总结 复习——寻找特定中位数 第一次的链接&#xff1a;寻找中位数本来以为…

香橙派OrangePi AIpro上手初体验

一、前言 非常感谢能够收到CSDN和香橙派的OrangePi AIpro开发板评测活动的邀请&#xff1b;收到的OrangePi AIpro实物如下所示&#xff1a; 二、OrangePi AIpro介绍 通过查询香橙派官网可以了解到OrangePi AIpro的相关信息如下&#xff1a;OrangePi AIPro 开发板是香橙派联合…

浙江大学数据结构MOOC-课后习题-第七讲-图4 哈利·波特的考试

题目汇总 浙江大学数据结构MOOC-课后习题-拼题A-代码分享-2024 题目描述 代码展示 照着教程视频来的&#xff0c;没啥好说的捏 #include <cstdlib> #include <iostream>#define MAXSIZE 100 #define IFINITY 65535 typedef int vertex; typedef int weightType;/…

【StableDiffusion】SD1.4、1.5、2.0、2.1 和 SDXL0.9-1.0、SDXL turbo 等的区别

总览 1.基础sd base model家族&#xff1a;SD1.4、SD1.5、SD1.5-LCM、SD2.0、SD2.0-768、SD2.1、SD2.1-768、SD2.1-UNCLIP 2.升级sdxl base model家族&#xff1a;SDXL0.9、SDXL1.0、SDXL1.0-LCM、SDXL-DISTILLED、SDXL-TURBO 3.专门用于视频生成的 SVD 家族&#xff1a;SVD、…