ARTICLE · 1294793
一台电脑同时服务多人:Ollama 并发推理实战
前几期,我们已经完成了 Ollama 的安装、局域网共享,以及大模型的 CPU/RAM 运行和性能优化。
现在,一台配置不错的电脑,已经可以作为本地 AI 服务器,供家里或办公室里的其他设备使用。
但这里还有一个问题:
如果两台电脑同时向同一个模型提问,Ollama 会怎么处理?
比如:
台式机正在让模型分析一段代码。 笔记本同时请求模型总结一篇文章。 另一台电脑也在使用同一个模型进行问答。
它们会一起生成回答,还是必须等前一个请求结束?
如果三个人同时使用,会不会让每个人的回答速度都变慢?
实际上,Ollama 提供了专门的并发处理和模型调度机制。
这一期,我们就通过几个环境变量和一组简单实验,看看怎样让一台电脑更合理地处理多个 AI 请求。
1. 先理解:并发和并行有什么区别?
这两个概念经常被放在一起讨论,但含义并不完全相同。
并发(Concurrency),指系统能够在一段时间内处理多个任务。
这些任务不一定在同一时刻真正执行,也可能轮流获得计算资源。
并行(Parallelism),则强调多个任务在同一时间实际执行。
举个简单的例子。
假设有两个人同时向 Ollama 发送请求。
第一种情况:
时间 ──────────────────────────────→请求 A:██████████请求 B: ██████████
请求 B 必须等待请求 A 完成。
这属于排队处理。
第二种情况:
时间 ──────────────────────────────→请求 A:██████████请求 B:████████████
两个请求的执行时间发生了重叠。
这才是我们希望测试的并行推理能力。
不过,并行不意味着两个请求都能保持原来单独运行时的速度。
因为 CPU、GPU、显存和内存带宽仍然是有限的。
并行处理的核心价值,是提高系统同时服务多个请求的能力,而不是保证每个请求都变得更快。
2. Ollama 是怎样处理多个请求的?
Ollama 的并发处理可以分为两个层面。
第一层:同一个模型处理多个请求。
例如,两台电脑都调用 qwen2.5:7b。
这时可以通过 OLLAMA_NUM_PARALLEL 调整同一个模型能够同时处理的请求数量。
第二层:多个不同模型同时加载。
例如:
qwen2.5:7bllama3.1:8bdeepseek-r1:7b
这些模型都可能被不同客户端调用。
此时,Ollama 需要决定能否让多个模型同时驻留在内存或显存中。
对应的配置是 OLLAMA_MAX_LOADED_MODELS。
如果请求过多,还涉及第三个问题:
暂时处理不了的请求应该排队多久?队列最多能容纳多少请求?
这由 OLLAMA_MAX_QUEUE 控制。
所以,今天最重要的三个参数就是:
OLLAMA_NUM_PARALLEL | |
OLLAMA_MAX_LOADED_MODELS | |
OLLAMA_MAX_QUEUE |
这三个参数解决的是不同问题,不能相互代替。
3. 第一招:让同一个模型同时处理两个请求
先来看最直接的场景。
假设我们已经下载了:
ollama run qwen2.5:7b现在希望它能够同时处理两个聊天请求。
在 Windows PowerShell 中执行:
[Environment]::SetEnvironmentVariable(”OLLAMA_NUM_PARALLEL”,”2”,”User”)
这段代码的含义如下。
OLLAMA_NUM_PARALLEL:
控制同一个模型允许的最大并行请求数量。
2:
将最大并行请求数设置为两个。
User:
将环境变量永久保存到当前 Windows 用户的环境配置中。
设置完成后,需要彻底退出 Ollama,再重新启动。
注意:Windows 版 Ollama 可能在系统托盘中后台运行。仅关闭 PowerShell 窗口,并不能确保服务已经重新加载环境变量。
设置为 1、2、4 有什么区别?
1 | ||
2 | ||
4 |
这里有个重要问题:
为什么不直接设置为 8,甚至 16?
因为并行请求需要额外的运行内存。
每个请求都有各自需要处理的上下文,Ollama 必须为这些请求分配足够的缓存资源。
因此,并行数量越高,通常意味着更高的内存或显存需求。
不能简单认为设置得越大,模型就越快。
4. 并发为什么会增加显存占用?
这就涉及我们第五期介绍过的 KV Cache。
模型处理上下文时,需要保留一部分注意力计算结果,以减少重复计算。
如果只有一个请求,就只需要为当前请求分配相应的上下文缓存。
如果两个请求同时运行,就需要为两个请求准备运行所需的缓存资源。
假设单个请求使用:
num_ctx = 8192当并行请求数设置为:
OLLAMA_NUM_PARALLEL = 4那么系统就需要考虑多个并行上下文带来的内存需求。
可以用下面的关系进行初步理解:
并行上下文总容量≈ 单请求上下文容量 × 并行请求数
例如:
8192 × 4 = 32768这不代表四个请求可以共享同一个 32768 Token 的对话,也不代表 KV Cache 的实际显存占用一定严格增加四倍。
它只是说明:
当单请求上下文长度不变时,提高并行数量,通常需要更多上下文缓存资源。
所以,如果你的显存只有 8GB 或 12GB,直接设置较大的并发数,可能并不合适。
对于显存比较充足的电脑,可以从 2 开始测试,再决定是否提高。
5. 第二招:控制同时加载的模型数量
前面的参数解决的是:
一个模型同时服务多少个请求?
现在再看另一个问题:
一台电脑同时运行多少个模型?
例如,电脑中已经安装:
qwen2.5:7bllama3.1:8bdeepseek-r1:7b
这三个模型的权重可以分别存放在硬盘上,但如果希望它们同时保持加载状态,就需要有足够的内存或显存。
Ollama 提供了:
OLLAMA_MAX_LOADED_MODELS例如:
[Environment]::SetEnvironmentVariable(”OLLAMA_MAX_LOADED_MODELS”,”2”,”User”)
这里的 2 表示最多允许同时加载两个模型。
不过,它只是数量上限。
并不是设置为 2,Ollama 就一定能够把两个模型同时装入显存。
如果模型过大、显存不足,系统仍然需要根据实际资源情况进行调度。
什么时候适合设置为 1?
如果电脑显存不多,而且主要使用一个大型模型,可以考虑:
[Environment]::SetEnvironmentVariable(”OLLAMA_MAX_LOADED_MODELS”,”1”,”User”)
这样可以限制同时加载的模型数量,避免多个模型竞争有限资源。
但缺点也很明显:
如果两个客户端分别请求不同模型,可能需要等待模型切换。
因此,这个参数的选择取决于使用习惯。
如果经常在多个小模型之间切换,且显存足够,可以尝试更高的值。
如果主要运行一个显存占用很大的模型,则不必追求同时加载多个模型。
6. 第三招:控制请求排队数量
当多个请求同时到达,而服务器暂时没有足够资源处理时,Ollama 可以把部分请求放入等待队列。
例如:
请求 A ──┐├── 正在处理请求 B ──┘请求 C ───── 等待请求 D ───── 等待
这时就涉及:
OLLAMA_MAX_QUEUE例如,可以设置:
[Environment]::SetEnvironmentVariable(”OLLAMA_MAX_QUEUE”,”16”,”User”)
这里的 16 表示最多允许 16 个请求处于等待队列中。
它并不意味着 Ollama 可以同时处理 16 个请求。
两者一定要区分:
OLLAMA_NUM_PARALLEL:控制同时执行多少个请求。 OLLAMA_MAX_QUEUE:控制最多允许多少个请求等待。
如果等待队列已满,Ollama 会拒绝额外请求,并可能返回:
HTTP 503Service Unavailable
这通常表示服务端当前过于繁忙。
排队数量是不是越大越好?
不是。
如果模型生成一条回答需要很长时间,那么排在后面的请求即使没有被拒绝,也可能需要等待很久。
因此,对于个人电脑或小规模局域网使用,不一定需要很大的队列。
适当限制等待数量,反而有助于避免大量请求长期积压。
这里的 16 只是用于演示的小规模配置,并不是所有电脑都适用的最佳值。
7. 实战:同时发送两个请求,测试真正的并发能力
原理讲完,接下来直接测试。
这里我们不需要两台电脑,也不需要安装额外软件。
只使用一台 Windows 电脑,通过 PowerShell 同时发送两个请求,就能够观察 Ollama 的处理情况。
第一步:准备测试环境
首先确认模型存在:
ollama list本次示例使用:
qwen2.5:7b如果你电脑里没有这个模型,可以将后续代码中的模型名称替换为已经安装的其他模型。
为了方便普通读者照着操作,本文继续使用 Ollama 默认端口:
http://127.0.0.1:11434第二步:先设置单请求运行
在 PowerShell 中执行:
[Environment]::SetEnvironmentVariable(”OLLAMA_NUM_PARALLEL”,”1”,”User”)
彻底退出并重新启动 Ollama。
接着预加载模型:
ollama run qwen2.5:7b ””这样可以尽量减少首次加载带来的干扰。
第三步:通过 PowerShell 同时发送两个请求
打开 PowerShell,执行以下代码:
# 基础设置$base = ”http://127.0.0.1:11434”$model = ”qwen2.5:7b”# 定义每个请求要执行的任务$task = {param($base, $model, $prompt)$json = @{model = $modelprompt = $promptstream = $falsekeep_alive = ”30m”options = @{num_ctx = 4096num_predict = 256}} | ConvertTo-Json -Depth 5$body = [System.Text.Encoding]::UTF8.GetBytes($json)$sw = [Diagnostics.Stopwatch]::StartNew()$r = Invoke-RestMethod `-Uri ”$base/api/generate” `-Method Post `-ContentType ”application/json; charset=utf-8” `-Body $body `-TimeoutSec 600$sw.Stop()[PSCustomObject]@{Seconds = [math]::Round($sw.Elapsed.TotalSeconds, 2)Tokens = $r.eval_countTokensPerSecond = if ($r.eval_duration -gt 0) {[math]::Round($r.eval_count * 1e9 / $r.eval_duration, 2)} else { 0 }}}# 准备两个不同的问题$prompt1 = ”请列举五种提高学习效率的方法,并逐条解释。”$prompt2 = ”请列举五种降低电脑能耗的方法,并逐条解释。”# 开始计时$clock = [Diagnostics.Stopwatch]::StartNew()# 同时启动两个后台请求$job1 = Start-Job -ScriptBlock $task `-ArgumentList $base, $model, $prompt1$job2 = Start-Job -ScriptBlock $task `-ArgumentList $base, $model, $prompt2# 等待请求完成$jobs = @($job1, $job2)$jobs | Wait-Job | Out-Null$clock.Stop()# 查看两个请求的结果$jobs | Receive-Job# 查看全部完成时间Write-Host ”两个请求总耗时:” `$clock.Elapsed.TotalSeconds ”秒”# 清理后台任务$jobs | Remove-Job
代码看起来比较长,但实际上只做了三件事:
① 构造两个聊天请求。
两个请求使用同一个模型,但问题不同。
② 使用Start-Job同时发送。
PowerShell 会创建两个后台任务,让两个 HTTP 请求的执行时间尽可能重叠。
③ 等待全部完成并统计时间。
通过 Wait-Job 等待两个任务结束,然后查看各自耗时和整体完成时间。
这里需要特别解释几个参数。
Start-Job | |
Wait-Job | |
Receive-Job | |
Remove-Job | |
Stopwatch | |
stream = $false | |
num_predict = 256 |
这段代码并不会创建两个 Ollama 服务器。
两个 PowerShell 任务最终仍然访问同一个 Ollama 服务。
因此,我们测试的是同一个模型服务对并发请求的处理能力。
第四步:修改为两个并行请求
第一次实验完成后,修改环境变量:
[Environment]::SetEnvironmentVariable(”OLLAMA_NUM_PARALLEL”,”2”,”User”)
然后彻底退出 Ollama,重新启动,再次预加载模型。
接着重复运行刚才的测试代码。
两次实验唯一需要重点改变的配置,就是:
第一次:OLLAMA_NUM_PARALLEL = 1第二次:OLLAMA_NUM_PARALLEL = 2
这样就能够观察并行数量变化对实际请求处理的影响。
8. 怎样判断并发有没有效果?
建议把两次实验的结果整理成表格。
这里不预先填写结果,因为不同显卡、模型和上下文配置的测试表现可能相差很大。
我们需要关注两个问题。
问题一:两个请求的整体完成时间有没有缩短?
如果在 OLLAMA_NUM_PARALLEL=2 时,两个请求能够更充分地重叠执行,那么整体完成时间可能缩短。
但具体收益取决于计算资源是否充足。
问题二:单个请求的生成速度有没有下降?
这同样很重要。
假设一个模型单独运行时,GPU 资源已经基本被充分利用。
此时让两个请求同时运行,不一定能够让每个请求维持原来的 Token/s。
甚至可能出现:
整体处理能力有所改善,但单个请求的生成速度下降。
因此,评价并发能力时不能只看某一个请求的速度。
更合理的指标是:
整体吞吐量= 测试期间完成的总输出 Token 数量÷ 整体经过时间
另外,PowerShell 后台任务的启动也会产生少量额外开销。
如果希望实验更加可靠,建议多运行几次,交换两组测试的先后顺序,并保持模型、输入内容、上下文和其他运行设置一致。
需要注意,PowerShell 测得的请求总耗时包含客户端等待时间,而 Ollama 返回的 eval_duration 主要用于统计生成阶段。两者不应直接混为一谈。
9. 实际使用时,应该怎么设置?
对于普通个人电脑,我不建议一开始就把所有并发参数调得很高。
可以根据使用场景选择。
这些只是适合入门测试的起点,并不是通用的最优配置。
例如,某些拥有大内存的电脑,即使显卡显存不足,也可能利用 CPU/RAM 运行多个模型。
但此时瓶颈可能转移到 CPU 性能和内存带宽上。
因此,硬件资源丰富,并不代表并发数量可以无限提高。
一组适合小规模共享的起步配置
假设你的电脑主要运行一个模型,同时服务两台设备,可以先尝试:
# 单个模型最多处理两个并行请求[Environment]::SetEnvironmentVariable(”OLLAMA_NUM_PARALLEL”,”2”,”User”)# 最多同时加载一个模型[Environment]::SetEnvironmentVariable(”OLLAMA_MAX_LOADED_MODELS”,”1”,”User”)# 最多允许16个请求等待[Environment]::SetEnvironmentVariable(”OLLAMA_MAX_QUEUE”,”16”,”User”)
设置完成后,重新启动 Ollama。
这套配置的思路是:
保留一个主要模型,让它尽量同时服务两个请求,并限制过多请求积压。
如果后续需要同时使用多个不同模型,再根据显存容量调整 OLLAMA_MAX_LOADED_MODELS。
10. 常见问题
为什么设置了 OLLAMA_NUM_PARALLEL=2,两个请求还是很慢?
并发数量只是服务端允许的最大并行请求数,并不意味着硬件有足够资源让两个请求都快速运行。
如果模型本身已经占用了大量显存,增加并发可能进一步提高缓存占用和计算压力。
可以先通过:
ollama ps检查模型当前的运行位置和上下文配置。
两台电脑同时使用,需要启动两个 Ollama 吗?
不需要。
第二期已经介绍过 Ollama 的局域网共享。
只要服务器允许局域网访问,两台设备就可以连接同一个 Ollama 服务。
并行处理能力由运行模型的服务器负责。
不过,局域网访问与并发调度是两个不同概念:网络能够连接,并不保证请求一定会并行执行。
OLLAMA_NUM_PARALLEL=4,是不是最多只能有四个人使用?
不是。
这个参数控制的是单个模型同时处理请求的数量。
如果更多请求到达,其他请求可以进入等待队列,直到有处理能力可用。
是否允许继续排队,还取决于 OLLAMA_MAX_QUEUE 等设置。
为什么切换到另一个模型后,需要等待很久?
因为新模型可能尚未加载。
如果内存或显存不足以同时容纳多个模型,Ollama 可能需要等待已有模型空闲并卸载,然后再加载新模型。
所以,频繁切换多个大型模型,可能产生明显的等待时间。
11. 小结
这一期,我们主要理解了 Ollama 的三个并发调度参数。
OLLAMA_NUM_PARALLEL控制同一模型能够同时处理多少个请求。
OLLAMA_MAX_LOADED_MODELS控制最多允许同时加载多少个模型。
OLLAMA_MAX_QUEUE控制最多允许多少个请求等待处理。
它们分别对应:
并行处理、模型加载和请求排队。
实际使用时,应该根据电脑硬件和使用人数选择合适的配置,而不是简单地将每个参数调到最大。
尤其要记住:
并发能力提高,不等于单个请求一定更快。
对于只有一个用户的电脑,优先保证单请求性能通常更加重要。
而对于需要服务两三台电脑的本地 AI 服务器,适当提高并发能力,可能改善多人同时使用时的整体体验。
这一期,我们已经让 Ollama 从“一个人使用的聊天工具”,进一步走向了“能够同时处理多个请求的本地 AI 服务”。
不过,到目前为止,模型主要还是在回答问题。
如果希望它不仅能够聊天,还能够调用外部功能、处理实际任务,就需要用到另一个重要能力:
Tool Calling(工具调用)。
下一期,我们就来看看,如何让 Ollama 不只会回答问题,还能真正使用工具。















































































