Skill Tracer
Skills › Scientific Agent Skills › arboreto › distributed_computing.md

distributed_computing.md

100 lines · skills/arboreto/references/distributed_computing.md at 5f2bc03

Open on GitHub
1# Dask execution and compatibility
2

Dask execution and compatibility

Raw lines 1 to 2
3## Released package versus repository source
4
5As reviewed 2026-09-30, PyPI Arboreto 0.1.6 constructs a metadata dataframe from
6an empty list even when metadata were not requested. Dask's newer dataframe
7backend rejects this with `TypeError: Must supply at least one delayed object`.
8Current Arboreto GitHub source moves that construction under `include_meta`,
9but the wheel remains 0.1.6. Installing the wheel does not include that source fix.
11Use the exact Python 3.11 dependency recipe in `SKILL.md`, and execute this
12before importing Arboreto or `dask.dataframe`:
14```python
15import dask
16dask.config.set({"dataframe.query-planning": False})
17```
19That switch selects the legacy backend retained by the tested Dask 2024.7.1.
20It is not a workaround for every current Dask release; newer versions no longer
21provide the legacy backend. Restart kernels that imported the backend too early.
22Dask and distributed must be the same pinned release on client, scheduler, and
23workers. Preserve SciPy 1.13.1 for sparse `.A` handling in the released package.
25An older Python 3.10.20 environment with Dask/distributed 2023.12.1, NumPy 1.26.4,
26pandas 1.5.3, scikit-learn 1.3.2, and SciPy 1.11.4 also passed the synthetic
27profiles. The same old Dask stack failed to import on Python 3.11.11. This is
28why the main recipe specifies an entire tested stack instead of loose bounds.

Released package versus repository source

As reviewed 2026-09-30, PyPI Arboreto 0.1.6 constructs a metadata dataframe from an empty list even when metadata were not requested. Dask's newer dataframe backend rejects this with TypeError: Must supply at least one delayed object. Current Arboreto GitHub source moves that construction under include_meta, but the wheel remains 0.1.6. Installing the wheel does not include that source fix.

Use the exact Python 3.11 dependency recipe in SKILL.md, and execute this before importing Arboreto or dask.dataframe:

import dask
dask.config.set({"dataframe.query-planning": False})

That switch selects the legacy backend retained by the tested Dask 2024.7.1. It is not a workaround for every current Dask release; newer versions no longer provide the legacy backend. Restart kernels that imported the backend too early. Dask and distributed must be the same pinned release on client, scheduler, and workers. Preserve SciPy 1.13.1 for sparse .A handling in the released package.

An older Python 3.10.20 environment with Dask/distributed 2023.12.1, NumPy 1.26.4, pandas 1.5.3, scikit-learn 1.3.2, and SciPy 1.11.4 also passed the synthetic profiles. The same old Dask stack failed to import on Python 3.11.11. This is why the main recipe specifies an entire tested stack instead of loose bounds.

Raw lines 3 to 29
30## Bounded local workers
32Illustrative real-data adapter; one-worker dense/sparse synthetic inference and
33the wrapper were executed with this context-manager pattern:
35```python
36import dask
37dask.config.set({"dataframe.query-planning": False})
38from distributed import LocalCluster, Client
39from arboreto.algo import grnboost2
40import pandas as pd
42if __name__ == "__main__":
43 expression = pd.read_csv("expression.tsv", sep="\t", index_col=0)
44 with LocalCluster(n_workers=2, threads_per_worker=1,
45 memory_limit="2GB", dashboard_address=None) as cluster:
46 with Client(cluster) as client:
47 network = grnboost2(expression_data=expression, tf_names=["TF1", "TF2"],
48 client_or_address=client, seed=777)
49 network.to_csv("network.tsv", sep="\t", index=False, header=False)
50```
52The memory limit is per worker, not for the whole job. Measure a pilot before
53choosing worker count: Arboreto scatters the TF matrix to every worker and the
54full expression matrix still resides on the client. A dense DataFrame is
55converted to NumPy internally; it has no inherent distributed-storage advantage.
56CSC can preserve sparse inputs, but regressions and target conversions still
57allocate memory. A shared filesystem is not inherently required when the client
58loads and scatters all inputs.
60The default Arboreto `"local"` path uses Dask's automatic worker configuration,
61not a promise to use every physical core. Explicit workers make the resource
62budget clear. Context managers close resources on exceptions; a supplied client
63is not closed by Arboreto. Reusing a client is supported upstream, but a repeated
64in-process-client probe here cancelled a future after its first run. Use a fresh
65client/cluster per run if this occurs; separate process clients passed all probes.

