vLLM学习1

news/2025/2/25 0:55:46

调用方式

一、vLLM 提供的两种调用方式

1. Offline Batched Inference(离线批处理)

  • 调用特点:一次性传入一批(batch)的请求,等待所有请求都处理完毕后,一次性返回推理结果。对用户而言,这是一个同步的过程:只有当这一批所有数据都推理完成,用户才能拿到结果。

  • 示例代码(基于vLLM官方示例):

    from vllm import LLM, SamplingParams
    
    # 1) 组织batch数据
    prompts = [
        "Hello, my name is",
        "The president of the United States is",
        "The capital of France is",
        "The future of AI is",
    ]
    
    # 2) 采样参数
    sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
    
    # 3) 初始化离线批处理实例,并加载指定模型
    llm = LLM(model="facebook/opt-125m")
    
    # 4) 推理
    outputs = llm.generate(prompts, sampling_params)
    
    # 5) 打印结果
    for output in outputs:
        print(f"Prompt: {output.prompt!r}, Generated text: {output.outputs[0].text!r}")
    
  • 背后原理

    1. 表面上是同步:用户会一次性提交一批请求(batch),等待所有请求都推理完成再返回。
    2. 实际上是“动态”:vLLM的核心引擎(LLMEngine)内部会根据当前GPU显存的使用情况,对batch做“动态”调度。在一个推理阶段(prefill或一次decode)里,如果显存无法容纳所有请求,vLLM会先让部分请求进入“running队列”,剩下的请求留在“waiting队列”里等待。
    3. 多阶段推理:当某些请求在一次推理阶段完成或结束(生成了结束符或达到最大长度),它们就会释放所占用的显存块。这样下一批等待的请求就能进入“running队列”,继续下一阶段推理。
    4. 对用户而言是透明的:用户只看到自己提交了一个batch,等所有结果都处理完后才拿到输出;但在内核引擎中,这个batch可能被分拆成多个子批次进行推理。

2. API Server For Online Serving(在线服务)

  • 调用特点:采用异步方式处理请求,随时可以接收新请求、并行处理多个请求;已完成的推理结果可以先行返回给客户端(尤其配合流式传输时,可以边生成边返回)。

  • vLLM 提供了两种在线API:

    1. OpenAI-Compatible API Server(官方推荐):兼容OpenAI的Completions和Chat API协议,使用方式与OpenAI API相同。
    2. Simple Demo API Server(官方已不再维护):仅适用于简单测试,不推荐在生产环境使用。
  • 示例命令

    (OpenAI-Compatible API):

    # 1) 启动服务
    python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-2-7b-hf
    
    # 2) 用curl发送请求(OpenAI风格)
    curl http://localhost:8000/v1/completions \
      -H "Content-Type: application/json" \
      -d '{
          "model": "meta-llama/Llama-2-7b-hf",
          "prompt": "San Francisco is a",
          "max_tokens": 7,
          "temperature": 0
      }'
    
  • 背后原理:

    1. 异步化处理:vLLM使用uvicorn + fastapi 实现一个异步服务器,内部封装了 AsyncLLMEngine
    2. 排队 + 调度:当多个请求同时到来,vLLM会先将请求放入一个异步队列,然后在内部调度器(Scheduler)的管理下,将请求动态加入“running队列”进行推理。
    3. 先完成先返回:只要有请求在当前推理阶段完成,就可以立即把结果返回给客户端,不需要等待其他请求一起结束。若开启流式输出,还能在生成过程中分段发送token给客户端。
    4. 同样使用PagedAttention:在线服务依然会利用PagedAttention进行显存优化;当显存不足时,还会做部分数据的swap到CPU或暂时排队等待,以提升吞吐。

二、LLMEngine:vLLM的内核引擎

img

