Last active
February 25, 2021 02:52
-
-
Save mivade/6b7656fa804ad771750f88eab51e65ee to your computer and use it in GitHub Desktop.
Sharing memory between processes with various methods
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": "code", | |
"execution_count": 1, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"%matplotlib inline\n", | |
"import sys\n", | |
"from subprocess import Popen, PIPE\n", | |
"from collections import OrderedDict\n", | |
"from itertools import cycle\n", | |
"\n", | |
"import matplotlib.pyplot as plt\n", | |
"import pandas as pd" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"python = sys.executable" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"files = [\n", | |
" 'buffer.py',\n", | |
" 'manager.py',\n", | |
" 'hdf5.py',\n", | |
"]\n", | |
"sizes = [1000, 10000, 100000, 1000000]\n", | |
"trials = 25" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"data = {\n", | |
" 'name': [],\n", | |
" 'n': [],\n", | |
" 'producer': [],\n", | |
" 'consumer': []\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": { | |
"scrolled": true | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Running benchmarks for array size 1000\n", | |
"Running benchmarks for array size 10000\n", | |
"Running benchmarks for array size 100000\n", | |
"Running benchmarks for array size 1000000\n" | |
] | |
} | |
], | |
"source": [ | |
"for n in sizes:\n", | |
" print(\"Running benchmarks for array size\", n)\n", | |
" for _ in range(trials):\n", | |
" for filename in files:\n", | |
" child = Popen([python, filename, str(n)], stdout=PIPE)\n", | |
" out, err = child.communicate()\n", | |
" result = out.split()\n", | |
"\n", | |
" data['name'].append(filename)\n", | |
" data['n'].append(n)\n", | |
" data['producer'].append(float(result[1]))\n", | |
" data['consumer'].append(float(result[3]))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"df = pd.DataFrame(data)\n", | |
"avg = OrderedDict([\n", | |
" ('name', []),\n", | |
" ('n', []),\n", | |
" ('producer_mean', []),\n", | |
" ('producer_std', []),\n", | |
" ('consumer_mean', []),\n", | |
" ('consumer_std', [])\n", | |
"])" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"for n in sizes:\n", | |
" for name in files:\n", | |
" df2 = df[(df.name == name) & (df.n == n)]\n", | |
" avg['name'].append(name)\n", | |
" avg['n'].append(n)\n", | |
" avg['producer_mean'].append(df2.producer.mean())\n", | |
" avg['producer_std'].append(df2.producer.std())\n", | |
" avg['consumer_mean'].append(df2.consumer.mean())\n", | |
" avg['consumer_std'].append(df2.consumer.std())\n", | |
"\n", | |
"avg = pd.DataFrame(avg)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style>\n", | |
" .dataframe thead tr:only-child th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: left;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>name</th>\n", | |
" <th>n</th>\n", | |
" <th>producer_mean</th>\n", | |
" <th>producer_std</th>\n", | |
" <th>consumer_mean</th>\n", | |
" <th>consumer_std</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>buffer.py</td>\n", | |
" <td>1000</td>\n", | |
" <td>0.000302</td>\n", | |
" <td>0.000026</td>\n", | |
" <td>0.000151</td>\n", | |
" <td>0.000025</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>manager.py</td>\n", | |
" <td>1000</td>\n", | |
" <td>0.001666</td>\n", | |
" <td>0.000228</td>\n", | |
" <td>0.000478</td>\n", | |
" <td>0.000076</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>hdf5.py</td>\n", | |
" <td>1000</td>\n", | |
" <td>0.003701</td>\n", | |
" <td>0.000393</td>\n", | |
" <td>0.003256</td>\n", | |
" <td>0.000255</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>buffer.py</td>\n", | |
" <td>10000</td>\n", | |
" <td>0.001119</td>\n", | |
" <td>0.000060</td>\n", | |
" <td>0.016928</td>\n", | |
" <td>0.000905</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>4</th>\n", | |
" <td>manager.py</td>\n", | |
" <td>10000</td>\n", | |
" <td>0.002053</td>\n", | |
" <td>0.000240</td>\n", | |
" <td>0.017622</td>\n", | |
" <td>0.000767</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>5</th>\n", | |
" <td>hdf5.py</td>\n", | |
" <td>10000</td>\n", | |
" <td>0.004105</td>\n", | |
" <td>0.000408</td>\n", | |
" <td>0.025828</td>\n", | |
" <td>0.002037</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>6</th>\n", | |
" <td>buffer.py</td>\n", | |
" <td>100000</td>\n", | |
" <td>0.009074</td>\n", | |
" <td>0.000788</td>\n", | |
" <td>0.017835</td>\n", | |
" <td>0.001237</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>7</th>\n", | |
" <td>manager.py</td>\n", | |
" <td>100000</td>\n", | |
" <td>0.006265</td>\n", | |
" <td>0.000330</td>\n", | |
" <td>0.020807</td>\n", | |
" <td>0.000847</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>8</th>\n", | |
" <td>hdf5.py</td>\n", | |
" <td>100000</td>\n", | |
" <td>0.006593</td>\n", | |
" <td>0.000497</td>\n", | |
" <td>0.028281</td>\n", | |
" <td>0.001849</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>9</th>\n", | |
" <td>buffer.py</td>\n", | |
" <td>1000000</td>\n", | |
" <td>0.086639</td>\n", | |
" <td>0.003298</td>\n", | |
" <td>0.020678</td>\n", | |
" <td>0.001462</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>10</th>\n", | |
" <td>manager.py</td>\n", | |
" <td>1000000</td>\n", | |
" <td>0.044939</td>\n", | |
" <td>0.002159</td>\n", | |
" <td>0.049126</td>\n", | |
" <td>0.003712</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>11</th>\n", | |
" <td>hdf5.py</td>\n", | |
" <td>1000000</td>\n", | |
" <td>0.032135</td>\n", | |
" <td>0.002422</td>\n", | |
" <td>0.035451</td>\n", | |
" <td>0.001274</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" name n producer_mean producer_std consumer_mean \\\n", | |
"0 buffer.py 1000 0.000302 0.000026 0.000151 \n", | |
"1 manager.py 1000 0.001666 0.000228 0.000478 \n", | |
"2 hdf5.py 1000 0.003701 0.000393 0.003256 \n", | |
"3 buffer.py 10000 0.001119 0.000060 0.016928 \n", | |
"4 manager.py 10000 0.002053 0.000240 0.017622 \n", | |
"5 hdf5.py 10000 0.004105 0.000408 0.025828 \n", | |
"6 buffer.py 100000 0.009074 0.000788 0.017835 \n", | |
"7 manager.py 100000 0.006265 0.000330 0.020807 \n", | |
"8 hdf5.py 100000 0.006593 0.000497 0.028281 \n", | |
"9 buffer.py 1000000 0.086639 0.003298 0.020678 \n", | |
"10 manager.py 1000000 0.044939 0.002159 0.049126 \n", | |
"11 hdf5.py 1000000 0.032135 0.002422 0.035451 \n", | |
"\n", | |
" consumer_std \n", | |
"0 0.000025 \n", | |
"1 0.000076 \n", | |
"2 0.000255 \n", | |
"3 0.000905 \n", | |
"4 0.000767 \n", | |
"5 0.002037 \n", | |
"6 0.001237 \n", | |
"7 0.000847 \n", | |
"8 0.001849 \n", | |
"9 0.001462 \n", | |
"10 0.003712 \n", | |
"11 0.001274 " | |
] | |
}, | |
"execution_count": 8, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"avg" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"def colorgen():\n", | |
" colors = cycle(plt.rcParams['axes.prop_cycle'].by_key()['color'])\n", | |
" for color in colors:\n", | |
" yield color" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "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\nYu/evQwZMgSASy+9tM7XOG/ePC655BIALrnkEubNmxd5rurrBOjatSuDBw+OPJ4/fz4DBgygf//+\nvPfee7z//vuYGVOmTOGRRx5h165dLFu2jLPPPjv6N1+kiRXuLCEtpfpHeVpKCoU7S2K2z6Qscni4\nKjuilM+Ph1d2RMc2rQ9r261bf75+SkpK5HFKSgrl5eWkpqZWOw5/KBcs1jyDpfJxZmZmpC30z8XB\n3L3WM2AqKipYtmwZGRkZ1dpvvvlmzjnnHBYvXszgwYN58cUXGT58OK+99hrPPPMMU6ZM4YYbbuCy\nyy6rtl7V96FVq1aUlJTUGVNNRUVFvPzyy6xduxYz48CBA5gZt99++0Gvs+bjDRs2cMcdd7BixQra\nt2/P5ZdfHnmPr7jiCsaOHUt6ejoXXnghqan685DEl9U+g7Iac3dlFRVktc+oY43Dl/AlR+IhHh1R\nqVu3brzzzjsAvPPOO2zYsOGgZdq2bcvevXvr3MbChQspLS2lqKiIJUuWMGjQoIOWGT58OE8++SSf\nffYZ+/bt44knnuC0007jjDPOYP78+RQVFQGwY8cOAEaNGsW9994bWX/lypUA/POf/6Rv377cdNNN\n5Ofn8+GHH7Jp0yaOPfZYrrrqKqZNmxZ5PQ1p3749bdu25e9//ztAnZPejz/+OJdddhmbNm1i48aN\nbN68me7du/PGG280uI89e/aQmZlJu3bt+M9//sPf/va3yHOdO3emc+fO/OhHP+Lyyy8PFLNIvHVs\n05rbJ/YjPS2Ftq1TSU9L4faJ/Q77n9z6JFXiMLOxZjZn9+7dh7WdeHREpYkTJ7Jjxw7y8vK47777\nOPHEEw9apl+/fqSmppKbm8tdd9110PMnn3wy55xzDoMHD2bGjBl07tz5oGUGDBjA5Zdfzsknn8wp\np5zClVdeSf/+/cnOzub73/8+X/7yl8nNzeV73/seAPfccw8FBQX069ePPn36cP/99wNw9913k5OT\nQ25uLhkZGZx99tksWbIkMlm+YMECvvOd7wR+/Q8++CDTp0/n1FNPxd2pPOy4ZcsWxowZA4QOU1Wd\nyK5836qeaVaX3NzcyOucOnUqQ4cOrfb85MmTOe644+jTp0/gmEXibVxeF5bedDqPXHkKS286nXF5\ndV4a1ygs6OGB5iQ/P99r3o/jgw8+4KSTTopqO0XF+yncWUJW+4wmSRqNYdasWbRp04brr78+3qEc\nkuLi4sj1Kj/96U/59NNP+eUvf9lk+7/mmmvo378/06ZNa7J9thSH8jcoTcvM3nb3/IaW00HcenRs\n07rZJIxk8cwzz3DbbbdRXl5O165dmTt3bpPte+DAgWRmZnLnnXc22T5FmiONOESkSehvMPEFHXFo\njkNERKKSVImjsa7jEBGRuiVV4hARkdhT4hARkagocTQjKqv+ucoSIZXKy8s55phjIsUeE1m3bt2Y\nOHFi5PHjjz+uCw6lWVHiaIZUVj1URmTt2rWRqrovvPACXbrE9qKnQ1FeXl5re0FBAe+9914TRyPS\nOJIqcTT6WVX7tsMnb4e+NwKVVW+8suoAZ599Ns888wwQupp80qRJkeeWL1/OkCFD6N+/P0OGDOGj\njz4CYO7cuUyYMIHRo0fTs2dPbrzxxsg6tZVbh1DC6927N8OGDePaa6+NvNf79u1j6tSpDBo0iP79\n+7Nw4cLIPi688ELGjh3LqFGjao39+uuv5yc/+clB7fXFfd555zF27Fi6d+/Ovffeyy9+8Qv69+/P\n4MGDI6Vh/vnPfzJ69GgGDhzIaaedFrnJ1WOPPRa5wn/48OGRbY4fP57Ro0fTq1cvZs+eHYnjvPPO\nY+DAgWRnZzNnzpxI+7PPPsuAAQPIzc3ljDPOqPd9kCQWpIRuc/saOHDgQeWCoy7pvHq++/99wf0n\nWaHvqx+Lbv1aqKx645VVz8zM9FWrVvnEiRO9pKTEc3Nzq70Pu3fv9rKyMnd3f+GFF3zChAnu7v7Q\nQw959+7dfdeuXV5SUuLHH3+8/+tf/6r2WquWWy8pKfGsrKzI+3bJJZdE9nHLLbdE4t65c6f37NnT\ni4uL/aGHHvIuXbpEtldT165d/d///rf37t3b161b54899ph/7WtfazDuL33pS75nzx7funWrH3XU\nUX7fffe5u/t3v/tdv+uuu9zd/fTTT/ePP/7Y3d3//ve/+8iRI93dPScnxwsLCyOxVm7zi1/8om/f\nvt0/++wzz87O9hUrVlR7Lyrbt2/f7lu3bq32XlQuU9f7UJPKqic+ApZV15Xjtdm3HRZ+G8pLQl8A\nC6+BE0ZAZqfD2nRlWXWg1rLqlaXGD0dlWfWMjIxIWfWjjz66zrLqQKSsupnVWVb9/fffj+yjZln1\nyZMnM2HCBLKyshg0aBBTp06lrKyM8847r9bXFLSs+tNPP13n6+zXrx8bN25k3rx5kTpWlXbv3s3X\n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\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
}, | |
{ | |
"data": { | |
"image/png": "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\nZDLjA4AAAAAASUVORK5CYII=\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"for which in ['producer', 'consumer']:\n", | |
" fig, ax = plt.subplots()\n", | |
" color = colorgen()\n", | |
" for name in ['buffer.py', 'manager.py', 'hdf5.py']:\n", | |
" avg[avg.name == name].plot.scatter(x='n', y='{}_mean'.format(which),\n", | |
" yerr='{}_std'.format(which),\n", | |
" c=next(color), ax=ax)\n", | |
"\n", | |
" ax.set_ylabel('Mean {} time [s]'.format(which))\n", | |
" ax.set_yscale('log')\n", | |
" ax.set_xscale('log')\n", | |
" ax.set_xlabel('Number of elements')\n", | |
" ax.legend(['multiprocessing.Array', 'multiprocessing.Manager.Namespace', 'HDF5'])" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python [conda root]", | |
"language": "python", | |
"name": "conda-root-py" | |
}, | |
"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" | |
}, | |
"widgets": { | |
"state": { | |
"34c6a4eb8ee648b1b217fa35092cbf07": { | |
"views": [ | |
{ | |
"cell_index": 4 | |
} | |
] | |
}, | |
"9153a10355554b94bb15a0ecd5d29b2c": { | |
"views": [ | |
{ | |
"cell_index": 4 | |
} | |
] | |
}, | |
"f29ccca5c7a4491db93214539ab797fe": { | |
"views": [ | |
{ | |
"cell_index": 4 | |
} | |
] | |
} | |
}, | |
"version": "1.2.0" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
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
import time | |
import ctypes | |
from multiprocessing import Process, Event, Array | |
from argparse import ArgumentParser | |
import numpy as np | |
def producer(buf, shape, event): | |
t0 = time.perf_counter() | |
buf[:] = np.random.random(shape) | |
event.set() | |
print("producer", time.perf_counter() - t0) | |
def consumer(buf, shape, event): | |
event.wait() | |
t0 = time.perf_counter() | |
a = np.frombuffer(buf.get_obj()) | |
_ = a**2 | |
print("consumer", time.perf_counter() - t0) | |
if __name__ == "__main__": | |
parser = ArgumentParser() | |
parser.add_argument('size', type=int) | |
args = parser.parse_args() | |
buf = Array(ctypes.c_double, args.size) | |
event = Event() | |
shape = args.size | |
procs = [Process(target=t, args=(buf, shape, event)) | |
for t in (producer, consumer)] | |
list(map(lambda p: p.start(), procs)) | |
list(map(lambda p: p.join(), procs)) |
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
import time | |
from multiprocessing import Process, Event | |
from argparse import ArgumentParser | |
import numpy as np | |
import h5py | |
def producer(shape, event): | |
t0 = time.perf_counter() | |
with h5py.File("shared.h5", "w") as hfile: | |
hfile.create_dataset('/data', data=np.random.random(shape), chunks=True) | |
event.set() | |
print("producer", time.perf_counter() - t0) | |
def consumer(_, event): | |
event.wait() | |
t0 = time.perf_counter() | |
with h5py.File("shared.h5", 'r') as hfile: | |
_ = hfile['/data'][:]**2 | |
print("consumer", time.perf_counter() - t0) | |
if __name__ == "__main__": | |
parser = ArgumentParser() | |
parser.add_argument('size', type=int) | |
args = parser.parse_args() | |
event = Event() | |
shape = args.size | |
procs = [Process(target=t, args=(shape, event)) | |
for t in (producer, consumer)] | |
list(map(lambda p: p.start(), procs)) | |
list(map(lambda p: p.join(), procs)) |
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
import time | |
from multiprocessing import Manager, Process | |
from argparse import ArgumentParser | |
import numpy as np | |
def producer(namespace, event): | |
t0 = time.perf_counter() | |
namespace.array = np.random.random(namespace.shape) | |
event.set() | |
print("producer", time.perf_counter() - t0) | |
def consumer(namespace, event): | |
event.wait() | |
t0 = time.perf_counter() | |
_ = namespace.array**2 | |
print("consumer", time.perf_counter() - t0) | |
if __name__ == "__main__": | |
parser = ArgumentParser() | |
parser.add_argument('size', type=int) | |
args = parser.parse_args() | |
with Manager() as mgr: | |
namespace = mgr.Namespace() | |
event = mgr.Event() | |
namespace.shape = args.size | |
procs = [Process(target=t, args=(namespace, event)) | |
for t in (producer, consumer)] | |
list(map(lambda p: p.start(), procs)) | |
list(map(lambda p: p.join(), procs)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment