Token导航 LogoToken导航TokenDH.com
AI 工具需要联网github未标认证来源可访问clear审计通过

kotlin-coroutinesKotlin 协程

Agent Skill

kotlin-coroutines 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

4,264

周安装

240

GitHub Stars

142

下载量

2,476
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:kotlin-coroutines(Kotlin 协程)
来源仓库:https://github.com/thebushidocollective/han
仓库路径:skills/kotlin-coroutines
安装命令:
npx skills add https://github.com/thebushidocollective/han --skill 'Kotlin Coroutines'
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/thebushidocollective/han --skill 'Kotlin Coroutines'

简介

kotlin-coroutines 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、代码变更或协作事项进行整理。
  • 通过 npx skills add 命令从指定 GitHub 路径安装并使用。
  • 安装前需确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。
  • 建议结合来源仓库和原始 README 核验具体用法和功能边界。

SKILL.md

Kotlin Coroutines

Introduction

Kotlin coroutines provide a powerful framework for asynchronous programming that is lightweight, expressive, and built on structured concurrency principles. Coroutines enable writing asynchronous code that looks and behaves like sequential code, eliminating callback hell and improving readability.

Unlike threads, coroutines are extremely lightweight—millions can run on limited resources. The coroutine framework includes suspend functions for non-blocking operations, builders for launching work, Flow for reactive streams, and comprehensive cancellation and exception handling mechanisms.

This skill covers coroutine fundamentals, builders, contexts, Flow, channels, and production patterns for Android development and server-side Kotlin.

Suspend Functions

Suspend functions are the building blocks of coroutines, enabling non-blocking operations that can be paused and resumed without blocking threads.

// Basic suspend function
suspend fun fetchUser(id: Int): User {
    delay(1000) // Suspends without blocking
    return User(id, "Alice")
}

data class User(val id: Int, val name: String)

// Calling suspend functions
suspend fun loadUserProfile(id: Int): UserProfile {
    val user = fetchUser(id)
    val posts = fetchPosts(user.id)
    return UserProfile(user, posts)
}

suspend fun fetchPosts(userId: Int): List<Post> {
    delay(500)
    return emptyList()
}

data class Post(val id: Int, val title: String)
data class UserProfile(val user: User, val posts: List<Post>)

// Sequential vs concurrent execution
suspend fun loadDataSequential(): Pair<User, List<Post>> {
    val user = fetchUser(1)
    val posts = fetchPosts(1)
    return user to posts
}

suspend fun loadDataConcurrent(): Pair<User, List<Post>> = coroutineScope {
    val userDeferred = async { fetchUser(1) }
    val postsDeferred = async { fetchPosts(1) }
    userDeferred.await() to postsDeferred.await()
}

// Suspend functions with callbacks
suspend fun fetchData(url: String): String = suspendCoroutine { continuation ->
    fetchDataWithCallback(url) { result, error ->
        if (error != null) {
            continuation.resumeWithException(error)
        } else {
            continuation.resume(result)
        }
    }
}

fun fetchDataWithCallback(
    url: String,
    callback: (String, Exception?) -> Unit
) {
    // Simulated callback-based API
    callback("data", null)
}

// Cancellable suspend functions
suspend fun downloadFile(url: String): ByteArray =
    suspendCancellableCoroutine { continuation ->
        val request = startDownload(url) { data, error ->
            if (error != null) {
                continuation.resumeWithException(error)
            } else {
                continuation.resume(data)
            }
        }

        continuation.invokeOnCancellation {
            request.cancel()
        }
    }

class DownloadRequest {
    fun cancel() {}
}

fun startDownload(url: String, callback: (ByteArray, Exception?) -> Unit):
    DownloadRequest {
    return DownloadRequest()
}

// Using withContext for dispatcher switching
suspend fun saveToDatabase(user: User) {
    withContext(Dispatchers.IO) {
        // Database operation on IO dispatcher
        println("Saving user: ${user.name}")
    }
}

