Skip to content

Matrix Multiplication with TaskVine

The quickstart used vine.Task to execute a Linux command. This exercise introduces vine.PythonTask, which executes a Python function with Python arguments and returns the function's value as task.output.

The application multiplies two pairs of matrices stored as CSV files. Each PythonTask reads declared input files from its worker sandbox and writes a declared output file for TaskVine to return.

Before you begin

Complete Access and Setup before starting. Both setup routes place the repository at ~/tutorial and provide the matrix dependencies in tutorial-env.

Check which Conda environment is active:

echo "${CONDA_PREFIX:-No Conda environment is active}"

The path should end in /tutorial-env. If it does not, activate the tutorial environment using the command for your setup:

Live tutorial

source /opt/tutorial/activate.sh

Self-managed

conda activate tutorial-env

Continue with either setup

1. Enter the example directory

cd ~/tutorial/examples/taskvine/matrix-files
ls

You should see at least:

README.md  data  environment.yml  matrix-files.py

After a previous run, you may also see generated directories such as vine-run-info or outputs. This is normal.

2. Check the matrix dependencies

The example includes a standalone environment.yml. You do not need to create another environment during this tutorial because tutorial-env already contains these packages:

dependencies:
  - python=3.11
  - ndcctools=7.17.1
  - cloudpickle=3.1.2
  - numpy=2.4.3

Each dependency has a purpose:

Dependency Purpose
Python Runs the manager and the function on workers.
TaskVine (ndcctools) Provides the manager, PythonTask, worker, and factory.
cloudpickle Serializes the Python function, its arguments, and its return value.
NumPy Reads, multiplies, and writes the CSV matrices.

A PythonTask serializes Python code and values; it does not automatically install imported third-party libraries. Because multiply_matrix_files imports NumPy, NumPy must be available in the worker's Python environment. Starting both the manager and vine_factory from tutorial-env gives them the same dependencies.

Confirm the important imports:

python -c "import cloudpickle, numpy; import ndcctools.taskvine; print('PythonTask environment: OK')"

3. Start the manager application

In the first terminal, run:

python matrix-files.py

The program creates a manager with a unique project name, submits two tasks, prints the manager's selected port, and waits:

Manager name: <MANAGER_NAME>
Listening on port: <PORT>
Factory scratch directory: <SCRATCH_DIRECTORY>

In a second terminal, activate this environment and run:
vine_factory ... --scratch-dir <SCRATCH_DIRECTORY> --manager-name <MANAGER_NAME>

Submitted two file-based PythonTasks. Waiting for the factory worker...

Leave the manager running.

4. Start a local TaskVine factory

Open a second terminal on the same tutorial server or self-managed Linux system.

Live tutorial

Connect to your assigned server if necessary, then activate the shared tutorial environment:

source /opt/tutorial/activate.sh

Self-managed

Activate the tutorial environment:

conda activate tutorial-env

Continue with either setup

Copy the complete vine_factory command printed by the manager and run it in the second terminal. It will look like:

vine_factory -T local --min-workers=1 --max-workers=2 \
  --timeout=60 \
  --scratch-dir "$HOME/vine_scratch/<MANAGER_NAME>" \
  --manager-name <MANAGER_NAME>

Use the complete command printed by the program. It contains the actual manager name and the matching absolute scratch-directory path.

AWS address warning

On the live tutorial server, a worker may briefly report that the public manager address is not one of the machine's local interfaces. If the worker then connects through a private 172.31.x.x address and tasks begin completing, the warning is harmless. If tasks remain waiting, ask an instructor for help.

The options have distinct purposes:

Option Meaning
-T local Launch workers as local processes instead of submitting them to an HPC batch system.
--manager-name Find the named manager through the TaskVine catalog.
--min-workers=1 Maintain at least one worker while the manager is active.
--max-workers=2 Allow the factory to scale up to two workers when tasks are waiting.
--timeout=60 Stop a worker after 60 seconds without a manager connection or work.
--scratch-dir Keep this run's factory files and worker executable separate from other runs.

Unlike the direct worker command used by the quickstart, the factory uses the project name to discover the manager and maintains the requested worker population. Catalog discovery requires internet access.

By default, vine_factory uses one shared factory scratch directory per user. A worker that remains briefly after Ctrl-C can keep files in that directory busy. This example instead uses $HOME/vine_scratch/<MANAGER_NAME>. The manager name includes the username and process ID, so every run receives a new factory scratch directory and does not overwrite another run's vine_worker executable. The 60-second worker timeout also limits how long a worker can remain after the manager or factory has stopped.

