feat: 批处理并发配置化 + 多进程 UI 开关

- config.toml 新增 [batch] 段(use_multi_process 默认 true、max_parallel_instances 默认 3)
- SystemConfig.BatchConfig 模型 + ConfigManager 解析/回写
- ResolveMaxParallelInstances 完全由配置驱动(无硬编码默认值):配置缺失/无效明确报错;
  use_multi_process=false 时并发 1(串行);环境变量可临时覆盖
- 批处理页签新增"使用多进程并行执行"开关(默认开启,绑定配置并保存)
- 部署目录 config.toml 手动追加 [batch] 段(default_config 是模板)

验证:2 项并行(配置并发 3)约 40s Completed,日志确认从 config 读取
This commit is contained in:
tian 2026-08-05 16:25:32 +08:00
parent 72d256e68e
commit db77b80cf7
6 changed files with 118 additions and 2 deletions

View File

@ -89,6 +89,15 @@ width_limit_meters = 3.0
# 别名树完整展示的最大层级深度0 = 仅根节点)
# 默认值 2即展示根节点 + 两层子节点
max_full_display_depth = 2
[batch]
# 是否启用多进程并行批处理(默认开启)
# 关闭时批处理串行执行(并发数视为 1
use_multi_process = true
# 并发副 Navisworks 实例数(范围 1-20默认 3
# 每个实例独立端口18778 起)与日志,用于剖面盒自动检测等任务加速
max_parallel_instances = 3
# 自定义物流类别
# 用于扩展内置类别,只需填写类别名称

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core.Animation;
using NavisworksTransport.Core.Collision;
using NavisworksTransport.Core.Config;
using NavisworksTransport.Core.Models;
using NavisworksTransport.Core.Services;
@ -154,11 +155,32 @@ namespace NavisworksTransport.Core
}
/// <summary>
/// 解析并行副实例数:环境变量 TRANSPORTPLUGIN_MAX_PARALLEL 可调1-20默认 3。
/// 解析并行副实例数:完全由 config.toml 的 [batch] 配置驱动use_multi_process + max_parallel_instances
/// 配置缺失/无效时明确报错(禁止 fallback 默认值);环境变量 TRANSPORTPLUGIN_MAX_PARALLEL 可临时覆盖(运维/测试)。
/// </summary>
private static int ResolveMaxParallelInstances()
{
int maxParallel = 3;
var batchConfig = ConfigManager.Instance.Current?.Batch;
if (batchConfig == null)
{
throw new InvalidOperationException("缺少批处理配置config.toml 的 [batch] 段未加载)");
}
if (!batchConfig.UseMultiProcess)
{
LogManager.Info("[批处理队列] 多进程已关闭config串行执行");
return 1;
}
if (batchConfig.MaxParallelInstances < 1 || batchConfig.MaxParallelInstances > 20)
{
throw new InvalidOperationException(
$"无效的并发实例数: {batchConfig.MaxParallelInstances}config.toml [batch] max_parallel_instances范围 1-20");
}
int maxParallel = batchConfig.MaxParallelInstances;
// 环境变量临时覆盖(运维/测试场景,显式设置才生效)
string raw = Environment.GetEnvironmentVariable("TRANSPORTPLUGIN_MAX_PARALLEL");
if (!string.IsNullOrWhiteSpace(raw) && int.TryParse(raw, out int parsed) && parsed >= 1 && parsed <= 20)
{

View File

@ -502,6 +502,17 @@ namespace NavisworksTransport.Core.Config
}
}
// 批处理配置(可选)
if (model.ContainsKey("batch"))
{
var batch = model["batch"] as TomlTable;
if (batch != null)
{
config.Batch.UseMultiProcess = GetBoolValueWithDefault(batch, "use_multi_process", true, missingItems);
config.Batch.MaxParallelInstances = GetIntValueWithDefault(batch, "max_parallel_instances", 3, missingItems);
}
}
// 加载自定义类别配置(可选)
if (model.ContainsKey("custom_category"))
{
@ -551,6 +562,7 @@ namespace NavisworksTransport.Core.Config
Logistics = new LogisticsConfig(),
CoordinateSystem = new CoordinateSystemConfig(),
AliasTree = new AliasTreeConfig(),
Batch = new BatchConfig(),
CustomCategories = new List<CustomCategoryConfigItem>()
};
}
@ -734,6 +746,17 @@ namespace NavisworksTransport.Core.Config
}
}
// 批处理配置回写
if (model.ContainsKey("batch"))
{
var batch = model["batch"] as TomlTable;
if (batch != null && config.Batch != null)
{
batch["use_multi_process"] = config.Batch.UseMultiProcess;
batch["max_parallel_instances"] = config.Batch.MaxParallelInstances;
}
}
// 更新自定义类别配置
// 注意由于Tomlyn对数组的处理限制自定义类别通过专门的API管理
// 这里不直接操作TOML模型而是在保存前通过模板合并

View File

@ -48,6 +48,11 @@ namespace NavisworksTransport.Core.Config
/// </summary>
public AliasTreeConfig AliasTree { get; set; }
/// <summary>
/// 批处理配置
/// </summary>
public BatchConfig Batch { get; set; } = new BatchConfig();
/// <summary>
/// 自定义类别列表
/// </summary>
@ -326,4 +331,20 @@ namespace NavisworksTransport.Core.Config
/// </summary>
public int MaxFullDisplayDepth { get; set; } = 2;
}
/// <summary>
/// 批处理配置
/// </summary>
public class BatchConfig
{
/// <summary>
/// 是否启用多进程并行批处理(默认开启;关闭时并发数视为 1串行执行
/// </summary>
public bool UseMultiProcess { get; set; } = true;
/// <summary>
/// 并发副 Navisworks 实例数(默认 3范围 1-20
/// </summary>
public int MaxParallelInstances { get; set; } = 3;
}
}

View File

@ -26,6 +26,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private BatchQueueStatus _statusFilter = BatchQueueStatus.All;
private string _progressText;
private bool _isExecuting;
private bool _useMultiProcess = true; // 默认开启,构造函数从配置加载
#endregion
@ -73,6 +74,27 @@ namespace NavisworksTransport.UI.WPF.ViewModels
set => SetProperty(ref _progressText, value);
}
/// <summary>
/// 是否启用多进程并行批处理(绑定 config.toml [batch] use_multi_process默认开启
/// </summary>
public bool UseMultiProcess
{
get => _useMultiProcess;
set
{
if (SetProperty(ref _useMultiProcess, value))
{
// 同步并保存到配置
var config = NavisworksTransport.Core.Config.ConfigManager.Instance.Current;
if (config?.Batch != null)
{
config.Batch.UseMultiProcess = value;
NavisworksTransport.Core.Config.ConfigManager.Instance.SaveConfig(config, notifyChange: false);
}
}
}
}
/// <summary>
/// 是否正在执行
/// </summary>
@ -134,6 +156,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
_queueItems = new ObservableCollection<BatchQueueItem>();
// 从配置加载多进程开关(默认开启)
var batchConfig = NavisworksTransport.Core.Config.ConfigManager.Instance.Current?.Batch;
if (batchConfig != null)
{
_useMultiProcess = batchConfig.UseMultiProcess;
}
// 初始化命令
ExecuteQueueCommand = new RelayCommand(async () => await ExecuteQueueAsync(), () => CanExecuteQueue);
StopExecutionCommand = new RelayCommand(StopExecution, () => true);

View File

@ -67,6 +67,18 @@ NavisworksTransport 批处理队列管理页签视图 - 采用与其他页签一
Foreground="{StaticResource NavisworksTextBrush}"
Margin="0,5,0,0"
TextWrapping="Wrap"/>
<!-- 多进程开关 -->
<StackPanel Orientation="Horizontal" Margin="0,8,0,0">
<CheckBox Content="使用多进程并行执行"
IsChecked="{Binding UseMultiProcess}"
FontSize="12"
Foreground="{StaticResource NavisworksTextBrush}"/>
<TextBlock Text="(并发数由 config.toml [batch] 配置)"
FontSize="10"
Foreground="{StaticResource NavisworksTextBrush}"
Margin="8,2,0,0"/>
</StackPanel>
</StackPanel>
</Border>