-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Implement delayed evaluation for the cell executions happening before a kernel is set up #1002
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
Conversation
The test error is a known/fixed error involving jpg images, which I don't think is related to this PR. |
Poked tests now that IPython rc2 has fixed the test failures. I'm fine with this implementation. Did you want to tackle the two tasks you assigned yourself (test, better notification) in this PR? |
Yes. When are we hoping to release a new version? I'd really like it in the next version. |
The installation work going on in #879 is going to take some time, so I think it's a pretty safe bet that this can make it in. |
Perhaps this can be in a quicker bugfix release, presuming I finish it quickly? I've seen it cause people confusion and problems. |
4.2 seems like the right target. It should be pretty soon. |
5944b00
to
d8ff19d
Compare
After thinking about this more, I think the HoldingKernel approach/kludge should be scrapped and instead we should implement proper support for the notebook to queue cell evaluations until a kernel is available. |
Okay, new plan: implement buffering for kernel messages at the kernel level (eliminating the need to check to see if the kernel is connected), and then also implement cell execution buffering for when the kernel is not set in the notebook (if needed...) |
d8ff19d
to
5f56f30
Compare
17e6b4d
to
fc69067
Compare
@minrk, @SylvainCorlay, @Carreau - this is ready for review. |
fc69067
to
e2f397a
Compare
Notebook.prototype.execute = function (cell) { | ||
var executed = cell.execute(); | ||
if (!executed) { | ||
this.pending_execution.push(cell) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to add the same cell more than once?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in - if people execute the cell twice, it's added twice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make the case that since the text is not retrieved until the cell is actually executed, we should just move the cell to the end when it is executed and already is pending. Does that sound better? (i.e., you can't execute, change text, then execute again in the current model if the kernel isn't set, but you can if the kernel is set and just not connected.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that approach
@blink1073 - I can see the case for the 'move-to-the-end' behavior, and I can also see the case for it not being there. In the commit message, I give a case where the move-to-the-end behavior is surprising: "This may still give surprising results, for example, if cell 1 defines a variable and cell 2 increments and prints the variable. What do you think? |
I think the right thing to do might be to clear the queue after itself if you rerun the same cell, and clear the prompt on remaining cells, so it is clear which cells are actually pending. |
The kernel queue seems great. I'm less fond of the notebook queue, and adding a |
I'm also less fond of the notebook queue as well - that's where the tricky logic is. The problem, as you point out, is that the cell.kernel can be null, and I'm not sure when exactly it is going to be null. The basic usecase I'm trying to address is starting up a notebook and immediately executing cells before a kernel is set up. I'll look into it more to see if it's clear when the cell.kernel is set, and if it can be set earlier. Edit: I'm also tempted to go back to having a HoldingKernel as a good-enough solution, but I'd rather not go back to that. |
but yeah, a long-running cell that was, perhaps, displaying continuously running output, would be a case to handle. We could support the user pressing the interrupt button to interrupt such a computation. |
I would think pressing interrupt should clear the read-only and |
@blink1073 - I agree. That said, making a cell read-only while executing is a pretty drastic change (possibly for the better, though). The kinds of subtleties that we are discussing with the notebook cell queue probably don't come up all that often (i.e., executing cells, then re-executing some of them, possibly while editing them, all without a kernel/session started in the notebook). To be consistent with how execution works when the kernel is running, we should do (3) above. Since it's difficult to guess when the notebook will have a kernel set vs. not set, it sounds like (3) above would be the least surprising alternative. |
I can agree with (3), but we should discuss the read-only approach for JupyterLab. |
@blink1073 - agreed. |
(3) is only tricky for the case that the Kernel object hasn't yet been instantiated since the kernel queue ought to handle it without telling it anything about cells. A slow-starting kernel does not affect when the Kernel is instantiated, it only affects when the kernel_ready event fires and true execution can begin. Currently, the Kernel object is instantiated as soon as the session REST API returns, which is quite prompt. If we could do any of:
then the easy to follow queue on the kernel would be all we need. |
I should say that (3) is actually the only version that makes sense to me. Asking to execute a cell shouldn't change behavior depending on how long it takes, so (2) doesn't seem right for me. And I would expect it to be hard to avoid annoying flashes when toggling read-only during execution from whatever we use for a visual indication that it has become read-only, even if for just a fraction of a second. |
Okay. I'm just about finished with another take on the Holding kernel that we can set at the very start. If the rest api really does take a very short time to get back with a session/kernel object, then that's probably good enough for me. I'll check to see if it's okay. Or - how about I slim down this PR to just have the kernel queue, and see how that works in practice. If we need to do something more for when the kernel is not set, I'll revisit this issue. |
d0ddb98
to
a7b122f
Compare
I don't think it's so prompt. I tried delaying kernel startup by adding the following patch to ipykernel: diff --git a/ipykernel/__main__.py b/ipykernel/__main__.py
index d1f0cf5..adeb68a 100644
--- a/ipykernel/__main__.py
+++ b/ipykernel/__main__.py
@@ -1,3 +1,6 @@
if __name__ == '__main__':
+ from time import sleep
+ print('sleeping')
+ sleep(5)
from ipykernel import kernelapp as app
app.launch_new_instance() and the notebook now is unresponsive (even with the kernel message queue) for those 5 seconds. |
Oh, wait, never mind. I was testing the wrong thing... |
I like that idea a lot. It should be a big improvement no matter what, and then we can better see the tradeoff of the more complicated buffering on the cell or notebook as a separate change. |
@minrk - ready for review. This seems to solve my use-case. |
👍 |
Awesome, thanks @jasongrout! |
Implement delayed evaluation for the cell executions happening before a kernel is set up
Thank you! That took a lot longer than I thought to get right. |
…ns happening before a kernel is set up This is an attempt at taking care of #994. We implement two queues for cell executions. One is at the notebook level, to queue up executions when a kernel does not exist. Another is at the kernel level, to queue up messages when the kernel is not connected. *Edit: We scrapped the notebook-level queue, and now just have a kernel-level message queue for when the kernel isn't connected*
…xecutions happening before a kernel is set up This is an attempt at taking care of jupyter#994. We implement two queues for cell executions. One is at the notebook level, to queue up executions when a kernel does not exist. Another is at the kernel level, to queue up messages when the kernel is not connected. *Edit: We scrapped the notebook-level queue, and now just have a kernel-level message queue for when the kernel isn't connected*
This is an attempt at taking care of #994. We implement two queues for cell executions. One is at the notebook level, to queue up executions when a kernel does not exist. Another is at the kernel level, to queue up messages when the kernel is not connected.
Edit: We scrapped the notebook-level queue, and now just have a kernel-level message queue for when the kernel isn't connected