diff --git a/advanced_topics/07_threading.ipynb b/advanced_topics/07_threading.ipynb index e8a1a36688775ebd745dfc791d472202eda0cf42..9bf762639b61832ee23f3863811aec73bbbee79b 100644 --- a/advanced_topics/07_threading.ipynb +++ b/advanced_topics/07_threading.ipynb @@ -28,20 +28,20 @@ "\n", "\n", "* [Threading](#threading)\n", - " * [Subclassing `Thread`](#subclassing-thread)\n", - " * [Daemon threads](#daemon-threads)\n", - " * [Thread synchronisation](#thread-synchronisation)\n", - " * [`Lock`](#lock)\n", - " * [`Event`](#event)\n", - " * [The Global Interpreter Lock (GIL)](#the-global-interpreter-lock-gil)\n", + " * [Subclassing `Thread`](#subclassing-thread)\n", + " * [Daemon threads](#daemon-threads)\n", + " * [Thread synchronisation](#thread-synchronisation)\n", + " * [`Lock`](#lock)\n", + " * [`Event`](#event)\n", + " * [The Global Interpreter Lock (GIL)](#the-global-interpreter-lock-gil)\n", "* [Multiprocessing](#multiprocessing)\n", - " * [`threading`-equivalent API](#threading-equivalent-api)\n", - " * [Higher-level API - the `multiprocessing.Pool`](#higher-level-api-the-multiprocessing-pool)\n", - " * [`Pool.map`](#pool-map)\n", - " * [`Pool.apply_async`](#pool-apply-async)\n", + " * [`threading`-equivalent API](#threading-equivalent-api)\n", + " * [Higher-level API - the `multiprocessing.Pool`](#higher-level-api-the-multiprocessing-pool)\n", + " * [`Pool.map`](#pool-map)\n", + " * [`Pool.apply_async`](#pool-apply-async)\n", "* [Sharing data between processes](#sharing-data-between-processes)\n", - " * [Read-only sharing](#read-only-sharing)\n", - " * [Read/write sharing](#read-write-sharing)\n", + " * [Read-only sharing](#read-only-sharing)\n", + " * [Read/write sharing](#read-write-sharing)\n", "\n", "\n", "<a class=\"anchor\" id=\"threading\"></a>\n", @@ -732,8 +732,8 @@ "\n", "\n", "Let's see this in action with a simple example. We'll start by defining a\n", - "little helper function which allows us to track the total memory usage, using\n", - "the unix `free` command:" + "horrible little helper function which allows us to track the total memory\n", + "usage:" ] }, { @@ -742,14 +742,24 @@ "metadata": {}, "outputs": [], "source": [ - "# todo mac version\n", + "import sys\n", "import subprocess as sp\n", "def memusage(msg):\n", - " stdout = sp.run(['free', '--mega'], capture_output=True).stdout.decode()\n", - " stdout = stdout.split('\\n')[1].split()\n", - " total = stdout[1]\n", - " used = stdout[2]\n", - " print('Memory usage {}: {} / {} MB'.format(msg, used, total))" + " if sys.platform == 'darwin':\n", + " total = sp.run(['sysctl', 'hw.memsize'], capture_output=True).stdout.decode()\n", + " total = int(total.split()[1]) // 1048576\n", + " usage = sp.run('vm_stat', capture_output=True).stdout.decode()\n", + " usage = usage.strip().split('\\n')\n", + " usage = [l.split(':') for l in usage]\n", + " usage = {k.strip() : v.strip() for k, v in usage}\n", + " usage = int(usage['Pages free'][:-1]) / 256.0\n", + " usage = int(total - usage)\n", + " else:\n", + " stdout = sp.run(['free', '--mega'], capture_output=True).stdout.decode()\n", + " stdout = stdout.split('\\n')[1].split()\n", + " total = int(stdout[1])\n", + " usage = int(stdout[2])\n", + " print('Memory usage {}: {} / {} MB'.format(msg, usage, total))" ] }, { @@ -823,8 +833,8 @@ "data? Go back to the code block above and:\n", "\n", "1. Modify the `process_chunk` function so that it modifies every element of\n", - " its assigned portion of the data before calculating and returning the sum.\n", - " For example:\n", + " its assigned portion of the data before the call to `time.sleep`. For\n", + " example:\n", "\n", " > ```\n", " > data[offset:offset + nelems] += 1\n", diff --git a/advanced_topics/07_threading.md b/advanced_topics/07_threading.md index 2c09234d29527148586a09133d28a437077dac47..14b89e782aad06a93858d39119acdbb47aa8b46b 100644 --- a/advanced_topics/07_threading.md +++ b/advanced_topics/07_threading.md @@ -22,20 +22,20 @@ module. If you want to be impressed, skip straight to the section on * [Threading](#threading) - * [Subclassing `Thread`](#subclassing-thread) - * [Daemon threads](#daemon-threads) - * [Thread synchronisation](#thread-synchronisation) - * [`Lock`](#lock) - * [`Event`](#event) - * [The Global Interpreter Lock (GIL)](#the-global-interpreter-lock-gil) + * [Subclassing `Thread`](#subclassing-thread) + * [Daemon threads](#daemon-threads) + * [Thread synchronisation](#thread-synchronisation) + * [`Lock`](#lock) + * [`Event`](#event) + * [The Global Interpreter Lock (GIL)](#the-global-interpreter-lock-gil) * [Multiprocessing](#multiprocessing) - * [`threading`-equivalent API](#threading-equivalent-api) - * [Higher-level API - the `multiprocessing.Pool`](#higher-level-api-the-multiprocessing-pool) - * [`Pool.map`](#pool-map) - * [`Pool.apply_async`](#pool-apply-async) + * [`threading`-equivalent API](#threading-equivalent-api) + * [Higher-level API - the `multiprocessing.Pool`](#higher-level-api-the-multiprocessing-pool) + * [`Pool.map`](#pool-map) + * [`Pool.apply_async`](#pool-apply-async) * [Sharing data between processes](#sharing-data-between-processes) - * [Read-only sharing](#read-only-sharing) - * [Read/write sharing](#read-write-sharing) + * [Read-only sharing](#read-only-sharing) + * [Read/write sharing](#read-write-sharing) <a class="anchor" id="threading"></a> @@ -638,19 +638,29 @@ any copying required. Let's see this in action with a simple example. We'll start by defining a -little helper function which allows us to track the total memory usage, using -the unix `free` command: +horrible little helper function which allows us to track the total memory +usage: ``` -# todo mac version +import sys import subprocess as sp def memusage(msg): - stdout = sp.run(['free', '--mega'], capture_output=True).stdout.decode() - stdout = stdout.split('\n')[1].split() - total = stdout[1] - used = stdout[2] - print('Memory usage {}: {} / {} MB'.format(msg, used, total)) + if sys.platform == 'darwin': + total = sp.run(['sysctl', 'hw.memsize'], capture_output=True).stdout.decode() + total = int(total.split()[1]) // 1048576 + usage = sp.run('vm_stat', capture_output=True).stdout.decode() + usage = usage.strip().split('\n') + usage = [l.split(':') for l in usage] + usage = {k.strip() : v.strip() for k, v in usage} + usage = int(usage['Pages free'][:-1]) / 256.0 + usage = int(total - usage) + else: + stdout = sp.run(['free', '--mega'], capture_output=True).stdout.decode() + stdout = stdout.split('\n')[1].split() + total = int(stdout[1]) + usage = int(stdout[2]) + print('Memory usage {}: {} / {} MB'.format(msg, usage, total)) ``` @@ -713,8 +723,8 @@ your data. But what if your worker processes need to be able to modify the data? Go back to the code block above and: 1. Modify the `process_chunk` function so that it modifies every element of - its assigned portion of the data before calculating and returning the sum. - For example: + its assigned portion of the data before the call to `time.sleep`. For + example: > ``` > data[offset:offset + nelems] += 1