为什么 withContext 在完成时不恢复到原始调度程序?
Why isn't withContext resuming to the original dispatcher on completion?
我正在编写一个应该 运行 在特定调度程序上的挂起函数。它可以从任何调度程序调用,因此它应该在返回时恢复到原始调度程序。
withContext
应该有所帮助,因为它指出:
This function uses dispatcher from the new context, shifting execution
of the block into the different thread if a new dispatcher is
specified, and back to the original dispatcher when it completes.
这是一个基本测试:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.setMain
import kotlinx.coroutines.withContext
fun log(message: String = "") {
println("[${Thread.currentThread().name}] $message")
}
suspend fun test9Odd(x: Int): Boolean {
return withContext(Dispatchers.IO) {
log("test9Odd for x = $x...")
delay(250)
x and 1 == 1
}
}
fun main(args: Array<String>) {
// setting Dispatcher.Main for the test:
val x = TestCoroutineDispatcher()
x.runCurrent()
Dispatchers.setMain(x)
runBlocking {
withContext(Dispatchers.Main) {
log("test9")
for (x in listOf(8, 97, 108)) {
val result = test9Odd(x)
log("Is $x odd? ${if (result) "yes" else "no"}")
}
}
}
}
我观察到的与上面的说法矛盾,上下文切换但返回时不恢复,它保持运行ning on worker-1
:
[main] test9
[DefaultDispatcher-worker-1] test9Odd for x = 8...
[DefaultDispatcher-worker-1] Is 8 odd? no
[DefaultDispatcher-worker-1] test9Odd for x = 97...
[DefaultDispatcher-worker-1] Is 97 odd? yes
[DefaultDispatcher-worker-1] test9Odd for x = 108...
[DefaultDispatcher-worker-1] Is 108 odd? no
我的问题是:为什么 main()
函数 运行ning 中的代码在第一次调用后没有回到主线程?
请注意,如果我在主函数中删除 withContext
, 然后 它会切换回主线程。但是,如果我用 launch
替换 withContext
,它不会改变这个问题。
我知道协程测试直到最近才被描述为“不稳定”并且难以以产生预期结果的方式进行设置。
他们最近对测试库进行了大修,不推荐使用 TestCoroutineDispatcher。
以下测试对我有效:
class Tests {
@Before
fun before() {
Dispatchers.setMain(StandardTestDispatcher())
}
@Test
fun `switch between dispatchers`() = runTest {
withContext(Dispatchers.Main) {
log("test9")
for (x in listOf(8, 97, 108)) {
val result = test9Odd(x)
log("Is $x odd? ${if (result) "yes" else "no"}")
}
}
}
}
输出:
[Test worker @coroutine#1] test9
[DefaultDispatcher-worker-1] test9Odd for x = 8...
[Test worker @coroutine#1] Is 8 odd? no
[DefaultDispatcher-worker-1] test9Odd for x = 97...
[Test worker @coroutine#1] Is 97 odd? yes
[DefaultDispatcher-worker-1] test9Odd for x = 108...
[Test worker @coroutine#1] Is 108 odd? no
这也有效:
fun before() {
Dispatchers.setMain(newSingleThreadContext("main"))
}
运行 它在这样的测试之外也有效:
fun main() {
Dispatchers.setMain(newSingleThreadContext("main"))
runBlocking {
withContext(Dispatchers.Main) {
log("test9")
for (x in listOf(8, 97, 108)) {
val result = test9Odd(x)
log("Is $x odd? ${if (result) "yes" else "no"}")
}
}
}
}
我正在编写一个应该 运行 在特定调度程序上的挂起函数。它可以从任何调度程序调用,因此它应该在返回时恢复到原始调度程序。
withContext
应该有所帮助,因为它指出:
This function uses dispatcher from the new context, shifting execution of the block into the different thread if a new dispatcher is specified, and back to the original dispatcher when it completes.
这是一个基本测试:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.setMain
import kotlinx.coroutines.withContext
fun log(message: String = "") {
println("[${Thread.currentThread().name}] $message")
}
suspend fun test9Odd(x: Int): Boolean {
return withContext(Dispatchers.IO) {
log("test9Odd for x = $x...")
delay(250)
x and 1 == 1
}
}
fun main(args: Array<String>) {
// setting Dispatcher.Main for the test:
val x = TestCoroutineDispatcher()
x.runCurrent()
Dispatchers.setMain(x)
runBlocking {
withContext(Dispatchers.Main) {
log("test9")
for (x in listOf(8, 97, 108)) {
val result = test9Odd(x)
log("Is $x odd? ${if (result) "yes" else "no"}")
}
}
}
}
我观察到的与上面的说法矛盾,上下文切换但返回时不恢复,它保持运行ning on worker-1
:
[main] test9
[DefaultDispatcher-worker-1] test9Odd for x = 8...
[DefaultDispatcher-worker-1] Is 8 odd? no
[DefaultDispatcher-worker-1] test9Odd for x = 97...
[DefaultDispatcher-worker-1] Is 97 odd? yes
[DefaultDispatcher-worker-1] test9Odd for x = 108...
[DefaultDispatcher-worker-1] Is 108 odd? no
我的问题是:为什么 main()
函数 运行ning 中的代码在第一次调用后没有回到主线程?
请注意,如果我在主函数中删除 withContext
, 然后 它会切换回主线程。但是,如果我用 launch
替换 withContext
,它不会改变这个问题。
我知道协程测试直到最近才被描述为“不稳定”并且难以以产生预期结果的方式进行设置。
他们最近对测试库进行了大修,不推荐使用 TestCoroutineDispatcher。
以下测试对我有效:
class Tests {
@Before
fun before() {
Dispatchers.setMain(StandardTestDispatcher())
}
@Test
fun `switch between dispatchers`() = runTest {
withContext(Dispatchers.Main) {
log("test9")
for (x in listOf(8, 97, 108)) {
val result = test9Odd(x)
log("Is $x odd? ${if (result) "yes" else "no"}")
}
}
}
}
输出:
[Test worker @coroutine#1] test9
[DefaultDispatcher-worker-1] test9Odd for x = 8...
[Test worker @coroutine#1] Is 8 odd? no
[DefaultDispatcher-worker-1] test9Odd for x = 97...
[Test worker @coroutine#1] Is 97 odd? yes
[DefaultDispatcher-worker-1] test9Odd for x = 108...
[Test worker @coroutine#1] Is 108 odd? no
这也有效:
fun before() {
Dispatchers.setMain(newSingleThreadContext("main"))
}
运行 它在这样的测试之外也有效:
fun main() {
Dispatchers.setMain(newSingleThreadContext("main"))
runBlocking {
withContext(Dispatchers.Main) {
log("test9")
for (x in listOf(8, 97, 108)) {
val result = test9Odd(x)
log("Is $x odd? ${if (result) "yes" else "no"}")
}
}
}
}