终止IronPython脚本
这可能不完全是一个关于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(),但它的行为稍微有点不同:
- 如果你的Python脚本没有使用
Thread.Sleep()
,那么它不会停止你的脚本; - 看起来你不能对同一个
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()