linux内核进程调度

linux内核杂记(12)-进程调度(7) 与调度相关的系统调用 nice() 设置进程的nice值 sched_setscheduler()设置进程的调度策略 sched_getscheduler()获得进程的调度策略 sched_setparam() 设置进程的实时优先级 sched_getparam() 获得进程的实时优先级 阅读详情

1. 什么是调度

现在的操作系统都是多任务的,为了能让更多的任务能同时在系统上更好的运行,需要一个管理程序来管理计算机上同时运行的各个任务(也就是进程)。个管理程序就是调度程序,它的功能说起来很简单:

1.决定哪些进程运行,哪些进程等待;

2.决定每个进程运行多长时间。

此外,为了获得更好的用户体验,运行中的进程还可以立即被其他更紧急的进程打断。
总之,调度是一个平衡的过程。一方面,它要保证各个运行的进程能够最大限度的使用CPU(即尽量少的切换进程,进程切换过多,CPU的时间会浪费在切换上);另一方面,保证各个进程能公平的使用CPU(即防止一个进程长时间独占CPU的情况)。

2. 调度实现原理

前面说过,调度功能就是决定哪个进程运行以及进程运行多长时间。决定哪个进程运行以及运行多长时间都和进程的优先级有关。为了确定一个进程到底能持续运行多长时间,调度中还引入了时间片的概念。

2.1 关于进程的优先级

进程的优先级有2种度量方法,一种是nice值,一种是实时优先级。nice值的范围是-20~+19,值越大优先级越低,也就是说nice值为-20的进程优先级最大。实时优先级的范围是0~99,与nice值的定义相反,实时优先级是值越大优先级越高。实时进程都是一些对响应时间要求比较高的进程,因此系统中有实时优先级高的进程处于运行队列的话,它们会抢占一般的进程的运行时间。

进程的2种优先级会让人不好理解,到底哪个优先级更优先?一个进程同时有2种优先级怎么办?

其实linux的内核早就有了解决办法。对于第一个问题,到底哪个优先级更优先?

答案是实时优先级高于nice值,在内核中,实时优先级的范围是 0~MAX_RT_PRIO-1

MAX_RT_PRIO的定义参见 include/linux/sched.h

1611 #define MAX_USER_RT_PRIO        100
1612 #define MAX_RT_PRIO             MAX_USER_RT_PRIO

nice值在内核中的范围是 MAX_RT_PRIO~MAX_RT_PRIO+40 即 MAX_RT_PRIO~MAX_PRIO

1614 #define MAX_PRIO                (MAX_RT_PRIO + 40)

第二个问题,一个进程同时有2种优先级怎么办?

答案很简单,就是一个进程不可能有2个优先级。一个进程有了实时优先级就没有Nice值,有了Nice值就没有实时优先级。

我们可以通过以下命令查看进程的实时优先级和Nice值:(其中RTPRIO是实时优先级,NI是Nice值)

$ ps -eo state,uid,pid,ppid,rtprio,ni,time,comm
S   UID   PID  PPID RTPRIO  NI     TIME COMMAND
S     0     1     0      -   0 00:00:00 systemd
S     0     2     0      -   0 00:00:00 kthreadd
S     0     3     2      -   0 00:00:00 ksoftirqd/0
S     0     6     2     99   - 00:00:00 migration/0
S     0     7     2     99   - 00:00:00 watchdog/0
S     0     8     2     99   - 00:00:00 migration/1
S     0    10     2      -   0 00:00:00 ksoftirqd/1
S     0    12     2     99   - 00:00:00 watchdog/1
S     0    13     2     99   - 00:00:00 migration/2
S     0    15     2      -   0 00:00:00 ksoftirqd/2
S     0    16     2     99   - 00:00:00 watchdog/2
S     0    17     2     99   - 00:00:00 migration/3
S     0    19     2      -   0 00:00:00 ksoftirqd/3

S     0    20     2     99   - 00:00:00 watchdog/3
S     0    21     2      - -20 00:00:00 cpuset
S     0    22     2      - -20 00:00:00 khelper

