[JAVA] Feder mit Kotorin --6 Asynchrone Verarbeitung

Übersicht / Beschreibung

In der Vergangenheit war die Anwendungsverarbeitung häufig ausreichend, um Ergebnisse synchron auszuführen und zu empfangen. In den letzten Jahren wurden jedoch mit dem Fortschritt mobiler Geräte wie Smartphones und Multi-Core-Prozessoren Eine asynchrone Verarbeitung, die mehrere Verarbeitungen gleichzeitig ausführen kann, ist ebenfalls erforderlich.

In Spring können Sie mithilfe der Annotation "@ Async" problemlos eine asynchrone Verarbeitung für einen anderen Thread durchführen. Lassen Sie uns überprüfen, wie eine asynchrone Verarbeitung mit "@ Async" erstellt wird.

Asynchrone Verarbeitung

Wenn Sie eine Anweisung in Java ausführen, erfolgt die Verarbeitung im Thread. Bei einem einzelnen Thread werden die Anweisungen nacheinander auf dem Thread verarbeitet. Eine gleichzeitige Verarbeitung ist daher nicht möglich.

Bereiten Sie daher mehrere Threads vor und führen Sie Anweisungen für jeden Thread aus. Führen Sie die Anweisung in einem anderen Thread aus, ohne darauf zu warten, dass das Ende die parallele Verarbeitung asynchron realisiert.

Threads.png

Annahme / Umwelt

Laufzeitversion

Spring Dependencies

Entwicklungsumgebung

Vorgehensweise / Erklärung

Einfache asynchrone Verarbeitung

Aktivieren Sie die asynchrone Verarbeitung

Nehmen Sie Einstellungen vor, um die asynchrone Verarbeitung in der Spring Boot-Anwendung zu aktivieren. Sie müssen lediglich die Annotation "@ EnableAsync" zur Konfigurationsklasse hinzufügen (Annotation "@ Configuration" oder die Klasse mit der Annotation "@ SpringBootApplication").

@SpringBootApplication
@EnableAsync
class SimpleApplication

Implementierung der asynchronen Verarbeitung

Fügen Sie die Annotation "@ Async" zu der Funktion hinzu, die Sie in einem anderen Thread asynchron verarbeiten möchten. Die Funktion mit dieser Annotation "@ Async" wird als asynchron zu verarbeitende Funktion behandelt, und die verarbeitete Anweisung wird in einem anderen Thread ausgeführt.

import org.slf4j.LoggerFactory
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Service
import java.util.concurrent.TimeUnit

@Service("Async Task Service")
class AsyncTaskService {

    val logger = LoggerFactory.getLogger(this::class.java.name)

    @Async
    fun standardTask() {
        logger.info("Task Start")
        TimeUnit.SECONDS.sleep(5)
        logger.info("Task End")
    }
}

Asynchroner Verarbeitungsaufruf

Platzieren Sie einen REST-Controller, der die für die asynchrone Verarbeitung verantwortliche Klasse mit der Annotation @ Async aufruft. Stellen Sie den Zugriffsendpunkt auf "/ async" ein. Dadurch kann dieser asynchrone Prozess unter "http: // localhost: 8080 / async" aufgerufen werden.

@RestController
@RequestMapping("/async")
class AsyncTaskController {

    @GetMapping
    fun callStandardTask() = service.standardTask()
}

Ausführung der asynchronen Verarbeitung

Rufen wir die asynchrone Verarbeitung fünfmal hintereinander auf.

$ curl  http://localhost:8080/async
$ curl  http://localhost:8080/async
$ curl  http://localhost:8080/async
$ curl  http://localhost:8080/async
$ curl  http://localhost:8080/async

Das Laufzeitprotokoll von Start und Ende jedes asynchronen Prozesses wird in der Standardausgabe wie unten gezeigt angezeigt.

2018-12-19 20:50:22.662  INFO 22121 --- [cTaskExecutor-1] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 20:51:00.545  INFO 22121 --- [cTaskExecutor-2] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 20:51:01.886  INFO 22121 --- [cTaskExecutor-3] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 20:51:04.397  INFO 22121 --- [cTaskExecutor-4] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 20:51:05.550  INFO 22121 --- [cTaskExecutor-5] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 20:51:06.887  INFO 22121 --- [cTaskExecutor-1] i.p.s.simple.service.AsyncTaskService    : Normal Task End
2018-12-19 20:51:09.400  INFO 22121 --- [cTaskExecutor-2] i.p.s.simple.service.AsyncTaskService    : Normal Task End
2018-12-19 20:52:03.338  INFO 22121 --- [cTaskExecutor-3] i.p.s.simple.service.AsyncTaskService    : Normal Task End
2018-12-19 20:52:05.123  INFO 22121 --- [cTaskExecutor-4] i.p.s.simple.service.AsyncTaskService    : Normal Task End
2018-12-19 20:52:06.290  INFO 22121 --- [cTaskExecutor-5] i.p.s.simple.service.AsyncTaskService    : Normal Task End

Wenn man sich dieses Ergebnis ansieht, kann bestätigt werden, dass 5 Threads von "cTaskExecutor-1" bis "cTaskExecutor-5" erstellt und verarbeitet werden und jeder asynchron verarbeitet wird.

Asynchrone Verarbeitung mit Thread-Pool

In dem zuvor ausgeführten asynchronen Prozess wurden Threads für die Anzahl der Aufrufe erstellt. Was ist, wenn dies eine Anwendung ist, die sehr oft aufgerufen wird? Es ist möglich, dass eine große Anzahl von Threads erstellt wird, wodurch die Systemressourcen erschöpft, die Leistung verringert und im schlimmsten Fall das System heruntergefahren wird. Es gibt viele Java EE-Anwendungsserver, mit denen die Anzahl der Threads als Plattform gesteuert werden kann. Aber was ist mit einer Spring Boot-Anwendung, die keinen Java EE-Anwendungsserver wie diesen verwendet?

Definition von ThreadPoolTaskExecutor

Wenn Sie im Frühjahr eine asynchrone Verarbeitung durchführen, wird durch Hinzufügen der Annotation "@ Async" standardmäßig "SimpleAsyncTaskExecutor" verwendet, um einen weiteren Thread zu erstellen und eine asynchrone Verarbeitung durchzuführen.

Wenn Sie andererseits den Thread-Pool konfigurieren möchten, um die Anzahl der Threads zu steuern, konfigurieren und verwenden Sie "ThreadPoolTaskExecutor". Definieren Sie in der Konfigurationsklasse mit "@ EnableAsync".

Im Folgenden erstellen wir zwei Arten von Pools.

@SpringBootApplication
@EnableAsync
class SimpleApplication {

    @Bean
    fun normalTaskExecutor(): TaskExecutor  = ThreadPoolTaskExecutor().apply {
        corePoolSize = 1
        setQueueCapacity(5)
        maxPoolSize = 1
        setThreadNamePrefix("NormalThread-")
        setWaitForTasksToCompleteOnShutdown(true)
    }

    @Bean
    fun prioritizedTaskExecutor(): TaskExecutor  = ThreadPoolTaskExecutor().apply {
        corePoolSize = 5
        setQueueCapacity(5)
        maxPoolSize = 5
        setThreadNamePrefix("PrioritizedThread-")
        setWaitForTasksToCompleteOnShutdown(true)
    }
}

Legen Sie die folgenden Attribute fest, um den Thread-Pool zu konfigurieren.

Name Inhalt
corePoolSize Erstellen Sie die Anzahl der Threads bis zu diesem Einstellungswert
setQueueCapacity Wenn die Anzahl von corePoolSize überschritten wird, wird bis zu diesem Einstellungswert in die Warteschlange gestellt
maxPoolSize Bei einer Warteschlange von maximal setQueueCapacity wird die Anzahl der Threads bis zu diesem Einstellungswert erstellt

ThreadPool.png

Implementierung der asynchronen Verarbeitung mit angegebenem ThreadPoolTaskExecutor

