Created
November 16, 2017 04:49
-
-
Save micahscopes/2f523a8f485d3fe53cc32cef450ca27f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# User friendly multiprocessing in Jupyter with ipywidgets" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"##### by Micah ([@micahscopes](http://wondering.xyz))\n", | |
"11/15/2017" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"##### A stoppable `multiprocessing.Process` subclass that displays its status:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": { | |
"run_control": { | |
"frozen": false, | |
"read_only": false | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"from multiprocessing import Process, Event\n", | |
"from ipywidgets import Output\n", | |
"from IPython.display import display\n", | |
"from time import sleep\n", | |
"\n", | |
"class ProcessWithStatus(Process):\n", | |
" def __init__(self):\n", | |
" self.output = Output()\n", | |
" self.exit = Event()\n", | |
" self.exited = Event()\n", | |
" super().__init__()\n", | |
" \n", | |
" with self.output:\n", | |
" print(self)\n", | |
" \n", | |
" def status(self):\n", | |
" display(self.output)\n", | |
" \n", | |
" def start(self): \n", | |
" super().start()\n", | |
" with self.output:\n", | |
" print(self)\n", | |
" print('running...')\n", | |
" \n", | |
" def stop(self):\n", | |
"# with self.output:\n", | |
" with self.output:\n", | |
" print('letting work finish before stopping...')\n", | |
" self.exit.set()\n", | |
" \n", | |
" self.exited.wait()\n", | |
" sleep(0.1) # Need to wait a little bit before the status is `stopped`\n", | |
" with self.output:\n", | |
" print(self)\n", | |
" \n", | |
" def work(self):\n", | |
" sleep(5)\n", | |
" pass\n", | |
" \n", | |
" def run(self):\n", | |
" while not self.exit.is_set():\n", | |
" # do the work\n", | |
" self.work()\n", | |
" \n", | |
" # when the work is done, signal that we are finished\n", | |
" self.exited.set()\n", | |
"\n", | |
"p = ProcessWithStatus()\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "7849905d904142a79b2a73c7731bfd86" | |
} | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"p.status()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"p.start()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"p.stop()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "7849905d904142a79b2a73c7731bfd86" | |
} | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"p.status()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"##### Adding start and stop buttons:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from ipywidgets import Button\n", | |
"\n", | |
"class ProcessWithControls(ProcessWithStatus):\n", | |
" def __init__(self):\n", | |
" self.start_button = Button(description='start')\n", | |
" self.start_button.on_click(lambda evt: self.start())\n", | |
" self.stop_button = Button(description='stop')\n", | |
" self.stop_button.on_click(lambda evt: self.stop())\n", | |
" \n", | |
" super().__init__()\n", | |
" \n", | |
" def controls(self):\n", | |
" display(self.start_button)\n", | |
" display(self.stop_button)\n", | |
" \n", | |
" def control_panel(self):\n", | |
" self.controls()\n", | |
" self.status()\n", | |
" \n", | |
" \n", | |
" " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "89711ccf151b4903b4c686b802e743e2" | |
} | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"p = ProcessWithControls()\n", | |
"p.status()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "58330af2e099454090fedc2013f0ef55" | |
} | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
}, | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "abe76bba34364dd5be13aab7fdb01207" | |
} | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"p.controls()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "58330af2e099454090fedc2013f0ef55" | |
} | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
}, | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "abe76bba34364dd5be13aab7fdb01207" | |
} | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
}, | |
{ | |
"data": { | |
"application/vnd.jupyter.widget-view+json": { | |
"model_id": "89711ccf151b4903b4c686b802e743e2" | |
} | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"p.control_panel()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"##### P.S. there's no reason you couldn't do something like this with multiple threads!" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.2" | |
}, | |
"latex_envs": { | |
"LaTeX_envs_menu_present": true, | |
"autocomplete": true, | |
"bibliofile": "biblio.bib", | |
"cite_by": "apalike", | |
"current_citInitial": 1, | |
"eqLabelWithNumbers": true, | |
"eqNumInitial": 1, | |
"hotkeys": { | |
"equation": "Ctrl-E", | |
"itemize": "Ctrl-I" | |
}, | |
"labels_anchors": false, | |
"latex_user_defs": false, | |
"report_style_numbering": false, | |
"user_envs_cfg": false | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Hey there,
Thanks for letting me know. Hopefully I can get to it some time, but no
guarantees, as I have a full time job I don't always have leftover energy
to keep up with all the open source stuff I'd like to work on.
Feel free to submit a PR if you happen to figure out a solution!
Micah
…It still works perfectly (ubuntu 20.0, python 3.8.7). Thank you!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sadly, it seem this no longer works, at least on windows (py 3.8.1/win64).
p.start() returns error: PicklingError: Can't pickle : it's not the same object as builtins.input