コトリンのスレッドとコルーチン
1前書き
このクイックチュートリアルでは、Kotlinでスレッドを作成して実行します。
後で、https://www.baeldung.com/kotlin-coroutines[Kotlin Coroutines]を支持して、それを完全に回避する方法について説明します。
2スレッドを作成する
Kotlinでスレッドを作成するのは、Javaでスレッドを作成するのと似ています。
Thread
クラスを拡張することもできます(Kotlinは多重継承をサポートしていないため推奨されません)。
class SimpleThread: Thread() {
public override fun run() {
println("${Thread.currentThread()} has run.")
}
}
あるいは、
Runnable
インターフェースを実装することもできます。
class SimpleRunnable: Runnable {
public override fun run() {
println("${Thread.currentThread()} has run.")
}
}
そして、Javaと同じように、
start()
メソッドを呼び出して実行することができます。
val thread = SimpleThread()
thread.start()
val threadWithRunnable = Thread(SimpleRunnable())
threadWithRunnable.start()
あるいは、Java 8のように、Kotlinはhttps://kotlinlang.org/docs/reference/java-interop.html#sam-conversions[SAM Conversions]をサポートしているので、それを利用してλを渡すことができます。
val thread = Thread {
println("${Thread.currentThread()} has run.")
}
thread.start()
2.2. Kotlin
thread()
関数
別の方法は、Kotlinが提供する
thread()
関数を考慮することです。
fun thread(
start: Boolean = true,
isDaemon: Boolean = false,
contextClassLoader: ClassLoader? = null,
name: String? = null,
priority: Int = -1,
block: () -> Unit
): Thread
この関数を使用すると、スレッドは次のようにして簡単にインスタンス化および実行できます。
thread(start = true) {
println("${Thread.currentThread()} has run.")
}
この関数は5つのパラメータを受け取ります。
-
__start –
__スレッドを直ちに実行する -
isDaemon
– スレッドをデーモンスレッドとして作成する -
contextClassLoader
– クラスのロードに使用するクラスローダー
リソース
**
name –
スレッドの名前を設定する
-
priority
– スレッドの優先順位を設定する
3コトリンコルーチン
より多くのスレッドを生成することで、より多くのタスクを同時に実行できるようになると考えるのは魅力的です。残念ながら、それは必ずしも真実ではありません。
作成するスレッドが多すぎると、状況によってはアプリケーションのパフォーマンスが低下する可能性があります。スレッドは、オブジェクトの割り当ておよびガベージコレクション中にオーバーヘッドを課すオブジェクトです。
これらの問題を克服するために、
Kotlinは非同期のノンブロッキングコードを書く新しい方法を紹介しました。
Coroutine
.
スレッドと同様に、コルーチンは並行して実行し、待機し、相互に通信することができますが、スレッドを作成する方がスレッドよりもはるかに安価です。
3.1. コルーチンコンテキスト
Kotlinがすぐに使えるコルーチンビルダーを紹介する前に、コルーチンコンテキストについて説明する必要があります。
コルーチンは常にさまざまな要素の集合であるコンテキストで実行されます。
主な要素は以下のとおりです。
-
-
複数の状態とライフサイクルを持つキャンセル可能なワークフローをモデル化
それはその完成で最高潮に達する
-
-
-
対応するコルーチンがその実行に使用するスレッドを決定します。ディスパッチャを使用すると、コルーチン実行を特定のスレッドに限定したり、スレッドプールにディスパッチしたり、制限なしで実行したりすることができます
-
次の段階でコルーチンを説明しながら、コンテキストの指定方法を見ていきます。
3.2.
ランチ
-
launch
関数は、現在のスレッド** をブロックせずに新しいコルーチンを開始し、そのコルーチンへの参照を
Job
オブジェクトとして返すコルーチンビルダーです。
runBlocking {
val job = launch(Dispatchers.Default) {
println("${Thread.currentThread()} has run.")
}
}
2つのオプションパラメータがあります。
-
context
– コルーチンが実行されるコンテキスト(実行されない場合)
定義されて、それはからコンテキストを継承します。
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html
それはから起動されています
**
start
– コルーチンの起動オプション。デフォルトでは、
コルーチンはただちに実行される予定です
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutinesで起動する
_Dispatchers.Default
を使用しているため、上記のコードはスレッドの共有バックグラウンドプールに実行されます。 experimental/-global-scope/index.html[
GlobalScope._
]
代わりに、同じディスパッチャを使用する
__GlobalScope.launch
__whを使用することもできます。
val job = GlobalScope.launch {
println("${Thread.currentThread()} has run.")
}
Dispatchers.Default
または
GlobalScope.launch
を使用すると、最上位のコルーチンが作成されます。軽量ですが、実行中にメモリリソースを消費することがあります。
GlobalScope
でコルーチンを起動する代わりに、スレッド(スレッドは常にグローバルです)、実行している操作の特定の範囲でコルーチンを起動できます。
runBlocking {
val job = launch {
println("${Thread.currentThread()} has run.")
}
}
この場合、コンテキストを指定せずに
__runBlocking
coroutineビルダー(後で説明します)内で新しいコルーチンを開始します。したがって、コルーチンは
runBlocking__のコンテキストを継承します。
3.3.
async
コルーチンがコルーチンを作成するために提供する別の機能は
async
です。
-
async
関数は新しいコルーチンを作成し、将来の結果を__Deferred <T>のインスタンスとして返します。
val deferred = async {
[email protected]"${Thread.currentThread()} has run."
}
deferred
は、最初は未知の結果に対するプロキシとして機能するオブジェクトを表す、ブロックされないキャンセル可能な未来です。
__launchと同様に、コルーチンを実行するコンテキストと起動オプションを指定できます。
val deferred = async(Dispatchers.Unconfined, CoroutineStart.LAZY) {
println("${Thread.currentThread()} has run.")
}
-
この場合、呼び出し側スレッドでコルーチンを開始する
Dispatchers
.
Unconfined
を使用してコルーチンを起動しましたが、最初の中断ポイントまでの間だけです。 **
ディスパッチャ
未設定__は、コルーチンがCPU時間を消費せず、共有データも更新しない場合に適しています。
-
さらに、Kotlinはオンデマンドで作成されたスレッドの共有プールを使用する
Dispatchers.IO
を提供します。
val deferred = async(Dispatchers.IO) {
println("${Thread.currentThread()} has run.")
}
集中的なI/O操作を行う必要がある場合は、
Dispatchers.IO
をお勧めします。
3.4.
runBlocking
以前は
runBlocking
を見ていましたが、今度はそれについてさらに詳しく説明しましょう。
-
runBlocking
は新しいコルーチンを実行し、現在のスレッドを完了するまでブロックする関数です。
前のスニペットの例として、コルーチンを起動しましたが、結果を待つことはありませんでした。
結果を待つために、
await()
suspendメソッドを呼び出す必要があります。
----//async code goes here
runBlocking {
val result = deferred.await()
println(result)
}
____await()はサスペンド関数と呼ばれるものです。 ** サスペンド関数はコルーチンまたは他のサスペンド関数からしか呼び出せません** このため、これを__runBlocking__呼び出しで囲みました。 ブロッキングコードを中断スタイルで記述された他のコードにリンクできるように、メイン関数とテストで__runBlocking__を使用します。 他のコルーチンビルダーと同じ方法で、実行コンテキストを設定できます。 [source,java,gutter:,true]
runBlocking(newSingleThreadContext(“dedicatedThread”)) {
val result = deferred.await()
println(result)
}
コルーチンを実行できる新しいスレッドを作成できることに注意してください。ただし、専用スレッドは高価なリソースです。そして、必要がなくなったら、リリースするか、アプリケーション全体で再利用する必要があります。 === ** 4結論** このチュートリアルでは、スレッドを作成することによって非同期のノンブロッキングコードを実行する方法を学びました。 スレッドに代わるものとして、コルーチンのコルーチン使用に対するアプローチがシンプルでエレガントであることもわかりました。 いつものように、このチュートリアルに示されているすべてのコードサンプルはhttps://github.com/eugenp/tutorials/tree/master/core-kotlin[Githubで利用可能]です。