Eine detaillierte Erklärung der Kotlin-Coroutine ist unmöglich, sie nicht zu verstehen

1. Einführung in Coroutinen

Lassen Sie uns zunächst eine Reihe von Fragen stellen. Nachdem alle diese Fragen verstanden haben, ist es möglicherweise einfacher, Kotlin-Coroutinen zu lernen:

1. Was ist Parallelität? Was ist Parallelität?

2. Was ist Multitasking? Was ist kollaboratives Multitasking? Was ist präventives Multitasking?

3. Was ist Synchronisation? Was ist asynchron?

4. Was ist nicht blockierend? Was blockiert?

5. Was ist hängen?

6. Was ist nicht blockierendes Suspendieren?

7. Was ist eine Coroutine?

8. Was ist eine Kotlin-Coroutine?

9. Wozu dienen Kotlin-Coroutinen?

1. Was ist Parallelität? Was ist Parallelität?

1) Parallelität bedeutet, dass nur eine Anweisung gleichzeitig ausgeführt wird. Da die CPU-Zeitscheibe jedoch sehr klein ist, können mehrere Anweisungen schnell umgeschaltet werden, was den Eindruck erweckt, dass wir den Effekt der gleichzeitigen Ausführung haben, der in Einzelausführungen vorhanden ist. Core- oder Multicore-CPU-Systeme.

2) Parallelität bedeutet, dass mehrere Anweisungen gleichzeitig ausgeführt werden, was in Multicore-CPU-Systemen der Fall ist.

Nehmen Sie ein Beispiel von Menschen, die im Leben Dampfbrötchen essen: Wenn eine Person drei Dampfbrötchen kauft, kann sie nur ein Dampfbrötchen gleichzeitig essen. Dies ist Parallelität. Wenn 3 Personen jeweils ein Dampfbrötchen kaufen, können sie die Dampfbrötchen gleichzeitig essen. Das ist Parallelität. Der Unterschied zwischen Parallelität und Parallelität besteht darin, ob Dinge gleichzeitig geschehen

2. Was ist Multitasking? Was ist kollaboratives Multitasking? Was ist präventives Multitasking?

1) Multitasking bedeutet, dass das Betriebssystem mehrere Aufgaben gleichzeitig erledigen kann. Beispielsweise kann ich mit meinem Laptop Android Studio und NetEase Cloud Music öffnen und beim Programmieren Musik hören.

2) Kollaboratives Multitasking bedeutet, dass eine Aufgabe CPU-Zeit erhält. Sofern sie die Nutzung der CPU nicht aufgibt, wird sie die CPU vollständig belegen. Daher müssen Aufgaben zusammenarbeiten. Nachdem sie die CPU für einen bestimmten Zeitraum genutzt hat, gibt sie die Nutzung auf. und das Gleiche gilt für andere Aufgaben. , um den normalen Betrieb des Systems sicherzustellen. Wird normalerweise in früheren Betriebssystemen wie Windows 3.1 angezeigt

3) Präventives Multitasking bedeutet, dass das Betriebssystem jeder Aufgabe die CPU-Nutzungszeit zuweist. Nachdem eine Aufgabe die CPU für einen bestimmten Zeitraum verwendet hat, entzieht das Betriebssystem der aktuellen Aufgabe die CPU-Nutzungsrechte und setzt sie an das Ende in die Abfragewarteschlange. Fragen Sie dann nach der nächsten Aufgabe. Erscheint im Allgemeinen in aktuell verwendeten Betriebssystemen wie Windows 95 und späteren Windows-Versionen.

Der Unterschied zwischen kooperativem Multitasking und präemptivem Multitasking: Wenn beim kooperativen Multitasking eine Aufgabe blockiert, wird auch das System blockiert. Wenn beim präventiven Multitasking eine Aufgabe blockiert ist, kann das System weiterhin normal ausgeführt werden.

3. Was ist Synchronisation? Was ist asynchron?

Synchronisation und Asynchronität im Computerbereich unterscheiden sich von Synchronisation und Asynchronität in unserem täglichen Leben, was es für viele Menschen schwierig macht, sie zu verstehen

