Press "Enter" to skip to content

Einstieg in Swift Concurrency – Teil 1

async/await-Basics

Die kommende Version 5.5 von Swift ist Teil von Xcode 13 und wird eine große Neuerung in der Programmiersprache mit sich bringen. Mithilfe der neuen Schlüsselwörter async und await lassen sich nun endlich asynchrone Befehle ausführen, ohne auf entsprechende Funktionen des Dispatch-Frameworks zurückgreifen zu müssen.

Das Grundprinzip hinter den neuen Swift-Schlüsselwörtern async und await ist denkbar simpel. Mit async kann man Funktionen deklarieren und so festlegen, dass diese asynchron ablaufen. Während die Funktion also ihre Befehle abarbeitet, kann die zugrundeliegende App von anderer Stelle weitere Befehle entgegennehmen und ausführen.

Möchte man eine mittels async deklarierte Funktion nutzen, muss man bei ihrem Aufruf das await-Keyword setzen. Dieses Pattern ist vergleichbar mit dem Error Handling in Swift, in dem Funktionen mit throws und zugehörige Aufrufe mit try gekennzeichnet werden.

Gelangt die Programmausführung an den Aufruf einer asynchronen Funktion mittels await, wird die Ausführung an dieser Stelle „angehalten“. Die App kann zwar weiterhin Befehle von anderer Stelle verarbeiten, doch alle Aufrufe, die nach await folgen, werden erst ausgeführt, wenn die darüber asynchron aufgerufene Funktion abgeschlossen ist.

Ein einfaches Beispiel zum Einsatz von async und await demonstriert das folgende (noch nicht optimierte) Beispiel. Darin wird über einen Button eine aufwendige Berechnung aufgerufen. Noch läuft der Code synchron ab, was dazu führt, dass bei Betätigung des Buttons die App so lange einfriert, bis das Ergebnis von der longTask()-Methode zurückgeliefert wird.

struct ContentView: View {
    @State private var result = 0
    
    var body: some View {
        VStack {
            Button("Start long task") {
                result = longTask()
            }
            Text("Ergebnis: \(result)")
        }
    }
}

func longTask() -> Int {
    var result = 0
    for value in 1...10_000_000 {
        result += value
    }
    return result
}

Die optimierte Variante mittels async und await zeigt das folgende Code-Beispiel. Die longTask()-Methode ist nun als async deklariert und kann ihre Befehle somit im Hintergrund ausführen (ohne die ganze App zu blockieren). Entsprechend muss beim Aufruf von longTask() wie beschrieben das await-Keyword gesetzt werden.

struct ContentView: View {
    @State private var result = 0
    
    var body: some View {
        VStack {
            Button("Start long task") {
                async {
                    result = await longTask()
                }
            }
            Text("Ergebnis: \(result)")
        }
    }
}

func longTask() async -> Int {
    var result = 0
    for value in 1...10_000_000 {
        result += value
    }
    return result
}

Durch diese Änderungen friert die App nicht länger ein, wenn man den Button betätigt. Ein Detail ist hierbei jedoch noch besonders wichtig: await kann nur in asynchronen Funktionen genutzt werden! Aus diesem Grund ist der Aufruf von longTask() in der Action des Button auch in einen async-Block gepackt. Da die body-Property selbst nicht async ist, kann man aus ihr heraus keine await-Aufrufe durchführen. Doch durch Einsatz eines async-Blocks könnt ihr an einer beliebigen Stelle im Code einen asynchronen Aufruf starten.

Euer Thomas

3 Kommentare

  1. Sergio Sergio

    wenn man dein code so modifiziert

    struct ContentView: View {
    @State private var result = 0
    @State private var result2 = 0

    var body: some View {
    VStack {
    Button(„Start long task“) {
    async {
    result = await longTask()
    }
    async {
    result2 = await longTask()
    }
    }
    Text(„Ergebnis: \(result+result2)“)
    }
    }
    }

    hat man zwei rechunungen die parallel läufen auf zwei versichiedene core des prozessor ?

    • Ja, die Berechnungen laufen in diesem Fall parallel. Und mach dir keine Gedanken wegen der Formatierung, da scheint WordPress etwas doof zu sein. Ich hab auch eine E-Mail zu deinem Kommentar bekommen, da sah die Formatierung super aus. 🙂

  2. Sergio Sergio

    sorry für die verlorengegangene formattierung des codes….

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Impressum

Thomas Sillmann
Kettererstraße 6
D-63739 Aschaffenburg
E-Mail: contact@thomassillmann.de
Mobil: +49 (0) 151 65125650
Web: https://www.thomassillmann.de/

Inhaltlich Verantwortlicher gemäß §55 Abs. 2 RStV: Thomas Sillmann (Anschrift siehe oben)

Haftungshinweis: Trotz sorgfältiger inhaltlicher Kontrolle übernehme ich keine Haftung für die Inhalte externer Links. Für die Inhalte der verlinkten Seiten sind ausschließlich deren Betreiber verantwortlich.

Kontakt und soziale Netzwerke

© 2019-2021 by Thomas Sillmann