Bounded local workers

Illustrative real-data adapter; one-worker dense/sparse synthetic inference and the wrapper were executed with this context-manager pattern:

import dask
dask.config.set({"dataframe.query-planning": False})
from distributed import LocalCluster, Client
from arboreto.algo import grnboost2
import pandas as pd

if __name__ == "__main__":
    expression = pd.read_csv("expression.tsv", sep="\t", index_col=0)
    with LocalCluster(n_workers=2, threads_per_worker=1,
                      memory_limit="2GB", dashboard_address=None) as cluster:
        with Client(cluster) as client:
            network = grnboost2(expression_data=expression, tf_names=["TF1", "TF2"],
                                client_or_address=client, seed=777)
    network.to_csv("network.tsv", sep="\t", index=False, header=False)

The memory limit is per worker, not for the whole job. Measure a pilot before choosing worker count: Arboreto scatters the TF matrix to every worker and the full expression matrix still resides on the client. A dense DataFrame is converted to NumPy internally; it has no inherent distributed-storage advantage. CSC can preserve sparse inputs, but regressions and target conversions still allocate memory. A shared filesystem is not inherently required when the client loads and scatters all inputs.

The default Arboreto "local" path uses Dask's automatic worker configuration, not a promise to use every physical core. Explicit workers make the resource budget clear. Context managers close resources on exceptions; a supplied client is not closed by Arboreto. Reusing a client is supported upstream, but a repeated in-process-client probe here cancelled a future after its first run. Use a fresh client/cluster per run if this occurs; separate process clients passed all probes.

Raw lines 30 to 66
67## Remote scheduler (illustrative; not executed)
69Use the same environment/backend configuration on all nodes. These are the
70current Dask CLI command forms; replace `scheduler.example` with your own trusted
71scheduler hostname:
73```bash
74# Head node
75DASK_DATAFRAME__QUERY_PLANNING=False dask scheduler
77# Worker node: four worker processes, one thread each, 4 GB each
78DASK_DATAFRAME__QUERY_PLANNING=False dask worker tcp://scheduler.example:8786 \
79 --nworkers 4 --nthreads 1 --memory-limit 4GB
80```
82`--nprocs` is stale; current workers use `--nworkers`. Avoid shell comments after
83continuation backslashes. `Client("tcp://scheduler.example:8786")` can be passed
84as `client_or_address` inside a context manager, after the pre-import backend
85configuration. TCP scheduler/worker connections are executable-code trust
86boundaries: use a trusted network and the deployment's configured TLS/auth setup.
88For a dashboard, enable it deliberately and inspect `client.dashboard_link`;
89`Client()` does not guarantee that a URL will be printed. Restrict dashboard
90exposure according to the deployment. Monitor worker restarts, spill, client
91memory, and target-level retry warnings before interpreting missing links.

Remote scheduler (illustrative; not executed)

Use the same environment/backend configuration on all nodes. These are the current Dask CLI command forms; replace scheduler.example with your own trusted scheduler hostname:

# Head node
DASK_DATAFRAME__QUERY_PLANNING=False dask scheduler

# Worker node: four worker processes, one thread each, 4 GB each
DASK_DATAFRAME__QUERY_PLANNING=False dask worker tcp://scheduler.example:8786 \
  --nworkers 4 --nthreads 1 --memory-limit 4GB

--nprocs is stale; current workers use --nworkers. Avoid shell comments after continuation backslashes. Client("tcp://scheduler.example:8786") can be passed as client_or_address inside a context manager, after the pre-import backend configuration. TCP scheduler/worker connections are executable-code trust boundaries: use a trusted network and the deployment's configured TLS/auth setup.

For a dashboard, enable it deliberately and inspect client.dashboard_link; Client() does not guarantee that a URL will be printed. Restrict dashboard exposure according to the deployment. Monitor worker restarts, spill, client memory, and target-level retry warnings before interpreting missing links.

Raw lines 67 to 92
93## Verified sources
95- [Arboreto user guide](https://arboreto.readthedocs.io/en/latest/userguide.html)
96- [Current Arboreto graph construction](https://github.com/aertslab/arboreto/blob/master/arboreto/core.py)
97- [Dask 2024.7.1 backend selection](https://github.com/dask/dask/blob/2024.7.1/dask/dataframe/__init__.py)
98- [Current Dask from_delayed](https://github.com/dask/dask/blob/main/dask/dataframe/dask_expr/io/_delayed.py)
99- [Dask command line](https://docs.dask.org/en/stable/deploying-cli.html)
100- [SciPy 1.14 removals](https://docs.scipy.org/doc/scipy/release/1.14.0-notes.html)