Pyinstaller打包部署在Win2008上的Bug排查之路

1.前言

python项目的部署工作基本是属于算法的最后阶段,同样也是最容易出现问题的阶段,毕竟IDE中的运行甚至debug都是可以直接给出问题,再加上开发机器的版本较新,也很少会出现各种各样的dll系统问题。win和linux部署相比,linux由于其系统相对较为简单,部署问题较少,但windows的部署所面临的bug则千奇百怪,尤其是较为老的服务器版本。

本次问题主要是算法库版本与windows服务器不兼容导致的,开发机使用了windows11,并且算法库均为最新版本;测试人员不够专业,没有使用与生产环境相同的测试环境;直到上线前期,不兼容问题出现,搜集了各类资料,最终定位解决。

2.系统环境信息

硬件环境
  • 处理器 12th Gen Intel® Core™ i5-12500H 3.10 GHz
  • 机带 RAM 32.0 GB (31.7 GB 可用)
  • 设备 ID B3E450C9-FC4F-4934-9ADC-C643A1484672
  • 产品 ID 00342-30616-35677-AAOEM
  • 系统类型 64 位操作系统, 基于 x64 的处理器
系统信息
  • 版本 Windows 11 家庭中文版
  • 版本号 24H2
  • 安装日期 ‎2024/‎12/‎27
  • 操作系统版本 26100.2605
  • 体验 Windows 功能体验包 1000.26100.36.0
生产服务器系统
  • 版本win2008 R2
开发阶段算法库版本
算法库 版本
pandas 2.2.0
numpy 1.26.4
lightgbm 4.4.0
pyinstaller 6.9.0
torch 2.3.0

4.Bug排查过程

1.问题发生--dll丢失

打包程序部署后,在win2008服务器上,系统报错丢失api-ms-win-core-path-l1-1-0.dll, 这Microsoft Windows 操作系统中的一个动态链接库(DLL)文件,主要与文件路径操作和路径管理相关。它是 Windows API(应用程序编程接口)的一部分,提供了一些核心功能,帮助 Windows 应用程序在操作系统中进行路径相关的操作。

2.dll丢失问题解决

DLL下载网站上下载这个库,分别放入C:\Windows\System32和C:\Windows\SysWOW64目录下,问题解决。此时运行框能够正常显示出来,表明dll确实问题已经解决,问题到这,都算是很简单的事件。

3.模型调用报错

紧接着,需要进行接口测试,传参后,程序报错,内容大致如下:

复制代码
0SError:[winError193]x1 不是有效的 Win32 应用程序。
Failed to load \lightghm\win\lib.Lightgbm.dll'. Most likely this dynlib/dll was not found when the applicat ion wfrozen

4.Pyinstaller降版本

最显眼的winError193故障报错,第一时间对此进行了排查(被这个故障报错干扰了判断),很多内容答案显示可能在 64 位 Windows 系统上尝试运行一个 32 位应用程序,或者反过来。比如,尝试用 32 位的应用程序加载 64 位的动态链接库(DLL),或者使用 64 位的程序加载 32 位的 DLL,会出现这个错误。

针对这个问题,重新下载了dll文件,并且使用了dll depends工具进行了相应排查,并没有发现任何问题。怀疑是Pyinstaller问题,将其降级到3.0+版本,并且重新进行了多次打包,问题没有解决。

5.lightgbm问题排查

由于winError193故障并没有找到有效的解决方案,开始怀疑是lightgbm的版本问题导致,并对此进行了相应的搜索,发现存在此类相关可能,经搜索,lightgbm可能不完全支持 Windows 2008 及其早期版本,这将会导致兼容性问题。

6.lightgbm降版本

经过搜集,针对windows2008的支持情况,选择了2.2.3版本的lightgbm,为了快速验证,构建了一个小项目进行打包测试,使用了lightgbm和torch,代码如下:

python 复制代码
import numpy as np
import lightgbm as lgb
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 1. 使用 LightGBM 进行分类任务
# 创建一个简单的二分类数据集
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 将数据转换为 LightGBM Dataset 格式
train_data = lgb.Dataset(X_train, label=y_train)
test_data = lgb.Dataset(X_test, label=y_test, reference=train_data)

# 设置 LightGBM 超参数
params = {
    'objective': 'binary',
    'metric': 'binary_error',
    'boosting_type': 'gbdt',
    'num_leaves': 31,
    'learning_rate': 0.05,
    'feature_fraction': 0.9,
}

# 训练 LightGBM 模型
lgb_model = lgb.train(params, train_data, valid_sets=[test_data], num_boost_round=100)

# 使用 LightGBM 模型进行预测
y_pred_lgb = lgb_model.predict(X_test)
y_pred_lgb = (y_pred_lgb > 0.5).astype(int)

# 评估 LightGBM 模型的准确度
accuracy_lgb = accuracy_score(y_test, y_pred_lgb)
print(f"LightGBM 分类模型准确率: {accuracy_lgb:.4f}")

