Obteniendo salida del núcleo de jupyter en (i) script de python
Me gustaría abrir varios núcleos desde una sola sesión de ipython, ejecutar código en esos núcleos y luego recopilar los resultados. Pero no puedo entender cómo recopilar los resultados, o incluso ver stdout / stderr. ¿Cómo puedo hacer estas cosas?
Lo que tengo hasta ahoraHe administrado los primeros dos pasos (abrir núcleos y ejecutar código en ellos) con un código como el siguiente:
from jupyter_client import MultiKernelManager
kernelmanager = MultiKernelManager()
remote_id = kernelmanager.start_kernel('python3')
remote_kernel = kernelmanager.get_kernel(remote_id)
remote = remote_kernel.client()
sent_msg_id = remote.execute('2+2')
[Agradezco cualquier sugerencia sobre cómo mejorar eso, o sobre cómo cerrar estos núcleos y clientes.]
Aquí,python3
puede ser el nombre de cualquiera de los núcleos que he configurado (que se pueden enumerar en la línea de comando conjupyter-kernelspec list
) Y parece que puedo ejecutar cualquier código razonable en lugar de'2+2'
. Por ejemplo, puedo escribir en un archivo, y ese archivo realmente se crea.
Ahora, el problema es cómo obtener el resultado. Puedo obtener un mensaje que aparentemente está relacionado como
reply = remote.get_shell_msg(sent_msg_id)
Esa respuesta es un diccionario como este:
{'buffers': [],
'content': {'execution_count': 2,
'payload': [],
'status': 'ok',
'user_expressions': {}},
'header': {'date': datetime.datetime(2015, 10, 19, 14, 34, 34, 378577),
'msg_id': '98e216b4-3251-4085-8eb1-bfceedbae3b0',
'msg_type': 'execute_reply',
'session': 'ca4d615d-82b7-487f-88ff-7076c2bdd109',
'username': 'me',
'version': '5.0'},
'metadata': {'dependencies_met': True,
'engine': '868de9dd-054b-4630-99b7-0face61915a6',
'started': '2015-10-19T14:34:34.265718',
'status': 'ok'},
'msg_id': '98e216b4-3251-4085-8eb1-bfceedbae3b0',
'msg_type': 'execute_reply',
'parent_header': {'date': datetime.datetime(2015, 10, 19, 14, 34, 34, 264508),
'msg_id': '2674c61a-c79a-48a6-b88a-1f2e8da68a80',
'msg_type': 'execute_request',
'session': '767ae562-38d6-41a3-a9dc-6faf37d83222',
'username': 'me',
'version': '5.0'}}
Esto está documentado enMensajería en Jupyter. Lo que no está documentado es cómo usar esto realmente, es decir, qué funciones uso, cuándo y dónde encuentro mensajes, etc. He vistoesta pregunta y su respuesta, que tiene información útil relacionada, pero no me lleva a la respuesta. Yesta respuesta tampoco obtiene ningún resultado útil.
Entonces, por ejemplo, he tratado de obtener también el msg con elmsg_id
dado en el resultado anterior, pero simplemente se cuelga. He intentado todo lo que puedo pensar, pero no puedo encontrar la manera de recuperar nada del núcleo. ¿Cómo lo hago? ¿Puedo transferir datos desde el núcleo en algún tipo de cadena? ¿Puedo ver su stdout y stderr?
Estoy escribiendo una magia ipython para ejecutar un fragmento de código en núcleos remotos. [Editar: esto ahora existe y está disponibleaquí.] La idea es tener una computadora portátil en mi computadora portátil y recopilar datos de varios servidores remotos con solo tener una pequeña celda mágica como esta:
%%remote_exec -kernels server1,server2
2+2
! hostname
yo sueloremote_ikernel
para conectarse a esos núcleos remotos de manera fácil y automática. Eso parece funcionar bien; Tengo mi comando mágico con todas sus campanas y silbatos funcionando muy bien, abriendo estos núcleos remotos y ejecutando el código. Ahora quiero obtener algunos de esos datos del control remoto que se envían a mi computadora portátil, presumiblemente serializándolos de alguna manera. Por el momento, creopickle.dumps
ypickle.loads
sería perfecto para esta parte; Solo tengo que obtener esos bytes creados y utilizados por estas funciones de un núcleo a otro. Prefiero no usar archivos reales para el decapado, aunque esto sería potencialmente aceptable.
Parece que es posible con cierta monstruosidad como esta:
remote.get_shell_msg(remote.execute('import pickle'))
sent_msg_id = remote.execute('a=2+2', user_expressions={'output':'pickle.dumps({"a":a})'})
reply = remote.get_shell_msg(sent_msg_id)
output_bytes = reply['content']['user_expressions']['output']['data']['text/plain']
variable_dict = pickle.loads(eval(output_bytes))
Y ahora,variable_dict['a']
es solo4
. Tenga en cuenta, sin embargo, queoutput_bytes
es una cadena que representa esos bytes, por lo que debe sereval
ed. Esto parece ridículo (y todavía no muestra cómo me volvería stdout). ¿Hay una mejor manera? ¿Y cómo me hago stdout?
Aunque no estoy contento con mi truco anterior, lo he usado con éxito para escribir un pequeño módulo llamadoremote_exec
alojado en github, como se describió anteriormente. El módulo me da un poco de magia de ipython que puedo usar para ejecutar código de forma remota en uno o más núcleos. Este es un proceso automático más o menos con el que definitivamente estoy satisfecho, excepto por el persistente conocimiento de lo que está sucediendo debajo.