2.2 关于时间片

有了优先级,可以决定谁先运行了。但是对于调度程序来说,并不是运行一次就结束了,还必须知道间隔多久进行下次调度。于是就有了时间片的概念。时间片是一个数值,表示一个进程被抢占前能持续运行的时间。也可以认为是进程在下次调度发生前运行的时间(除非进程主动放弃CPU,或者有实时进程来抢占CPU)。时间片的大小设置并不简单,设大了,系统响应变慢(调度周期长);设小了,进程频繁切换带来的处理器消耗。默认的时间片一般是10ms。

2.3 调度实现原理(基于优先级和时间片)
下面举个直观的例子来说明:
假设系统中只有3个进程ProcessA(NI=+10),ProcessB(NI=0),ProcessC(NI=-10),NI表示进程的nice值,时间片=10ms
1) 调度前,把进程优先级按一定的权重映射成时间片(这里假设优先级高一级相当于多5msCPU时间)。
  假设ProcessA分配了一个时间片10ms,那么ProcessB的优先级比ProcessA高10(nice值越小优先级越高),ProcessB应该分配10*5+10=60ms,以此类推,ProcessC分配20*5+10=110ms

2) 开始调度时,优先调度分配CPU时间多的进程。由于ProcessA(10ms),ProcessB(60ms),ProcessC(110ms)。显然先调度ProcessC

3) 10ms(一个时间片)后,再次调度时,ProcessA(10ms),ProcessB(60ms),ProcessC(100ms)。ProcessC刚运行了10ms,所以变成100ms。此时仍然先调度ProcessC

4) 再调度4次后(4个时间片),ProcessA(10ms),ProcessB(60ms),ProcessC(60ms)。此时ProcessB和ProcessC的CPU时间一样,这时得看ProcessB和ProcessC谁在CPU运行队列的前面,假设ProcessB在前面,则调度ProcessB

5) 10ms(一个时间片)后,ProcessA(10ms),ProcessB(50ms),ProcessC(60ms)。再次调度ProcessC

6) ProcessB和ProcessC交替运行,直至ProcessA(10ms),ProcessB(10ms),ProcessC(10ms)。

这时得看ProcessA,ProcessB,ProcessC谁在CPU运行队列的前面就先调度谁。这里假设调度ProcessA

7) 10ms(一个时间片)后,ProcessA(时间片用完后退出),ProcessB(10ms),ProcessC(10ms)。

8) 再过2个时间片,ProcessB和ProcessC也运行完退出。

这个例子很简单,主要是为了说明调度的原理,实际的调度算法虽然不会这么简单,但是基本的实现原理也是类似的:

1)确定每个进程能占用多少CPU时间(这里确定CPU时间的算法有很多,根据不同的需求会不一样)

2)占用CPU时间多的先运行

3)运行完后,扣除运行进程的CPU时间,再回到 1)

3. Linux上调度实现的方法

Linux上的调度算法是不断发展的,在2.6.23内核以后,采用了“完全公平调度算法”,简称CFS。

CFS算法在分配每个进程的CPU时间时,不是分配给它们一个绝对的CPU时间,而是根据进程的优先级分配给它们一个占用CPU时间的百分比。

比如ProcessA(NI=1),ProcessB(NI=3),ProcessC(NI=6),在CFS算法中,分别占用CPU的百分比为:ProcessA(10%),ProcessB(30%),ProcessC(60%)

因为总共是100%,ProcessB的优先级是ProcessA的3倍,ProcessC的优先级是ProcessA的6倍。

 Linux上的CFS算法主要有以下步骤:(还是以ProcessA(10%),ProcessB(30%),ProcessC(60%)为例)

1)计算每个进程的vruntime(注1),通过update_curr()函数更新进程的vruntime。

2)选择具有最小vruntime的进程投入运行。(注2)

3)进程运行完后,更新进程的vruntime,转入步骤2) (注3)

