首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

揭秘进程调度:让你的程序有序跑起来

近日见闻

Electron v28.2.0 发布,一款跨平台的桌面应用开发工具 --electron社区

Linus 发飙,批评谷歌内核贡献者的代码是垃圾,“你复制了一段不理解为何执行此操作的函数,这就是垃圾代码!”

过年前的时间过的很快,想起来一句话,幸福在于等幸福到来的那段日子。

摘抄:

为最坏的情况做好准备,

为最好的情况敞开心扉。

——斯鲁日特尔《莫斯科小猫》

小记

这两天和同事讨论起linux进程调度的问题,比如进程统计、那些进程优先运行、怎么调度等,对此在这里和大家一同复习一下。先来说说怎么查看进程。在使用Linux操作系统的过程中,掌握如何查看和管理进程是系统管理的重要技能之一。进程管理不仅有助于监控系统资源的使用情况,还能帮助排查问题和优化系统性能。

查看进程的常见命令

ps (Process Status)

ps命令是最基本同时也是最常用的进程查看命令,它能够列出系统中当前运行的所有进程信息。

基本用法

ps aux:显示所有进程信息

ps -ef:以全格式列出所有进程

ps -u [username]:列出指定用户的所有进程

如图所示

top

top命令提供了一个实时更新的进程状态动态视图。默认情况下,它以CPU使用率降序排列进程。

基本用法

执行top即可进入top界面,按q退出。

htop

htop是top命令的一个增强版本,提供了更友好的界面和更多的信息展示。

基本用法

安装htop(如果系统未预装):sudo apt-get install htop(Debian/Ubuntu)或者sudo yum install htop(CentOS/RedHat)

执行htop即可进入htop界面,按F10退出。

pstree

pstree命令展示的是进程之间的层级关系,以树状图的方式显示。

基本用法

pstree:展示系统中的所有进程及其关系

pstree [username]:展示指定用户的进程树

进程信息解读

无论是ps、top还是htop,它们都会显示以下几个重要的进程信息:

PID:进程ID

USER:运行该进程的用户

PR:进程优先级

NI:进程的“nice”值,即优先级数值

VIRT:虚拟内存使用量

RES:常驻内存量

SHR:共享内存量

S:进程状态(S睡眠,R运行,T停止,Z僵尸)

%CPU:占用的CPU百分比

%MEM:占用的内存百分比

TIME+:总的CPU时间

COMMAND:启动命令/命令行

掌握了如何查看进程,我们再来讨论一下进程是如何调度的。在Linux操作系统中,进程调度是操作系统最为核心的功能之一。它负责合理分配处理器资源,决定哪个进程何时运行,以及运行多长时间。本文将深入探讨Linux中的进程调度机制。

什么是进程调度?

进程调度是指操作系统按照一定的策略,动态地将处理器分配给等待运行的进程。调度的目的是为了优化系统性能,保证各类进程合理、公平地获取CPU使用权。

Linux进程调度的类型

Linux系统中的进程调度主要有两种类型:

完全公平调度器(Completely Fair Scheduler,CFS):从Linux内核版本2.6.23开始,CFS成为默认的进程调度器。CFS的设计目标是最大化利用CPU,并在进程间提供公平的CPU时间分配。

实时调度器(Real-Time Scheduler):用于实时任务,确保任务在规定时间内完成。包含两种策略:

FIFO(先进先出)

RR(轮转)

Linux进程调度策略

完全公平调度器(CFS)

CFS的核心思想是所有进程都应该获得相等的CPU时间。CFS将CPU资源分成时间片,用红黑树来管理所有可运行的进程,保证每个进程都能获得公平的时间片。

红黑树

红黑树是一种自平衡的二叉查找树,一种特殊的数据结构。在这棵树中,每个节点都有颜色属性,要么是红色,要么是黑色。因为它涉及多个操作的细节,比如插入、删除、旋转(左旋和右旋)、重新着色等,每个操作都必须维护红黑树的性质。感兴趣的可以自行查阅,这里贴一个简单的算法示例。这个实现并不完整,主要用于展示红黑树操作的基本概念。

class Node:

def __init__(self, data, color="red"):

self.data = data

self.color = color

self.parent = None

self.left = None

self.right = None

class RedBlackTree:

def __init__(self):

self.TNULL = Node(0, color="black")  # 创建一个空节点作为叶子节点

self.root = self.TNULL

def left_rotate(self, x):

# 左旋示意图:

#     x           y

#    / \         / \

#   a   y  =>   x   c

#      / \     / \

#     b   c   a   b

y = x.right

x.right = y.left

if y.left != self.TNULL:

y.left.parent = x

y.parent = x.parent

if x.parent == None:  # x是根节点

self.root = y

elif x == x.parent.left:  # x是其父节点的左子节点

x.parent.left = y

else:  # x是其父节点的右子节点

x.parent.right = y

y.left = x

x.parent = y

def right_rotate(self, y):

# 右旋示意图:

#      y           x

#     / \         / \

#    x   c  =>   a   y

#   / \             / \

#  a   b           b   c

x = y.left

y.left = x.right

if x.right != self.TNULL:

x.right.parent = y

x.parent = y.parent

if y.parent == None:  # y是根节点

self.root = x

elif y == y.parent.right:  # y是其父节点的右子节点

y.parent.right = x

else:  # y是其父节点的左子节点

y.parent.left = x

x.right = y

y.parent = x

def insert(self, key):

# 插入操作

node = Node(key)

node.parent = None

node.data = key

node.left = self.TNULL

node.right = self.TNULL

node.color = "red"  # 新节点必须是红色

y = None

x = self.root

while x != self.TNULL:

y = x

if node.data < x.data:

x = x.left

else:

x = x.right

node.parent = y

if y == None:

self.root = node

elif node.data < y.data:

y.left = node

else:

y.right = node

if node.parent == None:

node.color = "black"

return

if node.parent.parent == None:

return

self.fix_insert(node)  # 调用插入修复函数来维护红黑树的性质

def fix_insert(self, k):

# 插入节点后修复红黑树性质的函数

while k.parent.color == "red":

if k.parent == k.parent.parent.right:

u = k.parent.parent.left  # 叔叔节点

if u.color == "red":

u.color = "black"

k.parent.color = "black"

k.parent.parent.color = "red"

k = k.parent.parent

else:

if k == k.parent.left:

k = k.parent

self.right_rotate(k)

k.parent.color = "black"

k.parent.parent.color = "red"

self.left_rotate(k.parent.parent)

else:

# 与上面的代码一模一样,只不过是方向相反

u = k.parent.parent.right

if u.color == "red":

u.color = "black"

k.parent.color = "black"

k.parent.parent.color = "red"

k = k.parent.parent

else:

if k == k.parent.right:

k = k.parent

self.left_rotate(k)

k.parent.color = "black"

k.parent.parent.color = "red"

self.right_rotate(k.parent.parent)

if k == self.root:

break

self.root.color = "black"

def print_tree(self, node, indent, last):

# 用于打印红黑树的辅助函数

if node != self.TNULL:

print(indent, end=' ')

if last:

print("R----", end=' ')

indent += "     "

else:

print("L----", end=' ')

indent += "|    "

s_color = "RED" if node.color == "red" else "BLACK"

print(str(node.data) + "(" + s_color + ")")

self.print_tree(node.left, indent, False)

self.print_tree(node.right, indent, True)

特点

不基于固定时间片,而是动态分配

使用虚拟运行时间来进行比较,避免优先级倒置问题

当进程创建或唤醒时,它会被插入到红黑树中

当进程消耗时间片后,它会被重新插入到树中,保证调度的公平性

实时调度器

实时调度器为需要快速响应的实时任务提供服务,分为两种策略:

SCHED_FIFO(先进先出):没有时间片的概念,一旦获得CPU,除非自己放弃,或者有更高优先级的进程需要运行,否则会一直运行。

SCHED_RR(轮转):类似于SCHED_FIFO,但是每个进程运行一定的时间片后,如果还有其他同优先级的进程等待,则自动放弃CPU。

进程调度过程

当前运行进程的时间片用完或主动放弃CPU时,进程调度器被唤醒。

进程调度器选择下一个运行的进程。

如果有实时进程等待运行,根据实时调度策略选择进程。

如果没有实时进程,按照CFS策略从红黑树中选择下一个运行的进程。

结语

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OcUHNc9P60VwYm7mQlYmJggg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

相关快讯

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券