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

Scipy milp多进程优化后单进程再多进程执行挂起问题求助

SciPy milp 多进程挂起问题的原因与解决

问题现象

使用SciPy的milp求解混合整数线性规划时,单进程执行、首次多进程执行均正常,但按照「多进程执行→单进程执行→再次多进程执行」的顺序运行时,程序会无限挂起。复现代码如下:

import numpy as np
from multiprocessing import Pool

from scipy.optimize import LinearConstraint, milp

def task(identifier):
    c = -np.array([1., 2])
    A = np.array([[-1., 1], [-3, 2], [2, 3]])
    b_u = np.array([1., 12, 12])
    b_l = np.full_like(b_u, -np.inf)

    constraints = LinearConstraint(A, b_l, b_u)
    integrality = np.ones_like(c)

    res = milp(c=c, constraints=constraints, integrality=integrality)
    return res.x


with Pool() as pool:
    for result in pool.map(task, range(3)):
        print(f'Before: Got result: {result}')

print(task(4)) # 注释此行则程序正常,否则后续多进程会挂起

with Pool() as pool:
    for result in pool.map(task, range(3)):
        print(f'After: Got result: {result}')

环境版本:Python 3.10.11,NumPy 1.24.2,SciPy 1.11.3

原因分析

  • SciPy的milp底层依赖HiGHS求解器,该求解器首次初始化时会创建全局状态和线程相关资源。
  • 单进程调用milp后,这些全局资源未被正确清理;再次创建多进程时,Unix系统默认的fork机制会复制父进程的内存空间,包括HiGHS已初始化的全局状态。
  • HiGHS的全局状态并非进程安全,子进程继承后会引发资源竞争或死锁,最终导致程序挂起。

解决方法

方法1:调整执行顺序(临时简易方案)

如果业务逻辑允许,避免「多进程→单进程→多进程」的交替调用顺序。比如将所有单进程调用放在多进程执行之前,或者全部使用多进程完成计算。

方法2:使用spawn启动多进程(跨平台通用方案)

将多进程的启动方式改为spawn,这种方式会重新初始化Python解释器,不会继承父进程的全局状态,从根源上避免HiGHS的资源冲突。修改后的代码如下:

import numpy as np
from multiprocessing import Pool, set_start_method

from scipy.optimize import LinearConstraint, milp

def task(identifier):
    c = -np.array([1., 2])
    A = np.array([[-1., 1], [-3, 2], [2, 3]])
    b_u = np.array([1., 12, 12])
    b_l = np.full_like(b_u, -np.inf)

    constraints = LinearConstraint(A, b_l, b_u)
    integrality = np.ones_like(c)

    res = milp(c=c, constraints=constraints, integrality=integrality)
    return res.x

# 仅在主进程中调用一次,设置多进程启动方式为spawn
set_start_method('spawn')

with Pool() as pool:
    for result in pool.map(task, range(3)):
        print(f'Before: Got result: {result}')

print(task(4))

with Pool() as pool:
    for result in pool.map(task, range(3)):
        print(f'After: Got result: {result}')

注意:set_start_method必须在主进程中调用,且只能调用一次。

方法3:升级SciPy版本(长期修复方案)

该问题属于HiGHS求解器与多进程交互的兼容性问题,后续SciPy版本可能会修复此问题。可以尝试升级到最新版SciPy,验证是否解决挂起问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 09:15:33