You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于现有多进程代码实现单Inference Session多线程并行推理?

多线程处理ONNX推理会话的实现问题

我想要编写多线程代码,创建一个推理会话(Inference Session)并同时处理多张图像。目前找到的代码是用多进程实现的,想问下multiprocessing.Process类有没有相关参数能实现多线程需求,还是需要在其中引入多线程类?基于下面给出的代码,具体该怎么操作?

import onnxruntime as ort
import numpy as np
import multiprocessing as mp


def init_session(model_path):
    EP_list = ['CUDAExecutionProvider', 'CPUExecutionProvider']
    sess = ort.InferenceSession(model_path, providers=EP_list)
    return sess


class PickableInferenceSession:  # 这是一个包装类,用于让当前的InferenceSession类可被序列化
    def __init__(self, model_path):
        self.model_path = model_path
        self.sess = init_session(self.model_path)

    def run(self, *args):
        return self.sess.run(*args)

    def __getstate__(self):
        return {'model_path': self.model_path}

    def __setstate__(self, values):
        self.model_path = values['model_path']
        self.sess = init_session(self.model_path)


class IOProcess(mp.Process):
    def __init__(self):
        super(IOProcess, self).__init__()
        self.sess = PickableInferenceSession('model.onnx')

    def run(self):
        print("calling run")
        print(
            self.sess.run({}, {
                'a': np.zeros((3, 4), dtype=np.float32),
                'b': np.zeros((4, 3), dtype=np.float32)
            }))
        #print(self.sess)


if __name__ == '__main__':
    mp.set_start_method(
        'spawn')  # 这一点很重要,必须放在name==main代码块内
    io_process = IOProcess()
    io_process.start()
    io_process.join()

解答

核心结论

multiprocessing.Process本身是多进程实现,没有参数可以直接转成多线程。要实现多线程需求,要么直接改用threading.Thread类,要么在进程内部结合多线程使用。另外要注意:ONNX Runtime的InferenceSession本身并非线程安全,多线程共享会话时需要通过配置控制并行策略,避免资源冲突。

方案1:直接改用多线程(推荐单会话多场景)

不需要原代码中的序列化包装类,多线程共享同一进程内存,可直接复用推理会话实例:

import onnxruntime as ort
import numpy as np
import threading

def init_session(model_path):
    EP_list = ['CUDAExecutionProvider', 'CPUExecutionProvider']
    # 配置会话并行参数,避免多线程冲突
    sess_options = ort.SessionOptions()
    sess_options.inter_op_num_threads = 1  # 算子间并行设为1,避免多线程抢占资源
    sess_options.intra_op_num_threads = 4  # 算子内并行数,根据CPU核心数调整
    return ort.InferenceSession(model_path, sess_options=sess_options, providers=EP_list)

# 单张图像处理逻辑
def process_image(sess, image_data):
    result = sess.run({}, image_data)
    print(f"线程{threading.current_thread().name}处理完成,结果:{result}")

if __name__ == '__main__':
    # 初始化共享的推理会话
    model_path = 'model.onnx'
    sess = init_session(model_path)

    # 模拟多张待处理图像数据
    image_list = [
        {'a': np.zeros((3, 4), dtype=np.float32), 'b': np.zeros((4, 3), dtype=np.float32)},
        {'a': np.ones((3, 4), dtype=np.float32), 'b': np.ones((4, 3), dtype=np.float32)},
        {'a': np.random.rand(3,4).astype(np.float32), 'b': np.random.rand(4,3).astype(np.float32)}
    ]

    # 创建并启动多线程
    threads = []
    for idx, img_data in enumerate(image_list):
        thread = threading.Thread(target=process_image, args=(sess, img_data), name=f"Thread-{idx+1}")
        threads.append(thread)
        thread.start()

    # 等待所有线程执行完毕
    for thread in threads:
        thread.join()

    print("所有图像处理完成")

方案2:进程内结合多线程(适合多CPU核心场景)

如果需要保留多进程架构(比如利用独立CPU核心),可以在每个进程内部启动多线程处理图像批次:

import onnxruntime as ort
import numpy as np
import multiprocessing as mp
import threading

def init_session(model_path):
    EP_list = ['CUDAExecutionProvider', 'CPUExecutionProvider']
    sess_options = ort.SessionOptions()
    sess_options.inter_op_num_threads = 1
    sess_options.intra_op_num_threads = 2
    return ort.InferenceSession(model_path, sess_options=sess_options, providers=EP_list)

# 进程内的线程处理逻辑
def process_image_in_thread(sess, img_data):
    result = sess.run({}, img_data)
    print(f"进程{mp.current_process().name}的线程{threading.current_thread().name}处理完成:{result}")

class IOProcess(mp.Process):
    def __init__(self, image_batch):
        super().__init__()
        self.image_batch = image_batch
        self.sess = None

    def run(self):
        # 进程内初始化推理会话
        self.sess = init_session('model.onnx')
        # 启动多线程处理当前批次图像
        threads = []
        for idx, img_data in enumerate(self.image_batch):
            thread = threading.Thread(target=process_image_in_thread, args=(self.sess, img_data), name=f"Thread-{idx+1}")
            threads.append(thread)
            thread.start()
        for thread in threads:
            thread.join()

if __name__ == '__main__':
    mp.set_start_method('spawn')
    # 拆分图像为两个批次,分配给不同进程
    image_list = [
        {'a': np.zeros((3,4), np.float32), 'b': np.zeros((4,3), np.float32)},
        {'a': np.ones((3,4), np.float32), 'b': np.ones((4,3), np.float32)},
        {'a': np.random.rand(3,4).astype(np.float32), 'b': np.random.rand(4,3).astype(np.float32)},
        {'a': np.full((3,4), 2.0, np.float32), 'b': np.full((4,3), 2.0, np.float32)}
    ]
    batch1 = image_list[:2]
    batch2 = image_list[2:]

    # 启动两个进程
    p1 = IOProcess(batch1)
    p2 = IOProcess(batch2)
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print("所有进程的线程处理完成")

内容的提问来源于stack exchange,提问作者Johnzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 13:25:36