Как работят механизмите async и await под капака?
sobes.tech AI
Отговор от AI
Async/await в Swift е базиран на структурирана конкуренция и използва Dispatch/Global Actors. Механизмите, които работят под капака, са:
-
Стил на продължение: Асиметричните функции се компилират в стил на продължения. Вместо незабавно връщане на стойност, управлението се прехвърля към Swift runtime, който запазва текущото състояние на функцията (локални променливи, указател за изпълнение). Когато асинхронната операция приключи, runtime възобновява изпълнението на функцията от запазеното състояние.
-
Task: Всяко извикване на
asyncфункция създава или се присъединява към структуриранаTask.Taskпредставлява единица работа и формира йерархия. РодителскиятTaskочаква завършването на дъщернитеTask. -
Job:
Taskсе разбива на по-малки единици работа, наречениJob.Jobпредставлява фрагмент от код, който може да бъде изпълнен на изпълнител (Executor). -
Executor: Изпълнителят отговаря за стартирането на
Job. В стандартната библиотека се използват глобалниDispatchQueueкато изпълнители за повечето асинхронни задачи. Специфичните контексти (например,MainActor) имат свои специализирани изпълнители. -
Точки на спиране:
awaitе точка на спиране (suspension point). При достигане наawait, функцията се спира, управлението се прехвърля към извикващия код или изпълнителя, а текущиятJobприключва. Swift runtime запазва състоянието на функцията. -
Възобновяване: Когато асинхронната операция, на която е очаквал
await, приключи, Swift runtime създава новJobза продължаване на изпълнението на спрената функция. ТозиJobсе поставя в опашката на изпълнителя. -
Отмяна: Структурираната конкуренция поддържа йерархично отмяна. Отмяната на родителски
Taskавтоматично отменя всички негови дъщерниTask. Асиметричните операции могат да проверяват статуса на отмяна и да реагират съответно.
Ето опростен пример за компилация на async функция:
// Начална async функция
func fetchData() async -> Data {
// Асиметрична операция
let data = await URLSession.shared.data(from: url).0
return data
}
// Опростено представяне на компилация
// Вместо връщане, функцията приема Continuation
func fetchData(_ continuation: Continuation<Data, Error>) {
// Начален код на функцията
let url = URL(string: "...")! // Пример
// Стартиране на асинхронната операция
URLSession.shared.data(from: url) { data, _, error in
// Този блок се изпълнява след приключване на асинхронната операция
if let data = data {
// Предаване на резултата към continuation, възобновяване на функцията
continuation.resume(returning: data)
} else if let error = error {
continuation.resume(throwing: error)
} else {
// Обработка на други случаи
continuation.resume(throwing: NSError(domain: "", code: 0, userInfo: nil))
}
}
// Функцията приключва тук, очаквайки извикване на resume от continuation
}
Await по същество е синтактичен захар над управлението на Continuation и планирането на Job на изпълнителя. Спирането не блокира директно нишката, а позволява на изпълнителя да изпълнява други Job.