注1. 这里的vruntime是进程虚拟运行的时间的总和。vruntime定义在:kernel/sched_fair.c 文件的 struct sched_entity 中。
注2. 这里有点不好理解,根据vruntime来选择要运行的进程,似乎和每个进程所占的CPU时间百分比没有关系了。

1)比如先运行ProcessC,(vr是vruntime的缩写),则10ms后:ProcessA(vr=0),ProcessB(vr=0),ProcessC(vr=10)

2)那么下次调度只能运行ProcessA或者ProcessB。(因为会选择具有最小vruntime的进程)

长时间来看的话,ProcessA、ProcessB、ProcessC是公平的交替运行的,和优先级没有关系。

而实际上vruntime并不是实际的运行时间,它是实际运行时间进行加权运算后的结果。

比如上面3个进程中ProcessA(10%)只分配了CPU总的处理时间的10%,那么ProcessA运行10ms的话,它的vruntime会增加100ms。

以此类推,ProcessB运行10ms的话,它的vruntime会增加(100/3)ms,ProcessC运行10ms的话,它的vruntime会增加(100/6)ms。

实际的运行时,由于ProcessC的vruntime增加的最慢,所以它会获得最多的CPU处理时间。

上面的加权算法是我自己为了理解方便简化的,Linux对vruntime的加权方法还得去看源码。

注3.Linux为了能快速的找到具有最小vruntime,将所有的进程的存储在一个红黑树中。这样树的最左边的叶子节点就是具有最小vruntime的进程,新的进程加入或有旧的进程退出时都会更新这棵树。


 其实Linux上的调度器是以模块方式提供的,每个调度器有不同的优先级,所以可以同时存在多种调度算法。

每个进程可以选择自己的调度器,Linux调度时,首先按调度器的优先级选择一个调度器,再选择这个调度器下的进程。

4. 调度相关的系统调用

调度相关的系统调用主要有2类:

1) 与调度策略和进程优先级相关 (就是上面的提到的各种参数,优先级,时间片等等) - 下表中的前8个

2) 与处理器相关 - 下表中的最后3个

系统调用

描述

nice()

设置进程的nice值

sched_setscheduler()

设置进程的调度策略,即设置进程采取何种调度算法

sched_getscheduler()

获取进程的调度算法

sched_setparam()

设置进程的实时优先级

sched_getparam()

获取进程的实时优先级

sched_get_priority_max()

获取实时优先级的最大值,由于用户权限的问题,非root用户并不能设置实时优先级为99

sched_get_priority_min()

获取实时优先级的最小值,理由与上面类似

sched_rr_get_interval()

获取进程的时间片

sched_setaffinity()

设置进程的处理亲和力,其实就是保存在task_struct中的cpu_allowed这个掩码标志。该掩码的每一位对应一个系统中可用的处理器,默认所有位都被设置,即该进程可以再系统中所有处理器上执行。

用户可以通过此函数设置不同的掩码,使得进程只能在系统中某一个或某几个处理器上运行。

sched_getaffinity()

获取进程的处理亲和力

sched_yield()

暂时让出处理器


linux内核--进程调度(一) 引言:无论是在批处理系统还是分时系统中,用户进程数一般都多于处理机数、这将导致它们互相争夺处理机。另外,系统进程也同样需要使用处理机。这就要求进程调度程序按一定的策略,动态地把处理机分配给处于就绪队列中的某一个进程,以使之执行。   进程调度的具体功能可总结为如下几点:     作为进程调度的准备,进程管理模块必须将系统中各进程的执行情况和状态特征记录在各进程的PCB表中。并且,根据各 阅读详情

相关推荐

linux内核学习9:Linux的进程调度

一、什么是进程调度 出现背景: 无论是在批处理系统还是分时系统中,用户进程数一般都多于处理机数、这将导致它们互相争夺处理机。另外,系统进程也同样需要使用处理机。这就要求进程调度程序按一定的策略,动态地把处理机分配给处于就绪队列中的某一个进程,以使之执行。 进程调度,是确保进程能有效工作的一个内核子系统。 调度程序负责决定将哪些进程投入到运行,何时进行以及运行多长时间。 进程调度程序(通常简称为调度程序)可看成是可运行态进程之间分配有限的处理器时间资源的内核子系统。 进程调度是对TASK_RUNNING状