Geben Sie den Bean-Namen von "ThreadPoolTaskExecutor" explizit mit der Annotation "@ Async" an, wie unten gezeigt. Legt fest, welcher ThreadPoolTaskExecutor asynchron ist.

    @Async("prioritizedTaskExecutor")
    fun prioritizedTask() {
        logger.info("Prioritized Task Start")
        TimeUnit.SECONDS.sleep(5)
        logger.info("Prioritized Task End")
    }

    @Async("normalTaskExecutor")
    fun normalTask() {
        logger.info("Normal Task Start")
        TimeUnit.SECONDS.sleep(5)
        logger.info("Normal Task End")
    }

Ausführung der asynchronen Verarbeitung

Schauen wir uns das Ergebnis der asynchronen Verarbeitung an, wobei die Anzahl der Thread-Pools auf "1" gesetzt ist.

$ curl  http://localhost:8080/async/normal
$ curl  http://localhost:8080/async/normal
$ curl  http://localhost:8080/async/normal
$ curl  http://localhost:8080/async/normal
$ curl  http://localhost:8080/async/normal

Wie unten gezeigt, können Sie sehen, dass die Verarbeitung nur vom Thread "NormalThread-1" ausgeführt wird. Wie angegeben, wird es mit der Anzahl der Threads "1" verarbeitet.

2018-12-19 22:30:17.654  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 22:30:22.658  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task End
2018-12-19 22:30:24.437  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 22:30:29.441  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task End
2018-12-19 22:30:29.441  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 22:30:34.442  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task End
2018-12-19 22:30:34.443  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 22:30:39.445  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task End
2018-12-19 22:30:39.446  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task Start
2018-12-19 22:30:44.455  INFO 22746 --- [ NormalThread-1] i.p.s.simple.service.AsyncTaskService    : Normal Task End

Als nächstes betrachten wir die asynchrone Verarbeitung mit der Anzahl der Thread-Pools auf "5".

$ curl  http://localhost:8080/async/high
$ curl  http://localhost:8080/async/high
$ curl  http://localhost:8080/async/high
$ curl  http://localhost:8080/async/high
$ curl  http://localhost:8080/async/high

Hier können Sie sehen, dass 5 Threads von "HighThread-1" bis "HighThread-5" erstellt und verwendet wurden. Wie Sie sehen, können Sie unter Berücksichtigung der Steuerung des Thread-Pools problemlos eine asynchrone Verarbeitung durchführen.

2018-12-19 22:37:55.784  INFO 22746 --- [HighThread-1] i.p.s.simple.service.AsyncTaskService    : Prioritized Task Start
2018-12-19 22:37:57.469  INFO 22746 --- [HighThread-2] i.p.s.simple.service.AsyncTaskService    : Prioritized Task Start
2018-12-19 22:37:57.898  INFO 22746 --- [HighThread-3] i.p.s.simple.service.AsyncTaskService    : Prioritized Task Start
2018-12-19 22:37:58.956  INFO 22746 --- [HighThread-4] i.p.s.simple.service.AsyncTaskService    : Prioritized Task Start
2018-12-19 22:37:59.582  INFO 22746 --- [HighThread-5] i.p.s.simple.service.AsyncTaskService    : Prioritized Task Start
2018-12-19 22:38:00.787  INFO 22746 --- [HighThread-1] i.p.s.simple.service.AsyncTaskService    : Prioritized Task End
2018-12-19 22:38:02.473  INFO 22746 --- [HighThread-2] i.p.s.simple.service.AsyncTaskService    : Prioritized Task End
2018-12-19 22:38:02.900  INFO 22746 --- [HighThread-3] i.p.s.simple.service.AsyncTaskService    : Prioritized Task End
2018-12-19 22:38:03.957  INFO 22746 --- [HighThread-4] i.p.s.simple.service.AsyncTaskService    : Prioritized Task End
2018-12-19 22:38:04.586  INFO 22746 --- [HighThread-5] i.p.s.simple.service.AsyncTaskService    : Prioritized Task End

Zusammenfassung / Rückblick