1) Synchronisierung im Computerbereich bedeutet, dass der Anrufer beim Senden einer Aufrufanweisung auf die Ausführung der Anweisung warten muss, bevor er fortfahren kann. Es handelt sich um eine serielle Verarbeitungsmethode.

2) Asynchron im Computerbereich bedeutet, dass beim Senden einer aufrufenden Anweisung durch den Anrufer nicht auf die Ausführung der Anweisung gewartet werden muss und die Ausführung fortgesetzt wird. Es handelt sich um eine parallele Verarbeitungsmethode.

4. Was ist Blockieren? Was ist nicht blockierend?

Blockieren ist sehr einfach. Das bedeutet wörtlich. In Android blockiert es tatsächlich die Ausführung des Hauptthreads. Nicht blockierend bedeutet dann, dass die Ausführung des Hauptthreads nicht blockiert wird.

5. Was ist hängen?

Anhalten bedeutet, den aktuellen Status zu speichern und auf die Wiederaufnahme der Ausführung zu warten. Unter Android bedeutet Anhalten, dass die Arbeit des Hauptthreads nicht beeinträchtigt wird. Eine passendere Anweisung kann als Wechsel zu einem bestimmten Thread verstanden werden.

6. Was ist nicht blockierendes Suspendieren?

Durch die Erläuterung des obigen Konzepts bedeutet nicht blockierendes Anhalten, dass der Hauptthread nicht hängen bleibt und das Programm zur Ausführung auf einen anderen angegebenen Thread umgeschaltet wird.

7. Was ist eine Coroutine?

Coroutine, dessen englischer Name Coroutine ist, stammt aus den Sprachen Simula und Modula-2. Es handelt sich um eine kollaborative Multitasking-Implementierung und eine Programmieridee, die nicht auf eine bestimmte Sprache beschränkt ist. Die ursprüngliche Absicht des Coroutine-Designs besteht darin, Parallelitätsprobleme zu lösen und kollaboratives Multitasking komfortabler zu gestalten.

8. Was ist eine Kotlin-Coroutine?

Kotlin-Coroutinen sind einfach eine Reihe von Thread-Operations-Frameworks. Genauer gesagt handelt es sich um eine Reihe übergeordneter Tool-APIs, die auf Threads basieren, ähnlich dem Thread-Pool von Java. Sie können verstehen, dass Kotlin einige neue Konzepte erstellt hat, um Ihnen zu helfen Verwenden Sie besser diese APIs, mehr nicht

9. Wozu dienen Kotlin-Coroutinen?

1) Kotlin-Coroutinen können asynchronen Code so schreiben, dass er synchron aussieht, was Ihnen dabei hilft, die Callback-Hölle elegant zu meistern.

Nachdem wir die oben genannten Probleme geklärt haben, schauen wir nach unten

Die ausführlichste Einführung und fortgeschrittene Praxis der Kotlin-Coroutine für Android in der Geschichte

Grundlegende Einführung in Kotlin-Coroutinen

2. Grundlegende Verwendung von Kotlin-Coroutinen

Bevor wir über Konzepte sprechen, sprechen wir über die Verwendung.

Szenario: Starten Sie den Arbeitsthread, um eine zeitaufwändige Aufgabe auszuführen, und verarbeiten Sie die Ergebnisse dann im Hauptthread.

Gängige Verarbeitungsmethoden:

  • Rückrufe selbst definieren und bearbeiten
  • Thread/Thread-Pool verwenden, Callable
    Thread Thread(FeatureTask(Callable)).start
    Thread-Pool Submit(Callable)
  • Android: Handler, AsyncTask, Rxjava

Verwenden Sie Coroutinen:

coroutineScope.launch(Dispatchers.Main) {
    
     // 在主线程启动一个协程
    val result = withContext(Dispatchers.Default) {
    
     // 切换到子线程执行
        doSomething()  // 耗时任务
    }
    handResult(result)  // 切回到主线程执行
}

Hier muss Folgendes beachtet werden: Dispatchers.Main ist einzigartig für Android. Wenn es in einem Java-Programm verwendet wird, wird eine Ausnahme ausgelöst.

2.1 Drei Möglichkeiten zum Erstellen von Coroutinen

  1. Erstellt mit der runBlocking-Funktion der obersten Ebene:
runBlocking {
    ...
}
  1. Erstellt mit dem GlobalScope-Singleton-Objekt
GlobalScope.launch {
    ...
}
  1. Erstellen Sie selbst ein CoroutineScope-Objekt über CoroutineContext
val coroutineScope = CoroutineScope(context)
coroutineScope.launch {
    ...
}
  • Methode 1 eignet sich normalerweise für Unit-Testszenarien, wird jedoch in der Geschäftsentwicklung nicht verwendet, da es sich um eine Thread-Blockierung handelt.
  • Der Unterschied zwischen Methode zwei und der Verwendung von runBlocking besteht darin, dass der Thread nicht blockiert wird. Diese Verwendung wird jedoch in der Android-Entwicklung nicht empfohlen, da ihr Lebenszyklus nur durch den Lebenszyklus der gesamten Anwendung begrenzt ist und nicht abgebrochen werden kann.
  • Methode drei ist die empfohlenere Verwendungsmethode. Wir können den Lebenszyklus der Coroutine über den Kontextparameter verwalten und steuern (der Kontext ist hier nicht derselbe wie in Android, es ist ein allgemeineres Konzept, und es wird einen geben Kapselung der Android-Plattform. Mit der Verwendung von).

2.2 Warten auf einen Job

Schauen wir uns zunächst ein Beispiel an:

fun main() = runBlocking {
    
    
    launch {
    
    
        delay(100)
        println("hello")
        delay(300)
        println("world")
    }
    println("test1")
    println("test2")
}

Die Ausführungsergebnisse sind wie folgt:

test1
test2
hello
world

Nachdem wir eine Coroutine gestartet haben, können wir einen Verweis darauf behalten und explizit auf das Ende ihrer Ausführung warten. Beachten Sie, dass das Warten hier nicht blockierend ist und den aktuellen Thread nicht anhält.

fun main() = runBlocking {
    
    
    val job = launch {
    
    
        delay(100)
        println("hello")
        delay(300)
        println("world")
    }
    println("test1")
    job.join()
    println("test2")
}

Ausgabeergebnis:

test1
hello
world
test2

Analog zu Java-Threads gibt es auch eine Join-Methode. Threads sind jedoch an das Betriebssystem gebunden. Auf einigen CPUs ist die Join-Methode möglicherweise nicht wirksam.

2.3 Stornierung der Coroutine

In Analogie zu Threads bieten Java-Threads eigentlich keinen Mechanismus zum sicheren Beenden des Threads.
Die Thread-Klasse stellt eine Methode, die interrupt()-Methode, zum Unterbrechen der Ausführung des Threads bereit. Der Aufruf der Methode interrupt() bedeutet nicht, dass die vom Ziel-Thread ausgeführte Arbeit sofort gestoppt wird, sondern übermittelt lediglich eine Nachricht, die eine Unterbrechung anfordert. Der Thread unterbricht sich dann bei der nächsten geeigneten Gelegenheit.

Aber die Coroutine stellt eine cancel()-Methode bereit, um den Job abzubrechen.

fun main() = runBlocking {
    
    
    val job = launch {
    
    
        repeat(1000) {
    
     i ->
            println("job: test $i ...")
            delay(500L)
        }
    }
    delay(1300L) // 延迟一段时间
    println("main: ready to cancel!")
    job.cancel() // 取消该作业
    job.join() // 等待作业执行结束
    println("main: Now cancel.")
}

Ausgabeergebnis:

job: test 0 ...
job: test 1 ...
job: test 2 ...
main: ready to cancel!
main: Now cancel.

Sie können auch die Funktion cancelAndJoin verwenden, die Aufrufe zum Abbrechen und Beitreten kombiniert.

Frage:
Was passiert, wenn zuerst job.join() und dann job.cancel() aufgerufen wird?