suspend fun updateUI(user: User) {
    withContext(Dispatchers.Main) {
        // UI update on main thread
        println("Updating UI for: ${user.name}")
    }
}

Suspend functions are marked with the suspend modifier and can only be called from other suspend functions or coroutines, ensuring proper context.

Coroutine Builders

Coroutine builders launch coroutines with different lifecycle and result handling semantics, enabling structured and unstructured concurrency.

// launch: fire-and-forget coroutine
fun launchExample() {
    GlobalScope.launch {
        val user = fetchUser(1)
        println("User: ${user.name}")
    }
}

// async: coroutine with result
fun asyncExample() {
    GlobalScope.launch {
        val deferredUser = async { fetchUser(1) }
        val deferredPosts = async { fetchPosts(1) }

        val user = deferredUser.await()
        val posts = deferredPosts.await()

        println("Loaded ${posts.size} posts for ${user.name}")
    }
}

// runBlocking: bridges blocking and suspending worlds
fun runBlockingExample() = runBlocking {
    val user = fetchUser(1)
    println("User loaded: ${user.name}")
}

// coroutineScope: structured concurrency
suspend fun loadMultipleUsers(ids: List<Int>): List<User> = coroutineScope {
    ids.map { id ->
        async { fetchUser(id) }
    }.awaitAll()
}

// supervisorScope: independent child failures
suspend fun loadDataWithSupervisor(): List<User> = supervisorScope {
    val user1 = async { fetchUser(1) }
    val user2 = async {
        delay(100)
        throw Exception("Failed")
    }

    // user1 succeeds even if user2 fails
    listOfNotNull(
        try { user1.await() } catch (e: Exception) { null }
    )
}

// withTimeout: time-limited coroutines
suspend fun fetchWithTimeout(id: Int): User? {
    return try {
        withTimeout(2000) {
            fetchUser(id)
        }
    } catch (e: TimeoutCancellationException) {
        null
    }
}

// Structured concurrency with lifecycle
class ViewModel : CoroutineScope {
    private val job = SupervisorJob()
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job

    fun loadData() {
        launch {
            val user = fetchUser(1)
            // Update UI
        }
    }

    fun onCleared() {
        job.cancel()
    }
}

Structured concurrency with coroutineScope ensures child coroutines complete before the scope exits, preventing leaks and ensuring proper cleanup.

Coroutine Context and Dispatchers

Coroutine context defines the execution environment including dispatcher, job, exception handler, and coroutine name for debugging.

// Dispatchers for thread pools
suspend fun dispatcherExamples() {
    // Main: UI thread (Android/JavaFX)
    withContext(Dispatchers.Main) {
        println("On main thread: ${Thread.currentThread().name}")
    }

    // IO: for blocking I/O operations
    withContext(Dispatchers.IO) {
        println("On IO thread: ${Thread.currentThread().name}")
    }

    // Default: CPU-intensive work
    withContext(Dispatchers.Default) {
        println("On default thread: ${Thread.currentThread().name}")
    }

    // Unconfined: starts in caller thread, resumes where suspended
    withContext(Dispatchers.Unconfined) {
        println("Unconfined: ${Thread.currentThread().name}")
    }
}

// Coroutine context elements
fun contextExample() {
    val scope = CoroutineScope(
        Dispatchers.Main +
        SupervisorJob() +
        CoroutineName("MyCoroutine") +
        CoroutineExceptionHandler { _, throwable ->
            println("Caught: $throwable")
        }
    )

    scope.launch {
        println("Context: $coroutineContext")
    }
}

// Inheriting context
fun inheritContextExample() {
    CoroutineScope(Dispatchers.Main).launch {
        println("Parent: ${Thread.currentThread().name}")

        launch {
            // Inherits Dispatchers.Main
            println("Child: ${Thread.currentThread().name}")
        }

        launch(Dispatchers.IO) {
            // Overrides with IO dispatcher
            println("Override: ${Thread.currentThread().name}")
        }
    }
}