Asynchrone Verarbeitung ist eine Verarbeitung, die nicht nur in Webanwendungen, sondern auch in Stapelanwendungen effektiv verwendet werden kann. Auf diese Weise kann eine asynchrone Verarbeitung durchgeführt werden, während auf einfache Weise Threads erstellt und der Thread-Pool gesteuert werden kann. Es scheint also, dass es viele mögliche Situationen gibt, in denen sie verwendet werden kann.

Diese Quelle

Recommended Posts

Feder mit Kotorin --6 Asynchrone Verarbeitung
Feder mit Kotorin --5 Aktuator
Asynchrone Verarbeitung mit Spring Boot unter Verwendung von @Async
Frühling mit Kotorin ―― 1. SPRING INITIALIZR
Asynchrone Verarbeitung mit regelmäßiger Ausführung in Spring Boot
Frühling mit Kotorin --- 8. Aufbewahrungsschicht
Feder mit Kotorin ―― 7. Serviceschicht
Frühling mit Kotorin ―― 9. Datenbankmigration ―― Flyway
Verarbeitung beim Starten einer Anwendung mit Spring Boot
Feder mit Kotorin --2 RestController und Datenklasse
Weihnachten mit Verarbeitung
Frühling mit Kotorin - 8 Repository-Schicht - Ergänzung: H2-Datenbank
Selbstgemachte Validierung mit Spring
Mit Kotorin ―― 7. Scoping-Funktion
Mit Spring Boot herunterladen
Führen Sie nach der Standardauthentifizierung mit Spring Boot eine beliebige Verarbeitung aus.
Feder mit Kotorin ―― 3. Auslassen von Wellenklammern aus der Funktion
Steuern Sie den Spring Batch-Verarbeitungsablauf mit JavaConfig.
Erste Schritte mit der Verarbeitung von Doma-Annotationen
Generieren Sie mit Spring Boot einen Barcode
Hallo Welt mit Spring Boot
Java-Konfiguration mit Spring MVC
Implementieren Sie GraphQL mit Spring Boot
Beginnen Sie mit Spring Boot
Führen Sie LIFF mit Spring Boot aus
SNS-Login mit Spring Boot
Datei-Upload mit Spring Boot
Spring Boot beginnt mit dem Kopieren
Anmeldefunktion mit Spring Security
Verwenden von Mapper mit Java (Spring)
Spring Boot beginnend mit Docker
Hallo Welt mit Spring Boot
Setzen Sie Cookies mit Spring Boot
Verwenden Sie Spring JDBC mit Spring Boot
Modul mit Spring Boot hinzufügen
Erste Schritte mit Spring Boot
API mit Spring + Vue.js verknüpfen
[Swift] Asynchrone Verarbeitung mit PromiseKit
Erstellen Sie mit Spring Boot einen Mikrodienst
Präsentationsfolie mit Verarbeitung erstellt
Mail mit Spring Boot verschicken
Ich möchte eine asynchrone Verarbeitung und periodische Ausführung mit Rail durchführen !!!
Implementierte Authentifizierungsfunktion mit Spring Security ②
Versuchen Sie, die asynchrone Verarbeitung in Azure zu implementieren
Implementierte Authentifizierungsfunktion mit Spring Security ③
Erstellen Sie eine App mit Spring Boot 2
Datenbankverknüpfung mit doma2 (Spring Boot)
Implementieren Sie die deklarative Wiederholungsverarbeitung mit Spring Retry
Spring Boot Programmierung mit VS Code
Bis "Hallo Welt" mit Spring Boot
Erstellen Sie eine Anfrage-App mit Spring Boot
NLP4J 100 Sprachverarbeitungsklopfen mit NLP4J # 31 Verb
Implementierte Authentifizierungsfunktion mit Spring Security ①
Verarbeitungsgeschwindigkeit mit und ohne statische Aufladung
Erhalten Sie Validierungsergebnisse mit Spring Boot
Implementierung der asynchronen Verarbeitung in Tomcat
Erfahren Sie mehr über die Architektur der Spring Security-Authentifizierungsverarbeitung
Implementieren Sie den Dateidownload mit Spring MVC