You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SafeCollector performance improvements:
* Cache result of the context check thus speeding up safe collector on happy path by a factor of three
* Separate fast and slow paths in JobSupport to drastically change inlining decisions of the JVM that are crucial for leaf coroutines with flows
Strengthen flow context preservation invariant
* Add additional check in SafeCollector with an error message pointing to channelFlow
* Improve performance of the CoroutineId check in SafeCollector
* Change wording in documentation
FixesKotlin#1210
val result = currentContext.fold(0) fold@{ count, element ->
39
+
val key = element.key
40
+
val collectElement = collectContext[key]
41
+
if (key !==Job) {
42
+
return@fold if (element !== collectElement) Int.MIN_VALUE
43
+
else count +1
44
+
}
45
+
46
+
val collectJob = collectElement asJob?
47
+
val emissionParentJob = (element asJob).transitiveCoroutineParent(collectJob)
48
+
/*
49
+
* Things like
50
+
* ```
51
+
* coroutineScope {
52
+
* launch {
53
+
* emit(1)
54
+
* }
55
+
*
56
+
* launch {
57
+
* emit(2)
58
+
* }
59
+
* }
60
+
* ```
61
+
* are prohibited because 'emit' is not thread-safe by default. Use channelFlow instead if you need concurrent emission
62
+
* or want to switch context dynamically (e.g. with `withContext`).
63
+
*
64
+
* Note that collecting from another coroutine is allowed, e.g.:
65
+
* ```
66
+
* coroutineScope {
67
+
* val channel = produce {
68
+
* collect { value ->
69
+
* send(value)
70
+
* }
71
+
* }
72
+
* channel.consumeEach { value ->
73
+
* emit(value)
74
+
* }
75
+
* }
76
+
* ```
77
+
* is a completely valid.
78
+
*/
79
+
if (emissionParentJob !== collectJob) {
80
+
error(
81
+
"Flow invariant is violated: emission from another coroutine is detected (child of $emissionParentJob, expected child of $collectJob). "+
82
+
"FlowCollector is not thread-safe and concurrent emissions are prohibited. To mitigate this restriction please use 'flowChannel' builder instead of 'flow'"
83
+
)
84
+
}
85
+
count +1
86
+
}
87
+
if (result != collectContextSize) {
23
88
error(
24
-
"Flow invariant is violated: flow was collected in $collectContext, but emission happened in $emitContext. "+
25
-
"Please refer to 'flow' documentation or use 'flowOn' instead")
89
+
"Flow invariant is violated: flow was collected in $collectContext, but emission happened in $currentContext. "+
90
+
"Please refer to 'flow' documentation or use 'flowOn' instead"
0 commit comments