无论是离线批处理还是在线服务,都依赖于同一个核心组件——LLMEngine。它的主要功能包括:

  1. add_request()
    • 将每个请求转换成vLLM内部的统一数据结构(如SequenceGroup),并加入调度器(Scheduler)的waiting队列中。
    • 离线批处理场景下,这个函数是“同步式”的:会依次处理batch中的各条数据。
    • 在线场景下,会被重写为异步版本(AsyncLLMEngine),以便在协程中对每个请求进行处理。
  2. step()
    • 执行一次推理阶段(prefill算1次推理,decode的每一步也算1次推理)。
    • 调度器(Scheduler)决定哪些请求可以进入“running队列”,并为它们分配所需的显存块(Physical KV blocks)。
    • 模型(带有PagedAttention)根据这些分配信息执行推理,生成新的token并更新KV缓存。
    • 如果有请求在本次推理阶段完成(如达到或其它终止条件),则释放对应显存块,并将该请求从running队列中移除。
  3. abort_request()
    • 如果在推理过程中客户端断开连接,或用户取消了请求,可以调用此方法中断推理,释放对应资源。

总结:只要理解了 add_request()step() 这两个函数的核心逻辑,就掌握了LLMEngine的大部分精髓。它们背后涉及到很多“排队、调度、显存分配、PagedAttention”的复杂逻辑,源码中会有大量的封装与嵌套。


三、离线批处理与在线服务的内核差异

  1. 离线批处理
    • 对用户来说:一次性输入所有数据 -> 一次性得到全部输出。
    • 对LLMEngine来说:内部依然是“动态批”调度,不断有请求完成并释放显存,再让新的请求进来,但对用户是不可见的,属于“内部黑箱”。
  2. 在线服务
    • 对用户来说:随时可以发送请求;完成的结果可以第一时间返回。
    • 对LLMEngine来说:依旧是同一个调度器;不同在于用户随时可能发来新请求或断开已有请求,因此需要用异步队列、异步I/O的方式处理。
    • 核心思路相同:都是把请求排队 -> 等到一个推理阶段到来时,把合适数量的请求放入“running队列” -> PagedAttention完成这批的计算 -> 释放已完成请求的显存 -> 重复。

代码整体架构

img

这张图展示了 vLLM 内部代码整体架构,可以把它拆分为“中央控制端(Centralized Controller)”和“分布式Worker”两大部分。LLMEngine 就位于中央控制端的进程里,负责调度和管理请求,而真正的模型推理(包括PagedAttention等核心逻辑)会在一个或多个分布式Worker进程上执行(每个GPU对应一个Worker)。以下是对各模块的更详细解读:


一、LLMEngine 与 Centralized Controller

这部分都在同一个CPU进程中(如图中左侧所示),它包含了:

  1. LLMEngine(vllm/engine/llm_engine.py)
    • 这是用户直接调用的接口层,用于接收请求(prompt)并将其转给调度器进行处理。
    • LLMEngine本身并不直接执行推理,而是协调Scheduler、BlockSpaceManager等组件,并通过网络或进程通信,把模型计算任务发送给下游的Worker进程。
  2. Scheduler(vllm/core/scheduler.py)
    • 调度器:决定每一个“推理阶段”(如prefill或decode的某一步)要处理哪些请求,并且以什么方式把这些请求打包交给Worker来执行。
    • 当有多个请求或多个batch同时到来时,Scheduler会根据显存使用情况和优先级策略决定如何将它们安排到running队列、waiting队列或swap到CPU内存。
    • 在运行完某个阶段后,如果有请求产生了新token或已经完成推理,就相应地更新这些请求的状态并做后续处理(例如释放显存块)。
  3. BlockSpaceManager(vllm/core/block_manager.py)
    • 块空间管理器:负责管理所有token KV缓存的“块”在显存/内存中的分布情况,以及它们的生命周期。
    • 它会与调度器配合,决定在每个推理阶段,需要为哪些请求分配新的缓存块或回收哪些已经不再使用的块。
  4. BlockAllocator(vllm/core/…)
    • 显存/CPU分配器:将具体的物理内存(包括GPU显存、CPU内存)分配给BlockSpaceManager所需要的KV缓存块。
    • 当GPU显存不足时,可能将部分块swap到CPU,以腾出空间给新的请求。
    • 对应地,BlockSpaceManager会记录块在GPU上或CPU上,并在需要计算时重新把块拉回GPU。

总结:Centralized Controller进程中,LLMEngine是对外的“门面”,Scheduler是核心的调度大脑,BlockSpaceManagerBlockAllocator则负责管理KV缓存块在不同硬件介质间的具体分配和回收。


二、Distributed Workers(分布式Worker 进程)

如图中右侧部分所示,vLLM可以在分布式环境中使用,每个Worker通常对应一块GPU(也可在CPU模式或Ray模式下运行)。当前版本主要是单主机多GPU的场景,后续可能扩展为更多分布式方案。下列是Worker内部的关键组件:

  1. Worker(vllm/worker/worker.py)
    • Worker是一个进程,里面包含了CacheEngineWorker.model等对象。
    • 当Centralized Controller决定某些请求要进行推理时,就会将这些请求对应的KV块和输入数据传给某个Worker,由它执行模型计算并返回结果(新token、注意力分数等)。
  2. CacheEngine(vllm/worker/cache_engine.py)
    • 负责与PagedAttention配合,在Worker本地对KV缓存进行读写操作。
    • 当收到Scheduler的指令后,CacheEngine会根据请求发送的数据ID或位置,把对应的KV块取出来(或者新建)并调用PagedAttention进行推理中的注意力计算。
  3. Worker.model(vllm/model_executor/models/…)
    • 真正加载了大语言模型权重的模块。
    • 当需要进行前向推理时,Worker调用它来计算每一步生成所需的logits、隐层状态等,内部再调用PagedAttention的相关逻辑做注意力机制。
  4. PagedAttention(vllm/model_executor/layers/…)
    • 在Worker的模型层中具体实现的“分页/分块式注意力”机制。
    • 它将传统的KV缓存细粒度地切分为多个Block,并在计算注意力时只加载、更新相关Block,避免重复计算和显存浪费。
    • 与CacheEngine、BlockAllocator共同配合,实现动态地分配、回收和复用KV缓存。

总结:分布式Worker相当于是实际执行大模型推理的“工作站”,里面包含模型缓存管理等功能,通过PagedAttentionCacheEngine实现对KV缓存的高效操作。每个Worker与中央控制(Scheduler)相互通信,将请求对应的工作内容取过来执行,然后返回结果。


三、集中式调度 + 分布式推理 的好处

  1. 统一调度,简化架构
    • 由于Scheduler和BlockSpaceManager都在主进程上进行集中管理,减少了多GPU之间的“谁分配什么资源” 的冲突和协商开销。
    • Worker只需专注于执行分配到的计算任务,无需关心整体系统状态。
  2. 灵活的显存管理
    • Centralized Controller可以全局掌握所有请求与所有GPU/CPU的使用情况,做全局调度;比如当某块GPU显存满了,可以直接把部分KV块swap到CPU或调度到其他GPU。
    • Worker仅保留自己当前需要用到的块,剩余部分由BlockAllocator/BlockSpaceManager在后台统一管理。
  3. 扩展为多Worker
    • 如果单GPU算力不足,可增加多个Worker进程,每个进程对应一块GPU或一组GPU,分担推理工作。
    • 在后续版本中,vLLM也有望支持更多分布式策略(如TP/PP并行),进一步提升推理吞吐。

四、代码阅读指南

  • vllm/engine/llm_engine.py
    入口:LLMEngineAsyncLLMEngine。用户调用接口层,和Scheduler/BlockSpaceManager配合完成推理。
  • vllm/core/scheduler.py
    核心调度逻辑所在,负责推理阶段的决策,让哪些请求进入执行队列、哪些swap到CPU等。
  • vllm/core/block_manager.py & vllm/core/block_allocator.py
    管理KV缓存块的创建、删除、swap和引用计数。
  • vllm/worker/worker.py
    定义Worker进程的核心流程,包括接受任务、调用模型执行、返回结果。
  • vllm/worker/cache_engine.py
    在Worker侧管理KV缓存块的读写与paged attention计算对接。
  • vllm/model_executor/
    这里存放模型相关的执行逻辑与PagedAttention的实现。

加载模型与预分配显存

下面的内容主要围绕 vLLM 在正式启动推理服务前,会做的两件初始化工作:

  1. 加载模型(将大模型权重加载到 Worker 上)
  2. 预分配显存(在 GPU/CPU 上提前创建一批 KV Cache 块)

这样,当真正有请求(prompt)到达时,vLLM 就能直接使用这些预分配好的缓存块,而无需在推理过程中再做大规模内存申请或分配,极大提高了服务的启动效率和稳定性。下面会分步骤为你详细讲解其中原理和流程。


一、加载模型

1.1 加载的时机与方式

  • 时机:在 vLLM 正式开始处理第一个请求之前,就会先把你指定的基础模型(base model)加载到 Worker 进程中。

  • 方式:默认情况下,vLLM 使用 HuggingFace 模型仓库(Model Hub)来下载并加载对应的模型权重。

    • 如果你在使用在线加载方式,只需在启动参数或环境变量中指定相应的模型名称(如 "facebook/opt-125m""meta-llama/Llama-2-7b-hf" 等),vLLM 便会从 HuggingFace 上自动拉取权重并初始化。
    • 也可以通过设置环境变量,把默认源改为其他仓库(如 ModelScope)。

    img

1.2 多 Worker 环境下的加载

  • 每个 Worker(对应一块 GPU 或者 CPU 进程)会各自加载同一份基础模型权重到本地显存或内存中。
  • 当进入推理阶段时,Worker 就可以直接对这些已加载好的模型权重做前向计算(forward),结合 PagedAttention 完成生成任务。

提示:如果模型比较大,加载过程会消耗一定时间和显存。为保证服务稳定,通常你会先在所有 Worker 上完成加载,然后才开始对外提供推理 API。


二、预分配显存

在模型加载完成后,vLLM 还会进行一次“模拟实验”或“内存探测(profile)”,借此估算自己能创建多少 KV Cache 物理块,并为后续真正的推理分配足够的缓存空间。图示中称之为 “Before serving requests - 2. Profile memory usage” 和 “3. Pre-allocate KV blocks”。

2.1 为什么要预分配?

  • 减少推理时的分配开销:如果把创建 KV Cache 的操作放到推理进行时才做,大规模的内存分配可能导致延迟抖动或显存碎片。
  • 让调度器(Scheduler)更好工作:调度器需要知道 GPU/CPU 剩余多少块可以使用,才好动态决定将多少请求同时放到“running队列”里。
  • 便于发现配置或显存不足问题:如果你给定的 max_num_seqsmax_num_batched_tokens 太大,导致需要分配的 KV Cache 块数量远超 GPU 真实承受能力,vLLM 能在初始化时就发现并报错,而不是推理时才崩溃。

2.2 关键参数

初始化 LLMEngine 时,用户通常会提供两个重要的配置项:

  1. max_num_seqs
    • 在一个推理阶段里,vLLM Engine 最多能处理的序列(seq)数量。
    • 默认为 256,意味着同时处理 256 条请求(或 256 条不同的上下文)是上限。
  2. max_num_batched_tokens
    • 在一个推理阶段里,vLLM Engine 最多能处理的 token 数量。
    • 默认为 2048,表示同时会处理的 token 数总量上限。

vLLM 会据此来估计:如果在一个推理阶段,有多条请求,每条请求的序列长度合计多少 token,需要大概多少块 KV Cache,GPU/CPU 能否容纳得下。

2.3 计算分配给 KV Cache 的总显存

在做内存 profiling 的过程中,vLLM 会先用一批“虚拟请求”来做一次假想的前向推理(prefill 或 decode),测量不使用 KV Cache时模型本身的显存占用是多少(包括模型权重 + 中间激活等)。然后再去算:

分配给KV cache显存 = gpu总显存 - 不使用KV cache做1次推理时的显存占用(包括模型本身和推理过程中的中间数据)

这一步相当于先排除模型必需的显存占用后,看看还剩多少“空闲”容量可以用来分配 KV 缓存。

2.4 计算每个 KV Cache 块的大小

  • block_size
    每个物理块包含多少个 token 的 KV 内容(vLLM 默认是 16 个 token)。
  • 其它参数
    包括 Transformer 层数、head 数、head_size 以及数据类型(fp16/fp32)等等。
  • 最终会得到类似这样一个公式:

KaTeX parse error: Expected 'EOF', got '_' at position 13: \text{cache_̲block_size} = \…

其中“ × 2 \times 2 ×2”是因为在多数实现里 KV 是分开存储的(Key 和 Value 都需要分配)。如果是 fp16(dtype_size=2 bytes),则还要代入这个数。

2.5 计算可分配的总块数

一旦知道可分配给 KV cache 的总显存单块大小,就能算得总块数
KaTeX parse error: Expected 'EOF', got '_' at position 11: \text{num_̲blocks} = \frac…

