Defer debugpy and psutil imports until they are actually needed - #1543
Defer debugpy and psutil imports until they are actually needed#1543Carreau wants to merge 1 commit into
Conversation
Both imports were paid for on every kernel startup even though most sessions never debug or ask for usage information. * `IPythonKernel.debugger` is now a lazily-created property; the debugger (and the debugpy import) is only built on the first debug request. `poll_stopped_queue` is scheduled at that point rather than in `start()`. * `debugger_class` was a `Type` trait, which traitlets resolves — and therefore imports — as soon as the kernel is instantiated. It is replaced by a plain `debugger_class_name` string; `debugger_class` remains as a deprecated property, and subclasses still overriding it keep working with a DeprecationWarning. * `psutil` is imported through `_get_psutil()`, which caches the (possibly None) result on first use. On a local test (where I have optimisation in IPython and traitlets as well), this brings the startup time from 220ms to 170ms
722618c to
ac6ca05
Compare
|
CI failure will be taken care of by #1544 |
They still get paid at every kernel startup after this PR. The debugger information is needed at the latest when generating The import time of A benchmark showing the benefits would help here. Otherwise, there is a number of regressions here:
|
krassowski
left a comment
There was a problem hiding this comment.
As per comment above. Thank you for working on it!
|
Good point for subclasses, I'll see what I can do. It's true that I tested only with #1542; that is minimal up to startup point and shut off immediately; and for import only for kernelapp.
Fair; I did not think about this – but I would not consider kernel_info_reply to be part of startup; I need to check but at least the startup before the first kernel_info_request is faster, I'm assuming the first kernel_info_request is sent only once the kernel is started (I'll verify), so I still think it's a (partial) win, and this should make the time to ready. But I least that's fixable separately and only affect the I'm also profiling locally with modified jupyter_client, traitlets and IPython (to defer more stuff from there as well); and yes some thing like psutils are otherwise still in startup path via other packages; but I can try to publish profiles even with modified versions to give an idea of what can be achieved. |
|
I suppose another big things, is are we ok dropping debugger_class traitlet and deprecating it to at least have some way of making debugger import lazy ? |
|
See #1545 for how I think we can handle making kerne_info_reply faster by providing a config option. |
|
Here are the result of With #1542 merged in; to stop the kernel immediately and make it measurable. Also requires IPython'm main; traitlet and jupyter_client on latest releases
|
|
Also technically you should test with |
|
for Though it becomes brittle as there is no more guard in |


Both imports were paid for on every kernel startup even though most sessions never debug or ask for usage information.
IPythonKernel.debuggeris now a lazily-created property; the debugger (and the debugpy import) is only built on the first debug request.poll_stopped_queueis scheduled at that point rather than instart().debugger_classwas aTypetrait, which traitlets resolves — and therefore imports — as soon as the kernel is instantiated. It is replaced by a plaindebugger_class_namestring;debugger_classremains as a deprecated property, and subclasses still overriding it keep working with a DeprecationWarning.psutilis imported through_get_psutil(), which caches the (possibly None) result on first use.On a local test (where I have optimisation in IPython and traitlets as well), this brings the startup time from 220ms to 170ms