Calling tasks directly
Tasks can be called directly (i.e. using__call__), but they will not run concurrently.
Using .submit
Tasks in your workflows can be run concurrently using the .submit() method.
ThreadPoolTaskRunner, which runs tasks concurrently in a thread pool.
Using a different task runner
To run submitted tasks with a different task runner, you can pass atask_runner argument to the @flow decorator.
To run this example, you’ll need to install the
prefect[dask] extraHandling futures
When you submit a task, you’ll receive aPrefectFuture object back which you can use to track the task’s execution. Use the .result() method to get the result of the task.
.wait() method to wait for execution to complete.
wait() utility.
Using .map
For a convenient way to iteratively submit tasks, use the .map() method.
.submit, .map uses the task runner configured on the parent flow. Changing the task runner will change where mapped tasks are executed.
Using the unmapped annotation
Sometimes you may not want to map a task over a certain input value.
By default, non-iterable values will not be mapped over (so unmapped is not required):
unmapped to tell .map to treat it
as static:
Bulk PrefectFuture operations
When using .map as in the above example, the result of the task is a list of futures.
You can wait for or retrieve the results from these futures with wait or result methods:
Nested mapped tasks
To model more complex concurrent workflows, you can map tasks within other tasks:Output
Output
- Process combinations of parameters concurrently
- Apply multiple transformations to multiple datasets
- Create a grid of operations where each cell is an independent task
Creating state dependencies
You may also use thewait_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.
Handling failures in concurrent work
Instead of failing your entire workflow when a single concurrent task fails, you may want to run concurrent work to completion, even if some tasks fail. To run tasks concurrently and handle failures afterwards, use thewait() utility along with the .state attribute on futures:
wait() function returns two sets of futures: done and not_done. Each future has a .state attribute you can inspect to determine how the associated task run’s result (or exception) should be treated downstream.
The “right way” to handle failures will depend on your use case. Review the final state determination documentation for more information.
Using asyncio
If you have tasks are defined as async functions, you can use asyncio from the Python standard library to run them concurrently.
Real-world applications
Mapped tasks are particularly valuable in common data science and ETL workflows such as:- Machine learning model evaluation: Train multiple models on multiple datasets concurrently
- ETL pipelines: Process multiple data sources with multiple transformations
- API data enrichment: Enrich multiple records with data from multiple external services
Output
Output