chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
<!--[metadata]
|
||||
title = "Multiprocess logging"
|
||||
thumbnail = "https://static.rerun.io/multiprocessing/959e2c675f52a7ca83e11e5170903e8f0f53f5ed/480w.png"
|
||||
thumbnail_dimensions = [480, 480]
|
||||
tags = ["API example"]
|
||||
-->
|
||||
|
||||
Demonstrates how Rerun can work with the Python `multiprocessing` library.
|
||||
|
||||
<picture>
|
||||
<source media="(max-width: 480px)" srcset="https://static.rerun.io/multiprocessing/72bcb7550d84f8e5ed5a39221093239e655f06de/480w.png">
|
||||
<source media="(max-width: 768px)" srcset="https://static.rerun.io/multiprocessing/72bcb7550d84f8e5ed5a39221093239e655f06de/768w.png">
|
||||
<source media="(max-width: 1024px)" srcset="https://static.rerun.io/multiprocessing/72bcb7550d84f8e5ed5a39221093239e655f06de/1024w.png">
|
||||
<source media="(max-width: 1200px)" srcset="https://static.rerun.io/multiprocessing/72bcb7550d84f8e5ed5a39221093239e655f06de/1200w.png">
|
||||
<img src="https://static.rerun.io/multiprocessing/72bcb7550d84f8e5ed5a39221093239e655f06de/full.png" alt="">
|
||||
</picture>
|
||||
|
||||
## Used Rerun types
|
||||
[`Boxes2D`](https://www.rerun.io/docs/reference/types/archetypes/boxes2d), [`TextLog`](https://www.rerun.io/docs/reference/types/archetypes/text_log)
|
||||
|
||||
## Logging and visualizing with Rerun
|
||||
This example demonstrates how to use the Rerun SDK with `multiprocessing` to log data from multiple processes to the same Rerun viewer.
|
||||
It starts with the definition of the function for logging, the `task`, followed by typical usage of Python's `multiprocessing` library.
|
||||
|
||||
The function `task` is decorated with `@rr.shutdown_at_exit`. This decorator ensures that data is flushed when the task completes, even if the normal `atexit`-handlers are not called at the termination of a multiprocessing process.
|
||||
|
||||
```python
|
||||
@rr.shutdown_at_exit
|
||||
def task(child_index: int) -> None:
|
||||
rr.init("rerun_example_multiprocessing")
|
||||
|
||||
rr.connect_grpc()
|
||||
|
||||
title = f"task_{child_index}"
|
||||
rr.log(
|
||||
"log",
|
||||
rr.TextLog(
|
||||
f"Logging from pid={os.getpid()}, thread={threading.get_ident()} using the Rerun recording id {rr.get_recording_id()}"
|
||||
),
|
||||
)
|
||||
if child_index == 0:
|
||||
rr.log(title, rr.Boxes2D(array=[5, 5, 80, 80], array_format=rr.Box2DFormat.XYWH, labels=title))
|
||||
else:
|
||||
rr.log(
|
||||
title,
|
||||
rr.Boxes2D(
|
||||
array=[10 + child_index * 10, 20 + child_index * 5, 30, 40],
|
||||
array_format=rr.Box2DFormat.XYWH,
|
||||
labels=title,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
The main function initializes Rerun with a specific application ID and manages the multiprocessing processes for logging data to the Rerun viewer.
|
||||
|
||||
> Caution: Ensure that the `recording id` specified in the main function matches the one used in the logging functions
|
||||
```python
|
||||
def main() -> None:
|
||||
# … existing code …
|
||||
|
||||
rr.init("rerun_example_multiprocessing")
|
||||
rr.spawn(connect=False) # this is the Viewer that each child process will connect to
|
||||
|
||||
task(0)
|
||||
|
||||
for i in [1, 2, 3]:
|
||||
p = multiprocessing.Process(target=task, args=(i,))
|
||||
p.start()
|
||||
p.join()
|
||||
```
|
||||
|
||||
## Run the code
|
||||
To run this example, make sure you have the Rerun repository checked out and the latest SDK installed:
|
||||
```bash
|
||||
pip install --upgrade rerun-sdk # install the latest Rerun SDK
|
||||
git clone git@github.com:rerun-io/rerun.git # Clone the repository
|
||||
cd rerun
|
||||
git checkout latest # Check out the commit matching the latest SDK release
|
||||
```
|
||||
Install the necessary libraries specified in the requirements file:
|
||||
```bash
|
||||
pip install -e examples/python/multiprocessing
|
||||
```
|
||||
To experiment with the provided example, simply execute the main Python script:
|
||||
```bash
|
||||
python -m multiprocessing # run the example
|
||||
```
|
||||
If you wish to customize it, explore additional features, or save it use the CLI with the `--help` option for guidance:
|
||||
```bash
|
||||
python -m multiprocessing --help
|
||||
```
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Shows how rerun can work with multiprocessing."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import multiprocessing
|
||||
import os
|
||||
import threading
|
||||
|
||||
import rerun as rr # pip install rerun-sdk
|
||||
|
||||
|
||||
# Python does not guarantee that the normal atexit-handlers will be called at the
|
||||
# termination of a multiprocessing.Process. Explicitly add the `shutdown_at_exit`
|
||||
# decorator to ensure data is flushed when the task completes.
|
||||
@rr.shutdown_at_exit # type: ignore[misc]
|
||||
def task(child_index: int) -> None:
|
||||
# In the new process, we always need to call init with the same `application_id`.
|
||||
# By default, the `recording_id`` will match the `recording_id`` of the parent process,
|
||||
# so all of these processes will have their log data merged in the viewer.
|
||||
# Caution: if you manually specified `recording_id` in the parent, you also must
|
||||
# pass the same `recording_id` here.
|
||||
rr.init("rerun_example_multiprocessing")
|
||||
|
||||
# We then have to connect to the viewer instance.
|
||||
rr.connect_grpc()
|
||||
|
||||
title = f"task_{child_index}"
|
||||
rr.log(
|
||||
"log",
|
||||
rr.TextLog(
|
||||
f"Logging from pid={os.getpid()}, thread={threading.get_ident()} using the rerun recording id {rr.get_recording_id()}",
|
||||
),
|
||||
)
|
||||
if child_index == 0:
|
||||
rr.log(title, rr.Boxes2D(array=[5, 5, 80, 80], array_format=rr.Box2DFormat.XYWH, labels=title))
|
||||
else:
|
||||
rr.log(
|
||||
title,
|
||||
rr.Boxes2D(
|
||||
array=[10 + child_index * 10, 20 + child_index * 5, 30, 40],
|
||||
array_format=rr.Box2DFormat.XYWH,
|
||||
labels=title,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Test multi-process logging to the same Rerun server")
|
||||
parser.parse_args()
|
||||
|
||||
rr.init("rerun_example_multiprocessing")
|
||||
rr.spawn(connect=False) # this is the viewer that each child process will connect to
|
||||
|
||||
task(0)
|
||||
|
||||
for i in [1, 2, 3]:
|
||||
p = multiprocessing.Process(target=task, args=(i,))
|
||||
p.start()
|
||||
p.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,12 @@
|
||||
[project]
|
||||
name = "multiprocess_logging"
|
||||
version = "0.1.0"
|
||||
readme = "README.md"
|
||||
dependencies = ["rerun-sdk"]
|
||||
|
||||
[project.scripts]
|
||||
multiprocess_logging = "multiprocess_logging:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
Reference in New Issue
Block a user