- Asynchronous code - can be suspended and resumed later.
- Parallel code - multiple pieces of code run simultaneously.
- A program that uses parallel and asynchronous code carries out multiple operations at a time; it suspends operations that are waiting for an external system, and makes it easier to write this code in a memory-safe way.
- concurrency to refer to this common combination of asynchronous and parallel code.
Asynchronous Functions
- synchronous functions and methods, which either run to completion, throw an error, or never return.
Asynchronous function or method still does one of those three things, but that can be suspended while it’s partway through execution.
To indicate that a function or method is asynchronous, you write the async keyword in its declaration.
When calling an asynchronous method, execution suspends until that method returns. Use await in front of the call to mark the possible suspension point
example :
func listPhotos(inGallery name: String) async -> [String] {
let result = // some asynchronous networking code
return result
}
let photoNames = await listPhotos(inGallery: "Summer Vacation")
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
let photo = await downloadPhoto(named: name)
show(photo)
Places in your program can call asynchronous functions or methods:
- Code in the body of an asynchronous function, method, or property.
- Code in the static main() method of a structure, class, or enumeration that’s marked with
@main
. - Code in an unstructured child task
In above example, Instead of returning whole array at once after all of the array’s elements are ready, wait for one element of the collection at a time using an asynchronous sequence using for-await-in loop.
example :
import Foundation
let handle = FileHandle.standardInput
for try await line in handle.bytes.lines {
print(line)
}
for-await-in loop can be used for any types that conforms to the AsyncSequence protocol. Similarly for-in for Sequence.
Calling Asynchronous Functions in Parallel
Calling an asynchronous function with await runs only one piece of code at a time.
To call an asynchronous function and let it run in parallel with code around it, write async in front of let when you define a constant, and then write await each time you use the constant.
example :
async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])
let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
- Call asynchronous functions with await when the code on the following lines depends on that function’s result. This creates work that is carried out sequentially.
- Call asynchronous functions with async-let when you don’t need the result until later in your code. This creates work that can be carried out in parallel.
Structured Concurrency
A task is a unit of work that can be run asynchronously as part of your program. All asynchronous code runs as part of some task.
- Task can be added as a child to a Task Group.
- async-let syntax creates a child task.
- Each task in a task group has the same parent task, and each task can have child tasks. Because of the explicit relationship between tasks and task groups, this approach is called structured concurrency
Unstructured Concurrency
- Unstructured task doesn’t have a parent task.
- To create an unstructured task that runs on the current actor, call the Task.init(priority:operation:) initializer.
- To create an unstructured task that’s not part of the current actor, known more specifically as a detached task, call the Task.detached(priority:operation:) class method.
Actors
- Actors are reference types.
- Unlike classes, actors allow only one task to access their mutable state at a time, which makes it safe for code in multiple tasks to interact with the same instance of an actor.
- You create an instance of an actor using the same initializer syntax as structures and classes. When you access a property or method of an actor, you use await to mark the potential suspension point.
example :
actor TemperatureLogger {
let label: String
var measurements: [Int]
private(set) var max: Int
init(label: String, measurement: Int) {
self.label = label
self.measurements = [measurement]
self.max = measurement
}
}
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max)
Top comments (0)