weixin_40535588的博客 5709

《Linux内核设计与实现》读书笔记(四)- 进程的调度

主要内容: 什么是调度 调度实现原理 Linux上调度实现的方法 调度相关的系统调用 1. 什么是调度 现在的操作系统都是多任务的,为了能让更多的任务能同时在系统上更好的运行,需要一个管理程序来管理计算机上同时运行的各个任务(也就是进程)。 这个管理程序就是调度程序,它的功能说起来很简单: 决定哪些进程运行,哪些进程等待 决定每个进程运行多长时间 此外,为了获得...

weixin_33816946的博客 307

ETL第八章无人售货机零售项目实践

ETL实战项目——无人售货机

m0_52058217的博客 4418

【STM32F407】第7章 RTX5任务管理

论坛原始地址(持续更新):【安富莱】RTX5内核教程,采用CMSIS-RTOS V2封装层,已经更新发布至第9章 (2021-12-27) - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz! 第7章 RTX5任务管理 对于初学者,特别是对于没有RTOS基础的同学来说,了解RTX5的任务管理非常重要,了解任务管理的目的就是让初学者从裸机的,单任务编程过渡到带OS的,多任务编程上来。搞清楚了这点,那么RTX5学习就算入门了。 目录 7.1 初学者重要提示 7.2...

Simon223的博客 1910

408计算机复试专业课问答汇总

408计算机复试专业课问答汇总

weixin_45930223的博客 3698

从‘眼花缭乱’到‘心中有数’:rs-fMRI统计分析全流程避坑指南(附DPABI操作截图)

本文详细解析了rs-fMRI统计分析的全流程,从质量控制到统计模型选择,再到多重比较校正和结果解读。特别针对DPABI软件操作中的常见陷阱提供实用指南,帮助研究者避免FDR和GRF校正等关键环节的错误,实现从数据混乱到清晰分析的转变。

weixin_33686714的博客 398

嵌入式开发:周期调度和代码执行时间理解

已剪辑自: https://mp.weixin.qq.com/s/gaT7D1IgkBxxEOj-DNaLPw汽车嵌入开发中,我们常常听到这样的名词:1ms Task、5ms Task、10ms Task…试问:"1ms Task是说这个任务要执行1ms吗?"本文,带着这个疑问,展开讨论。程序员按照需求,负责写代码,这些代码最终被CPU执行,进而控制执行器,以此达到预期功能。如果想要达到预期功能,对应的功能代码就要被CPU执行,多长时间执行一次呢?:这取决于具体的功能。

qq_41854911的博客 1615

手把手教你用smarteye搭建免费GB28181监控平台(含海康设备接入避坑指南)

本文提供了一份基于SmartEye搭建免费GB28181视频监控平台的实战指南。详细介绍了从服务器部署、GB28181协议核心配置,到海康威视等主流设备接入的完整流程,并重点分享了设备注册失败、无法预览等常见问题的深度排错方法,旨在帮助中小企业及开发者低成本实现多品牌监控设备的统一管理。

pz89012345的博客 326

MBD软件开发之调度方式

无论是采用<A:应用层模型+底层手工代码集成>的方式,还是<B:底层Simulink化封装的完全模型化开发>的方式,应用层的算法反正都要以某种形式的接口,塞到上述某个任务里。周期性任务是最常见的,基本上,按照触发源层级分,硬件中断触发的周期最精确,说10ms就是准的10ms;但是,不加调度有可能会导致低效的模型,比如说,回到Simulink本身,如果不加任何调度,生成的嵌入式代码后,实质上就是个单/多周期的周期性任务(代码中会生成一个每个步长调用的函数 rtOneStep,其中执行整个模型代码)。

weixin_43015338的博客 1049

【头歌】链栈的基本操作及应用

