What’s the difference between async let, tasks, and task groups? async let、tasks 和 task groups 之间有什么区别?

What’s the difference between async let, tasks, and task groups? async let、tasks 和 task groups 之间有什么区别?

温馨提示:本文最后更新于2025-02-08 16:24:41,某些文章具有时效性,若有错误或已失效,请在下方留言

Swift’s async letTask, and task groups all solve a similar problem: they allow us to create concurrency in our code so the system is able to run them efficiently. Beyond that, the way they work is quite different, and which you’ll choose depends on your exact scenario.
Swift 的异步 letTask 和 task 组都解决了一个类似的问题:它们允许我们在代码中创建并发,以便系统能够有效地运行它们。除此之外,它们的工作方式完全不同,您将选择哪种取决于您的确切情况。

To help you understand how they differ, and provide some guidance on where each one is a good idea, I want to walk through the key behaviors of each of them.
为了帮助您了解它们的不同之处,并就每个选项在哪些方面是个好主意提供一些指导,我想介绍一下它们中的每一个的关键行为。

First, async let and Task are designed to create specific, individual pieces of work, whereas task groups are designed to run multiple pieces of work at the same time and gather the results. As a result, async let and Task have no way to express a dynamic amount of work that should run in parallel.
首先,async let 和 Task 旨在创建特定的单独工作,而 task groups 旨在同时运行多个工作并收集结果。因此,async let 和 Task 无法表示应并行运行的动态工作量。

For example, if you had an array of URLs and wanted to fetch them all in parallel, convert them into arrays of weather readings, then average them to a single Double, task groups would be a great choice because you won’t know ahead of time how many URLs are in your array. Trying to write this using async let or Task just wouldn’t work, because you’d have to hard-code the exact number of async let lines rather than just loop over an array.
例如,如果你有一个 URL 数组,并且想要并行获取它们,将它们转换为天气读数数组,然后将它们平均为单个 Double,那么任务组将是一个不错的选择,因为你不会提前知道数组中有多少个 URL。尝试使用 async let 或 Task 来编写这个是行不通的,因为你必须硬编码 async let 行的确切数量,而不仅仅是遍历一个数组。

Second, task groups automatically let us process results from child tasks in the order they complete, rather than in an order we specify. For example, if we wanted to fetch five pieces of data, task groups allow us to use group.next() to read whichever of the five comes back first, whereas using async let and Task would require us to await values in a specific, fixed order.
其次,任务组会自动让我们按照子任务完成的顺序处理子任务的结果,而不是按照我们指定的顺序。例如,如果我们想获取 5 个数据,任务组允许我们使用 group.next() 来读取 5 个数据中先返回的那个,而使用 async let 和 Task 则需要我们以特定的固定顺序等待值。

That alone is a helpful feature of task groups, but in some situations it goes from helpful to crucial. For example, if you have three possible servers for some data and want to use whichever one responds fastest, task groups are perfect – you can use addTask() once for each server, then call next() only once to read whichever one responded fastest.
仅此一项就是任务组的一个有用功能,但在某些情况下,它从有用变为关键。例如,如果你有三个可能的服务器来存储某些数据,并且想要使用响应最快的服务器,那么任务组是完美的——你可以为每个服务器使用一次 addTask(),然后只调用 next() 一次来读取响应最快的服务器。

Third, although all three forms of concurrency will automatically be marked as cancelled if their parent task is cancelled, only Task and task group can be cancelled directly, using cancel() and cancelAll() respectively. There is no equivalent for async let.
第三,尽管如果父任务被取消,所有三种形式的并发都会自动标记为已取消,但只有 Task 和 task group 可以分别使用 cancel() 和 cancelAll() 直接取消。async let 没有等效项。

Fourth, because async let doesn’t give us a handle to the underlying task it creates for us, it’s not possible to pass that task elsewhere – we can’t start an async let task in one function then pass that task to a different function. On the other hand, if you create a task that returns a string and never throws an error, you can pass that Task<String, Never> object around as needed.
第四,因为 async let 没有给我们一个它为我们创建的底层任务的句柄,所以不可能将该任务传递到其他地方——我们不能在一个函数中启动一个 async let 任务,然后将该任务传递给另一个函数。另一方面,如果创建一个返回字符串且从不引发错误的任务,则可以根据需要传递该 Task<String, Never> 对象。

And finally, although task groups can work with heterogeneous results – i.e., child tasks that return different types of data – it takes the extra work of making an enum to wrap the data. async let and Task do not suffer from this problem because they always return a single result type, so each result can be different.
最后,尽管任务组可以处理异构结果(即返回不同类型数据的子任务),但它需要额外的工作来制作枚举来包装数据。async let 和 Task 不会遇到这个问题,因为它们总是返回单个结果类型,因此每个结果都可以不同。

By sheer volume of advantages you might think that async let is clearly much less useful than both Task and task groups, but not all those points carry equal weight in real-world code. In practice, I would suggest you’re likely to:
从优势的绝对数量来看,您可能会认为 async let 显然比 Task 和 task groups 有用得多,但在实际代码中,并非所有这几点都具有相同的权重。在实践中,我建议你可能会:

  • Use async let the most; it works best when there is a fixed amount of work to do.
    使用 async let 最频繁;当有固定数量的工作要做时,它的效果最好。
  • Use Task for some places where async let doesn’t work, such as passing an incomplete value to a function.
    将 Task 用于 async let 不起作用的某些位置,例如将不完整的值传递给函数。
  • Use task groups least commonly, or at least use them directly least commonly – you might build other things on top of them.
    最不经常使用任务组,或者至少最不经常直接使用它们 – 你可能会在它们之上构建其他东西。

I find that order is pretty accurate in practice, for a number of reasons:
我发现 order 在实践中非常准确,原因有很多:

  1. I normally want results from all the work I start, so being able to skip some or get results in completion order is less important.
    我通常希望从我开始的所有工作中获得结果,因此能够跳过一些或按完成顺序获取结果并不重要。
  2. It’s surprisingly common to want to work with different data types, which is clumsy with task groups.
    想要使用不同的数据类型是出乎意料的普遍情况,这对于任务组来说很笨拙。
  3. If I need to be able to cancel tasks, Task is similar enough to async let that it’s easy to move across to Task without going all the way to a task group.
    如果我需要能够取消任务,Task 与 async let 非常相似,因此可以轻松移动到 Task,而无需一直转到任务组。

So, again I would recommend you start with async let, move to Task if needed, then go to task groups only if there’s something specific they offer that you need.
所以,我再次建议你从 async let 开始,如果需要,移动到 Task,然后只有在他们需要的特定内容时才转到 Task groups。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享