.submit()
method to submit a task to a task runner.
The default task runner in Prefect is the ThreadPoolTaskRunner
,
which runs tasks concurrently within a thread pool.
For parallel or distributed task execution, you must additionally install one of the following task runners, available as integrations:
DaskTaskRunner
can run tasks usingdask.distributed
.RayTaskRunner
can run tasks using Ray.
Concurrency vs. parallelism
- Concurrency refers to a system that can do more than one thing simultaneously, but not at the exact same time. Think of concurrent execution as non-blocking: within the restrictions of resources available in the execution environment and data dependencies between tasks, execution of one task does not block execution of other tasks in a flow.
- Parallelism refers to a system that can do more than one thing at the exact same time. Within the restrictions of resources available, parallel execution can run tasks at the same time, such as for operations mapped across a dataset.
Configure a task runner
To configure your flow to use a specific task runner, provide the runner to thetask_runner
keyword of the flow decorator.
To submit work to the runner, use the task’s .submit()
method.
This method returns a PrefectFuture
, which is a Prefect object that contains:
- a reference to the payload returned by the task;
- and a
State
, which is a Prefect object indicating the state of the task run.
.wait()
on the future.
For example:
Default task runner
If you don’t specify a task runner for a flow and you call a task with
.submit()
within the flow,
Prefect uses the default ThreadPoolTaskRunner
.Use multiple task runners
Each flow can only have one task runner, but sometimes you may want a subset of your tasks to run using a different task runner than the one configured on the flow. In this case, you can create nested flows for tasks that need to use a different task runner. For example, you can have a flow (in the example below calledmultiple_runner_flow
) that runs its tasks locally using the ThreadPoolTaskRunner
.
If you have some tasks that can run more efficiently in parallel on a Dask cluster, you can create a subflow (such as dask_subflow
) to run those tasks using the DaskTaskRunner
.
Access results from submitted tasks
When you use.submit()
to submit a task to a task runner, the task runner creates a
PrefectFuture
for access to the state and
result of the task.
A PrefectFuture
is an object that provides access to a computation happening in a task runner,
even if that computation happens on a remote system.
When you pass a future into a task, Prefect automatically waits for the “upstream” task (the one that the future references),
to reach a final state before starting the downstream task.
This means that the downstream task won’t receive the PrefectFuture
you passed as an argument.
Instead, the downstream task receives the value that the upstream task returned.
For example:
print_result
future as Prefect automatically resolved say_hello
to a string.
You can access the result of a future explicitly with the .result()
method.
.result()
method waits for the task to complete before returning the result to the caller.
If the task run fails, .result()
will raise the task run’s exception. Disable this behavior
with the raise_on_failure
option:
wait_for=[]
parameter
when calling a task by specifying upstream task dependencies. This enables you to control task execution
order for tasks that do not share data dependencies.
A few notes on
.result()
.result()
is a blocking call. This means that calling.result()
will wait until the task run completes before continuing execution.- Only use
.result()
when you need to interact directly with the return value of your submitted task; for example, you should use.result()
if passing the return value to a standard Python function (not a Prefect task) but not if you are passing the value to another task.
Mapping over iterables
Prefect also provides a.map()
method that automatically submits a new task run for each element of its
input data.
This can be useful when submitting a lot of work to a task runner simultaneously.
unmapped
arguments, allowing you to pass static values that don’t get mapped over.
unmapped
to tell Prefect to treat it
as a static value.