{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "Al3t64xqN0DN3JmLKHOVn2", "type": "CODE" } }, "outputs": [], "source": [ "%use coroutines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Три оси многозадачности" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "TawmM9V8by8RGHfhNv7D3m", "type": "MD" } }, "source": [ "### Синхронный х однопоточный х неконкурентный " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "XzjwoelmODMg8pmaJRe1KK", "type": "CODE" } }, "outputs": [], "source": [ "repeat(10){\n", " println(\"Line number $it\")\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "UuTmCNAMCpUAHaAwWVYJPy", "type": "CODE" } }, "outputs": [], "source": [ "import java.util.stream.*\n", "\n", "IntStream.range(0, 100).sum()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "f6DGHwBOIRvKuYjtxVRn0W", "type": "MD" } }, "source": [ "### Синхронный х однопоточный х конкурентный" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "O1DPfMSAedOChaqU5JWXrU", "type": "CODE" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "null\n", "java.util.ConcurrentModificationException\n", "\tat java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1095)\n", "\tat java.base/java.util.ArrayList$Itr.next(ArrayList.java:1049)\n", "\tat Line_0_jupyter.(Line_0.jupyter.kts:6)\n", "\tat java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)\n", "\tat java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)\n", "\tat java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)\n", "\tat kotlin.script.experimental.jvm.BasicJvmScriptEvaluator.evalWithConfigAndOtherScriptsResults(BasicJvmScriptEvaluator.kt:122)\n", "\tat kotlin.script.experimental.jvm.BasicJvmScriptEvaluator.invoke$suspendImpl(BasicJvmScriptEvaluator.kt:48)\n", "\tat kotlin.script.experimental.jvm.BasicJvmScriptEvaluator.invoke(BasicJvmScriptEvaluator.kt)\n", "\tat kotlin.script.experimental.jvm.BasicJvmReplEvaluator.eval(BasicJvmReplEvaluator.kt:49)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.InternalEvaluatorImpl$eval$resultWithDiagnostics$1.invokeSuspend(InternalEvaluatorImpl.kt:127)\n", "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)\n", "\tat kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)\n", "\tat kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:277)\n", "\tat kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:95)\n", "\tat kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:69)\n", "\tat kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)\n", "\tat kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:48)\n", "\tat kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.InternalEvaluatorImpl.eval(InternalEvaluatorImpl.kt:127)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.CellExecutorImpl$execute$1$result$1.invoke(CellExecutorImpl.kt:79)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.CellExecutorImpl$execute$1$result$1.invoke(CellExecutorImpl.kt:77)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.ReplForJupyterImpl.withHost(ReplForJupyterImpl.kt:758)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.CellExecutorImpl.execute(CellExecutorImpl.kt:77)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.execution.CellExecutor$DefaultImpls.execute$default(CellExecutor.kt:12)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.ReplForJupyterImpl.evaluateUserCode(ReplForJupyterImpl.kt:581)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.ReplForJupyterImpl.access$evaluateUserCode(ReplForJupyterImpl.kt:136)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.ReplForJupyterImpl$evalEx$1.invoke(ReplForJupyterImpl.kt:439)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.ReplForJupyterImpl$evalEx$1.invoke(ReplForJupyterImpl.kt:436)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.ReplForJupyterImpl.withEvalContext(ReplForJupyterImpl.kt:417)\n", "\tat org.jetbrains.kotlinx.jupyter.repl.impl.ReplForJupyterImpl.evalEx(ReplForJupyterImpl.kt:436)\n", "\tat org.jetbrains.kotlinx.jupyter.messaging.IdeCompatibleMessageRequestProcessor$processExecuteRequest$1$response$1$1.invoke(IdeCompatibleMessageRequestProcessor.kt:140)\n", "\tat org.jetbrains.kotlinx.jupyter.messaging.IdeCompatibleMessageRequestProcessor$processExecuteRequest$1$response$1$1.invoke(IdeCompatibleMessageRequestProcessor.kt:139)\n", "\tat org.jetbrains.kotlinx.jupyter.execution.JupyterExecutorImpl$Task.execute(JupyterExecutorImpl.kt:42)\n", "\tat org.jetbrains.kotlinx.jupyter.execution.JupyterExecutorImpl$executorThread$1.invoke(JupyterExecutorImpl.kt:82)\n", "\tat org.jetbrains.kotlinx.jupyter.execution.JupyterExecutorImpl$executorThread$1.invoke(JupyterExecutorImpl.kt:80)\n", "\tat kotlin.concurrent.ThreadsKt$thread$thread$1.run(Thread.kt:30)\n" ] } ], "source": [ "val list = (0..100).toMutableList()\n", "\n", "list.forEach {\n", " if(it % 2 == 0) list.remove(it)\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "N3QIwvANEngnvMgsCVJatN", "type": "CODE" } }, "outputs": [], "source": [] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "x9nGAXOgOlWxd4cu6Smio8", "type": "MD" } }, "source": [ "### Синхронный х многопоточный х неконкурентный" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "lRJGB0cHhpjQTdRdGynG0G", "type": "CODE" } }, "outputs": [], "source": [ "val sum = IntStream.range(0, 100).parallel().sum()\n", "\n", "println(sum)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "1lLEGWWbB6qnFr1qjfSGpo", "type": "CODE" } }, "outputs": [], "source": [] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "OTRLxfWLADkMoc9ViJfeEq", "type": "MD" } }, "source": [ "### Асинхронный х однопоточный х неконкурентный" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "r1yVVtgMhexxzx7gGVmeIg", "type": "CODE" } }, "outputs": [], "source": [ "fun runLongTask(result: Int = 8): Int {\n", " Thread.sleep(100)\n", " println(\"Task complete: $result\")\n", " return result\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "8YvIKfD1I7cfbiPRMpk0DC", "type": "CODE" } }, "outputs": [], "source": [ "import java.util.concurrent.*\n", "\n", "val executor = Executors.newSingleThreadExecutor()\n", "\n", "val future = executor.submit {\n", " val result = runLongTask()\n", " println(result)\n", " result\n", "}\n", "\n", "future.get()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "nyjKPayaltq8gBzq2bIP1c", "type": "MD" } }, "source": [ "### Асинхронный х однопоточный х конкурентный " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "UreOIHJpXQYfkjeHOvf1Bq", "type": "CODE" } }, "outputs": [], "source": [ "interface Observable{\n", " fun onChange(callback: (Int) -> Unit)\n", "}\n", "\n", "val observable: Observable by lazy{ TODO() }" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "1in8iE7mL9m895XWUNh0Sl", "type": "CODE" } }, "outputs": [], "source": [ "val list: MutableList = mutableListOf()\n", "\n", "observable.onChange { \n", " list.add(it)\n", "}" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "TczpOZrkCKogcT7x7XWAUT", "type": "MD" } }, "source": [ "### Асинхронный х многопоточный х неконкурентный" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "YvgL8fFuneP9USjjnsfiQj", "type": "CODE" } }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "9NS1h5b5lJ0BEzieUt6xrr", "type": "CODE" } }, "outputs": [], "source": [ "val executor: ExecutorService = Executors.newFixedThreadPool(4)\n", "\n", "repeat(8){\n", " executor.submit{\n", " runLongTask(it)\n", " }\n", "}" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "REBgToVc8iKIrODCWXPdZj", "type": "MD" } }, "source": [ "### Синхронный х многопоточный х конкурентный" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "3AjItM8WtjFE9qJo9JvZFW", "type": "CODE" } }, "outputs": [], "source": [ "import kotlin.io.path.Path\n", "import kotlin.io.path.writeText\n", "\n", "val file = Path(\"someFile.txt\")\n", "\n", "val data: List = emptyList()\n", "\n", "data.stream()\n", " .parallel()\n", " .forEach { \n", " file.writeText(it)\n", " }" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "XDCp5EjIq8v6ABeo5q2K6S", "type": "MD" } }, "source": [ "### Асинхронный х многопоточный х конкурентный" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "taOKUd5Gc9U6TuGVFZJvew", "type": "CODE" } }, "outputs": [], "source": [ "val cache = mutableMapOf\n", "\n", "val consumer: (Int) -> Unit = TODO()\n", "\n", "\n", "repeat(8){ i->\n", " executor.submit{\n", " val result = cache.getOrPut(i){\n", " runLongTask(i)\n", " }\n", " consumer(result)\n", " }\n", "}" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "bSK4aInljsXYinbOTNSLdc", "type": "MD" } }, "source": [ "## Инструменты" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "qjWpglMy3eSM475ozgnDPA", "type": "MD" } }, "source": [ "#### Thread" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "nEZ6jKJhVHhsjMvptTQ3rU", "type": "CODE" } }, "outputs": [], "source": [ "import kotlin.concurrent.*\n", "\n", "val t = thread {\n", " runLongTask()\n", "}\n", "t.join()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "k35GcE4VUIMtrznZ0C3BmC", "type": "CODE" } }, "outputs": [], "source": [] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "bX0GaqyAH6q7Max0Tky7DW", "type": "MD" } }, "source": [ "#### Future" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "TVhCm0JtWiYFFqWYORxuya", "type": "CODE" } }, "outputs": [], "source": [ "val future = executor.submit{\n", " runLongTask()\n", "}\n", "\n", "future.get()\n", "future.cancel(true)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "a5BY9U8m9OeZSSsS0yGRSZ", "type": "MD" } }, "source": [ "#### CompletableFuture" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "2rchFZt5trGqzOCuU3aPvz", "type": "CODE" } }, "outputs": [], "source": [ "import java.util.concurrent.*\n", "\n", "val cf = CompletableFuture.supplyAsync{\n", " runLongTask()\n", "}\n", "\n", "val cf2 = cf.whenComplete{ res, _ ->\n", " runLongTask(res - 1)\n", "}\n", "\n", "val cf3 = cf.whenComplete{ res, _ ->\n", " runLongTask(res + 1)\n", "}\n", "\n", "cf2.join()\n", "cf3.join()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "izHWuE5ZZo1hphjMmc7BHj", "type": "MD" } }, "source": [ "#### Lock" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "JTXxcGnvTS36OVX6GkJfkK", "type": "CODE" } }, "outputs": [], "source": [ "import java.util.concurrent.locks.*\n", "\n", "val list = mutableListOf()\n", "val lock = ReentrantLock()\n", "\n", "val cf4 = CompletableFuture.supplyAsync{\n", " val res = runLongTask(4)\n", " lock.withLock { \n", " list.add(res)\n", " }\n", "}\n", "\n", "val cf5 = CompletableFuture.supplyAsync{\n", " val res = runLongTask(5)\n", " lock.withLock { \n", " list.add(res)\n", " }\n", "}\n", "\n", "cf4.join()\n", "cf5.join()\n", "\n", "list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Reactive streams" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A(val value: Int)\n", "class B(val value: Int)\n", "\n", "val aFlow = flowOf()\n", "val bFlow = flowOf()\n", "\n", "val combined = aFlow.zip(bFlow){ a, b->\n", " a.value + b.value\n", "}.debounce(2.seconds)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Actor" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sealed class Event {\n", " class Open(val transactionId: Int): Event()\n", " class Close(val tranactionId: Int): Event()\n", "}\n", "\n", "fun interface Actor {\n", " suspend fun receive(event: Event)\n", "}\n", "\n", "val actor = object : Actor {\n", " private var transaction: Int? = null\n", " override suspend fun receive(event: Event) {\n", " when (event) {\n", " is Event.Open -> if (transaction != null) {\n", " error(\"Transaction already open\")\n", " } else {\n", " transaction = event.transactionId\n", " }\n", " is Event.Close ->if (transaction != event.tranactionId) {\n", " error(\"Wrong transaction id: ${event.tranactionId}\")\n", " } else {\n", " transaction = null\n", " }\n", " }\n", " }\n", "\n", "}" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "YDqoXAD2XEED9MSPRuMMzL", "type": "MD" } }, "source": [ "## Сорта асинхронности" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "kb1ccsTMIZX3aacLF6gPrJ", "type": "MD" } }, "source": [ "#### Callback" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "jZrkouEiPJnMCCpxTFlgVP", "type": "CODE" } }, "outputs": [], "source": [ "import java.net.*\n", "import java.net.http.*\n", "import java.net.http.HttpResponse.*\n", "\n", "val client: HttpClient = HttpClient.newHttpClient()\n", "\n", "val request : HttpRequest = HttpRequest.newBuilder()\n", " .uri(URI.create(\"https://sciprog.center\"))\n", " .GET().build()\n", "\n", "val regex = \"\"\"href=\\\"(.+\\.png)\\\"\"\"\".toRegex()\n", "\n", "client.sendAsync(request, BodyHandlers.ofString())\n", " .thenApply{ it.body() }\n", " .thenApply{ \n", " val resources = regex.findAll(it).map{it.groupValues[1]}\n", "\n", " resources.forEach { resourceName->\n", " val resourceRequest : HttpRequest = HttpRequest.newBuilder()\n", " .uri(URI.create(\"https://sciprog.center$resourceName\"))\n", " .GET().build()\n", " client.sendAsync(resourceRequest, BodyHandlers.ofByteArray()).thenAccept{ resourceResponse ->\n", " val bodyBytes = resourceResponse.body()\n", " //do something with the body\n", " }\n", " }\n", " resources\n", " }\n", " .thenAccept{ println(it.toList()) }\n", " .join()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "7zwURNaHnaTgOTAZumDDcd", "type": "MD" } }, "source": [ "#### Реактивные потоки" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "datalore": { "hide_input_from_viewers": true, "hide_output_from_viewers": true, "node_id": "lPXl5Gkvu7CuhlhUV7YJab", "type": "CODE" } }, "outputs": [], "source": [] } ], "metadata": { "datalore": { "base_environment": "default", "computation_mode": "JUPYTER", "package_manager": "pip", "packages": [], "report_row_ids": [], "version": 3 }, "kernelspec": { "display_name": "Kotlin", "language": "kotlin", "name": "kotlin" }, "language_info": { "codemirror_mode": "text/x-kotlin", "file_extension": ".kt", "mimetype": "text/x-kotlin", "name": "kotlin", "nbconvert_exporter": "", "pygments_lexer": "kotlin", "version": "1.9.23" } }, "nbformat": 4, "nbformat_minor": 4 }