终止IronPython脚本

2 投票
2 回答
4284 浏览
提问于 2025-04-17 23:57

这可能不完全是一个关于IronPython的问题,所以也许有其他Python开发者能帮忙。

我想在我的.Net桌面应用程序中使用IronPython来运行Python脚本,并希望给用户一个强制终止脚本的功能。以下是我的测试脚本(我刚开始学Python,所以可能不太正确):

import atexit
import time
import sys

@atexit.register
def cleanup():
    print 'doing cleanup/termination code'
    sys.exit()

for i in range(100):
    print 'doing something'
    time.sleep(1)

(注意,我可能想在某些脚本中指定一个“atexit”函数,这样它们可以在正常或强制终止时进行一些清理工作)。

在我的.Net代码中,我使用以下代码来终止脚本:

_engine.Runtime.Shutdown();

这导致脚本的atexit函数被调用,但脚本实际上并没有终止——for循环仍然在继续。有几个其他的StackOverflow文章(这里这里)说sys.exit()应该可以解决这个问题,那我到底漏掉了什么呢?

2 个回答

0

看起来如果你在使用“.NET 5”或更高版本,那么终止Thread可能会有点问题。

Thread.Abort()在“.NET 5”或更高版本上是不被支持的,会抛出PlatformNotSupportedException这个错误。你可能会找到一个解决方案,使用Thread.Interrupt(),但它的行为稍微有点不同:

  1. 如果你的Python脚本没有使用Thread.Sleep(),那么它不会停止你的脚本;
  2. 看起来你不能对同一个Thread调用Abort两次,但你可以对它调用Interrupt两次。所以,如果你的Python脚本使用了finally块或者“上下文管理器”,你可以通过调用Thread.Interrupt()两次(中间加点延迟)来中断它。
2

看起来,想要友好地终止一个正在运行的脚本是比较困难的。一个我见过的方法是把IronPython引擎放在另一个线程里,如果需要停止脚本,就中止这个线程。

不过我不太喜欢这种粗暴的方法,因为这样可能会导致脚本使用的资源(比如文件)没有被正确关闭。

最后,我创建了一个这样的C#辅助类:-

public class HostFunctions
{
    public bool AbortScript { get; set; }

    // Other properties and functions that I want to expose to the script...
}

当主应用程序想要终止脚本时,它会把AbortScript设置为true。这个对象会通过作用域传递给正在运行的脚本:-

_hostFunctions = new HostFunctions();
_scriptScope = _engine.CreateScope();
_scriptScope.SetVariable("HostFunctions", _hostFunctions);

在我的脚本中,我只需要在合适的地方放置检查,看看是否请求了中止,然后做出相应的处理,比如:-

for i in range(100):
    print 'doing something'
    time.sleep(1)
    if HostFunctions.AbortScript:
        cleanup()

撰写回答