-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8e4e0e4
Showing
12 changed files
with
953 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/.idea | ||
*.iml | ||
target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# kotlinx.coroutines | ||
Two libraries built upon Kotlin coroutines: | ||
* `kotlinx-coroutines-async` with convenient interfaces/wrappers to commonly | ||
used asynchronous API shipped with standard JDK, namely promise-like `CompletableFuture` | ||
and asynchronous channels from `java.nio` package | ||
* `kotlinx-coroutines-generate` provides ability to create `Sequence` objects | ||
generated by coroutine body containing `yield` suspension points | ||
|
||
## Examples | ||
### Async | ||
```kotlin | ||
import kotlinx.coroutines.async | ||
import java.util.concurrent.CompletableFuture | ||
|
||
private fun startLongAsyncOperation(v: Int) = | ||
CompletableFuture.supplyAsync { | ||
Thread.sleep(1000) | ||
"Result: $v" | ||
} | ||
|
||
fun main(args: Array<String>) { | ||
val future = async<String> { | ||
(1..5).map { | ||
await(startLongAsyncOperation(it)) | ||
}.joinToString("\n") | ||
} | ||
|
||
println(future.get()) | ||
} | ||
``` | ||
|
||
### Generate | ||
``` | ||
import kotlinx.coroutines.generate | ||
fun main(args: Array<String>) { | ||
val sequence = generate<Int> { | ||
for (i in 1..5) { | ||
yield(i) | ||
} | ||
} | ||
println(sequence.joinToString(" ")) | ||
} | ||
``` | ||
|
||
For more examples you can look at `kotlinx-coroutines-async-example-ui` sample | ||
project or in tests directories. | ||
|
||
## Maven | ||
|
||
Add jcenter repository (if you don't have it yet) | ||
|
||
```xml | ||
<repository> | ||
<snapshots> | ||
<enabled>false</enabled> | ||
</snapshots> | ||
<id>central</id> | ||
<name>bintray</name> | ||
<url>http://jcenter.bintray.com</url> | ||
</repository> | ||
``` | ||
|
||
Add a dependency: | ||
|
||
```xml | ||
<dependency> | ||
<groupId>org.jetbrains.kotlinx</groupId> | ||
<artifactId>kotlinx-coroutines-generate</artifactId> | ||
<version>0.1</version> | ||
</dependency> | ||
``` | ||
|
||
## Gradle | ||
|
||
Just add a dependency: | ||
|
||
```groovy | ||
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-generate:0.1' | ||
``` | ||
|
||
jcenter repository should be configured by default in gradle, but if it's not you may need to include it: | ||
|
||
```groovy | ||
repositories { | ||
jcenter() | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>org.jetbrains.kotlinx</groupId> | ||
<artifactId>kotlinx-coroutines</artifactId> | ||
<version>0.1-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>kotlinx-coroutines-async-example-ui</artifactId> | ||
<packaging>jar</packaging> | ||
|
||
<name>Example of asyncUi usage</name> | ||
|
||
<properties> | ||
<kotlin.version>1.1-SNAPSHOT</kotlin.version> | ||
</properties> | ||
|
||
<build> | ||
<sourceDirectory>src/main/kotlin</sourceDirectory> | ||
<testSourceDirectory>src/test/kotlin</testSourceDirectory> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-deploy-plugin</artifactId> | ||
<configuration> | ||
<skip>true</skip> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.jetbrains.kotlinx</groupId> | ||
<artifactId>kotlinx-coroutines-async</artifactId> | ||
<version>${version}</version> | ||
<scope>compile</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
48 changes: 48 additions & 0 deletions
48
kotlinx-coroutines-async-example-ui/src/main/kotlin/main.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import kotlinx.coroutines.asyncUi | ||
import java.awt.Insets | ||
import java.util.concurrent.CompletableFuture | ||
import javax.swing.* | ||
|
||
private fun createAndShowGUI() { | ||
val frame = JFrame("Async UI example") | ||
frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE | ||
|
||
val jProgressBar = JProgressBar(0, 100).apply { | ||
value = 0 | ||
isStringPainted = true | ||
} | ||
|
||
val jTextArea = JTextArea(11, 10) | ||
jTextArea.margin = Insets(5, 5, 5, 5) | ||
jTextArea.isEditable = false | ||
|
||
val panel = JPanel() | ||
|
||
panel.add(jProgressBar) | ||
panel.add(jTextArea) | ||
|
||
frame.contentPane.add(panel) | ||
frame.pack() | ||
frame.isVisible = true | ||
|
||
asyncUi { | ||
for (i in 1..10) { | ||
// 'append' method and consequent 'jProgressBar.setValue' are called | ||
// within Swing event dispatch thread | ||
jTextArea.append( | ||
await(startLongAsyncOperation(i)) | ||
) | ||
jProgressBar.value = i * 10 | ||
} | ||
} | ||
} | ||
|
||
private fun startLongAsyncOperation(v: Int) = | ||
CompletableFuture.supplyAsync { | ||
Thread.sleep(1000) | ||
"Message: $v\n" | ||
} | ||
|
||
fun main(args: Array<String>) { | ||
SwingUtilities.invokeLater(::createAndShowGUI) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>org.jetbrains.kotlinx</groupId> | ||
<artifactId>kotlinx-coroutines</artifactId> | ||
<version>0.1-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>kotlinx-coroutines-async</artifactId> | ||
<packaging>jar</packaging> | ||
|
||
<name>Kotlin async library based on CompletableFuture</name> | ||
|
||
<properties> | ||
<kotlin.version>1.1-SNAPSHOT</kotlin.version> | ||
</properties> | ||
|
||
<build> | ||
<sourceDirectory>src/main/kotlin</sourceDirectory> | ||
<testSourceDirectory>src/test/kotlin</testSourceDirectory> | ||
</build> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.apache.commons</groupId> | ||
<artifactId>commons-io</artifactId> | ||
<version>1.3.2</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package kotlinx.coroutines | ||
|
||
import java.net.SocketAddress | ||
import java.nio.ByteBuffer | ||
import java.nio.channels.AsynchronousFileChannel | ||
import java.nio.channels.AsynchronousServerSocketChannel | ||
import java.nio.channels.AsynchronousSocketChannel | ||
import java.nio.channels.CompletionHandler | ||
import java.util.concurrent.CompletableFuture | ||
import java.util.concurrent.TimeUnit | ||
import javax.swing.SwingUtilities | ||
|
||
/** | ||
* Run asynchronous computations based on [c] coroutine parameter | ||
* | ||
* Execution starts immediately within the 'async' call and it runs until | ||
* the first suspension point is reached ('await' call with some CompletableFuture). | ||
* Remaining part of coroutine will be executed as it's passed into 'whenComplete' | ||
* call of awaited Future. | ||
* | ||
* @param c a coroutine representing asynchronous computations | ||
* @param continuationWrapper represents a function that wraps execution parts | ||
* between subsequent 'await' calls. | ||
* For example it could be 'SwingUtilities.invokeLater', providing ability to | ||
* call UI-related methods between 'await' calls | ||
* | ||
* @return CompletableFuture object representing result of computations | ||
*/ | ||
fun <T> async( | ||
continuationWrapper: ContinuationWrapper? = null, | ||
coroutine c: FutureController<T>.() -> Continuation<Unit> | ||
): CompletableFuture<T> { | ||
val controller = FutureController<T>(continuationWrapper) | ||
c(controller).resume(Unit) | ||
return controller.future | ||
} | ||
|
||
/** | ||
* Run asynchronous computations based on [c] coroutine parameter. | ||
* Continuation parts (everything besides awaited futures) | ||
* | ||
* @param c a coroutine representing asynchronous computations | ||
* | ||
* @return CompletableFuture object representing result of computations | ||
* @See async | ||
*/ | ||
fun asyncUi( | ||
coroutine c: FutureController<Unit>.() -> Continuation<Unit> | ||
) { | ||
if (SwingUtilities.isEventDispatchThread()) { | ||
async({ SwingUtilities.invokeLater(it) }, c) | ||
} | ||
else { | ||
SwingUtilities.invokeLater { | ||
async({ SwingUtilities.invokeLater(it) }, c) | ||
} | ||
} | ||
} | ||
|
||
typealias ContinuationWrapper = (() -> Unit) -> Unit | ||
|
||
open class FutureController<T>( | ||
private val continuationWrapper: ContinuationWrapper? | ||
) { | ||
val future = CompletableFuture<T>() | ||
|
||
suspend fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>) { | ||
f.whenComplete { value, throwable -> | ||
wrapContinuationIfNeeded { | ||
if (throwable == null) | ||
machine.resume(value) | ||
else | ||
machine.resumeWithException(throwable) | ||
} | ||
} | ||
} | ||
|
||
private fun wrapContinuationIfNeeded(block: () -> Unit) { | ||
continuationWrapper?.invoke(block) ?: block() | ||
} | ||
|
||
operator fun handleResult(value: T, c: Continuation<Nothing>) { | ||
future.complete(value) | ||
} | ||
|
||
operator fun handleException(t: Throwable, c: Continuation<Nothing>) { | ||
future.completeExceptionally(t) | ||
} | ||
|
||
// | ||
// IO parts | ||
// | ||
suspend fun AsynchronousFileChannel.aRead( | ||
buf: ByteBuffer, | ||
position: Long, | ||
c: Continuation<Int> | ||
) { | ||
this.read(buf, position, null, AsyncIOHandler(c)) | ||
} | ||
|
||
suspend fun AsynchronousFileChannel.aWrite( | ||
buf: ByteBuffer, | ||
position: Long, | ||
c: Continuation<Int> | ||
) { | ||
this.write(buf, position, null, AsyncIOHandler(c)) | ||
} | ||
|
||
suspend fun AsynchronousServerSocketChannel.aAccept( | ||
c: Continuation<AsynchronousSocketChannel> | ||
) { | ||
this.accept(null, AsyncIOHandler(c)) | ||
} | ||
|
||
suspend fun AsynchronousSocketChannel.aConnect( | ||
socketAddress: SocketAddress, | ||
c: Continuation<Unit> | ||
) { | ||
this.connect(socketAddress, null, AsyncVoidIOHandler(c)) | ||
} | ||
|
||
suspend fun AsynchronousSocketChannel.aRead( | ||
buf: ByteBuffer, | ||
timeout: Long = 0L, | ||
timeUnit: TimeUnit = TimeUnit.MILLISECONDS, | ||
c: Continuation<Int> | ||
) { | ||
this.read(buf, timeout, timeUnit, null, AsyncIOHandler(c)) | ||
} | ||
|
||
suspend fun AsynchronousSocketChannel.aWrite( | ||
buf: ByteBuffer, | ||
timeout: Long = 0L, | ||
timeUnit: TimeUnit = TimeUnit.MILLISECONDS, | ||
c: Continuation<Int> | ||
) { | ||
this.write(buf, timeout, timeUnit, null, AsyncIOHandler(c)) | ||
} | ||
|
||
private class AsyncIOHandler<E>(val c: Continuation<E>) : CompletionHandler<E, Nothing?> { | ||
override fun completed(result: E, attachment: Nothing?) { | ||
c.resume(result) | ||
} | ||
|
||
override fun failed(exc: Throwable, attachment: Nothing?) { | ||
c.resumeWithException(exc) | ||
} | ||
} | ||
|
||
private class AsyncVoidIOHandler(val c: Continuation<Unit>) : CompletionHandler<Void?, Nothing?> { | ||
override fun completed(result: Void?, attachment: Nothing?) { | ||
c.resume(Unit) | ||
} | ||
|
||
override fun failed(exc: Throwable, attachment: Nothing?) { | ||
c.resumeWithException(exc) | ||
} | ||
} | ||
} |
Oops, something went wrong.