shared-ndarray2


Nameshared-ndarray2 JSON
Version 2.0.1 PyPI version JSON
download
home_pagehttps://gitlab.com/osu-nrsg/shared-ndarray2
SummaryInterface for NumPy ndarray using multiprocessing SharedMemory
upload_time2024-05-16 23:11:38
maintainerNone
docs_urlNone
authorRandall Pittman
requires_python<4.0,>=3.8
licenseMIT
keywords numpy shared_memory ndarray
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # shared-ndarray2  <!-- omit in toc -->

`SharedNDArray` encapsulates a NumPy `ndarray` interface for using shared memory in
multiprocessing, using `multiprocessing.shared_memory` in Python 3.8+.

- [Quick Start](#quick-start)
- [Requirements](#requirements)
- [Similar Projects](#similar-projects)
- [Usage](#usage)
  - [Creation](#creation)
    - [`SharedNDArray()`](#sharedndarray)
    - [`SharedNDArray.from_shape()` or `shared_ndarray.from_shape()`](#sharedndarrayfrom_shape-or-shared_ndarrayfrom_shape)
    - [`SharedNDArray.from_array()` or `shared_ndarray.from_array()`](#sharedndarrayfrom_array-or-shared_ndarrayfrom_array)
  - [Using like `np.ndarray`](#using-like-npndarray)
  - [Releasing Shared Memory](#releasing-shared-memory)
  - [`.lock` attribute](#lock-attribute)
  - [Typed SharedNDArray](#typed-sharedndarray)

## Quick Start

```python
import multiprocessing
from multiprocessing.managers import SharedMemoryManager

import numpy as np

from shared_ndarray2 import SharedNDArray


def process_data(arr: SharedNDArray):
    # Work with data
    arr[:] += 1


with SharedMemoryManager() as mem_mgr:
    arr = SharedNDArray.from_array(mem_mgr, np.arange(1024))
    p = multiprocessing.Process(target=process_data, args=(arr,))
    p.start()
    p.join()
    assert np.all(arr[:] == np.arange(1, 1025))
```

## Requirements

- Python 3.8+
- NumPy 1.21+

## Similar Projects

- [SharedArray](https://pypi.org/project/SharedArray/) - POSIX-only. Quite a different
  paradigm, uses pre-Python 3.8 memory-sharing constructs, requires building a C module
  with `gcc`.
- [shared-ndarray](https://pypi.org/project/shared-ndarray/) - POSIX-only. Similar (uses
  NumPy ndarray `buffer` arg), uses pre-Python 3.8 memory-sharing constructs (requires
  `posix_ipc`).

## Usage

### Creation

There are three methods for constructing a `SharedNDArray`.

#### `SharedNDArray()`

To create a `SharedNDArray` object from existing shared memory that represents a NumPy
array, use the regular constructor providing _shape_ and _dtype_, either with an existing
`multiprocessing.SharedMemory` object or the name of one:

```python
shm = SharedMemory(create=True, size=1024)
arr = SharedNDArray(shm, (1024,), np.uint8)
# -or-
arr = SharedNDArray(shm.name, (1024,), np.uint8)
```

#### `SharedNDArray.from_shape()` or `shared_ndarray.from_shape()`

This method allocates shared memory managed by a SharedMemoryManager to represent a NumPy
`ndarray` with some _shape_ and _dtype_.

```python
with SharedMemoryManager as mem_mgr:
    arr = SharedNDArray.from_shape(mem_mgr, (3, 1024, 1024), dtype=np.uint16)
    # ... Use arr with e.g. multiprocessing.Pool or multiprocess.Process
    # ... Be sure process instances join/terminate before exiting SharedMemoryManager context manager
```

<div style="font-size: small; margin-left: 4em">

Note: _`shared_ndarray.from_shape()` is a standlone function and correctly types the
`SharedNDArray`, whereas the classmethod might (in mypy) or might not (in pyright)_

</div>

#### `SharedNDArray.from_array()` or `shared_ndarray.from_array()`

This method allocates shared memory managed by a SharedMemoryManager to represent a some
provided NumPy `ndarray` and copies that ndarray into the shared memory

```python
x = np.arange(100.0).reshape(2, 2, 25)
with SharedMemoryManager as mem_mgr:
    arr = SharedNDArray.from_array(mem_mgr, x)
    assert np.all(arr[:] == x[:])
    # ... Use arr as above...
```

<div style="font-size: small; margin-left: 4em">

Note: _`shared_ndarray.from_array()` is a standlone function and correctly types the
`SharedNDArray`, whereas the classmethod might (in mypy) or might not (in pyright)_

</div>

### Using like `np.ndarray`

The point of `SharedNDArray` is to remove the boilerplate of creating shared memory,
passing around shapes and dtypes and reconstructing `np.ndarray` objects. `SharedNDArray`
does this last step with its `.get()` method, which creates a `np.ndarray` on-the-fly
using the shared memory buffer. The `__getitem__()` and `__setitem__()` methods use the
`.get()` method to get the np.ndarray to access the data, so multi-dimensional indexing
and slicing work the same as with an `ndarray`. Other `np.ndarray` methods are not
directly implemented but may be accessed by first calling `.get()`, e.g.
`arr.get().mean()`.

### Releasing Shared Memory

`SharedNDArray` implements a `__del__()` method that calls the
[`.close()`](https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory.close)
method on the `SharedMemory` when the instance is destroyed (i.e. at process exit). When
the shared memory is unlinked in the parent process (either manually with
[`shm.unlink()`](https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory.unlink)
or by exiting a `SharedMemoryManager` context manager) the shared_memory is properly
released. However if a sub-process is not joined or terminated before the shared memory is
unlinked a warning will be emitted about "`leaked shared_memory objects to clean up at
shutdown`".

### `.lock` attribute

The `__init__()`, `from_shape()`, and `from_array()` methods may be given a `lock=True`
argument that will also create a `multiprocessing.Lock` object and include it in the
`SharedNDArray`, accesible as the `.lock` attribute. It should be noted, however, that it
doesn't work well to pass a `multiprocessing.Lock` as an argument to a
`multiprocessing.Pool` function, for reasons described
[here](https://stackoverflow.com/questions/25557686/python-sharing-a-lock-between-processes#comment72803059_25558333).
Thus by default `.lock` is set to `None`.

### Typed SharedNDArray

`SharedNDArray` is able to be typed with NumPy types. When using the `from_array()`
constructor, it is also able to inherit the type of the `ndarray` if it is typed using
`numpy.typing.NDArray` (new in NumPy 1.21). Typing information does not pass through with
slicing (`__getitem__`), however.

```python
x: npt.NDArray[np.int_] = np.arange(1024)
arr = SharedNDArray(mem_mgr, x)  # type of x is SharedNDArray[int_]
arr2 = arr[:]  # arr2 is typing.Any
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://gitlab.com/osu-nrsg/shared-ndarray2",
    "name": "shared-ndarray2",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.8",
    "maintainer_email": null,
    "keywords": "numpy, shared_memory, ndarray",
    "author": "Randall Pittman",
    "author_email": "randallpittman@outlook.com",
    "download_url": "https://files.pythonhosted.org/packages/71/92/5a4cb880a09ad0d906b107227591e90c626dd45b1800db49b48f4ffa614b/shared_ndarray2-2.0.1.tar.gz",
    "platform": null,
    "description": "# shared-ndarray2  <!-- omit in toc -->\n\n`SharedNDArray` encapsulates a NumPy `ndarray` interface for using shared memory in\nmultiprocessing, using `multiprocessing.shared_memory` in Python 3.8+.\n\n- [Quick Start](#quick-start)\n- [Requirements](#requirements)\n- [Similar Projects](#similar-projects)\n- [Usage](#usage)\n  - [Creation](#creation)\n    - [`SharedNDArray()`](#sharedndarray)\n    - [`SharedNDArray.from_shape()` or `shared_ndarray.from_shape()`](#sharedndarrayfrom_shape-or-shared_ndarrayfrom_shape)\n    - [`SharedNDArray.from_array()` or `shared_ndarray.from_array()`](#sharedndarrayfrom_array-or-shared_ndarrayfrom_array)\n  - [Using like `np.ndarray`](#using-like-npndarray)\n  - [Releasing Shared Memory](#releasing-shared-memory)\n  - [`.lock` attribute](#lock-attribute)\n  - [Typed SharedNDArray](#typed-sharedndarray)\n\n## Quick Start\n\n```python\nimport multiprocessing\nfrom multiprocessing.managers import SharedMemoryManager\n\nimport numpy as np\n\nfrom shared_ndarray2 import SharedNDArray\n\n\ndef process_data(arr: SharedNDArray):\n    # Work with data\n    arr[:] += 1\n\n\nwith SharedMemoryManager() as mem_mgr:\n    arr = SharedNDArray.from_array(mem_mgr, np.arange(1024))\n    p = multiprocessing.Process(target=process_data, args=(arr,))\n    p.start()\n    p.join()\n    assert np.all(arr[:] == np.arange(1, 1025))\n```\n\n## Requirements\n\n- Python 3.8+\n- NumPy 1.21+\n\n## Similar Projects\n\n- [SharedArray](https://pypi.org/project/SharedArray/) - POSIX-only. Quite a different\n  paradigm, uses pre-Python 3.8 memory-sharing constructs, requires building a C module\n  with `gcc`.\n- [shared-ndarray](https://pypi.org/project/shared-ndarray/) - POSIX-only. Similar (uses\n  NumPy ndarray `buffer` arg), uses pre-Python 3.8 memory-sharing constructs (requires\n  `posix_ipc`).\n\n## Usage\n\n### Creation\n\nThere are three methods for constructing a `SharedNDArray`.\n\n#### `SharedNDArray()`\n\nTo create a `SharedNDArray` object from existing shared memory that represents a NumPy\narray, use the regular constructor providing _shape_ and _dtype_, either with an existing\n`multiprocessing.SharedMemory` object or the name of one:\n\n```python\nshm = SharedMemory(create=True, size=1024)\narr = SharedNDArray(shm, (1024,), np.uint8)\n# -or-\narr = SharedNDArray(shm.name, (1024,), np.uint8)\n```\n\n#### `SharedNDArray.from_shape()` or `shared_ndarray.from_shape()`\n\nThis method allocates shared memory managed by a SharedMemoryManager to represent a NumPy\n`ndarray` with some _shape_ and _dtype_.\n\n```python\nwith SharedMemoryManager as mem_mgr:\n    arr = SharedNDArray.from_shape(mem_mgr, (3, 1024, 1024), dtype=np.uint16)\n    # ... Use arr with e.g. multiprocessing.Pool or multiprocess.Process\n    # ... Be sure process instances join/terminate before exiting SharedMemoryManager context manager\n```\n\n<div style=\"font-size: small; margin-left: 4em\">\n\nNote: _`shared_ndarray.from_shape()` is a standlone function and correctly types the\n`SharedNDArray`, whereas the classmethod might (in mypy) or might not (in pyright)_\n\n</div>\n\n#### `SharedNDArray.from_array()` or `shared_ndarray.from_array()`\n\nThis method allocates shared memory managed by a SharedMemoryManager to represent a some\nprovided NumPy `ndarray` and copies that ndarray into the shared memory\n\n```python\nx = np.arange(100.0).reshape(2, 2, 25)\nwith SharedMemoryManager as mem_mgr:\n    arr = SharedNDArray.from_array(mem_mgr, x)\n    assert np.all(arr[:] == x[:])\n    # ... Use arr as above...\n```\n\n<div style=\"font-size: small; margin-left: 4em\">\n\nNote: _`shared_ndarray.from_array()` is a standlone function and correctly types the\n`SharedNDArray`, whereas the classmethod might (in mypy) or might not (in pyright)_\n\n</div>\n\n### Using like `np.ndarray`\n\nThe point of `SharedNDArray` is to remove the boilerplate of creating shared memory,\npassing around shapes and dtypes and reconstructing `np.ndarray` objects. `SharedNDArray`\ndoes this last step with its `.get()` method, which creates a `np.ndarray` on-the-fly\nusing the shared memory buffer. The `__getitem__()` and `__setitem__()` methods use the\n`.get()` method to get the np.ndarray to access the data, so multi-dimensional indexing\nand slicing work the same as with an `ndarray`. Other `np.ndarray` methods are not\ndirectly implemented but may be accessed by first calling `.get()`, e.g.\n`arr.get().mean()`.\n\n### Releasing Shared Memory\n\n`SharedNDArray` implements a `__del__()` method that calls the\n[`.close()`](https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory.close)\nmethod on the `SharedMemory` when the instance is destroyed (i.e. at process exit). When\nthe shared memory is unlinked in the parent process (either manually with\n[`shm.unlink()`](https://docs.python.org/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory.unlink)\nor by exiting a `SharedMemoryManager` context manager) the shared_memory is properly\nreleased. However if a sub-process is not joined or terminated before the shared memory is\nunlinked a warning will be emitted about \"`leaked shared_memory objects to clean up at\nshutdown`\".\n\n### `.lock` attribute\n\nThe `__init__()`, `from_shape()`, and `from_array()` methods may be given a `lock=True`\nargument that will also create a `multiprocessing.Lock` object and include it in the\n`SharedNDArray`, accesible as the `.lock` attribute. It should be noted, however, that it\ndoesn't work well to pass a `multiprocessing.Lock` as an argument to a\n`multiprocessing.Pool` function, for reasons described\n[here](https://stackoverflow.com/questions/25557686/python-sharing-a-lock-between-processes#comment72803059_25558333).\nThus by default `.lock` is set to `None`.\n\n### Typed SharedNDArray\n\n`SharedNDArray` is able to be typed with NumPy types. When using the `from_array()`\nconstructor, it is also able to inherit the type of the `ndarray` if it is typed using\n`numpy.typing.NDArray` (new in NumPy 1.21). Typing information does not pass through with\nslicing (`__getitem__`), however.\n\n```python\nx: npt.NDArray[np.int_] = np.arange(1024)\narr = SharedNDArray(mem_mgr, x)  # type of x is SharedNDArray[int_]\narr2 = arr[:]  # arr2 is typing.Any\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Interface for NumPy ndarray using multiprocessing SharedMemory",
    "version": "2.0.1",
    "project_urls": {
        "Homepage": "https://gitlab.com/osu-nrsg/shared-ndarray2",
        "Repository": "https://gitlab.com/osu-nrsg/shared-ndarray2"
    },
    "split_keywords": [
        "numpy",
        " shared_memory",
        " ndarray"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "29df96edf07fff44be15042a24d1a616532f28c5f7d6febb4ccd703dac42d874",
                "md5": "948536e6aae9b21df6ec18189d900dd0",
                "sha256": "d18dac0a558ae27836b250bceaee5561877c75f348907c0ab98aa25cba339727"
            },
            "downloads": -1,
            "filename": "shared_ndarray2-2.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "948536e6aae9b21df6ec18189d900dd0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.8",
            "size": 8893,
            "upload_time": "2024-05-16T23:11:36",
            "upload_time_iso_8601": "2024-05-16T23:11:36.483243Z",
            "url": "https://files.pythonhosted.org/packages/29/df/96edf07fff44be15042a24d1a616532f28c5f7d6febb4ccd703dac42d874/shared_ndarray2-2.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "71925a4cb880a09ad0d906b107227591e90c626dd45b1800db49b48f4ffa614b",
                "md5": "0813f91a227f3bdafe0ad3fb34a7ff28",
                "sha256": "3f85f266220640f7067b029bd31b42a11f7cfd88cd4ce05c94d9ce3a68d413e3"
            },
            "downloads": -1,
            "filename": "shared_ndarray2-2.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "0813f91a227f3bdafe0ad3fb34a7ff28",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8",
            "size": 8336,
            "upload_time": "2024-05-16T23:11:38",
            "upload_time_iso_8601": "2024-05-16T23:11:38.113563Z",
            "url": "https://files.pythonhosted.org/packages/71/92/5a4cb880a09ad0d906b107227591e90c626dd45b1800db49b48f4ffa614b/shared_ndarray2-2.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-16 23:11:38",
    "github": false,
    "gitlab": true,
    "bitbucket": false,
    "codeberg": false,
    "gitlab_user": "osu-nrsg",
    "gitlab_project": "shared-ndarray2",
    "lcname": "shared-ndarray2"
}
        
Elapsed time: 3.27411s