ASP.NET Core中Com对象方法阻塞,单元测试可并行执行?
我之前也碰到过类似的Matlab COM对象在ASP.NET Core中无法并行执行的问题,结合你的场景来看,核心矛盾在于单元测试的线程模型和IIS/ASP.NET Core的运行环境差异,下面是具体的排查方向和解决办法:
1. COM 线程单元状态(STA/MTA)冲突
Matlab的MLApp COM对象本质是**单线程单元(STA)**组件,这类组件要求每个实例绑定到一个独立的STA线程。单元测试中,Task.Run虽然默认用MTA线程池线程,但.NET会自动为STA COM对象创建配套的STA线程来调度;而ASP.NET Core的请求处理线程默认是MTA,且IIS的STA线程池配额可能有限,导致多个COM请求排队等待可用的STA线程,最终串行执行。
修复方法:
显式在STA线程中初始化和调用Matlab对象。你可以修改MatlabRunner的构造逻辑,强制在STA线程中创建MLApp实例:
public class MatlabRunner : IDisposable { private MLApp.MLApp _matlab; private bool _disposed; public MatlabRunner() { if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) { var resetEvent = new ManualResetEvent(false); var staThread = new Thread(() => { _matlab = new MLApp.MLApp(); resetEvent.Set(); }); staThread.SetApartmentState(ApartmentState.STA); staThread.Start(); resetEvent.WaitOne(); } else { _matlab = new MLApp.MLApp(); } } public string Execute(string command) => _matlab.Execute(command); public void Quit() { _matlab?.Quit(); Marshal.ReleaseComObject(_matlab); _matlab = null; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) Quit(); _disposed = true; } ~MatlabRunner() => Dispose(false); }
同时,把接口方法改为异步,避免阻塞请求线程:
[HttpGet("Verify")] public async Task<JsonResult> Verify(string lot = null, string lotStatus = null, int? NumPorts = null, int? wafer = null) { File.AppendAllText(@"C:\Logs\log.txt", $"\nReceived Request! {DateTime.Now}\n"); var command = "pause(10)"; string result = ""; try { // 用Task.Factory.StartNew指定STA线程调度 result = await Task.Factory.StartNew(() => { using var runner = new MatlabRunner(); return runner.Execute(command); }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); } catch(Exception e) { File.AppendAllText(@"C:\Logs\log.txt", $"{e.StackTrace} | {e.InnerException} | {e.GetType()} | {e.Source} | {e.GetBaseException()}"); } finally { File.AppendAllText(@"C:\Logs\log.txt", $"\nQuit! {DateTime.Now}\n"); } return new JsonResult(result); }
2. IIS 线程池配额限制
IIS默认的STA线程池数量有限(通常是20左右),如果你的并行请求数超过这个配额,后续请求会排队等待。另外,工作线程数不足也会导致串行处理。
修复方法:
- 打开IIS管理器,找到你的应用程序池,右键选择高级设置
- 调整线程池参数:
- 把最大工作线程数从默认的100调至200+
- 把最小工作线程数对应调大(比如设为50)
- 如果有STA线程最大数量选项,设置为至少10(根据你的并行需求调整)
3. Matlab COM 对象的单实例复用
部分Matlab版本的COM对象默认会复用进程,即使你创建多个MLApp实例,实际也会指向同一个Matlab进程,导致命令串行执行。
修复方法:
检查任务管理器,当并行请求时是否生成了多个Matlab进程。如果只有一个,尝试强制创建新实例:
// 在MatlabRunner构造函数中替换MLApp初始化代码 var matlabType = Type.GetTypeFromProgID("Matlab.Application"); _matlab = (MLApp.MLApp)Activator.CreateInstance(matlabType, true);
4. IIS 应用程序池托管模式问题
如果你的应用程序池使用经典模式,会采用旧的ASP.NET线程模型,可能和COM对象的并行执行冲突。
修复方法:
把应用程序池的托管管道模式改为集成模式(ASP.NET Core推荐的运行模式)。
内容的提问来源于stack exchange,提问作者gfree

