Future 与轮询:Async Rust 并发模型的底层机制与生产实践

《Rust 程序设计语言》第十七章:异步编程基础:Async、Await、Future 与 Stream 本文介绍了Rust异步编程的核心概念,包括Future、Stream、async/await语法及其应用场景。主要内容包括: 基础概念:异步编程通过Future和Stream实现并发,async/await语法简化异步代码编写。Future表示未来可能就绪的值,Stream是异步版的迭代器。 关键工具: async标记可暂停的代码块 await等待异步操作完成 运行时(runtime)管理异步任务执行 join/race等组合器处理多个Future 典型应用: 网络请求并发处理 消息通道实现任务间通信 流式 阅读详情

Future 与轮询:Async Rust 并发模型的底层机制与生产实践

cover

一、线程不是免费的:高并发场景下的调度成本

操作系统线程的创建成本约 8MB 栈空间加上内核态上下文切换的微秒级开销。当服务需要同时处理 10 万个连接时(如 WebSocket 推送、IoT 设备接入),线程池模型要么因为线程数不足导致连接排队,要么因为线程数过多导致 CPU 在上下文切换上空转。Go 的 goroutine 通过 M:N 调度将协程映射到少量系统线程,但每个 goroutine 仍需 2KB 起始栈和运行时调度器的介入。

Rust 的 async/await 选择了不同的路径:Future 是一个状态机,.await 点之间的代码在同一个栈帧上执行,无需独立的栈空间。一个 async 函数的 Future 大小取决于其跨 .await 持有的变量集合,通常在几十到几百字节之间。这意味着 10 万个并发 Future 仅占用数十 MB 内存,而非 GB 级别的线程栈。但这个模型并非没有代价——理解 Future 的轮询机制、Tokio 运行时的调度策略,以及 Pin 的必要性,是写出正确且高效异步代码的前提。

二、从轮询到唤醒:Future 状态机的编译期变换

2.1 Future trait 的本质

Future::poll 是整个异步模型的核心。每个 Future 不是被"等待",而是被反复"轮询":就绪时返回 Poll::Ready,未就绪时返回 Poll::Pending 并注册 Waker。Waker 是调度器与 Future 之间的桥梁——当 IO 就绪时,操作系统通过 epoll/kqueue 唤醒 Waker,Waker 通知调度器重新 poll 该 Future。

sequenceDiagram
    participant S as 调度器
    participant F as Future 状态机
    participant W as Waker
    participant OS as 操作系统(epoll)

    S->>F: poll(cx)
    alt IO 未就绪
        F->>W: 注册 Waker 到 cx
        F-->>S: Poll::Pending
        OS->>W: IO 就绪,唤醒
        W->>S: 将 Future 重新加入就绪队列
        S->>F: poll(cx) 再次轮询
    else IO 已就绪
        F-->>S: Poll::Ready(result)
    end

2.2 async/await 的编译期变换

编译器将 async 函数变换为一个实现了 Future 的状态机 enum。每个 .await 点对应一个状态,跨 .await 的局部变量成为 enum 的字段。关键约束:enum 的大小必须在编译期确定,因此所有跨 .await 的变量必须实现 Sized。此外,由于 enum 变体之间共享栈空间,自引用的 async 代码(一个变量引用另一个变量)会导致 Pin 约束——Future 被 poll 时不能被 Move,否则自引用会失效。

2.3 Tokio 运行时的调度策略

Tokio 使用工作窃取(Work Stealing)调度器。每个工作线程维护一个本地就绪队列,当本地队列为空时从其他线程窃取任务。这种设计减少了全局锁竞争,同时保证了任务调度的公平性。tokio::spawn 将 Future 发送到当前工作线程的本地队列,如果队列过长则溢出到全局队列供其他线程窃取。

三、生产级异步并发模式

3.1 并发限流与背压控制

use tokio::sync::Semaphore;
use std::sync::Arc;

/// 并发限流器:限制同时执行的异步任务数量
/// 通过 Semaphore 实现背压,防止下游服务被压垮
pub struct ConcurrencyLimiter {
    semaphore: Arc<Semaphore>,
    max_concurrency: usize,
}

impl ConcurrencyLimiter {
    pub fn new(max_concurrency: usize) -> Self {
        Self {
            semaphore: Arc::new(Semaphore::new(max_concurrency)),
            max_concurrency,
        }
    }

    /// 执行带限流的异步任务
    /// 当并发数达到上限时,新任务会等待信号量释放
    pub async fn run<F, T>(&self, future: F) -> T
    where
        F: std::future::Future<Output = T>,
    {
        // 获取许可——如果达到并发上限则异步等待
        let _permit = self.semaphore.acquire().await
            .expect("Semaphore 不应被关闭");

        // _permit 在作用域结束时自动释放许可
        future.await
    }

    /// 带超时的限流执行,防止信号量等待时间过长
    pub async fn run_with_timeout<F, T>(
        &self,
        future: F,
        timeout: std::time::Duration,
    ) -> Result<T, LimiterError>
    where
        F: std::future::Future<Output = T>,
    {
        let permit = tokio::time::timeout(timeout, self.semaphore.acquire())
            .await
            .map_err(|_| LimiterError::AcquireTimeout)?
            .map_err(|_| LimiterError::SemaphoreClosed)?;

        // 使用 RAII guard 确保即使 future panic 也能释放许可
        let result = tokio::time::timeout(timeout, future).await;

        drop(permit); // 显式释放,虽然 Drop 也会自动调用

        result.map_err(|_| LimiterError::ExecutionTimeout)
    }
}

#[derive(Debug)]
pub enum LimiterError {
    AcquireTimeout,
    ExecutionTimeout,
    SemaphoreClosed,
}

3.2 优雅关闭与任务取消

use tokio::sync::broadcast;
use tokio::task::JoinSet;

/// 优雅关闭管理器:确保所有异步任务在退出前完成清理
pub struct GracefulShutdown {
    cancel_tx: broadcast::Sender<()>,
    tasks: JoinSet<()>,
}

impl GracefulShutdown {
    pub fn new() -> Self {
        let (cancel_tx, _) = broadcast::channel(1);
        Self {
            cancel_tx,
            tasks: JoinSet::new(),
        }
    }

    /// 注册一个支持取消的异步任务
    pub fn spawn<F>(&mut self, future: F)
    where
        F: std::future::Future<Output = ()> + Send + 'static,
    {
        let mut cancel_rx = self.cancel_tx.subscribe();
        self.tasks.spawn(async move {
            tokio::select! {
                _ = future => {
                    // 任务正常完成
                }
                _ = cancel_rx.recv() => {
                    // 收到取消信号,执行清理
                }
            }
        });
    }

    /// 发送取消信号并等待所有任务完成清理
    pub async fn shutdown(&mut self) {
        // 广播取消信号
        let _ = self.cancel_tx.send(());

        // 等待所有任务完成,设置总超时防止挂起
        let deadline = tokio::time::sleep(std::time::Duration::from_secs(30));
        tokio::pin!(deadline);

        loop {
            tokio::select! {
                Some(_) = self.tasks.join_next() => {
                    // 一个任务完成
                }
                _ = &mut deadline => {
                    // 超时,强制中止剩余任务
                    self.tasks.abort_all();
                    break;
                }
                else => {
                    // 所有任务已完成
                    break;
                }
            }
        }
    }
}

3.3 异步流式处理管道

use tokio::sync::mpsc;
use futures::stream::{self, StreamExt};

/// 多阶段异步处理管道
/// 每个阶段独立并发,通过 channel 背压传递数据
pub async fn pipeline<I, O>(
    input: Vec<I>,
    stage1_concurrency: usize,
    stage2_concurrency: usize,
) -> Vec<O>
where
    I: Send + 'static,
    O: Send + 'static,
{
    let (tx1, rx1) = mpsc::channel(stage1_concurrency * 2);
    let (tx2, mut rx2) = mpsc::channel(stage2_concurrency * 2);

    // 阶段一:并发处理输入
    let producer = tokio::spawn(async move {
        for item in input {
            if tx1.send(item).await.is_err() {
                break; // 下游已关闭
            }
        }
    });

    // 阶段二:并发转换
    let stage1 = tokio::spawn(async move {
        let mut stream = tokio_stream::wrappers::ReceiverStream::new(rx1);
        let results = stream::iter(std::iter::from_fn(|| {
            // 从 receiver 取数据并处理
            None // 实际实现中替换为具体处理逻辑
        }));
    });

    // 收集最终结果
    let mut output = Vec::new();
    while let Some(item) = rx2.recv().await {
        output.push(item);
    }

    let _ = producer.await;
    output
}

