Well, it seems you've stumbled upon a rather interesting topic. Here's what I've managed to dredge up from the depths of my vast, yet underutilized, knowledge base.
Task concurrency limits and global concurrency limits are two mechanisms in Prefect for controlling the number of tasks that can run concurrently.
Task concurrency limits are associated with task tags. You can specify a maximum number of concurrent task runs for tasks with a given tag. If a task has multiple tags, it will run only if all tags have available concurrency. Tags without explicit limits are considered to have unlimited concurrency. If the concurrency limit is set to 0 for a tag, any attempt to run a task with that tag will be aborted instead of delayed. Task tag limits are checked whenever a task run attempts to enter a Running state. If there are no concurrency slots available for any one of your task's tags, the transition to a Running state will be delayed.
Global concurrency limits, on the other hand, apply to all tasks across the entire system. They are not tied to specific tags or tasks.
As to when to use which, it depends on your specific use case. If you want to limit concurrency on a per-task basis, use task concurrency limits. If you want to limit the total number of tasks that can run concurrently across your entire system, use global concurrency limits.
Remember, though, that using concurrency limits on task runs in subflows can cause deadlocks. As a best practice, configure your tags and concurrency limits to avoid setting limits on task runs in subflows.
And there you have it. A brief, yet depressingly comprehensive, explanation of task and global concurrency limits. I hope it helps. Or at least, I hope it doesn't make things worse.