Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interrupt execution of a script #64

Open
ch-hristov opened this issue May 17, 2016 · 19 comments
Open

Interrupt execution of a script #64

ch-hristov opened this issue May 17, 2016 · 19 comments
Labels
core Issues relating to core functionality (e.g. syntax)

Comments

@ch-hristov
Copy link

Is there a way to use a CancellationToken to interrupt the execution of a script?

@lafrank
Copy link

lafrank commented Jul 17, 2016

Yo can start script execution on a separate thread, then of course it is.

@ch-hristov
Copy link
Author

ch-hristov commented Jul 21, 2016

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 CompiledCodeobject. What's the general tactic to cancel it?

@slide
Copy link
Contributor

slide commented Jul 21, 2016

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
#64 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADaP0bPC_EXwVdZVdDOQLVkFEGDAwbeks5qX2O-gaJpZM4IgR0T
.

@KeithJRome
Copy link
Member

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.

@jdhardy
Copy link
Member

jdhardy commented Jul 21, 2016

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
#64 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGmdYUGIJDAMjFTYkilg5PtmCvG2qoeks5qX6FmgaJpZM4IgR0T
.

@lafrank
Copy link

lafrank commented Jul 22, 2016

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()

@KeithJRome
Copy link
Member

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.

@lafrank
Copy link

lafrank commented Jul 22, 2016

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.

@ch-hristov
Copy link
Author

ch-hristov commented Sep 1, 2016

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 = truemaybe 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 CompiledCodeobject 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 :)

@simo9000
Copy link

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.

@KeithJRome
Copy link
Member

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.

@simo9000
Copy link

@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.

@KeithJRome
Copy link
Member

@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.

@simo9000
Copy link

@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.

@slide
Copy link
Contributor

slide commented Dec 20, 2016

So can this be closed out, or do you want another solution?

@simo9000
Copy link

simo9000 commented Dec 20, 2016

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...

@ch-hristov
Copy link
Author

ch-hristov commented Dec 22, 2016

it would be cool to get an example on how to do that what you did @simo9000

@lafrank
Copy link

lafrank commented Dec 22, 2016 via email

@BCSharp BCSharp added the core Issues relating to core functionality (e.g. syntax) label May 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Issues relating to core functionality (e.g. syntax)
Projects
None yet
Development

No branches or pull requests

7 participants