四、异步模型的边界:何时不该用 async

Async Rust 并非银弹,以下场景中同步代码或线程池更合适:

CPU 密集型计算。async fn 中的计算代码如果不包含 .await 点,会独占工作线程直到完成,阻塞同一线程上的其他任务。对于 CPU 密集型工作(如加密、压缩、数值计算),应使用 tokio::task::spawn_blocking 将任务卸载到专用线程池,避免阻塞 Tokio 的 IO 线程。

文件 IO。Linux 上 tokio::fs 底层仍使用 spawn_blocking 包装同步 IO 调用,因为 Linux 的 io_uring 支持在 Tokio 中尚不完善。对于大量小文件读写,直接使用 std::fs 配合线程池可能更高效。

复杂状态机。当业务逻辑涉及大量状态转换和超时处理时,select! 嵌套会变得难以维护。此时使用 Actor 模型(如 actix)或状态机库(如 smol)可以更清晰地表达逻辑。

FFI 调用。调用 C 库时,如果 C 函数是阻塞的,必须通过 spawn_blocking 包装。如果 C 库有自己的异步机制,需要手动实现 Future 并正确注册 Waker。

适用边界。Async Rust 最适合高并发 IO 密集型场景:HTTP 服务、WebSocket、数据库连接池、消息队列消费者。对于低并发、CPU 密集或简单脚本场景,同步代码更简洁且无运行时依赖。

五、总结

Async Rust 的核心设计是 Future 状态机 + Waker 唤醒机制,通过编译期变换将 async/await 语法转化为零分配的状态机轮询。本文从 Future 的 poll 语义出发,展示了并发限流器、优雅关闭管理器和异步管道三个生产级模式。落地路线建议:第一步,使用 tokio::spawn 处理独立异步任务,通过 JoinSet 管理任务生命周期;第二步,引入 Semaphore 实现并发限流,防止下游服务过载;第三步,使用 broadcast channel 实现优雅关闭,确保 SIGTERM 信号后所有任务完成清理;第四步,CPU 密集型任务统一走 spawn_blocking,通过基准测试验证线程池大小配置。

PRD撰写效率翻倍秘籍:我是如何用大模型+飞书文档搭建自动化工作流的 本文分享了如何利用大模型与飞书文档构建自动化工作流,以大幅提升PRD撰写效率。通过结构化需求输入、设计模块化提示词模板,并借助自动化脚本桥接数据与文档,产品经理可将繁琐的文档撰写工作自动化,从而将精力聚焦于产品战略与用户洞察。 阅读详情

相关推荐

fastadmin云快充充电桩系统部署文档uniapp

多商户 嘎嘎快充V1.0部署文档 一、服务器环境: 服务器配置4核心8GB内存5M带宽以上配置 VX next1402 只支持linux环境 nginx1.22 php7.2 开启redis、fileinfo扩展,关闭禁用workerman gatewayworkerman需要的函数,如pcntl相关的函数 mysql5.7 supervisor redis 注意: 1.站点必须配置https、websocket配置wss 2.注意开放直连服务端口:2024,并添加到安全组 二、必

itholiday2014的博客 1632

Rust从入门到精通 如何理解 future 的基本机制:运行时**轮询**其所负责的每一个 future

本文深入探讨了 Rust 中异步编程相关的关键 traits:Future、Pin、Unpin、Stream 和 StreamExt。重点解析了 Future trait 的核心机制,包括其定义中的 Output 关联类型和 poll 方法如何通过 Poll 枚举返回状态(Ready/Pending)。文章还解释了 Pin 类型的作用和必要性,说明了为什么某些场景需要固定(pin)future 才能被轮询。最后简要提及了异步运行时如何协调多个 future 的执行,以及 Unpin trait 在 Box&

