简体   繁体   English

如何在 Kotlin 中获取协程的名称?

[英]How to get the name of a coroutine in Kotlin?

I'm curious about the internal working of a coroutine when suspended on the main thread.我很好奇协程在主线程上suspended时的内部工作。 The real question is how to log a suspended function which is a coroutine on the main thread.真正的问题是如何在主线程上记录作为协程的suspended函数。 Where exactly the execution is taking place?执行究竟发生在哪里? Is it a virtual thread?是虚拟线程吗?

If you are talking about logging the coroutine name:如果您正在谈论记录协程名称:

You can achieve this by你可以通过

  1. Give name to coroutine(if you want custom name): launch(CoroutineName("My-Coroutine"))给协程命名(如果你想要自定义名称): launch(CoroutineName("My-Coroutine"))

  2. Enable the logging in IntelliJ toolbar menu: Run -> Edit Configuration and add在 IntelliJ 工具栏菜单中启用日志记录:运行 -> 编辑配置并添加

-Dkotlinx.coroutines.debug in VM options. -Dkotlinx.coroutines.debug在 VM 选项中。

编辑配置中的 VM 选项

Then you can see @My-Coroutine in logcat.然后就可以在logcat中看到@My-Coroutine了。

Try below code after Edit Configuration change:在编辑配置更改后尝试以下代码:

fun main() = runBlocking {
println("   'runBlocking': I'm working in thread ${Thread.currentThread().name}")

val job = launch(CoroutineName("my-custom-name")) {
    println("   'runBlocking': I'm working in thread ${Thread.currentThread().name}")

}

job.join()}

Result:结果: 结果

The other answers don't answer the question directly " How to get the name of a coroutine in Kotlin? ";其他答案没有直接回答问题“如何在 Kotlin 中获取协程的名称? ”; instead, they suggest how to name a coroutine.相反,他们建议如何命名协程。

If inside a coroutine, the name can be retrieved using currentCoroutineContext()[CoroutineName] .如果在协程内部,可以使用currentCoroutineContext()[CoroutineName]检索名称。

If outside a coroutine, there's no direct way to retrieve the name using a reference to a Job or Deferred (too bad).如果在协程之外,则没有直接的方法来使用对JobDeferred的引用来检索名称(太糟糕了)。 However, there's a reflection hack that can be used.但是,有一个可以使用的反射技巧。 Of course, the usual warnings come attached, which are, no type safety and hacking into internal APIs that may change anytime.当然,通常会附带警告,即没有类型安全性和侵入可能随时更改的内部 API。

@Suppress("UNCHECKED_CAST")
val nameString = AbstractCoroutine::class.memberFunctions
    .single { it.name == "nameString" } as Function1<AbstractCoroutine<*>, String>
val name = nameString(job as AbstractCoroutine<*>)
    .replace("\"", "")
    .takeWhile { it != '#' }

The method/function containing this code has to be marked with @InternalCoroutinesApi .包含此代码的方法/函数必须用@InternalCoroutinesApi标记。

You can give name to coroutine using CoroutineName(name:String) method at the time of creating coroutine:您可以在创建协程时使用CoroutineName(name:String)方法为协程CoroutineName(name:String)

repeat(5) {
            GlobalScope.launch(CoroutineName("$it")) {
                displayGreetingsFor(it)
            }
        }

To retrive the name given to coroutine use coroutineContext[CoroutineName.Key] as shown below:要检索赋予协程的名称,请使用coroutineContext[CoroutineName.Key] ,如下所示:

private suspend fun displayGreetingsFor(i: Int) {
        delay(100)
        println(
            " ${coroutineContext[CoroutineName.Key]} is executing on thread : ${Thread.currentThread().name}"
        )
    }

This is will print following o/p on console:这将在控制台上打印以下 o/p:

CoroutineName(0) is executing on thread : DefaultDispatcher-worker-3
CoroutineName(1) is executing on thread : DefaultDispatcher-worker-2
CoroutineName(2) is executing on thread : DefaultDispatcher-worker-8
CoroutineName(3) is executing on thread : DefaultDispatcher-worker-6
CoroutineName(4) is executing on thread : DefaultDispatcher-worker-5

Here is a sample from docs and i guess this is closest you can get. 以下是来自docs的示例,我猜这是最接近你可以得到的。

import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    launch { // context of the parent, main runBlocking coroutine
        println("main runBlocking      : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
        println("Unconfined            : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher 
        println("Default               : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
        println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
    }    
}

will print this. 会印这个。

Unconfined            : I'm working in thread main
Default               : I'm working in thread DefaultDispatcher-worker-1
newSingleThreadContext: I'm working in thread MyOwnThread
main runBlocking      : I'm working in thread main

Read more here 在这里阅读更多

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM