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

Excel Solver多循环耗时过长,求年度收益优化提速方案

提速Excel Solver循环求解年度收益最大化问题的可行方案

我明白你现在的痛点——用VBA循环调用Solver处理365天的小时数据,结果要跑4-5小时,确实太影响效率了。结合你的业务场景和现有代码,我整理了几个针对性的提速方案,你可以逐一尝试:

一、先优化VBA代码与Excel运行环境

这些都是立竿见影的小改动,不用调整核心逻辑:

  • 删除冗余的Solver设置:你的代码里连续调用了两次SolverOk,这完全是重复操作,直接删掉第二次调用,一次就足够初始化求解器设置了。每次SolverReset和SolverOk都有额外开销,能省则省。
  • 关闭屏幕刷新与事件触发:在循环开始前加上这两行代码,循环结束后再恢复:
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    ' 循环代码...
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    
    这能大幅减少Excel界面渲染的耗时,尤其是循环次数多的时候。
  • 禁用自动计算:如果你的工作表有大量联动公式,每次Solver求解后自动计算会拖慢速度。循环前设置:
    Application.Calculation = xlCalculationManual
    
    循环结束后改回xlCalculationAutomatic,甚至可以在每次SolverSolve后只手动计算必要的区域(比如Range("V13").Calculate),而不是全表计算。

二、优化Solver引擎与参数

这是影响求解速度的核心因素:

  • 检查是否可以切换到线性求解器:如果你的收益-成本约束和目标函数都是线性的(没有平方、指数、对数这类非线性运算),直接把Engine:=1改成Engine:=2(单纯形LP引擎)。线性求解器的速度比GRG非线性快得多,单次求解时间可能直接砍到原来的1/5甚至更少,这是最值得优先验证的点!
  • 调整GRG非线性引擎的参数:如果必须用非线性引擎,调用SolverOptions来优化迭代效率,比如:
    SolverOptions Convergence:=0.001, Iterations:=1000, AutoScale:=False
    
    适当提高收敛阈值(比如从默认的0.0001调到0.001)可以减少不必要的迭代次数;如果你的数据量级稳定,关闭自动缩放也能节省时间。

三、优化数据结构与求解逻辑

  • 用固定小工作表承载单日模型:每次在大表中动态定位行号,Solver需要额外解析引用地址。你可以新建一个名为DailyModel的小工作表,把单日的输入数据(G、D列等)复制到这个表的固定区域,约束和变量都用这个表的固定单元格引用。循环时只需要更新DailyModel的数据,调用Solver求解后再把结果复制回原表对应行。这样能减少Solver解析动态引用的开销。
  • 尝试批量处理多天数据(业务允许的话):如果相邻几天的决策没有跨天约束(比如没有库存结转、产能累积这类关联),可以尝试合并几天(比如7天)作为一个求解单元,减少循环次数。不过这得看你的业务逻辑是否允许,要是每天决策完全独立,这步收益不大,但如果有部分共享约束,能有效减少总求解时间。

四、切换到Python方案(长期最优解)

你之前说没找到有效的Python实现,其实用scipy.optimize就能完美替代Excel Solver,而且速度快很多,还能并行处理。给你一个简化的框架:

线性场景示例代码(如果你的模型是线性的)

import pandas as pd
from scipy.optimize import linprog
from joblib import Parallel, delayed  # 用来并行处理,提速更明显

# 读取年度数据
df = pd.read_excel('你的数据文件.xlsx')

# 定义单日求解函数
def solve_single_day(day_data, f3_val, f6_val, f12_val):
    # 目标函数:最大化收益,转成最小化负收益(linprog默认求最小)
    # 这里需要替换成你V13单元格对应的收益计算公式,把它拆解成变量H、I、J的线性组合
    c = -day_data['收益计算系数'].values  # 示例,实际要根据你的公式推导
    
    # 整理约束条件:A_ub @ x <= b_ub,A_eq @ x = b_eq
    A_ub = []
    b_ub = []
    
    # H <= G 的约束:x0 <= G值
    for g in day_data['G']:
        A_ub.append([1, 0, 0])
        b_ub.append(g)
    
    # I <= D 且 I >=0 的约束
    for d in day_data['D']:
        A_ub.append([0, 1, 0])
        b_ub.append(d)
    A_ub.append([0, -1, 0])
    b_ub.append(0)
    
    # J <= F3、J <= M、J >=0 的约束
    for m in day_data['M']:
        A_ub.append([0, 0, 1])
        b_ub.append(min(f3_val, m))
    A_ub.append([0, 0, -1])
    b_ub.append(0)
    
    # 其他约束(比如N列、O列的约束)按同样逻辑整理
    
    # 变量边界
    bounds = [(0, None), (0, None), (0, None)]  # H、I、J的上下限,根据实际调整
    
    # 求解
    res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method='highs')
    return res.x

# 读取全局参数(F3、F6、F12这些固定值)
f3 = df.loc[2, 'F']  # 假设F3在第3行F列,实际根据你的表调整
f6 = df.loc[5, 'F']
f12 = df.loc[11, 'F']

# 按天拆分数据(每24行一天)
daily_blocks = [df.iloc[i:i+24] for i in range(0, len(df), 24)]

# 并行求解(用所有CPU核心,速度翻倍)
results = Parallel(n_jobs=-1)(delayed(solve_single_day)(block, f3, f6, f12) for block in daily_blocks)

# 把结果写回原表
for idx, block in enumerate(daily_blocks):
    df.loc[block.index, ['H', 'I', 'J']] = results[idx]

# 保存结果
df.to_excel('求解结果.xlsx', index=False)

如果是非线性模型,就用scipy.optimize.minimize,定义好目标函数和约束条件即可。Python的优势在于,求解器效率更高,还能并行处理365天的数据,把总耗时压缩到几十分钟甚至更短。

优先建议你先尝试前两步(VBA优化+切换线性引擎),这两步不需要改太多代码,就能快速看到效果;如果还是达不到预期,再考虑数据结构优化或者切换到Python方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:51:26