{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Threading and forking combined\n", "\n", "Mixing multiprocessing and threading is generally problematic and a recipe for deadlocks.\n", "\n", "The following code was entered in 2016 at https://bugs.python.org/issue27422 in the Python bug tracker:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "starting 0\n", "starting 1\n", "starting 2\n", "starting 3\n", "starting 4\n", "starting 5\n", "starting 6\n", "starting 7\n", "starting 8\n", "starting 9\n", "starting 10\n", "starting 11\n", "starting 12\n", "starting 13\n", "starting 14\n", "starting 15\n", "running 2\n", "finished 2\n", "running 4\n", "finished 4\n", "finished 1\n", "finished 0\n", "running 1\n", "running 6\n", "running 0\n", "running 5\n", "running 3\n", "finished 6\n", "running 15\n", "finished 5\n", "running 7\n", "finished 3\n", "finished 15\n", "finished 7\n", "running 8\n", "running 14\n", "finished 8\n", "running 13\n", "finished 14\n", "finished 13\n", "running 9\n", "running 10\n", "finished 9\n", "finished 10\n", "running 12\n", "running 11\n", "finished 12\n", "finished 11\n" ] } ], "source": [ "import multiprocessing\n", "import subprocess\n", "import sys\n", "\n", "from concurrent.futures import ThreadPoolExecutor\n", "\n", "\n", "def run(arg):\n", " print(f\"starting {arg}\")\n", " p = multiprocessing.Process(target=print, args=(\"running\", arg))\n", " p.start()\n", " p.join()\n", " print(f\"finished {arg}\")\n", "\n", "\n", "if __name__ == \"__main__\":\n", " n = 16\n", " tests = range(n)\n", " with ThreadPoolExecutor(n) as pool:\n", " for r in pool.map(run, tests):\n", " pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Usually, threading is recommended after the fork, not before. Otherwise, the locks used when executing the threads are duplicated across the processes. If one of these processes dies with a lock, all other processes with this lock are deadlocked." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.13 Kernel", "language": "python", "name": "python313" }, "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.13.0" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "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 }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }