首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >揭秘进程调度:让你的程序有序跑起来

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

作者头像
希里安
发布2024-01-30 15:43:42
发布2024-01-30 15:43:42
6160
举报
文章被收录于专栏:希里安希里安

小记

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

查看进程的常见命令

ps (Process Status)

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

基本用法

  • ps aux:显示所有进程信息
  • ps -ef:以全格式列出所有进程
  • ps -u [username]:列出指定用户的所有进程

如图所示

top

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

基本用法

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

htop

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

基本用法

  • 安装htop(如果系统未预装):sudo apt-get install htop(Debian/Ubuntu)或者sudo yum install htop(CentOS/RedHat)
  • 执行htop即可进入htop界面,按F10退出。

pstree

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

基本用法

  • pstree:展示系统中的所有进程及其关系
  • pstree [username]:展示指定用户的进程树

进程信息解读

无论是pstop还是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系统中的进程调度主要有两种类型:

  1. 完全公平调度器(Completely Fair Scheduler,CFS):从Linux内核版本2.6.23开始,CFS成为默认的进程调度器。CFS的设计目标是最大化利用CPU,并在进程间提供公平的CPU时间分配。
  2. 实时调度器(Real-Time Scheduler):用于实时任务,确保任务在规定时间内完成。包含两种策略:
    • FIFO(先进先出)
    • RR(轮转)

Linux进程调度策略

完全公平调度器(CFS)

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

红黑树

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

代码语言:javascript
复制
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。

进程调度过程

  1. 当前运行进程的时间片用完或主动放弃CPU时,进程调度器被唤醒。
  2. 进程调度器选择下一个运行的进程。
  3. 如果有实时进程等待运行,根据实时调度策略选择进程。
  4. 如果没有实时进程,按照CFS策略从红黑树中选择下一个运行的进程。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-01-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 希里安 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 查看进程的常见命令
    • ps (Process Status)
    • top
    • htop
    • pstree
  • 进程信息解读
  • 什么是进程调度?
  • Linux进程调度的类型
  • Linux进程调度策略
    • 完全公平调度器(CFS)
    • 实时调度器
  • 进程调度过程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档