Skip to content

Commit

Permalink
Changes necessary to get async kernel startup working
Browse files Browse the repository at this point in the history
Inspired by #402, but needing support for python 2.7, these changes
essentially apply the same model used in Notebook for supporting
coroutines with appropriately placed yield statements in order to
start (and restart) multiple kernels simultaneously within the same
server instance.
  • Loading branch information
kevin-bates committed Feb 19, 2019
1 parent e813086 commit 5103959
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 9 deletions.
9 changes: 5 additions & 4 deletions jupyter_client/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import time

import zmq

from tornado import gen
from ipython_genutils.importstring import import_item
from .localinterfaces import is_local_ip, local_ips
from traitlets import (
Expand Down Expand Up @@ -205,6 +205,7 @@ def _close_control_socket(self):
self._control_socket.close()
self._control_socket = None

@gen.coroutine
def start_kernel(self, **kw):
"""Starts a kernel on this host in a separate process.
Expand Down Expand Up @@ -246,8 +247,7 @@ def start_kernel(self, **kw):

# launch the kernel subprocess
self.log.debug("Starting kernel: %s", kernel_cmd)
self.kernel = self._launch_kernel(kernel_cmd, env=env,
**kw)
self.kernel = yield gen.maybe_future(self._launch_kernel(kernel_cmd, env=env, **kw))
self.start_restarter()
self._connect_control_socket()

Expand Down Expand Up @@ -324,6 +324,7 @@ def shutdown_kernel(self, now=False, restart=False):

self.cleanup(connection_file=not restart)

@gen.coroutine
def restart_kernel(self, now=False, newports=False, **kw):
"""Restarts a kernel with the arguments that were used to launch it.
Expand Down Expand Up @@ -361,7 +362,7 @@ def restart_kernel(self, now=False, newports=False, **kw):

# Start new kernel.
self._launch_args.update(kw)
self.start_kernel(**self._launch_args)
yield gen.maybe_future(self.start_kernel(**self._launch_args))

@property
def has_kernel(self):
Expand Down
21 changes: 16 additions & 5 deletions jupyter_client/multikernelmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

import os
import uuid

import zmq

from tornado import gen
from traitlets.config.configurable import LoggingConfigurable
from ipython_genutils.importstring import import_item
from traitlets import (
Expand Down Expand Up @@ -82,6 +82,7 @@ def __len__(self):
def __contains__(self, kernel_id):
return kernel_id in self._kernels

@gen.coroutine
def start_kernel(self, kernel_name=None, **kwargs):
"""Start a new kernel.
Expand All @@ -107,9 +108,9 @@ def start_kernel(self, kernel_name=None, **kwargs):
parent=self, log=self.log, kernel_name=kernel_name,
**constructor_kwargs
)
km.start_kernel(**kwargs)
yield gen.maybe_future(km.start_kernel(**kwargs))
self._kernels[kernel_id] = km
return kernel_id
raise gen.Return(kernel_id)

@kernel_method
def shutdown_kernel(self, kernel_id, now=False, restart=False):
Expand Down Expand Up @@ -186,15 +187,25 @@ def signal_kernel(self, kernel_id, signum):
"""
self.log.info("Signaled Kernel %s with %s" % (kernel_id, signum))

@kernel_method
@gen.coroutine
def restart_kernel(self, kernel_id, now=False):
"""Restart a kernel by its uuid, keeping the same ports.
Parameters
==========
kernel_id : uuid
The id of the kernel to interrupt.
The id of the kernel to restart.
now : bool, optional
If True, the kernel is forcefully restarted *immediately*, without
having a chance to do any cleanup action. Otherwise the kernel is
given 1s to clean up before a forceful restart is issued.
In all cases the kernel is restarted, the only difference is whether
it is given a chance to perform a clean shutdown or not.
"""
km = self.get_kernel(kernel_id)
yield gen.maybe_future(km.restart_kernel(now))
self.log.info("Kernel restarted: %s" % kernel_id)

@kernel_method
Expand Down

0 comments on commit 5103959

Please sign in to comment.