ironpython3
ironpython3 copied to clipboard
Interrupt execution of a script
Is there a way to use a CancellationToken to interrupt the execution of a script?
Yo can start script execution on a separate thread, then of course it is.
It's on a separate thread than the main, but as much as I saw there's no built in way to provide a cancellation token to the Execute()
method of CompiledCode
object. What's the general tactic to cancel it?
Maybe we want to add an ExecuteAsync, or BeginExecute or something.
On Thu, Jul 21, 2016 at 5:19 AM Hristo Hristov [email protected] wrote:
It's on a separate thread than the main, but as much as I saw there's no built in way to provide a cancellation token to the Execute() method of ScriptingEngine. What's the general tactic to cancel it?
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/IronLanguages/ironpython3/issues/64#issuecomment-234236908, or mute the thread https://github.com/notifications/unsubscribe-auth/AADaP0bPC_EXwVdZVdDOQLVkFEGDAwbeks5qX2O-gaJpZM4IgR0T .
Passing a token to it wouldn't really accomplish much - you still need to inspect the token from the script code and abort (CancellationToken is a cooperative yielding mechanism, not pre-emptive).
I would just publish the cancellation token into your script's context dictionary and allow scripts to call ThrowIfCancellationRequested()
or perform more graceful aborts if necessary. Otherwise, requesting cancellation on the token's source will not really do anything.
One option would be to have an easy way to inject a KeyboardInterrupt (i.e. Ctrl-C) into a running script. I have a funny feeling there's already a way to do this (so that ipy.ee can generate KeyboardInterrupt when ^C is pressed), but maybe it was one of those ideas I never got around to finishing.
On Thu, Jul 21, 2016 at 9:42 AM, Keith Rome [email protected] wrote:
Passing a token to it wouldn't really accomplish much - you still need to inspect the token from the script code and abort (CancellationToken is a cooperative yielding mechanism, not pre-emptive).
I would just publish the cancellation token into your script's context dictionary and allow scripts to call ThrowIfCancellationRequested() or perform more graceful aborts if necessary. Otherwise, requesting cancellation on the token's source will not really do anything.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/IronLanguages/ironpython3/issues/64#issuecomment-234312062, or mute the thread https://github.com/notifications/unsubscribe-auth/AAGmdYUGIJDAMjFTYkilg5PtmCvG2qoeks5qX6FmgaJpZM4IgR0T .
I am not sure whether you want to cancel the running script from within the script or from the hosting environment. On the other hand, why do you want to use CancellationToken and not calling Thread.Abort() instead and handle ThreadAbortException as you need ?
Option 1, cancelling from script : you could add the Thread.CurrentThread object of the thread called Execute() to the script context as a variable. Then from python the script call its Abort() method. Something like this :
try
{
//...
ScriptScope execScope = PyEngine.CreateScope();
ScriptScope .SetVariable("ExecThread", Thread.CurentThread);
PyEngine.Execute(execScope);
//...
}
catch (ThreadAbortException Ex)
{
// cleanup code
}
And from Python script :
ExecThread.Abort()
Option 2, from hosting application : simply call Abort() method of the thread called Execute()
Thread.Abort()
is pre-emptive and a pretty nasty last-ditch thing to do. And it won't give you the expected result if the script spawns any other threads, submits background work using TP.QUWI or uses async completions (which can resume on other threads in the threadpool) - either directly or indirectly.
Yeah, I know it's a nasty way but I do not have any better idea, and for simple scripts it works. I believe, the ultimate solution could be some method of signaling if IronPython supported it. I mean like calling Engine.Abort()...whatever it would do internally.
I want to resurrect the discussion here...I don't want to deal with Thread.Abort()
and all the nasty things that it could leave ( e.g unallocated resources ).. Maybe there should be a built in way to do this with IronPython .. telling the CompiledCode.Cancel
= true
maybe will break the execution of the script if its active by pushing sys.exit() in the execution stack? I also don't want to tell to the users that they should always check if the task in the hosting environment has been cancelled or not it's very annoying.
PS.My scripts aren't simple..they consist of around 1k lines of code each so you can imagine how tedious it would be to check on every occasion if the task has been cancelled or not..
Edit 2 : @lafrank you could pass the cancellation token , the problem is that you still need to check it everytime you do something in your script
Edit 3 : I'm really expecting to pass my cancellation token to the execute method of the CompiledCode
object and have it stop when I tell it to stop. Isn't there a way to hook before python performs any operation?
Edit 4 : You could subscribe to C# object event and sys.exit() when the event is invoked :)
I would love to see this feature added. I have an application that uses IronPython to execute user provided scripts so graceful exit hooks within the script are not an option. I want to add a "Stop" button to terminate the execution of any script at an arbitrary point and Thread.Abort
is to ugly.
You could always use sys.settrace()
to install your own per-statement trace handler function (from the C# side), and decide whether to let the script continue execution. It's a pretty simple thing to do, and might give you just enough control to do what you want.
@KeithJRome I just gave the sys.settrace()
idea a try. It "works" but it is not providing per-statement trace handling but rather per-scope handling. The python documentation indicates this:
The trace function is invoked (with event set to 'call') whenever a new local scope is entered
To confirm, I attempted to interrupt the following two scripts using a handler via sys.settrace()
:
import time
time.sleep(3)
print('done')
and
import time
def sleep():
time.sleep(3)
def p():
print('done')
sleep()
p()
I was not able to prevent the print statement in the first script but was able to interrupt the second one. I think sys.settrace()
is better than nothing but I still think a true per-statement handler or a CancellationToken would be a nice feature to stop a script dead in it's tracks without resorting to Thread.Abort.
@simo9000 try using the 'line' event. That's the event I've used before to suspend running code on "breakpoints" in a custom debugger IDE.
@KeithJRome thanks for pushing me to understand sys.settrace()
better. It turns out I was not returning anything from my handler so tracing behavior was not as I excepted. I now have a configuration that does exactly what I expect it to.
So can this be closed out, or do you want another solution?
I'm good with the sys.settrace()
option. I don't think it should be embedded in the library since tracing will have a performance impact. I only wanted it in a debug context where performance can be sacrificed for enhanced control. I like the option @KeithJRome helped steer me to since i can toggle it on and off based on the execution context.
However, it was @juno-craft that asked for the feature originally...
it would be cool to get an example on how to do that what you did @simo9000
I'd also appreciate seeing an example of how to stop the script gracefully from the traceback handler. I write a .Net app in c# for hosting Python scripts and do use a traceback handler for debugging it, but I have no idea how to stop the script from within the handler. Well, except Thread.Abort() :-)
On Thu, Dec 22, 2016 at 10:47 AM, juno-craft [email protected] wrote:
it would be cool if to get an example on how to do that what you used @simo9000 https://github.com/simo9000
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/IronLanguages/ironpython3/issues/64#issuecomment-268760853, or mute the thread https://github.com/notifications/unsubscribe-auth/AO-XZLyTV8v_tEjV2jhpfANC2gdn57M9ks5rKkcigaJpZM4IgR0T .
https://github.com/simo9000/Consola/blob/editor/Consola/Library/scriptSession.cs