2301_79516858的博客 882

Spark数据倾斜问题+解决方案

1、数据倾斜 数据倾斜指的是,并行处理的数据集中,某一部分(如Spark或Kafka的一个Partition)的数据显著多于 其它部分,从而使得该部分的处理速度成为整个数据集处理的瓶颈 数据倾斜俩大直接致命后果 1)数据倾斜直接会导致一种情况:Out Of Memory 2)运行速度慢 主要是发生在Shuffle阶段。同样Key的数据条数太多了。导致了某个key(下图中的80亿条)所在的Task数 据量太大了。远远超过其他Task所处理的数据量 一个经验结论是:一般情况下,OOM的原因都是数据倾斜 2、如

诸葛搏毅 6772

Rust 任务(Tasks)系统深度解析:基于 Comprehensive Rust 掌握 Tokio 轻量级线程与 async 块并发模型

本文是 Google Android 团队 Rust 课程(Comprehensive Rust)Async 基础篇中「Tasks」一节的完整技术展开,围绕 Rust 的**任务(task)系统**这一轻量级线程模型,讲解任务的本质(由执行器轮询的顶层 Future)、任务内部的嵌套 Future 结构、以及如何用 `tokio::spawn` 与 `async` 块编写并发的 TCP 服务器。读

gitblog_01036的博客 1164

GEO生信数据挖掘实战:从临床信息提取到多维分组可视化(聚类与PCA)

本文以GSE1297数据集为例,详细讲解了GEO生信数据挖掘中临床信息提取与分组构建的实战流程。通过R语言解析样本元数据,利用字符串处理技术从文本中精准构建疾病与对照分组,并强调使用层次聚类图和PCA图进行可视化验证,确保分组合理性与分析可靠性,为后续差异表达等高级分析奠定坚实基础。

cheese的博客 361

【实战指南】DBeaver EE Windows版高效破解与配置全解析

本文详细解析了DBeaver EE Windows版的高效破解与配置方法,涵盖Java环境配置、破解包部署、配置文件修改等关键步骤,并提供了性能优化和数据库连接的最佳实践。适用于需要解锁企业版高级功能的数据库开发人员,帮助提升工作效率。

weixin_28837817的博客 1908

Rust异步编程之async与.await

介绍了Rust中异步编程基本语法async与.await和Future,以及常见的运行时

飞鹰技术 1098

GT-Power柴油机瞬态性能仿真与优化——基于EGR-VGT耦合控制策略【附案例】

本文探讨了GT-Power在柴油机瞬态性能仿真与优化中的应用,重点分析了EGR-VGT耦合控制策略的实际效果。通过案例研究展示了如何通过仿真优化提升柴油机的动力响应速度和排放性能,为车辆工程领域的工程师提供了实用的技术参考。

green的博客 763

comprehensive-rust 课程解读:Rust Async 异步编程基础——Futures、async/await、任务与运行时