This tutorial deliberately leaves worker cores, memory, and disk unspecified. For other applications and HPC batch systems, the factory can select a different batch type, request worker resources, read a configuration file, and manage a larger worker range. See the official TaskVine factory overview and vine_factory command reference.

5. Inspect the results

Return to the manager terminal. The two tasks may finish in either order.

You should finish with output similar to:

Completed A x B on <WORKER_ADDRESS>: [[19.0, 22.0], [43.0, 50.0]]
Completed C x D on <WORKER_ADDRESS>: [[6.0, 2.0], [8.0, 4.0]]

File-based PythonTask matrix multiplication complete.
Outputs: outputs/result-ab.csv and outputs/result-cd.csv

Inspect the returned files:

cat outputs/result-ab.csv
cat outputs/result-cd.csv

After the manager completes, return to the factory terminal and press Ctrl-C. The factory is a long-running worker-management process and does not exit merely because one manager run has finished.

6. Connect the code to the execution model

The full program is matrix-files.py. The sections below isolate the important TaskVine concepts.

Define the worker function

def multiply_matrix_files(input_a, input_b, output):
    import numpy as np

    matrix_a = np.loadtxt(input_a, delimiter=",")
    matrix_b = np.loadtxt(input_b, delimiter=",")
    result = np.matmul(matrix_a, matrix_b)
    np.savetxt(output, result, delimiter=",", fmt="%g")
    return result.tolist()

The worker function contains every step it needs: importing NumPy, loading both inputs, multiplying them, writing the output, and returning the result. NumPy is an external dependency, so it must be available in the environment used by the manager and workers.

Create a named manager and factory scratch directory

manager_name = f"taskvine-matrix-files-{getpass.getuser()}-{os.getpid()}"
scratch_dir = Path.home() / "vine_scratch" / manager_name
scratch_dir.mkdir(parents=True, exist_ok=True)
manager = vine.Manager(port=0, name=manager_name)

Port 0 selects an available port. The project name is advertised through the TaskVine catalog, allowing vine_factory --manager-name to discover the manager without copying its hostname and port.

The username distinguishes participants, while the process ID gives every run a fresh name. The same manager name also gives the factory an isolated scratch directory under the participant's home directory.

Declare manager-side files

matrix_a = manager.declare_file(str(DATA_DIR / "matrix-a.csv"))
matrix_b = manager.declare_file(str(DATA_DIR / "matrix-b.csv"))
result_ab = manager.declare_file(str(OUTPUT_DIR / "result-ab.csv"))

Files are declared before tasks consume or produce them. The input declarations identify existing manager-side files. The output declaration identifies where TaskVine should materialize a returned file.

Attach files using sandbox names

task_ab = vine.PythonTask(
    multiply_matrix_files,
    "matrix-a.csv",
    "matrix-b.csv",
    "result.csv",
)
task_ab.add_input(matrix_a, "matrix-a.csv")
task_ab.add_input(matrix_b, "matrix-b.csv")
task_ab.add_output(result_ab, "result.csv")
task_ab.set_tag("A x B")
task_ab.set_cores(1)
manager.submit(task_ab)

Every task executes in a private worker sandbox. The remote names passed to add_input and add_output must match the filenames used by the Python function.

TaskVine transfers the two inputs into the sandbox, executes multiply_matrix_files, retrieves result.csv, and materializes it as outputs/result-ab.csv on the manager side. The returned matrix remains available separately as the PythonTask's completed.output value.

Collect returned Python values

while not manager.empty():
    completed = manager.wait(5)
    if not completed:
        continue

    result = completed.output

wait(5) returns a completed task or returns nothing after five seconds. The application continues waiting while submitted tasks remain. Results may arrive in either order.

Unlike the quickstart's command task, completed.output is not captured command-line text. For a PythonTask, it is the value returned by multiply_matrix_files.

Task versus PythonTask

vine.Task vine.PythonTask
Executes a Unix command line Executes a Python function
Quickstart runs grep and wc Matrix example runs multiply_matrix_files
Standard output is command text Output is the function's Python return value
Useful for commands, scripts, and executables Useful for Python-native computation
Input and output files may be attached Inherits Task file and resource methods

Both task types are submitted with manager.submit, scheduled on workers, and returned through manager.wait.

Further reading

TaskVine hands-on navigation