另外,在算法的开始和结束时,栈都应该是空的,所以匹配到最后还要判断栈是否为空,若空,则说明匹配成功,返回1。其中表达式只包含三种括号,花括号{}、中括号[]、圆括号(),即它仅由 (、)、[、]、{、}六个字符组成。预期输出: 栈中元素依次为:12 47 5 8 6 92 45 63 75 38 4 29 弹出的栈顶元素 e=29 栈空否:0(1:空 0:否) 栈顶元素 e=4 栈的长度为11 清空栈后,栈空否:1(1:空 0:否)// 若栈不空,则用e返回S的栈顶元素,并返回OK;

qq_39977056的博客 4383

Python爬虫实战:携程旅游攻略爬取全流程解析(动态接口+反爬破解+异步爬取)

本文介绍了携程旅游攻略的爬取全流程,涵盖静态和动态页面抓取、异步请求、高级反爬策略以及数据存储和简单分析。增加用户评论和评分抓取结合NLP分析攻略文本情感与关键词建立旅游推荐系统自动化代理IP池和验证码识别模块。

2201_76125261的博客 2039

【Linux系统内核探索】进程调度

进程调度是操作系统内核的核心功能之一,负责在多个进程之间分配CPU时间,使得系统能够同时运行多个进程。因为计算机的CPU资源有限,操作系统需要决定在任何时刻哪个进程能够使用CPU执行任务,这个过程就是进程调度。Linux进程调度经历了多个阶段的优化,目前主流的Linux内核使用的是完全公平调度器。CFS调度器的核心思想是通过精确计算每个进程的“虚拟运行时间”来决定调度的公平性。CFS调度器不会简单依赖于时间片,而是通过调度树来快速查找下一个应运行的进程。

2301_79969994的博客 2350

出现 Connection Failed [MySQL][ODBC Driver]Access denied for user ‘root‘@x(using password:YES)解决方法

Connection Failed [MySQL][ODBC 8.0(w) Driver]Access denied for user 'root'@xxxx (using password:YES)

码农研究僧的博客 1060

Linux 内核进程调度

CPU消耗型进程需要高的吞吐率,IO消耗型进程需要强的响应性,这两点都是调度器需要考虑的。为了更快响应IO消耗型进程,内核提供了一个抢占(preempt)机制,使优先级更高的进程,去抢占优先级低的进程运行。

LiuYong_01的博客 1517

彻底讲透 SAP 中的 client-safe:从 CDS、AMDP 到 ABAP Cloud 的客户端隔离设计

SAP系统中的client-safe概念定义了技术边界:访问client-dependent数据的对象必须确保只看到单个client数据,而访问client-independent数据的对象则天然满足条件。这一原则直接影响CDS视图、AMDP等核心组件,并与ABAP Cloud开发模型紧密集成。在业务系统中,client isolation要求用户只能看到当前登录client的数据。SAP通过语言版本、对象规则和静态检查强制执行这一约束,特别是在ABAP Cloud开发中,AMDP方法和发布的API必须满足

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 3264

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Linux内核中的进程调度-进程调度基础

在深入探讨Linux内核的精妙世界中,进程调度无疑是最具挑战性也最为关键的一个环节。它作为操作系统核心功能的一部分,犹如交响乐团中的指挥家,精准而高效地协调着系统中各个进程的执行顺序和时间分配,确保整个系统的性能表现与资源利用达到最佳平衡。Linux内核的进程调度器不仅负责决定哪个进程将在CPU上运行,何时运行,还涉及到优先级管理、实时性保证、多处理器调度策略等诸多复杂问题。

qq_45652092的博客 1755

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Linux的进程调度及内核实现

Linux进程调度机制分析:本文详细解析了Linux内核的进程调度实现,包括关键数据结构(task_struct、sched_class)、调度策略(CFS公平调度、RT实时调度)及触发机制。CFS采用红黑树管理进程,通过vruntime实现公平分配;RT调度器则通过优先级队列处理实时任务。调度过程分为主动/被动触发,最终通过schedule()完成上下文切换。文章还涉及进程状态转换、优先级规则及调度器核心算法的实现细节。

asbcddasds的博客 797

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