# 2. 使用 PyTorch 构建神经网络进行回归任务
# 创建一个简单的回归数据集
X_reg, y_reg = make_classification(n_samples=1000, n_features=20, n_informative=5, n_classes=2, random_state=42)

# 划分训练集和测试集
X_train_reg, X_test_reg, y_train_reg, y_test_reg = train_test_split(X_reg, y_reg, test_size=0.2, random_state=42)

# 将数据转换为 PyTorch Tensor
X_train_tensor = torch.tensor(X_train_reg, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train_reg, dtype=torch.float32).view(-1, 1)
X_test_tensor = torch.tensor(X_test_reg, dtype=torch.float32)
y_test_tensor = torch.tensor(y_test_reg, dtype=torch.float32).view(-1, 1)

# 定义一个简单的神经网络
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(20, 64)
        self.fc2 = nn.Linear(64, 32)
        self.fc3 = nn.Linear(32, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 初始化模型,定义损失函数和优化器
model = SimpleNN()
criterion = nn.MSELoss()  # 由于是回归任务,使用均方误差损失
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练神经网络模型
epochs = 100
for epoch in range(epochs):
    model.train()
    optimizer.zero_grad()
    outputs = model(X_train_tensor)
    loss = criterion(outputs, y_train_tensor)
    loss.backward()
    optimizer.step()
    
    if (epoch + 1) % 10 == 0:
        print(f"Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}")

# 使用神经网络模型进行预测
model.eval()
with torch.no_grad():
    y_pred_nn = model(X_test_tensor)

# 计算模型的均方误差
mse = criterion(y_pred_nn, y_test_tensor)
print(f"神经网络回归模型均方误差: {mse.item():.4f}")

打包测试后发现,2.2.3版本的lightgbm能够正常运行在win2008上,说明lightgbm降版本可以解决当前的系统报错问题。

7.问题解决

lightgbm进行降版本,使用2.2.3版本,重新打包后,发到win2008的测试环境中测试,正常运行,正常建模,问题得到解决。

5.总结

1算法库版本与系统兼容性问题

  1. 在项目的部署过程中,算法库版本与生产环境的系统兼容性问题是常见的挑战。特别是在Windows 2008 R2服务器上部署现代算法库时,由于操作系统较旧且不再接收微软的更新,很多新的库和API可能无法正常工作。
  2. 例如,在此次部署中,开发环境中使用了较新的算法库版本(如lightgbm 4.4.0),而在Windows 2008服务器上,这些库可能存在兼容性问题,导致程序运行时出现报错(如dll丢失)。在这种情况下,选择适配服务器环境的较旧版本的算法库(如lightgbm 2.2.3)往往能够解决问题。
  3. 在进行生产环境部署时,确保开发环境与生产环境的一致性,包括操作系统和算法库版本的兼容性,对于顺利部署和避免不必要的技术障碍至关重要。

2.PyInstaller与系统环境的配合

  1. PyInstaller作为一个将Python程序打包为可执行文件的工具,尽管在现代开发环境中表现良好,但在老旧的操作系统上可能会遇到意外的兼容性问题。
  2. 在此次案例中,虽然PyInstaller被用于打包Python程序,但由于系统环境较为陈旧,导致报错(如winError193),这通常是因为32位与64位架构的不兼容所引起的。降级PyInstaller版本(如3.0+版本)并重新打包,未能直接解决问题。通过进一步排查发现,问题的根源在于使用的lightgbm版本与Windows 2008的兼容性。
  3. 在使用PyInstaller打包程序时,除了关注打包本身的设置外,还需要特别考虑目标服务器的操作系统版本及其支持的Python库版本,以确保打包后的程序能够在目标环境中正常运行。
相关推荐
Pan Zonghui11 小时前
GitHub Bug反馈与修复全流程指南
github·bug
初圣魔门首席弟子1 天前
bug 2026.05.15(以前能运行的java springboot项目突然间不能运行后台数据了)
java·开发语言·bug
Desenberg1 天前
【Claude Code】因为中途修改配置路径导致Claude Code 插件安装失败
windows·bug
QuestLab2 天前
维护 Hermes Agent CN 过程中的碎碎念,以及从bug上得到的一点点启发
bug
java修仙传2 天前
Java 实习日记:一次 Excel 导入校验 Bug 的定位与数据更新逻辑优化
java·数据库·bug·excel·后端开发
当战神遇到编程2 天前
软件测试基础入门:从 BUG 到测试用例设计完整指南
测试用例·bug
Bear on Toilet5 天前
3. BUG篇
bug
编程探索者小陈5 天前
【测试】之BUG篇
bug
棋宣5 天前
uni-app编译到微信小程序中,父传子props首次传递数据不接收的bug
微信小程序·uni-app·bug
wqdian_com5 天前
华为手机浏览器的一个bug
服务器·华为·bug