Sobes.tech
Senior

Ինչպես են աշխատում async և await մեխանիզմները թաքնված?

sobes.tech AI

Պատասխան AI-ից

Swift- ի Async/await կառուցվածքային կոնկուրենության վրա է հիմնված և օգտագործում է Dispatch/Global Actors-ները: Մտածող մեխանիզմները, որոնք աշխատում են ներքևում, են՝

  1. Կոնտինյուացիայի ոճը: Ասինխրոն ֆունկցիաները կոմպիլյացվում են կոնտինյուացիայի ոճով: Փոխարենը անմիջապես վերադարձնել արժեքը, կառավարումը փոխանցվում է Swift runtime-ին, որը պահպանում է ֆունկցիայի ընթացիկ վիճակը (տեղական փոփոխականներ, կատարողական ցուցիչ): Երբ ասինխրոն օպերացիան ավարտվի, runtime-ը վերականգնում է ֆունկցիայի կատարումը պահված վիճակից:

  2. Task: Յուրաքանչյուր async ֆունկցիայի կանչը ստեղծում կամ միանում է կառուցվածքային Task-ին: Task ներկայացնում է աշխատանքային միավոր և ձևավորում է հիերարխիա: Պատկանող Task-ը սպասում է ենթաTask-ների ավարտին:

  3. Job: Task-ը բաժանվում է փոքր աշխատանքային միավորների՝ Job-ների: Job-ը ներկայացնում է կոդի հատված, որը կարող է կատարվել կատարողում (Executor):

  4. Executor: Կատարողը պատասխանատու է Job-ի մեկնարկի համար: Ստանդարտ գրադարանում օգտագործվում են գլոբալ DispatchQueue-ներ որպես կատարողներ մեծամասնության ասինխրոն առաջադրանքների համար: Սպեցիֆիկ կոնտեքստերը (օր., MainActor) ունեն իրենց մասնագիտացված կատարողներ:

  5. Հետաձգման կետեր: await-ը հապաղման կետ է: Երբ հասնում է await-ին, ֆունկցիան դադարում է, կառավարումը փոխանցվում է կանչող կոդին կամ կատարողին, և ընթացիկ Job-ը ավարտվում է: Swift runtime-ը պահպանում է ֆունկցիայի վիճակը:

  6. Վերականգնում: Երբ ասինխրոն օպերացիան, որի սպասում էր await-ը, ավարտվի, Swift runtime-ը ստեղծում է նոր Job՝ շարունակելու համար դադարեցված ֆունկցիայի կատարումը: Այս Job-ը դրվում է կատարողի հերթում:

  7. Չեղարկում: Կառուցվածքային կոնկուրենությունը աջակցում է հիերարխիկ չեղարկմանը: Պատկանող 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-ի կանչին
}

Await-ը հիմնականում սինտաքսիկ շաքար է Continuation-ի կառավարման և Job-ի պլանավորման վրա կատարողին: Հետաձգումը ուղղակիորեն չի բլոկավորում հոսքը, այլ թույլ է տալիս կատարողին իրականացնել այլ Job-եր։