// ThreadLocal context element
val threadLocalValue = ThreadLocal<String>()

suspend fun threadLocalExample() {
    threadLocalValue.set("initial")

    withContext(threadLocalValue.asContextElement("new value")) {
        println("In context: ${threadLocalValue.get()}")
    }

    println("After context: ${threadLocalValue.get()}")
}

// Custom context element
data class UserId(val id: Int) : AbstractCoroutineContextElement(Key) {
    companion object Key : CoroutineContext.Key<UserId>
}

suspend fun customContextExample() {
    withContext(UserId(42)) {
        val userId = coroutineContext[UserId]
        println("User ID: ${userId?.id}")
    }
}

Dispatchers determine which thread pool executes the coroutine. Context elements are inherited by child coroutines and can be overridden.

Flow for Reactive Streams

Flow represents a cold stream of values that are computed on demand, providing reactive programming capabilities with backpressure and transformation operators.

// Basic Flow
fun numberFlow(): Flow<Int> = flow {
    for (i in 1..5) {
        delay(100)
        emit(i)
    }
}

suspend fun collectFlow() {
    numberFlow().collect { value ->
        println("Received: $value")
    }
}

// Flow builders
fun flowBuilders() {
    // flowOf: emit fixed values
    val fixedFlow = flowOf(1, 2, 3, 4, 5)

    // asFlow: convert collections
    val listFlow = listOf(1, 2, 3).asFlow()

    // flow: custom emission logic
    val customFlow = flow {
        repeat(3) {
            emit(it)
            delay(100)
        }
    }
}

// Flow transformations
suspend fun flowTransformations() {
    numberFlow()
        .map { it * 2 }
        .filter { it > 5 }
        .take(3)
        .collect { println(it) }
}

// Flow combining
suspend fun combineFlows() {
    val flow1 = flowOf(1, 2, 3)
    val flow2 = flowOf("A", "B", "C")

    // zip: pairs elements
    flow1.zip(flow2) { num, letter ->
        "$num$letter"
    }.collect { println(it) }

    // combine: latest from each
    flow1.combine(flow2) { num, letter ->
        "$num$letter"
    }.collect { println(it) }
}

// Flow exception handling
suspend fun flowExceptionHandling() {
    flow {
        emit(1)
        emit(2)
        throw Exception("Error!")
    }.catch { e ->
        println("Caught: ${e.message}")
        emit(-1)
    }.collect { println(it) }
}

// StateFlow and SharedFlow
class DataRepository {
    private val _users = MutableStateFlow<List<User>>(emptyList())
    val users: StateFlow<List<User>> = _users

    private val _events = MutableSharedFlow<Event>()
    val events: SharedFlow<Event> = _events

    suspend fun loadUsers() {
        val loaded = fetchUsers()
        _users.value = loaded
    }

    suspend fun emitEvent(event: Event) {
        _events.emit(event)
    }

    private suspend fun fetchUsers(): List<User> {
        delay(100)
        return listOf(User(1, "Alice"))
    }
}

data class Event(val type: String)

// Flow on different dispatchers
suspend fun flowWithContext() {
    flow {
        emit(1)
        emit(2)
    }
    .flowOn(Dispatchers.IO)
    .collect { value ->
        // Collected on caller's context
        println("Value: $value")
    }
}

// Channel Flow for hot streams
fun channelFlowExample() = channelFlow {
    launch {
        repeat(3) {
            send(it)
            delay(100)
        }
    }

    launch {
        repeat(3) {
            send(it * 10)
            delay(150)
        }
    }
}

Flow is cold—it doesn't execute until collected. StateFlow holds state, SharedFlow broadcasts events, and channelFlow enables concurrent emissions.

Channels for Communication

Channels provide communication primitives for sending and receiving values between coroutines, similar to BlockingQueue but suspending.