> 本文基于 Google Android 团队维护的 Rust 培训课程 [comprehensive-rust](https://link.gitcode.com/i/0a832b9543e51ae71de28fbd00aa78f4) 中 Concurrency(并发)模块的 "Async Basics" 章节撰写。该章节的入口文档为 [src/concurrency/async.md](ht

gitblog_00497的博客 410

MacOS新手必看:HomeBrew安装避坑指南(含M1芯片适配方案)

本文为MacOS新手提供全面的HomeBrew安装指南,特别包含M1/M2芯片适配方案。从系统准备到核心安装流程,再到日常维护和高级配置,详细解析每个步骤的潜在问题及解决方案,帮助用户高效管理Mac软件。

weixin_28831399的博客 471

MitoZ|动物线粒体基因组组装注释软件

一、MitoZ是什么 是基于python3开发的可以自动过滤双端测序的原始数据、mt基因组组装、mt基因组注释以及mt基因组可视化的工具。 官方的说明文档地址:https://gitee.com/CHANyp/MitoZ#citation 二、MitoZ的安装 git clone https://gitee.com/CHANyp/MitoZ.git cd MitoZ/version_2.4-alpha tar -jxvf release_MitoZ_v2.4-alpha.tar.bz2 三、运行Mito

qq_50637636的博客 1万+

Rust Async/Await 速通指南:Future 模型、Tokio 运行时与并发陷阱实战(RustTraining 系列)

> 本文是 [Rust Patterns 训练书](https://link.gitcode.com/i/3e1960e8fc0be0e7b1bf413cb73a94dd) 第 16 章「Async/Await Essentials」的完整展开。核心围绕三个问题:Rust 的 `Future` 为何与 Go goroutine、Python asyncio 本质不同;如何用 Tokio 快速写出并

gitblog_01034的博客 336

AUTOSAR进阶图解==>AUTOSAR_SWS_ECUStateManager

AUTOSAR ECU State Manager 摘要 AUTOSAR ECU状态管理器(EcuM)是Classic Platform 4.4.0规范中的核心模块,负责管理ECU的整个生命周期,包括启动、运行、关机和睡眠等状态转换。EcuM通过协调各基础软件模块的初始化过程,确保系统可靠运行。 主要功能包括: 启动管理 - 控制从硬件初始化到应用运行的完整启动序列 状态转换 - 管理RUN/POST_RUN/SHUTDOWN等状态切换 唤醒验证 - 区分真实与虚假唤醒事件 关机序列 - 确保安全关机保存关

一名留德华的,康德的信徒的,专注于汽车电子领域的博客 2477

揭秘Rust异步运行时:从Future到Waker的底层机制全解析

掌握rust异步编程核心机制,深入解析Future、Waker与运行时协作原理。涵盖异步任务调度、轮询触发及零成本抽象优势,适用于高性能网络服务与并发场景。底层逻辑全揭秘,值得收藏。

PixelGlow的博客 607

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

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

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

100-exercises-to-learn-rust 异步编程实战指南:async/.await、Future 与 tokio 运行时

Rust 的并发编程并不只有线程这一条路。本指南以《100-exercises-to-learn-rust》课程第 8 章(`book/src/08_futures/`)为骨架,系统讲解 `async`/`.await` 语法、`Future` trait、`tokio` 运行时以及协作式调度的底层原理,并结合仓库中的 [练习源码](https://link.gitcode.com/i/7e7a1

gitblog_00035的博客 975

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Rust 中的 Poll 机制与状态机转换:异步运行时的底层真相

Rust 的 Poll 与状态机转换机制,是编译器与运行时合作的杰作。它让异步逻辑在零运行时开销下实现安全、可预测的并发。每一次.await,背后都是一次类型驱动的状态跳转;每一次,都在为系统级并发打下可控的基石。Rust 不追求“看似简单”的异步,而追求“可证明正确”的并发。Poll 与状态机正是这种哲学的工程化体现。

yuluping_yu的博客 936

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Rust 异步编程速查手册:async-book 总结与参考卡深度解析

本手册以 RustTraining 仓库中 [async-book](https://link.gitcode.com/i/b3d4eafc5123b1c3fb3a7ec36f97a54b) 的收尾章节《Summary and Reference Card》为骨架,将全套异步学习材料浓缩成一份可直接查阅、可复制运行的技术速查卡:从 `async fn → Future` 的心智模型,到 `join

gitblog_00265的博客 1100

comprehensive-rust 课程精讲:深入理解 Rust 异步并发模型(Async / Future / Runtime)

Rust 的异步编程(Async)是 Google Android 团队在 comprehensive-rust 课程中重点教授的高阶并发模型,它让单个线程可以同时驱动大量任务,是编写高并发 I/O 服务的核心手段。本篇以课程文档 [welcome-async.md](https://link.gitcode.com/i/44a7ea5dd11d940db8706d8b80848189) 为骨架,

gitblog_00474的博客 340

Rust 异步编程学习路线:从 Future 到生产级实践 —— RustTraining 之 Async Book 完全指南

RustTraining 仓库的 `async-book` 是一套面向从零到生产级的 Rust 异步编程系统训练材料,其核心章节 [async-book/src/ch00-introduction.md](https://link.gitcode.com/i/ffe3ebe4ea492775a32268284c32059e) 是该书的总纲与学习路线图。与绝大多数从 `#[tokio::main]`

gitblog_00456的博客 226

RustTraining Async Book:深入解析 Poll 机制——从 Executor 轮询循环到 spurious wake

> 本文以 RustTraining 仓库中 [async-book](https://link.gitcode.com/i/bc90290c9489d485eb3ba0f2f83c5137) 的第 3 章 [How Poll Works](https://link.gitcode.com/i/e9355bacad3c3e79d6374110fc962a1e) 为骨架,完整继承其核心概念、最小 e

gitblog_00376的博客 364

Wasmtime 异步主机函数实战:C API 下的 fuel 让出、continuation 与 call future 轮询

本文以仓库中 [docs/examples-async.md](https://link.gitcode.com/i/7868022528c91f2d4628338812cfc26b) 所对应的异步主机函数(Async Host Functions)示例为主线,完整演示如何将 Wasmtime 配置为异步运行模式:通过燃料(fuel)机制周期性让出执行权、定义可暂停/恢复的异步主机函数,并通过轮询

gitblog_01185的博客 320

Rust Executor 与 Future、await 关系浅析

摘要: Executor(执行器)是异步任务的核心调度器,负责轮询(poll)Future并管理任务生命周期。Future定义异步计算的状态机,由Executor驱动;await仅是语法糖,用于挂起当前任务并交还控制权,不参与调度。三者分工明确:Future是被动任务,Executor主动调度,await实现挂起。示例展示了它们的协作流程,Executor通过Waker机制唤醒挂起的Future。关键区别在于:Executor驱动执行和调度,Future描述计算,await仅控制流程暂停。

weixin_40398522的博客 651

Rust 中的 Future Trait:从抽象定义到异步执行的核心机制

在 Rust 的异步生态中,Futuretrait 是一切异步编程的基石。它不仅定义了异步计算的最小抽象接口,更承载了 Rust 在无运行时(runtime-free)条件下实现异步并发的设计哲学。理解Future的定义与实现机制,是理解 Rust async/await 语义与执行模型的关键。Rust 的Future本质上是一种惰性状态机(lazy state machine)。在标准库中,它定义如下:一个Future表示一个可能尚未完成的计算结果,通过轮询(polling)机制推进其执行。

yuluping_yu的博客 889

Rust异步编程——1、Async 编程简介

async是 Rust 选择的 异步编程模型,下面我们来介绍下它的优缺点,以及何时适合使用。

码刀攻城 666

【Rust】16-async/await、Future 与执行器模型

本文深入解析了Rust异步编程的核心机制。主要内容包括:async函数返回Future对象,需要执行器轮询才能推进;Future trait的poll方法及其状态转换原理;await关键字的内部实现基于状态机;Pin防止自引用结构移动;Waker唤醒机制的任务调度流程;执行器模型的工作方式;以及常见问题如Send约束、生命周期处理和阻塞操作等。文章特别强调了Rust异步并非多线程,而是协作式任务调度,并指出了开发者常见误解。最后推荐了进一步学习的资源。

阿正的梦工坊 305

Rust 精要系列(八)—— 异步编程与 Future 深入解析

Rust 的异步系统是一种零成本抽象通过编译器在编译阶段生成高效的状态机,实现与同步代码几乎相同的性能。同时,借助严格的类型系统,Rust 保证了异步代码在多任务并发下的内存与线程安全。从Future的惰性求值到运行时调度的精妙设计,Rust 让开发者可以在无需垃圾回收的前提下,编写出高效、安全、可预测的并发程序。在下一篇中,我们将继续深入探讨Rust 的模块化设计与大型项目架构实践,帮助你更系统地组织与维护复杂的 Rust 工程。

guanmingyuangmy的博客 790
上一篇: 所有权即安全:深入 Rust 内存模型与编译期保证机制
下一篇: 浏览器内的推理引擎:WASM 端侧 AI 推理的架构与实现
第一程序员
博客等级 码龄1年 1万+粉丝 1822原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值