Unity中启动外部进程如何避免编辑器冻结并读取输出?
解决Unity调用外部进程时编辑器冻结的问题
你的问题出在同步读取标准输出上:motion.StandardOutput.ReadLine()是阻塞式调用,当外部进程没有输出时,这个方法会卡住Unity的主线程,直接导致编辑器冻结——哪怕你在单独线程启动进程,读取操作还是在Update(主线程)里执行的,根本没解决阻塞问题。
以下是可行的解决方案,核心思路是异步读取外部进程输出,再把数据传到主线程处理:
using UnityEngine; using System; using System.Collections.Concurrent; using System.Diagnostics; public class StdIOHandler : MonoBehaviour { // 线程安全队列,存储外部进程输出的数据 private readonly ConcurrentQueue<string> _outputQueue = new ConcurrentQueue<string>(); private Process _externalProcess; void Start() { try { _externalProcess = new Process(); _externalProcess.StartInfo.CreateNoWindow = true; _externalProcess.StartInfo.RedirectStandardOutput = true; _externalProcess.StartInfo.UseShellExecute = false; _externalProcess.StartInfo.FileName = "cmd.exe"; string batPath = @"C:\Users\gummi\Desktop\hallow3\motion\demo\motion.bat"; _externalProcess.StartInfo.Arguments = $"/c \"{batPath}\""; // 给路径加引号,避免空格导致命令执行失败 // 绑定输出接收事件,异步处理外部进程输出 _externalProcess.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { _outputQueue.Enqueue(e.Data); } }; // 允许进程触发事件 _externalProcess.EnableRaisingEvents = true; // 启动进程并开始异步读取输出 _externalProcess.Start(); _externalProcess.BeginOutputReadLine(); } catch (Exception e) { Debug.LogError($"启动进程失败: {e.Message}"); } } void Update() { // 主线程从队列批量取数据,无阻塞 while (_outputQueue.TryDequeue(out string data)) { Debug.Log($"收到外部数据: {data}"); } } void OnDestroy() { // 清理资源,防止外部进程残留 if (_externalProcess != null && !_externalProcess.HasExited) { _externalProcess.Kill(); } _externalProcess?.Dispose(); } }
关键改动说明:
- 使用
ConcurrentQueue存储输出:保证多线程读写的安全性,因为输出事件是在后台线程触发的。 - 绑定
OutputDataReceived事件:外部进程有输出时自动触发,异步读取不会阻塞主线程。 - 调用
BeginOutputReadLine():启动系统级的异步读取流程,无需手动管理线程。 - 在
Update中批量处理队列数据:主线程安全调用Unity API,避免跨线程操作日志的问题。 - 增加
OnDestroy清理逻辑:防止Unity停止运行后,外部进程在后台残留。
内容的提问来源于stack exchange,提问作者MuSolar
相关产品推荐
相关产品推荐