// Basic channel usage
suspend fun channelExample() {
    val channel = Channel<Int>()

    launch {
        for (x in 1..5) {
            channel.send(x)
        }
        channel.close()
    }

    for (y in channel) {
        println("Received: $y")
    }
}

// Buffered channels
fun bufferedChannelExample() {
    val channel = Channel<Int>(capacity = 4)

    GlobalScope.launch {
        for (x in 1..10) {
            println("Sending $x")
            channel.send(x)
        }
        channel.close()
    }

    GlobalScope.launch {
        delay(1000)
        for (y in channel) {
            println("Received: $y")
            delay(200)
        }
    }
}

// Channel types
fun channelTypes() {
    // Rendezvous: no buffer, sender suspends until receiver
    val rendezvous = Channel<Int>()

    // Buffered: specified capacity
    val buffered = Channel<Int>(10)

    // Unlimited: unlimited buffer
    val unlimited = Channel<Int>(Channel.UNLIMITED)

    // Conflated: keeps only latest value
    val conflated = Channel<Int>(Channel.CONFLATED)
}

// Produce builder
fun produceNumbers(): ReceiveChannel<Int> = GlobalScope.produce {
    for (x in 1..5) {
        send(x * x)
        delay(100)
    }
}

suspend fun consumeNumbers() {
    val channel = produceNumbers()
    channel.consumeEach { println(it) }
}

// Multiple consumers
suspend fun multipleConsumers() {
    val channel = Channel<Int>()

    repeat(3) { id ->
        launch {
            for (value in channel) {
                println("Consumer $id received: $value")
            }
        }
    }

    repeat(10) {
        channel.send(it)
        delay(100)
    }

    channel.close()
}

// Select expression for multiple channels
suspend fun selectExample() {
    val channel1 = produce { send("A") }
    val channel2 = produce { send("B") }

    select<Unit> {
        channel1.onReceive { value ->
            println("From channel1: $value")
        }
        channel2.onReceive { value ->
            println("From channel2: $value")
        }
    }
}

fun CoroutineScope.produce(block: suspend () -> Unit): ReceiveChannel<String> {
    return produce {
        block()
    }
}

Channels enable fan-out (multiple consumers), fan-in (multiple producers), and pipeline patterns for concurrent data processing.

Cancellation and Exception Handling

Coroutines support cooperative cancellation and structured exception handling to ensure proper resource cleanup and error propagation.

// Basic cancellation
suspend fun cancellationExample() {
    val job = GlobalScope.launch {
        repeat(1000) { i ->
            println("Working: $i")
            delay(500)
        }
    }

    delay(2000)
    println("Cancelling...")
    job.cancel()
    job.join()
    println("Cancelled")
}

// Checking for cancellation
suspend fun checkCancellation() {
    GlobalScope.launch {
        var i = 0
        while (isActive) {
            println("Computing: ${i++}")
        }
    }
}

// Non-cancellable work
suspend fun nonCancellableCleanup() {
    val job = GlobalScope.launch {
        try {
            repeat(1000) {
                delay(500)
            }
        } finally {
            withContext(NonCancellable) {
                println("Cleanup in non-cancellable context")
                delay(1000)
                println("Cleanup complete")
            }
        }
    }

    delay(1000)
    job.cancelAndJoin()
}

// Timeout handling
suspend fun timeoutExample() {
    try {
        withTimeout(1000) {
            repeat(100) {
                delay(100)
                println("Working...")
            }
        }
    } catch (e: TimeoutCancellationException) {
        println("Timed out")
    }
}

// Exception handling in coroutines
suspend fun exceptionHandlingExample() {
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Caught: $exception")
    }

    GlobalScope.launch(handler) {
        throw Exception("Coroutine failed")
    }

    delay(100)
}