对于 CPU 端同理,只不过 CPU 内存通常比较大(默认上限可能写成 4GB、8GB 或用户自定义),可以用类似的逻辑算出可分配的块数(当 GPU 空间不够时,Scheduler 会把一部分块 swap 到 CPU)。

2.6 在 GPU 上创建预分配的空 Tensor

img

最后,vLLM 会调用类似 BlockAllocator._allocate_kv_cache() 这样的函数,在 GPU 或 CPU 上逐层(num_layers 次)创建这些空张量(torch.empty(...)),并将它们存放到一个列表里,组成 “KV Cache” 池。

  • 这些空张量就相当于分割好的“片段”,每个分片能容纳一部分 token 的键值对。
  • 当有新请求到来,需要一个 block 时,BlockManager/BlockAllocator 只要把一个空闲块分配给它,无需再进行张量创建。

优点

  • 减少了运行时的 Fragmentation(碎片化)风险。
  • 可以快速映射到调度策略,让 Scheduler 知道当前空闲块、在用块、swap 块的数量与位置,进行更精细的管理。

三、预分配带来的好处与注意点

  1. 启动后显存占用“突增”是正常现象
    • 由于 vLLM 把一部分空张量提前开辟好了,你可能会看到 GPU 显存一下子就用掉了相当大比例。但这些张量实际是空数据,只是占位;真正放入 Token KV 时才会写入内容。
  2. 参数调得过大可能导致 OOM
    • 如果你指定的 max_num_seqsmax_num_batched_tokens 太高,而 GPU 显存不足,vLLM 在初始化时就会报错或内存不足的问题,而不是推理时才发现。
    • 这其实是个安全机制,让你知道当前配置不可行。
  3. 调度器与预分配
    • 一旦 KV block 预分配完毕,Scheduler 就能准确地知道有多少块可用,并且在推理阶段分配/回收这些块给不同请求。如果用完了,新的请求就只能等,或者把不活跃的块swap到 CPU。
  4. 可能影响多进程部署
    • 在多进程(或多容器)中部署时,各自进程都要预分配一份 KV cache,会进一步增加显存占用,需要格外留意调优。

四、小结

  • 加载模型:先把大模型的权重加载到每个 Worker 上,保证 Worker 拥有完整的计算能力。
  • 预分配显存:
    1. 内存测量:通过一次模拟推理,估计模型本身占用多少显存,并计算剩余可用于 KV cache 的空间;
    2. 计算块大小 & 总块数:基于 block_size、头数、层数等模型结构,推断需要多少块;
    3. 在 GPU/CPU 上创建空 Tensor:一下子把这批块都预先分配好,供后续推理阶段快速使用。

这两步完成后,vLLM 才算真正“就绪”,能够在请求到来时立即投入推理,无需临时分配更多大块内存,从而减少延迟、提高吞吐与稳定性。

从这部分内容也能看出,vLLM 在设计上十分注重实际系统工程需求:

  • 启动时就对显存做充分的准备;
  • 运行时则配合调度器和 PagedAttention,以“块”为单位执行分配与回收,实现弹性、灵活的高并发推理。

Scheduler调度

下面这部分内容讲的是 vLLM推理阶段如何利用调度器(Scheduler)对请求进行分配、执行、以及在显存不足时如何处理“swap”等操作。简单来说,调度器需要在每一个推理步骤(Prefill 或 Decode 的某一时刻)动态地决定哪些请求进入运行、哪些需要等待、哪些请求要被暂时Swap到CPU内存。下面会分几个要点为你详细拆解。


1. 三种队列:Waiting / Running / Swapped

1)Waiting队列

  • 刚刚到达、尚未开始推理或者中途需要继续等待显存的请求,会被放在等待队列里。
  • 当调度器检测到有空闲的KV缓存块或GPU显存足够时,就可以把这些请求从Waiting队列拉到Running队列里执行。

2)Running队列

  • 当前正在GPU上执行推理(prefill或decode)的请求。
  • 这些请求已经被分配了相应的KV缓存块(Block),可以进行一步或多步的前向计算。
  • 如果请求完成生成,或者中途需要释放资源,调度器会将它从Running队列移出。

3)Swapped队列

  • 当GPU显存紧张、KV缓存块无法满足新的token生成时,调度器可能会把部分正在运行的请求(尤其是“后到达”或“优先级较低”的请求)从GPU“换出”(swap)到CPU内存里,以释放GPU空间给其他请求继续运行。
  • 被swap出去的请求,其KV缓存也会被移到CPU上保存。等待下一次调度时,如果GPU显存再度可用,这些请求可重新加载回到GPU并恢复推理。

提示:Swapped队列在前面章节的示例图里未出现,这里才正式提出,表示vLLM在高并发、显存不足的情况下会使用“swap”策略。


2. 预备知识:后来先抢占 (Preemption)

在 vLLM 的调度策略里,有一项关键手段叫**“后来先抢占”**(Preemption),大致含义是:

如果一个新的请求到来(或正在等待中),需要分配KV缓存,但 GPU 上已没有空闲块可用,调度器会从 Running队列里“挑出最晚加入的请求”(或优先级更低的请求)将其 Swap 到 CPU,把腾出来的块让给新的(或优先级更高的)请求继续推理**。

这是典型的“后进先出”式抢占策略,目的是:

  1. 尽快满足新请求或更高优先级请求的需求(尤其是在在线服务模式下,对新的交互请求响应速度至关重要)。
  2. 被swap出去的请求也并非放弃,只是暂时中断;等到GPU显存重新腾出块后,再将它们从Swapped队列移回Running。

3. 调度器在每一步做什么?

正如图示“At every step, the scheduler”所示,每一个推理步骤(包括一次prefill或一次decode)开始时,调度器要做的事情主要有:

  1. 决定本次要运行的请求集合
    • 如果GPU上还有空闲的KV缓存块,调度器就从Waiting队列里取请求加到Running队列;
    • 如果没有可用块,且有新请求需要空间,则可能触发Swap,把一些正在Running的请求移到Swapped,以腾出块给新请求。
  2. 调用BlockSpaceManager和BlockAllocator
    • 为新加入Running队列的请求分配实际的KV块;
    • 处理块共享(多个请求可能共享某些前缀块);
    • 回收或删除已经完成的KV块;
    • 对被Swap或被抢占的请求,其KV块会移动到CPU或被标记为“swapped out”。
  3. 更新请求的状态
    • 已完成生成(到达或最大长度)的请求,从Running队列移除,释放块。
    • 中途被Swap到CPU的请求,改到Swapped队列;
    • 其它仍在进行的请求,继续保留在Running队列,以便下一步decode阶段接着计算。

4. 处理流程示例

可以用一个简单的示例来说明:

  1. 有新的请求A到达
    • 如果GPU上还有多余块,调度器把请求A从Waiting -> Running,并在BlockAllocator中为它分配若干物理块。
  2. 这时又来了请求B,而GPU已无可用块
    • 调度器查看Running队列,找到最晚加入或优先级低的请求X,将它从Running -> Swapped,并把对应KV缓存块swap到CPU内存。
    • 释放的块就能分配给请求B。
    • 请求X暂时在Swapped队列等待,下次调度看有没有机会回到GPU。
  3. 下一次解码阶段时
    • 如果GPU上又有空闲块(比如某个请求Y已经完成生成,释放了块),调度器就可以从Swapped队列拉回请求X(从Swapped -> Running),把它的KV缓存重新搬回GPU上,让它继续未完成的解码。
  4. 重复这一过程,直到所有请求都完成或被abort。

5. 优势与注意点

  1. 充分利用显存
    • 当有空闲块就多接收新的请求,加速吞吐;
    • 当显存吃紧时,就对暂时不急或后到的请求进行Swap,保障系统不会崩溃或OOM。
  2. 保证性能与响应
    • “后来先抢占”优先给新请求或更高优先级请求留出显存,可以减少高优先级请求的等待。
    • 但也意味着被Swap出去的请求要等一段时间才能回来继续解码,性能上会受点影响。
  3. Swap带来的I/O开销
    • 每次Swap都需要将KV缓存数据从GPU转移到CPU,对带宽和速度有一定损耗。
    • 这在高并发场景下是必要的折衷:总比让请求一直等待或者触发OOM要好。
  4. 队列状态的监控
    • 在实际部署时,可以观察到Scheduler日志里waiting/running/swapped三类队列的规模变化;
    • 如果Swapped队列长期过大,可能需要减小并行度或增加GPU资源。