Stornierung ist kollaborativ
Coroutinen können nicht unbedingt storniert werden. Die Stornierung von Coroutinen ist kollaborativ. Ein Teil des Coroutine-Codes muss kooperieren, bevor er abgebrochen werden kann.
Alle Suspendierungsfunktionen in kotlinx.coroutines können abgebrochen werden. Sie prüfen, ob die Coroutine abgebrochen wird, und lösen bei Abbruch eine CancellationException aus.
Wenn die Coroutine eine Berechnungsaufgabe ausführt und nicht auf Abbruch prüft, kann sie nicht abgebrochen werden.

fun main() = runBlocking {
    
    
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
    
    
        var nextPrintTime = startTime
        var i = 0
        while (i < 5) {
    
     // 一个执行计算的循环,只是为了占用 CPU
            // 每秒打印消息两次
            if (System.currentTimeMillis() >= nextPrintTime) {
    
    
                println("job: hello ${
      
      i++} ...")
                nextPrintTime += 500L
            }
        }
    }
    delay(1300L) // 等待一段时间
    println("main: ready to cancel!")
    job.cancelAndJoin() // 取消一个作业并且等待它结束
    println("main: Now cancel.")
}

Das Druckergebnis zu diesem Zeitpunkt:

job: hello 0 ...
job: hello 1 ...
job: hello 2 ...
main: ready to cancel!
job: hello 3 ...
job: hello 4 ...
main: Now cancel.

Es ist ersichtlich, dass die Coroutine nicht abgebrochen wurde. Um die Coroutine wirklich am Funktionieren zu hindern, müssen wir regelmäßig überprüfen, ob die Coroutine im aktiven Zustand ist.

Jobstatus prüfen
Eine Möglichkeit besteht darin, Code hinzuzufügen, um den Coroutine-Status in while(i<5) zu überprüfen
Der Code lautet wie folgt:< /span>

while (i < 5 && isActive)

Das bedeutet, dass unsere Arbeit nur ausgeführt wird, wenn sich die Coroutine im aktiven Zustand befindet.

Eine andere Methode verwendet die Funktion in der Coroutine-Standardbibliothek ensureActive(), ihre Implementierung ist wie folgt:

public fun Job.ensureActive(): Unit {
    
    
    if (!isActive) throw getCancellationException()
}

Code wie folgt anzeigen:

while (i < 5) { // 一个执行计算的循环,只是为了占用 CPU
    ensureActive()
    ...
}

secureActive() löst sofort eine Ausnahme aus, wenn sich die Coroutine nicht im aktiven Zustand befindet.

verwendet yield()
yield() auf die gleiche Weise wie ensureActive.
Die erste Arbeit, die yield ausführen wird, besteht darin, zu prüfen, ob die Aufgabe abgeschlossen ist. Wenn der Job abgeschlossen wurde, wird eine CancellationException geworfen, um die Coroutine zu beenden. Yield sollte bei einer planmäßigen Prüfung zuerst abgerufen werden.

while (i < 5) { // 一个执行计算的循环,只是为了占用 CPU
    yield()
    ...
}

2.4 Warten auf das Ausführungsergebnis der Coroutine

Für Coroutinen ohne Rückgabewerte verwenden Sie die Startfunktion, um sie zu erstellen. Wenn ein Rückgabewert erforderlich ist, erstellen Sie sie über die asynchrone Funktion.
Verwenden Sie die asynchrone Methode, um einen verzögerten Auftrag (auch einen Job) zu starten, und Sie können die Methodewait() aufrufen, um das Ausführungsergebnis zu erhalten.
sieht wie der folgende Code aus:

val asyncDeferred = async {
    ...
}

val result = asyncDeferred.await()

deferred kann auch abgebrochen werden. Der Aufruf der Methode „await()“ für eine abgebrochene, verzögerte Ausführung löst eine
JobCancellationException-Ausnahme aus.

Wenn deferred.cancel() nach deferred.await aufgerufen wird, passiert ebenfalls nichts, da die Aufgabe beendet ist.

Die spezifische Verwendung von Async wird später bei asynchronen Aufgaben erläutert.

2.5 Ausnahmebehandlung von Coroutinen