【linux kernel】linux内核的进程调度—调度策略

linux内核的进程调度—调度策略 (注:下文代码片段均出自linux内核版本4.1.15) 文章目录linux内核的进程调度—调度策略一、调度策略(1-1)stop调度策略(1-2)deadline调度策略(1-3)realtime调度策略(1-4)CFS调度策略(1-5)idle调度策略二、调度时刻三、执行调度 在linux内核中,默认实现了5种调度策略: (1)stop调度策略 (2)deadline调度策略 (3)realtime调度策略 (4)CFS调度策略 (5)idle调度策略 以上5种调度策

iriczhao的博客 4676

Linux-Linux内核-进程调度

/////Linux调度器是以模块的方式提供的,这允许不同类型的进程可以针对型的选择调度算法。调度器类提供不同的调度算法,像CFS就是一个针对普通进程的调度器类(定义在kernel/sched_fair.c中),在Linux中称之为SCHED_NORMAL(在POSIX中称为SCHED_OTHER)。每个调度器都有一个优先级,内核会选择优先级最高的调度器,然后由该调度器调度进程并执行。...

李木子的博客 2618

进程调度的艺术:从概念本质到 Linux 内核实现

在校大学生小胡想要去当兵,首先通知学校,得去跟辅导员宝报备,当兵一年回来继续学习,需要保留学籍,辅导员给了小胡一份档案,里面记录了小胡的信息,学校一份,给了小胡一份,当兵回来之后,需要恢复学籍,然后辅导员根据上次离开的学习信息,继续给小胡安排。优先级是进程得到CPU资源的先后顺序。学校--CPU 导员--调度器 小胡--进程 学籍--进程运行的临时数据,CPU寄存器里面的内容(当前进程上下文数据),它是系统启动后创建的第一个用户态进程,是所有其他进程的 “祖先”,在进程树中处于根节点位置。

2302_79376097的博客 2226

Linux 内核中的进程调度:从 CFS 到实时调度

Linux 内核中的进程调度是一个核心组件,它负责分配 CPU 时间给不同的进程和线程。进程调度通过调度器类、调度策略、优先级等机制,实现了 CPU 资源的合理分配。工作也要流程化,进程调度就像是系统中的任务管理工具,它确保了 CPU 资源的合理分配和系统的高效运行。在实际应用中,我们需要选择合适的调度策略,合理设置优先级,避免长时间占用 CPU,使用 nice 值,以及监控调度行为,以实现系统的最佳性能和可靠性。

jiang_style的博客 4510

Linux内核进程管理和调度

Linux内核进程管理和调度,进程,线程,进程调度,完全公平调度CFS,EEVDF调度器,sched-ext

chenxiaosongcsdn的博客 2556

Linux内核进程调度时机和过程

1、调度类型和时机 调度触发有两种类型,进程主动触发的主动调度和被动调度,被动调度又叫抢占式调度。 主动调度:进程主动触发以下情况,然后陷入内核态,最终调用schedule函数,进行调度。 1、当进程发生需要等待IO的系统调用,如read、write。 2、进程主动调用sleep时。 3、进程等待占用信用量或mutex时,注意spin锁不会触发调度,可能在空转。 被动调度:当发生以下情况时会发生被动调度: 1、tick_clock,cpu的时钟中断,一般是10ms一次,也有1ms一次的,取决于cpu的主频,

C/C++Linux、音视频、DPDK 3681

【Linux内核】进程调度

本篇博客将会介绍linux中的进程调度策略

m0_74215144的博客 862

【Linux系统】进程调度:内核 O(1) 的进程调度算法

本文详解讲解:Linux内核真实的进程调度算法、通过哈希结构+多队列(active/expired)的结构 解决进程优先级排序问题与进程饥饿问题

从不依靠,从不寻找,非常沉默,非常骄傲。 你必须非常努力,才能看起来毫不费力。 1255
上一篇: linux内存管理深入分析
下一篇: Linux 虚拟地址,逻辑地址,物理地址
LinuxWorking
博客等级 码龄10年 24粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值