揭秘Linux进程调度:5大策略和性能分析专家指南
发布时间: 2025-01-06 00:50:17 阅读量: 13 订阅数: 2
Linux进程调度:深入理解与实践
![da14531_产品中文简介.pdf](https://lpccs-docs.renesas.com/da14683_secure_boot/_images/secure_boot_overview.png)
# 摘要
本文全面探讨了Linux操作系统中的进程调度机制,从理论基础到深入剖析,再到性能分析实战,最后展望了调度技术的发展趋势。文章首先介绍了Linux进程调度的基本概念,包括进程与线程的区别以及进程状态模型。随后,详细分析了标准Linux调度策略,包括SCHED_OTHER、SCHED_FIFO和SCHED_RR等,以及调度策略的历史演进和CFS调度器的特点。在深入剖析环节,文章深入探讨了CFS调度器的工作原理、实时调度器的实现机制以及CPU亲和性对调度决策的影响。第四章通过介绍性能分析工具,测试环境搭建以及实际案例分析,提供了调度性能优化的实践指南。最后,文章预测了容器化、新硬件技术以及云平台对Linux进程调度未来发展的影响,并提出了相应的优化方向。
# 关键字
Linux进程调度;CFS;实时调度;性能分析;CPU亲和性;调度优化
参考资源链接:[DA14531: 全球最小最省电的蓝牙5.1 SoC引领IoT革命](https://wenku.csdn.net/doc/645f47755928463033a7d350?spm=1055.2635.3001.10343)
# 1. Linux进程调度概述
Linux作为现代操作系统的核心之一,其进程调度机制是理解和优化系统性能的关键。本章将介绍Linux进程调度的基础知识,概述其在系统中的角色和重要性。
## 1.1 进程调度的目的和任务
进程调度是操作系统中的一项重要功能,其主要任务是决定哪个进程获得CPU的使用权,并安排其运行。调度器通过一套预定的算法,保证CPU资源的合理分配,使得系统中的任务能够高效、公平地执行。
## 1.2 Linux进程调度的基本类型
在Linux中,进程调度可以大致分为两类:抢占式调度和协作式调度。抢占式调度器可以在任何时候中断当前进程的执行,将CPU控制权转移给其他进程;而协作式调度器则依赖进程主动放弃CPU资源。
## 1.3 Linux内核调度器的演进
从最初的O(1)调度器,到目前广泛使用的完全公平调度器(CFS),Linux内核调度器在性能和设计上持续改进。CFS通过虚拟时间的概念提供了一个更为精细的调度策略,目标是为每个进程提供等价的CPU时间片,优化了进程调度的公平性和效率。
Linux进程调度作为操作系统中最为核心的部分之一,随着技术的发展,不断涌现出新的调度策略和优化技术。接下来的章节将进一步探讨这些策略和技术,以及它们如何影响系统性能。
# 2. Linux进程调度策略的理论基础
## 2.1 Linux进程调度的基本概念
### 2.1.1 进程与线程的区别
在Linux操作系统中,进程和线程是两个密切相关但有所区别的概念。进程可以视为是正在运行的程序的实例,每个进程都有自己的地址空间、系统资源分配以及进程控制块(PCB)。而线程作为进程的一部分,它是CPU调度的基本单位。一个进程可以包含多个线程,这些线程共享父进程的资源和内存空间,但每个线程拥有自己独立的栈空间和程序计数器。
一个关键的区别点在于资源隔离和上下文切换的开销。进程间资源隔离更加严格,因此切换进程时的上下文开销更大;线程之间共享资源,切换时的上下文开销较小,因此线程更适合于需要频繁切换的场景。
### 2.1.2 Linux进程状态模型
Linux进程状态模型主要包含以下几种状态:
- **运行态(Running)**:进程正在CPU上运行或者准备运行。
- **就绪态(Runnable)**:进程已经具备运行的所有资源,只等待CPU分配时间片。
- **睡眠态(Sleeping)**:进程由于等待某些事件发生(如输入输出操作完成)而暂停运行。
- 其中睡眠态还细分为可中断和不可中断两种,可中断睡眠态(Interruptible sleep)下,进程能够响应信号;不可中断睡眠态(Uninterruptible sleep)则不响应任何信号。
- **停止态(Stopped)**:进程被暂停执行,通常由接收到特定信号(如SIGSTOP)所致。
- **僵尸态(Zombie)**:进程结束但其父进程尚未读取其退出状态,此时进程已无实际运行内容,仅保留进程控制块以便父进程获取信息。
## 2.2 标准的Linux进程调度策略
### 2.2.1 SCHED_OTHER公平调度策略
Linux中的SCHED_OTHER是一个通用的调度策略,通常也称为CFS(Completely Fair Scheduler)调度器,这是一种公平调度策略,旨在提供所有进程之间的“公平”调度。它不是基于时间片轮转或优先级的调度,而是基于虚拟运行时间的概念来决定进程调度的顺序。CFS调度器的核心思想是尽量使得所有可运行进程在同一时间内的虚拟运行时间大致相同。
CFS调度器通过红黑树来管理运行队列中的进程,根据进程的虚拟运行时间,以及权重(nice值)动态调整进程在红黑树中的位置,这样可以保持运行队列的平衡。
### 2.2.2 SCHED_FIFO实时调度策略
实时调度策略在系统响应时间和确定性方面拥有非常高的要求。SCHED_FIFO是一种先进先出的实时调度策略,它不使用动态优先级。在这种策略下,一旦一个实时进程开始运行,除非它自己放弃CPU(例如通过调用sleep),或者有更高优先级的实时进程出现,否则它将一直占用CPU直到完成任务。这种策略的响应时间是可预测的,因此非常适合硬实时系统。
### 2.2.3 SCHED_RR实时调度策略
SCHED_RR(Round Robin)是另一种实时调度策略,类似于SCHED_FIFO,但它引入了时间片的概念。即使进程仍处于运行状态,一旦使用完分配给它的固定时间片,调度器就会将其放入队列尾部,将CPU让给其他同优先级的进程。这种方式可以保证即使有多个实时进程在运行,每个进程都有机会轮流使用CPU,从而提供更公平的调度。
## 2.3 Linux调度策略的演进
### 2.3.1 早期Linux调度器的设计
Linux早期的调度器基于简单的轮转调度算法,即每个进程轮流运行一小段时间。这种方法简单,但在处理大量进程或需要不同优先级的任务时性能不佳。由于其简单性,早期调度器在处理进程调度时缺乏灵活性和响应性。
### 2.3.2 CFS调度器的引入与影响
为了解决早期调度器的不足,CFS调度器被引入Linux内核中。CFS的引入极大地提升了Linux系统的调度性能,特别是对于需要高响应性和公平性的多用户交互场景。CFS通过红黑树的使用,能够实现进程的高效调度,同时确保系统资源的均衡分配。
### 2.3.3 新调度器的持续优化与发展
随着技术的进步,Linux调度器也在持续发展与优化。例如,引入BF调度器(Bubble Fair Scheduler)等,这些调度器主要的目的是在维持公平性的同时进一步优化性能,尤其是针对那些具有多核心处理器的现代硬件系统。新调度器的设计致力于解决特定的问题,如任务的延迟敏感性、实时性能要求以及云环境下的资源调度等。
# 3. Linux进程调度策略深入剖析
在本章节中,我们将深入探讨Linux内核中进程调度器的核心原理和机制。理解这些机制对于优化系统性能,以及进行系统级编程和管理至关重要。本章将从三个维度出发,揭示CFS调度器的运作机制、实时调度器的实现,以及CPU亲和性对调度决策的影响。
## 3.1 CFS调度器的工作原理
### 3.1.1 虚拟运行时间的概念
CFS(Completely Fair Scheduler,完全公平调度器)是Linux内核的一个主要调度器,用于管理非实时进程。CFS的核心理念是“每个进程公平地分配CPU时间片”,从而实现进程间的公平调度。为了达到这个目标,CFS引入了虚拟运行时间的概念,来衡量进程应获得的CPU执行时间。
虚拟运行时间是在实际物理时间基础上的一个计算值,它反映了进程的“饥饿程度”或需要执行的“工作量”。具体而言,一个进程的虚拟运行时间会随着其等待执行的时间增加而线性增长。这个计算过程中不考虑进程实际使用了多少CPU时间,而是基于“公平分享”的原则,确保所有进程都会得到等比例的CPU时间。
### 3.1.2 红黑树的使用与管理
为了有效地管理这些虚拟运行时间,CFS使用了一种高效的数据结构——红黑树。红黑树是一种自平衡的二叉查找树,它通过特定的平衡规则维持树的平衡,确保任何查找、插入和删除操作都保持在对数时间复杂度内。
在CFS中,每个运行队列(runqueue)都持有一颗红黑树,进程作为节点被插入到树中。根据进程的虚拟运行时间进行排序,这样最左边的节点通常具有最小的虚拟运行时间,意味着它最“饥饿”,需要优先调度。CFS调度器会选择红黑树最左侧的节点进行调度,确保最饥饿的进程获得服务。
红黑树的使用是CFS调度器的关键所在,它保证了调度的效率和公平性。调度器每次选择任务时,都会从树中挑选出当前虚拟运行时间最小的进程,从而实现了对CPU的公平分配。
## 3.2 实时调度器的实现机制
### 3.2.1 实时调度器的优先级计算
相对于CFS面向非实时进程的调度,Linux还提供了针对实时进程的调度策略。实时调度器主要分为两类:SCHED_FIFO和SCHED_RR。实时进程的调度策略更为简单直接,它们根据进程的优先级来分配CPU时间。
SCHED_FIFO是一个无时间片的先入先出(FIFO)调度策略,没有时间片的概念,一旦一个进程获得CPU,它将一直执行,直到它主动释放CPU,或者被更高优先级的实时进程抢占。而SCHED_RR则是带时间片的FIFO策略,每个进程都有一个固定长度的时间片,当时间片耗尽后,除非它是唯一可运行的实时进程,否则它必须让出CPU。
实时进程的优先级计算非常直接:每个实时进程都有一个静态优先级,这个优先级在进程的生命周期内通常是不变的。在SCHED_FIFO中,如果有多个实时进程可运行,调度器会优先运行优先级最高的进程。在SCHED_RR中,如果多个进程具有相同的最高优先级,调度器会采用轮转的方式,按顺序执行这些进程。
### 3.2.2 抢占式与协作式调度
实时调度器使用的是抢占式调度策略,即高优先级的实时进程可以随时抢占正在运行的低优先级实时进程。这种抢占策略保证了高优先级任务能够获得及时的CPU资源,满足其对响应时间的严格要求。
与此相对的是协作式调度,这主要用在非实时调度策略中,例如CFS。在这种模式下,进程需要在适当的时候主动放弃CPU,例如在执行阻塞操作或等待I/O操作完成时。协作式调度依赖于进程的良好行为,这在实时应用中是不可取的,因为非实时进程的不可预测行为可能会导致实时任务得不到及时处理。
## 3.3 CPU亲和性与调度决策
### 3.3.1 CPU亲和性的概念及其作用
CPU亲和性(CPU affinity)是指进程或线程对CPU的偏好设置,它决定了进程在哪些CPU核心上运行。合理配置CPU亲和性可以有效减少进程在不同CPU核心间的迁移,从而降低上下文切换的开销,并且能够更好地利用CPU缓存,提高程序的执行效率。
在Linux中,可以使用`taskset`命令或相应的库函数来设置进程的CPU亲和性。例如,一个运行在多核CPU上的web服务器进程,可以通过设置CPU亲和性,将其绑定到特定的核心上运行,从而避免频繁地被调度到其他核心上,减少因缓存未命中导致的性能损失。
### 3.3.2 调度器如何处理CPU亲和性
在CFS调度器中,处理CPU亲和性的主要数据结构是位图,称为cpusets。调度器使用cpusets来标识进程的亲和性掩码,即进程可以在哪些CPU上运行。当调度器选择下一个要运行的进程时,它会考虑该进程的cpusets,优先选择那些能够运行在当前CPU的进程,从而尽量避免不必要的进程迁移。
实时调度器则提供了一种方法来强制设置进程的CPU亲和性。例如,在SCHED_FIFO调度策略下,一旦进程设置了CPU亲和性,它将一直占用这个CPU核心,直到它自己释放或被更高优先级的实时进程抢占。这种方式适合于对实时性要求极高的应用,但是可能会导致CPU资源的不均衡使用。
## 3.4 Linux调度器的未来发展趋势
Linux进程调度器一直是活跃的研究领域,随着硬件和软件环境的变化,调度器也需要不断适应新的需求。例如,随着多核处理器和虚拟化技术的发展,调度器需要更好地处理并发性和性能隔离的问题。在云计算和容器化技术普及的背景下,调度器还需要支持资源配额管理和多租户环境下的隔离机制。
### 3.4.1 多核处理器的挑战与机遇
多核处理器的普及给Linux调度器带来了挑战,同时也提供了优化性能的新机遇。挑战主要在于如何更高效地管理多个核心间的负载均衡,避免产生核心之间的资源竞争和过载现象。机遇则体现在调度器可以利用更多的CPU资源,提升并发处理能力,通过更细致的调度策略来提高整体性能。
### 3.4.2 特定硬件加速器的调度策略
随着专用硬件加速器的广泛使用(如GPU、TPU等),Linux调度器也需要适应这一趋势。调度器不仅要管理CPU资源,还需要考虑如何更高效地利用这些专用加速器。调度器可能需要支持异构计算环境中的任务调度,确保能够将适合在特定硬件上执行的任务有效分配到相应的加速器上。
## 3.5 小结
Linux进程调度器作为操作系统的核心组件,其设计理念和实现机制直接影响到系统的性能和稳定性。通过深入理解CFS调度器的工作原理、实时调度器的优先级计算和抢占机制,以及CPU亲和性对调度决策的影响,系统开发者和管理员可以更好地优化和调整系统性能,以满足不同应用场景的需求。随着硬件的发展和新型计算模型的出现,Linux调度器也必将持续进化,以支持更多的使用场景和性能要求。
# 4. Linux进程调度性能分析实战
在本章中,我们将深入探讨Linux进程调度器的性能分析实战。性能分析是IT系统优化和故障诊断的重要环节。通过性能分析,我们不仅可以识别系统瓶颈,还能了解调度器的决策过程以及如何根据实际应用场景优化调度策略。
## 4.1 性能分析工具介绍
### 4.1.1 常用的性能分析工具概述
Linux系统下有多种性能分析工具,它们各自有不同的特点和用途。其中,`perf`是一个广泛使用的性能分析工具,它能够提供丰富的性能监控和分析功能。`sysstat`包中的`iostat`和`mpstat`能够分别提供CPU和磁盘I/O的统计信息。`htop`和`atop`提供了更为直观的实时系统监控界面,方便用户即时查看进程状态和资源使用情况。
### 4.1.2 使用perf分析调度性能
`perf`工具的核心功能是采样分析,即通过采样机制定期收集系统运行时的性能数据。`perf`能够对进程、函数、指令等多种性能指标进行采样分析,非常适合用来分析Linux调度器的行为。
下面是使用`perf`分析CPU调度性能的一个简单例子:
```bash
perf record -a -g -- sleep 60
```
这条命令将记录整个系统的性能数据,`-a`选项表示监控所有CPU,`-g`选项表示生成调用图,`--`之后跟上要监控的命令。执行上述命令后,系统将会在后台进行采样,60秒后通过`perf report`命令生成性能报告。
```bash
perf report
```
在执行完毕后,你可以通过`perf report`查看采样结果,它将展示各个函数调用的占比,此时可以特别关注调度相关函数,如`do_sched_yield`等。
## 4.2 调度器性能测试与优化
### 4.2.1 测试环境的搭建
在进行性能测试之前,需要准备一个稳定的测试环境。这通常包括一个或多个性能稳定的测试服务器,以及一套能够准确模拟生产环境中负载的测试脚本。在测试环境中,我们可以使用特定的负载生成工具,如`stress`,来模拟不同的工作负载。
```bash
stress --cpu 4 --io 2 --vm 2 --vm-bytes 128M --timeout 600s
```
上面的命令将会模拟4个CPU负载、2个IO负载、2个虚拟内存负载,每个虚拟内存负载分配128MB内存,测试持续时间为10分钟。
### 4.2.2 性能优化的方法与策略
性能优化是一个循环迭代的过程,通常包括以下步骤:
1. 识别瓶颈:使用性能分析工具识别系统瓶颈所在,如CPU饱和、I/O等待、内存不足等。
2. 实施优化:根据识别出的瓶颈进行针对性优化,比如调整CPU亲和性、优化内存使用、提高I/O效率等。
3. 验证优化效果:再次使用性能分析工具验证优化后的性能指标,确保问题得到解决。
在调整调度策略时,可以根据`perf`报告的结果,调整相应进程的nice值或使用cgroups来限制某些进程的CPU时间片,达到优化调度的目的。
## 4.3 调度策略的实际案例分析
### 4.3.1 实时应用的调度优化
实时应用,如音频处理、视频监控等,对响应时间要求极严。在Linux系统中,实时进程可以通过设置进程的优先级来获得更快的调度响应。下面是修改进程优先级的一个例子:
```bash
renice -n -20 -p 12345
```
`renice`命令用于修改进程的优先级,`-n`选项后跟上优先级的数值,`-p`选项后跟上进程ID。这个例子中,我们将PID为12345的进程优先级提高到最高级别-20。
在实际应用中,如果系统中存在大量实时进程,可能需要使用cgroups来对实时进程进行分组管理,以便更好地控制资源分配和保证实时性。
### 4.3.2 大规模系统中的调度挑战
在大规模系统中,进程调度面临更多的挑战。集群环境下,需要考虑负载均衡和资源隔离,以保障各节点的性能和稳定性。Kubernetes等容器编排工具通过调度器来分配容器到不同的节点上运行,同时考虑硬件资源的使用和调度策略的优化。
下表是一个简单的大规模系统中调度策略的选择:
| 系统类型 | 需求 | 推荐策略 |
|-----------|------|-----------|
| 实时系统 | 响应时间 < 10ms | 使用SCHED_FIFO策略 |
| 数据中心 | 高吞吐量,可接受小幅度延迟 | 使用CFS策略,调整权重 |
| 云计算平台 | 资源动态伸缩,成本优化 | 结合CFS和实时策略,使用自动伸缩 |
对于大规模系统的调度挑战,需要深入研究和测试不同的调度策略,并结合具体的应用场景和硬件资源状况来制定综合的调度策略。通过持续的性能监控和分析,不断优化调度策略,以满足系统的高性能和稳定性需求。
# 5. Linux进程调度的未来方向
## 5.1 容器化对进程调度的影响
### 5.1.1 容器环境下的资源隔离与调度
随着云计算和容器技术的快速发展,Linux进程调度器需要适应容器化环境下的特殊需求。容器化技术通过轻量级的虚拟化,实现了应用的快速部署、高效隔离和便捷管理。容器通常共享同一宿主机的操作系统内核,但需保证在隔离的环境中运行,这就要求调度器必须能够细致地控制资源分配。
容器化环境下的调度器不仅仅需要考虑进程或线程的优先级和运行时间,还需要考虑容器资源的限制,比如CPU和内存。调度器的决策将影响容器内进程的性能,因此调度策略需要在确保隔离的同时,优化资源利用和负载均衡。
例如,调度器需要能够处理不同容器的CPU亲和性设置,确保容器内部的进程能够尽可能地在指定的CPU核心上运行。同时,调度器应能够对容器进行动态的资源分配,根据实时负载和资源使用情况调整资源分配,确保系统整体性能最优化。
### 5.1.2 Kubernetes调度器的介绍
Kubernetes作为目前最流行的容器编排平台,其内建的调度器对容器化的进程调度产生了巨大影响。Kubernetes调度器负责将容器化的应用部署到集群中最佳的节点上。它综合考虑了诸如资源请求、约束条件、负载平衡、数据本地性和亲和性等因素。
Kubernetes调度器将每个容器抽象为一个Pod,每个Pod可以包含一个或多个容器。在调度时,调度器会评估所有节点的资源容量,然后将Pod调度到满足其资源需求的节点上。此外,它还考虑了节点上的亲和性规则,以及Pod的反亲和性规则,这些规则可以用来定义Pod之间的关系和节点间的选择偏好。
Kubernetes调度器支持不同级别的调度策略。例如,它可以使用预设的污点(Taints)和容忍度(Tolerations)来控制Pod是否可以在某些节点上运行。这允许用户定义复杂的调度规则,如将一组Pod仅调度到特定的节点上,或确保具有特定标签的节点不运行某些Pod。
## 5.2 新硬件与调度器的结合
### 5.2.1 多核处理器的挑战与机遇
现代计算机系统普遍采用多核处理器,这为Linux进程调度带来了新的挑战和机遇。多核处理器的出现显著提升了并发处理能力,但同时也要求调度器能够有效地在多个核心间分配任务,以实现真正的并行处理。
调度器需要解决的核心问题是如何有效利用所有可用的CPU核心,避免某些核心过载而其他核心闲置的情况。调度器必须不断监控和评估系统的负载状态,以及时调整任务的分配。在多核环境中,为了减少缓存失效和内存延迟,调度策略可能更偏向于将紧密相关或频繁交互的线程分配到同一核心或邻近核心。
调度器的性能在多核处理器上尤为重要。Linux内核引入了诸如工作窃取(work-stealing)的调度策略,允许空闲核心“窃取”任务从忙碌核心的队列中,从而更好地平衡核心间的负载。
### 5.2.2 特定硬件加速器的调度策略
除了多核处理器,新的硬件加速器如GPU、FPGA等也被广泛用于特定类型的计算密集型任务中。这些加速器拥有不同的调度需求和机制。调度器需要与这些硬件深度集成,以实现高效的资源利用和性能优化。
例如,在使用GPU进行深度学习训练时,调度器需要识别这些任务的特殊性,并将其合理分配到GPU资源上。调度器应能够处理这些加速器的异构性,同时还需要考虑CPU与加速器之间的数据传输效率和处理协同性。
Linux内核正逐步引入对这些硬件加速器的支持。例如,通过Direct Rendering Manager (DRM) 和 Compute Unified Device Architecture (CUDA) API,调度器能够更好地管理和分配GPU资源。这为用户提供了更灵活的硬件使用方式,并能够根据应用的需求和性能特性进行动态优化。
## 5.3 云平台下的调度优化
### 5.3.1 云原生应用的调度需求
云原生应用是指专为云计算环境设计的应用程序,它们具有高度的可伸缩性、弹性和微服务架构。这些应用对于调度器有着特别的要求,以确保在云环境中能够高效、可靠地运行。
云原生应用的调度需求包括但不限于:快速启动和停止实例的能力、对动态变化负载的快速响应、以及跨多个数据中心或云服务提供商的负载均衡。为了实现这些需求,调度器需要具备细粒度的资源控制能力,并能够实现智能的资源优化。
例如,调度器需要能够根据当前的资源需求自动伸缩应用实例的数量,确保应用在访问量增加时能够无缝扩展,并在需求下降时释放资源以节省成本。此外,调度器还需要考虑应用的服务质量(QoS)要求,以优化用户体验和提高资源利用率。
### 5.3.2 自动伸缩与调度策略的集成
在云平台中,自动伸缩是保障资源高效使用和应用性能的关键技术。自动伸缩通常与负载均衡、资源调度紧密集成,它可以基于实时的性能指标和预设的策略动态调整资源分配。
现代云平台的调度器通常集成了自动伸缩功能,根据预设的伸缩策略和阈值,自动增加或减少计算资源。例如,如果云原生应用的响应时间超过设定的目标范围,则调度器可能会触发自动伸缩机制,启动更多的实例来分担负载。反之,如果负载降低,则自动缩减实例数以减少资源消耗。
这种集成实现了资源分配的自动化和弹性化,使得应用能够更加适应不断变化的工作负载。为了达到这一目标,调度器需要紧密监控各种性能指标,如CPU使用率、内存使用率、网络流量等,并根据这些指标实时调整资源分配。
通过使用容器化技术,如Docker和Kubernetes,以及云平台的自动伸缩服务,开发者和运维人员可以更加轻松地管理大规模的分布式系统。这些技术和服务不断推动Linux进程调度器向更高的灵活性、智能化和自动化发展。
为了更直观地理解不同调度策略和工具的使用,下面是一张表格,展示了几个流行调度策略的对比:
| 调度策略 | 特点 | 应用场景 |
|----------|------|----------|
| SCHED_OTHER | 公平调度策略,适用于普通进程 | 用户空间进程,非实时任务 |
| SCHED_FIFO | 先入先出的实时调度策略 | 实时性能要求高的进程 |
| SCHED_RR | 循环调度策略,类似于FIFO | 实时进程,需保证公平性 |
| CFS | 完全公平调度器,动态优先级 | 所有类型的进程,优化多核处理器利用率 |
在选择合适的调度策略时,系统管理员需要根据具体的应用负载特性和性能要求来决定,不同的场景下调度策略的效率和适用性会有所差异。
0
0