Python.NET 3.0.0下C#控制台程序Ctrl+C无法触发问题求助
问题描述
我使用Python.NET 3.0.0从C#控制台程序中执行Python脚本,核心代码如下:
执行Python脚本的代码
public void executePy { using (Py.GIL()) { var pythonThreadID = PythonEngine.GetPythonThreadID(); _pythonThreadIds.Add(pythonThreadID); var scope = Py.CreateScope(); var file = PythonEngine.Compile(fileContent); scope.Execute(file); dynamic mod = scope.Get("data"); mod(abc); } }
上述代码每60秒循环运行一次。
中断Python线程的代码
public async stopThreads() { if (_pythonThreadIds.Count > 0) { foreach (var id in _pythonThreadIds) { using (Py.GIL()) { PythonEngine.Interrupt(id); } } PythonEngine.EndAllowThreads(_state); PythonEngine.Shutdown(); } }
基类触发停止的代码
public async Task StopThreadClasses() { try { // cancel all running processes _cts.Cancel(); foreach (ITB obj in _commandBaseClasses) { await obj.Stop(); } } catch (Exception ex) { //log_message } finally { _cts.Dispose(); } }
问题现象:当控制台程序循环执行executePy代码时,Ctrl+C无法被程序识别;仅运行C#代码、未触发Python线程时,Ctrl+C可正常识别并终止线程。每个类的StopThreads函数会在用户按下Ctrl+C时触发,但当前场景下未生效。
排查建议
- 检查GIL持有对信号处理的阻塞:Python的GIL会阻塞操作系统信号(包括Ctrl+C触发的SIGINT),如果
executePy中mod(abc)执行耗时久且持续持有GIL,会导致C#主线程无法及时响应Ctrl+C。建议将Python执行逻辑改为非阻塞调用,或者在Python脚本中添加信号捕获逻辑,定期检查中断标志。 - 验证
PythonEngine.Interrupt的有效性:Interrupt需要目标Python线程处于可中断状态(比如执行Python字节码的间隙),如果mod(abc)是纯原生扩展调用(无Python字节码执行),Interrupt可能失效。可以在Python脚本中插入time.sleep(0.1)这类会释放GIL的操作,让线程有机会响应中断。 - 确认
_state变量的正确性:PythonEngine.EndAllowThreads(_state)中的_state必须是BeginAllowThreads返回的有效状态对象,若未正确初始化或已释放,会导致该行代码失效,甚至引发异常阻止后续Shutdown执行。 - 检查Ctrl+C信号处理优先级:C#控制台的Ctrl+C信号处理可能被Python的信号逻辑覆盖,可在C#代码中显式注册
Console.CancelKeyPress事件,确保事件处理程序优先获取控制权,比如在处理逻辑中先强制终止Python线程,再执行后续停止操作。 - 排查
_pythonThreadIds的准确性:确保每次执行executePy时添加的线程ID是当前活跃的Python线程ID,无重复添加或未移除已结束的线程ID。若线程ID无效,Interrupt调用不会产生效果。 - 验证异步停止逻辑的等待有效性:
stopThreads是异步函数,需确认基类StopThreadClasses中await obj.Stop()确实等待了stopThreads执行完成,避免因未等待导致中断操作不彻底。 - 调整
PythonEngine.Shutdown的执行时机:Shutdown会彻底关闭Python引擎,需确保所有Python线程已被中断并退出后再调用,否则可能导致资源泄漏或阻塞。
内容的提问来源于stack exchange,提问作者qwerty
相关产品推荐
相关产品推荐