Da eine CancellationException ausgelöst wird, wenn die Coroutine abgebrochen wird, können wir die Aussetzungsfunktion in einen Try/Catch-Codeblock einschließen, sodass der Ressourcenbereinigungsvorgang im Final-Codeblock ausgeführt werden kann.

fun main() = runBlocking {
    
    
    val job = launch {
    
    
        try {
    
    
            delay(100)
            println("try...")
        } catch (e: Exception) {
    
    
            println("exception: ${
      
      e.message}")
        } finally {
    
    
            println("finally...")
        }
    }
    delay(50)
    println("cancel")
    job.cancel()
    print("Done")
}

Ergebnis:

cancel
Doneexception: StandaloneCoroutine was cancelled
finally...

2.6 Zeitüberschreitung der Coroutine

In der Praxis besteht die überwiegende Mehrheit der Gründe für den Abbruch einer Coroutine darin, dass es zu einer Zeitüberschreitung kommen kann. Wenn Sie manuell einen Verweis auf einen zugehörigen Job verfolgen und ihn starten, verwenden Sie die Funktion withTimeout.

fun main() = runBlocking {
    
    
    withTimeout(300) {
    
    
        println("start...")
        delay(100)
        println("progress 1...")
        delay(100)
        println("progress 2...")
        delay(100)
        println("progress 3...")
        delay(100)
        println("progress 4...")
        delay(100)
        println("progress 5...")
        println("end")
    }
}

Ergebnis:

start...
progress 1...
progress 2...
Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 300 ms

withTimeout löst TimeoutCancellationException aus, was eine Unterklasse von CancellationException ist. Wir haben den auf der Konsole gedruckten Stacktrace noch nie gesehen. Dies liegt daran, dass CancellationException in einer abgebrochenen Coroutine als normaler Grund für das Ende der Coroutine-Ausführung angesehen wird. In diesem Beispiel verwenden wir jedoch withTimeout korrekt in der Hauptfunktion. Bei Bedarf müssen wir Ausnahmen aktiv abfangen und behandeln.

Natürlich geht es auch anders: mit withTimeoutOrNull.

withTimeout kann von einem Wert zurückgegeben werden. Die Ausführung der Funktion withTimeout blockiert und wartet auf die Rückgabe des Ergebnisses oder auf eine Zeitüberschreitung, um eine Ausnahme auszulösen. withTimeoutOrNull wird genauso verwendet wie withTimeout, außer dass es nach einer Zeitüberschreitung null zurückgibt.

Zusammenfassen

Tatsächlich ist es sehr einfach, es zu meistern. Es gibt nur zwei wichtige Punkte:

  1. Finden Sie eine gute Auswahl an Videomaterialien und folgen Sie dem von den Experten zusammengestellten Wissensrahmen zum Studieren.
  2. Übe mehr. (Der Vorteil von Videos besteht darin, dass sie sehr interaktiv sind und sich leicht konzentrieren lassen.)

Man muss weder ein Genie sein noch über starke Talente verfügen. Solange man diese beiden Dinge tut, ist die Erfolgswahrscheinlichkeit kurzfristig sehr hoch.

Wenn viele junge und fortgeschrittene Android-Ingenieure ihre Fähigkeiten verbessern wollen, müssen sie oft selbst forschen und wachsen. Der unsystematische Lerneffekt ist ineffizient, langwierig und nicht hilfreich. Die Screenshots einiger der folgenden Informationen wurden von mir über mehrere Monate hinweg zusammengestellt und sind voller Aufrichtigkeit: Sie eignen sich besonders für Android-Programmierer mit 3–5 Jahren Entwicklungserfahrung, von denen sie lernen können .

  • Laden Sie den Direktlink herunter, um es selbst zu erhalten
  • Die oben genannten erweiterten BATJ-Fabrik-Lernmaterialien können kostenlos mit allen geteilt werden. Freunde, die die Vollversion benötigen, können den folgenden QR-Code scannen.

Supongo que te gusta

Origin blog.csdn.net/Code1994/article/details/129448142
Recomendado
Clasificación