1313import time
1414
1515import zmq
16-
16+ from concurrent .futures import Future
17+ from tornado import gen
1718from ipython_genutils .importstring import import_item
1819from .localinterfaces import is_local_ip , local_ips
1920from traitlets import (
@@ -192,6 +193,15 @@ def _launch_kernel(self, kernel_cmd, **kw):
192193 """
193194 return launch_kernel (kernel_cmd , ** kw )
194195
196+ @gen .coroutine
197+ def launch_kernel_async (self , kernel_cmd , ** kw ):
198+ """actually launch the kernel
199+
200+ override in a subclass to launch kernel subprocesses differently
201+ """
202+ res = yield gen .maybe_future (launch_kernel (kernel_cmd , ** kw ))
203+ raise gen .Return (res )
204+
195205 # Control socket used for polite kernel shutdown
196206
197207 def _connect_control_socket (self ):
@@ -205,8 +215,8 @@ def _close_control_socket(self):
205215 self ._control_socket .close ()
206216 self ._control_socket = None
207217
208- def start_kernel (self , ** kw ):
209- """Starts a kernel on this host in a separate process.
218+ def pre_start_kernel (self , ** kw ):
219+ """Prepares a kernel for startup in a separate process.
210220
211221 If random ports (port=0) are being used, this method must be called
212222 before the channels are created.
@@ -243,14 +253,53 @@ def start_kernel(self, **kw):
243253 env .update (self .kernel_spec .env or {})
244254 elif self .extra_env :
245255 env .update (self .extra_env )
256+ kw ['env' ] = env
246257
247- # launch the kernel subprocess
248- self .log .debug ("Starting kernel: %s" , kernel_cmd )
249- self .kernel = self ._launch_kernel (kernel_cmd , env = env ,
250- ** kw )
258+ return kernel_cmd , kw
259+
260+ def post_start_kernel (self , ** kw ):
251261 self .start_restarter ()
252262 self ._connect_control_socket ()
253263
264+ def start_kernel (self , ** kw ):
265+ """Starts a kernel on this host in a separate process.
266+
267+ If random ports (port=0) are being used, this method must be called
268+ before the channels are created.
269+
270+ Parameters
271+ ----------
272+ `**kw` : optional
273+ keyword arguments that are passed down to build the kernel_cmd
274+ and launching the kernel (e.g. Popen kwargs).
275+ """
276+ kernel_cmd , kw = self .pre_start_kernel (** kw )
277+
278+ # launch the kernel subprocess
279+ self .log .debug ("Starting kernel: %s" , kernel_cmd )
280+ self .kernel = self ._launch_kernel (kernel_cmd , ** kw )
281+ self .post_start_kernel (** kw )
282+
283+ @gen .coroutine
284+ def start_kernel_async (self , ** kw ):
285+ """Starts a kernel in a separate process in an asynchronous manner.
286+
287+ If random ports (port=0) are being used, this method must be called
288+ before the channels are created.
289+
290+ Parameters
291+ ----------
292+ `**kw` : optional
293+ keyword arguments that are passed down to build the kernel_cmd
294+ and launching the kernel (e.g. Popen kwargs).
295+ """
296+ kernel_cmd , kw = self .pre_start_kernel (** kw )
297+
298+ # launch the kernel subprocess
299+ self .log .debug ("Starting kernel (async): %s" , kernel_cmd )
300+ self .kernel = yield self .launch_kernel_async (kernel_cmd , ** kw )
301+ self .post_start_kernel (** kw )
302+
254303 def request_shutdown (self , restart = False ):
255304 """Send a shutdown request via control channel
256305 """
0 commit comments