parsl.jobs.strategy.Strategy
- class parsl.jobs.strategy.Strategy(*, strategy: str | None, max_idletime: float)[source]
Scaling strategy.
As a workflow dag is processed by Parsl, new tasks are added and completed asynchronously. Parsl interfaces executors with execution providers to construct scalable executors to handle the variable work-load generated by the workflow. This component is responsible for periodically checking outstanding tasks and available compute capacity and trigger scaling events to match workflow needs.
Here’s a diagram of an executor. An executor consists of blocks, which are usually created by single requests to a Local Resource Manager (LRM) such as slurm, condor, torque, or even AWS API. The blocks could contain several task blocks which are separate instances on workers.
|<--min_blocks |<-init_blocks max_blocks-->| +----------------------------------------------------------+ | +--------block----------+ +--------block--------+ | executor = | | task task | ... | task task | | | +-----------------------+ +---------------------+ | +----------------------------------------------------------+
- The relevant specification options are:
min_blocks: Minimum number of blocks to maintain
init_blocks: number of blocks to provision at initialization of workflow
max_blocks: Maximum number of blocks that can be active due to one workflow
active_tasks = pending_tasks + running_tasks Parallelism = slots / tasks = [0, 1] (i.e, 0 <= p <= 1)
For example:
- When p = 0,
=> compute with the least resources possible. infinite tasks are stacked per slot.
blocks = min_blocks { if active_tasks = 0 max(min_blocks, 1) { else
- When p = 1,
=> compute with the most resources. one task is stacked per slot.
blocks = min ( max_blocks, ceil( active_tasks / slots ) )
- When p = 1/2,
=> We stack upto 2 tasks per slot before we overflow and request a new block
let’s say min:init:max = 0:0:4 and task_blocks=2 Consider the following example: min_blocks = 0 init_blocks = 0 max_blocks = 4 tasks_per_node = 2 nodes_per_block = 1
In the diagram, X <- task
at 2 tasks:
+---Block---| | | | X X | |slot slot| +-----------+
at 5 tasks, we overflow as the capacity of a single block is fully used.
+---Block---| +---Block---| | X X | ----> | | | X X | | X | |slot slot| |slot slot| +-----------+ +-----------+
Methods
__init__
(*, strategy, max_idletime)Initialize strategy.
add_executors
(executors)- add_executors(executors: Sequence[ParslExecutor]) None [source]