Skip to content

awaitAll and joinAll extensions #323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Apr 27, 2018
Merged

awaitAll and joinAll extensions #323

merged 14 commits into from
Apr 27, 2018

Conversation

qwwdfsad
Copy link
Collaborator

Fixes #171

* this function immediately resumes with [CancellationException].
*/
public suspend fun Iterable<Job>.awaitAll(): Unit {
val jobs = this as? Collection<Job> ?: this.toList()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if jobs collection is changed after calling .awaitAll() extension on it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends on mutation. In the worst case, awaitAll will hang (if concurrent mutator removes an element while awaitAll prepares its handles), but a non-trivial effort is required to write such code.

Behaviour in such case is undefined, what does user expect if he creates a collection of jobs, shares it and mutates in one coroutine while awaiting them in another?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, semantically we want awaitAll to operate on a some kind of snapshot. The challenge is how far we are ready to go for an optimal implementation. The easy, but not efficient, way it so to always take a snapshot of collection first, then await on it.

@@ -20,7 +20,8 @@ public suspend fun awaitAll(vararg jobs: Job): Unit = jobs.asList().awaitAll()
*/
public suspend fun Collection<Job>.awaitAll() {
if (isEmpty()) return
AwaitAll(this).await()
val snapshot = ArrayList(this)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to use toList, it can exploit collection immutability, when we have one.

* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting,
* this function immediately resumes with [CancellationException].
*/
public suspend fun awaitAll(vararg jobs: Job): Unit = jobs.asList().awaitAll()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This list can be awaited without taking snapshot.

elizarov and others added 4 commits April 26, 2018 11:30
# Conflicts:
#	common/kotlinx-coroutines-core-common/src/test/kotlin/kotlinx/coroutines/experimental/channels/ArrayBroadcastChannelTest.kt
#	common/kotlinx-coroutines-core-common/src/test/kotlin/kotlinx/coroutines/experimental/channels/ArrayChannelTest.kt
#	common/kotlinx-coroutines-core-common/src/test/kotlin/kotlinx/coroutines/experimental/channels/ConflatedChannelTest.kt
#	common/kotlinx-coroutines-core-common/src/test/kotlin/kotlinx/coroutines/experimental/channels/LinkedListChannelTest.kt
#	common/kotlinx-coroutines-core-common/src/test/kotlin/kotlinx/coroutines/experimental/channels/ProduceTest.kt
#	common/kotlinx-coroutines-core-common/src/test/kotlin/kotlinx/coroutines/experimental/channels/RendezvousChannelTest.kt
Invoke clearTimeout on cancellation in JSDispatcher
Remove delayed task on cancellation from ThreadSafeHeap on cancellation to avoid memory leak
@elizarov elizarov merged commit b4c7b40 into develop Apr 27, 2018
@elizarov
Copy link
Contributor

Merged!

@elizarov elizarov deleted the await-all branch April 27, 2018 09:11
@olgachotinun
Copy link

olgachotinun commented May 29, 2018

Hi! I was wondering when this will be released. And if You could update the coroutines guidel saying awaitAll is coming, I just spent hours trying select with onAwait() combo to accomplish similar thing from https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#switch-over-a-channel-of-deferred-values and ended up implementing my own version of awaitAll() . Let me try too uptake new version of coroutines instead. Thanks!

@qwwdfsad
Copy link
Collaborator Author

Hi @olgachotinun
We're almost ready for the next release, please stay tuned.

if You could update the coroutines guide saying awaitAll is coming

We can't really do it, having "what's coming in the next release" in the guide is slightly confusing, especially for "planned" public API which is frequently changed during initial implementation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants