进程与线程的关键区别

线程共享进程内的 Python 对象;独立进程有自己的地址空间。进程之间交换工作和结果,需要相应的传输机制,不能把一个普通全局列表当作天然共享列表。

实验沿用转换脚本的 conversion_worker 名称,把模型转换替换成平方计算,只观察 spawn、Pool 和 starmap。

import multiprocessing
import subprocess
import sys

def conversion_worker(value):
    return value * value

if __name__ == "__main__":
    ctx = multiprocessing.get_context("spawn")
    with ctx.Pool(2) as pool:
        print("pool", pool.starmap(conversion_worker, [(2,), (3,)]))
    result = subprocess.run(
        [sys.executable, "-c", "print('child')"],
        check=True, capture_output=True, text=True,
    )
    print("subprocess", result.stdout.strip())

下载并运行本节 example.py。只使用 Python 标准库;推荐 Python 3.12,最低 Python 3.11。

运行结果:

pool [4, 9]
subprocess child

starmap 把每一项参数元组展开传给 worker,并收集结果。入口保护让 spawn 启动的子解释器导入模块时,不会再次无限创建进程池。worker 放在模块顶层,也便于新进程按名称找到它。

Slime 里的对应职责

转换工具把权重分片交给进程池;部署代码用 multiprocessing.Process 启动路由或模型服务;subprocess 启动已有外部程序。它们都创建进程,但调用合同不同。

展开 Slime 源码:模型转换进程池

模型转换进程池
tools/convert_torch_dist_to_hf_parallel.py · L511–L530
快照 2f2318653f6f794dddd321eff7c9d4b7b174643f· 查看固定版本源码

    ctx = multiprocessing.get_context("spawn")
    with ctx.Pool(num_workers) as pool:
        results = pool.starmap(
            conversion_worker,
            [
                (
                    i,
                    key_chunks[i],
                    args,
                    megatron_args,
                    args.model_name,
                    state_dict_metadata_dict,
                    load_max_workers,
                    save_max_workers,
                )
                for i in range(num_workers)
            ],
        )

    final_weight_map = {}
展开 Slime 源码:_start_router

_start_router
slime/backends/sglang_utils/deployment.py · L49–L62
快照 2f2318653f6f794dddd321eff7c9d4b7b174643f· 查看固定版本源码

        router_args.disable_health_check = True

    logger.info(f"Launch router with args: {router_args}")

    process = multiprocessing.Process(
        target=run_router,
        args=(router_args,),
    )
    process.daemon = True
    process.start()
    time.sleep(3)
    assert process.is_alive()
    logger.info(f"Router launched at {router_ip}:{router_port}, Prometheus port: {router_args.prometheus_port}")
    return router_ip, router_port
机制执行什么结果怎样回来
Pool.starmapPython worker 函数进程池收集 Python 返回值
Process(target=...)一个指定的 Python 入口需要另行安排 Queue、Pipe、文件或其他通信
subprocess.run/Popen外部命令返回码、stdout、stderr 等

超时与退出不能混用

Popen.communicate(timeout=...) 超时不会自动替你杀死子进程;后续要明确终止、等待和收集输出。信号与进程组操作属于系统边界,也不能当作 asyncio Task.cancel 的同义词。

Slime 的 signal.alarm 超时和 fcntl.flock 文件锁是其他配套机制,平台适用范围需要单独核对。完整位置在用法索引中。

复述检查

await 不会把任务变成独立进程。进程池有自己的启动、通信和回收成本;同步的 starmap 等待也不能直接放进事件循环里就称为非阻塞。

语义核对:multiprocessing、subprocess。

本节对应的全部源码位置

下面把同类用法在 Slime 中的每个扫描位置接回本节讲解;点击文件名可查看完整源码快照。重复出现的 API 共用解释,具体输入与清理由所在函数决定。

展开本节 2 条源码记录
记录 / 讲解源码位置原代码
occ-002282
有接收者线索
tools/convert_torch_dist_to_hf_parallel.py:512
<module>
with ctx.Pool(num_workers) as pool:
occ-002283
有接收者线索
tools/convert_torch_dist_to_hf_parallel.py:513
<module>
results = pool.starmap(

专题首页 · 上一节 · 下一节:13 · Future、回调与跨线程事件循环 · 源码与教程对照 · 全部用法