6. 小结

通过这部分内容,你可以看到在 vLLM 里,“调度器”(Scheduler)发挥了至关重要的角色——在每个推理阶段,决定哪些请求可以用GPU继续生成,哪些请求要放在waiting或swap。这一切都围绕着“KV Cache块”这种核心资源展开:

  • 有空闲块 → 请求能进“running”,
  • 无空闲块 → 可能触发“swap”以释放块,
  • 完成或终止 → 回收块并移出队列。

同时,“后来先抢占(Preemption)”进一步让vLLM在GPU显存紧张时能优雅地处理新请求并避免系统崩溃,从而使得在线推理服务在高并发、大模型、有限显存的情况下依旧能维持可观的吞吐与响应速度。

总而言之,这就是图中展示的调度流程:当请求到来 -> LLMEngine将其加到Scheduler等待 -> 每步推理(prefill/decode)之前,Scheduler根据可用块分配或swap -> Worker执行运算 -> 重复直到请求结束。这也是 vLLM 能在实践中高效运行的关键所在。


http://www.niftyadmin.cn/n/5864895.html

相关文章

std::thread的同步机制

在 C 中,std::thread 用于创建和管理线程。为了确保多个线程能正确、安全地访问共享资源,避免数据竞争和不一致问题,需要使用同步机制。 互斥锁(std::mutex) 原理:互斥锁是一种最基本的同步原语&#xff…

Linux 命令大全完整版(12)

Linux 命令大全 5. 文件管理命令 ln(link) 功能说明&#xff1a;连接文件或目录。语  法&#xff1a;ln [-bdfinsv][-S <字尾备份字符串>][-V <备份方式>][--help][--version][源文件或目录][目标文件或目录] 或 ln [-bdfinsv][-S <字尾备份字符串>][-V…

UE_C++ —— Gameplay Modules

目录 一&#xff0c;Module Creation INI File Setup 二&#xff0c;Multiple Gameplay Modules 三&#xff0c;Limitations 编译成 DLL 的游戏相关类的集合&#xff1b;正如引擎本身由一组模块构成一样&#xff0c;每个游戏也是由一个或多个游戏模块构成的&#xff1b;这些…

docker中常用的命令

一、服务命令 systemctl start docker.service 启动docker服务 systemctl stop docker.service 关闭docker服务 systemctl enable docker.service 设置docker服务开机启动 systemctl disable docker.service .禁止docker服务开机自启动 二、镜像命令 d…

前端已死?什么是前端

前端&#xff08;Front-End&#xff09;是用户与数字产品&#xff08;如网站、应用程序等&#xff09;直接交互的部分&#xff0c;负责呈现视觉界面、处理用户输入并确保流畅的体验。它是用户看到和操作的一切内容&#xff0c;与后端&#xff08;服务器、数据库等&#xff09;共…

使用 Python 和 OpenCV 从一组图片合成 MP4 格式的视频

概要 在创建动画、制作幻灯片&#xff0c;从生成的图像数据中导出动态视频时&#xff0c;我们需要将一系列静态图片合成一个视频。 提示&#xff1a;不涉及AIGC生成 安装依赖 代码需要安装 OpenCV 库。可以通过命令行安装&#xff1a; pip install opencv-python 完整代码…

浏览器下载vue.js.devtools,谷歌浏览器和edg浏览器

1、谷歌浏览器下载&#xff1a; 情况一&#xff1a;如果谷歌应用商店可以打开&#xff0c;那么就直接到谷歌应用商店下载&#xff0c;直接搜索vue.js.devtools添加扩展即可。 情况二&#xff1a;谷歌浏览器的谷歌应用商城打不开&#xff0c;那么就百度搜索极简插件找到vue.js.…

QString是 Qt 框架中的一个核心类,基本用法使用:创建、字符串拼接、截取、查找、替换、分割、大小写转换、比较。

QString 是 Qt 框架中的一个核心类&#xff0c;用于处理字符串数据。它提供了许多功能来处理文本操作&#xff0c;包括但不限于字符串拼接、分割、大小写转换等。下面是一些 QString 的常见用法示例&#xff1a; 创建 QString 你可以通过多种方式创建 QString 对象&#xff1…