// Structured exception handling
suspend fun structuredExceptions() = coroutineScope {
    val job1 = launch {
        delay(100)
        throw Exception("Job 1 failed")
    }

    val job2 = launch {
        delay(200)
        println("Job 2 completed")
    }

    // job2 is cancelled when job1 fails
}

// SupervisorScope for independent failures
suspend fun supervisorExample() = supervisorScope {
    val job1 = launch {
        delay(100)
        throw Exception("Job 1 failed")
    }

    val job2 = launch {
        delay(200)
        println("Job 2 completed")
    }

    // job2 continues even if job1 fails
}

// Error handling with try-catch
suspend fun errorHandling() {
    coroutineScope {
        launch {
            try {
                fetchUser(1)
            } catch (e: Exception) {
                println("Error: ${e.message}")
            }
        }
    }
}

Cancellation is cooperative—coroutines must check isActive or call suspending functions. Exception handling respects structured concurrency boundaries.

Best Practices

  1. Use structured concurrency with scopes to ensure coroutines are properly managed and cancelled when no longer needed
  2. Choose appropriate dispatchers for the work type: IO for blocking operations, Default for CPU work, Main for UI updates
  3. Handle cancellation cooperatively by checking isActive in loops and using suspending functions that support cancellation
  4. Prefer Flow over callbacks for reactive streams to gain backpressure, operators, and structured lifecycle management
  5. Use supervisorScope for independent operations to prevent one failure from cancelling unrelated coroutines
  6. Avoid GlobalScope except for truly application-wide work to prevent leaks and maintain structured concurrency benefits
  7. Apply withContext for dispatcher switching instead of launching new coroutines to maintain structure and reduce overhead
  8. Handle exceptions explicitly with try-catch or CoroutineExceptionHandler to prevent silent failures
  9. Use StateFlow for state and SharedFlow for events to provide observable streams with proper lifecycle awareness
  10. Test coroutines with TestCoroutineDispatcher to control time and ensure deterministic test execution

Common Pitfalls

  1. Using GlobalScope for scoped work causes memory leaks when coroutines outlive their relevant context like activities or view models
  2. Blocking inside coroutines with Thread.sleep or blocking I/O defeats the purpose and can exhaust thread pools
  3. Not handling cancellation in long-running loops causes coroutines to continue executing after cancellation
  4. Forgetting suspend modifier on functions that call other suspend functions causes compilation errors
  5. Catching CancellationException and not rethrowing it prevents proper cancellation propagation in structured concurrency
  6. Using delay(0) to yield is less clear than explicitly calling yield() for cooperative multitasking
  7. Creating too many coroutines unnecessarily can degrade performance; batch or throttle operations when possible
  8. Not using withContext for dispatcher switching and instead launching unnecessary child coroutines adds complexity
  9. Assuming immediate execution after launch; coroutines may not start until dispatcher has capacity
  10. Mixing callbacks and coroutines incorrectly without proper bridging creates race conditions and leaks

When to Use This Skill

Use Kotlin coroutines when building Android applications for asynchronous operations like network calls, database queries, or any I/O-bound work that should not block the main thread.

Apply coroutines in server-side Kotlin applications with Ktor or Spring Boot for handling concurrent requests efficiently without thread-per-request overhead.

Employ Flow for reactive streams in MVVM architecture, replacing LiveData or RxJava for state management and event propagation with lifecycle awareness.

Leverage structured concurrency for coordinating multiple async operations, ensuring proper cancellation when navigating away from screens or closing connections.

Use channels for producer-consumer patterns, pipelines, or any scenario requiring explicit communication between concurrent coroutines.

Resources

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

OpenCode

25.9%
按下载量换算641

Codex

24.13%
按下载量换算597

Claude Code

16.7%
按下载量换算413

windsurf

11.5%
按下载量换算285

Antigravity

7.57%
按下载量换算187

Gemini CLI

3.6%
按下载量换算89

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源字段存在多来源差异,先按来源优先级自动处理,无法消解时进入异常复核队列。

来源信息

继续浏览同类 Skills