6-1-2 协程作用域-全局作用域详解

19 阅读6分钟

Kotlin 协程全局作用域详解

全局作用域是Kotlin协程中最基本但也是最容易误用的作用域。正确理解和使用全局作用域对编写健壮的协程代码至关重要。

1. GlobalScope 基础

1.1 什么是 GlobalScope

// GlobalScope 定义
public object GlobalScope : CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = EmptyCoroutineContext
}

// 默认使用 Dispatchers.Default 调度器
// 生命周期与应用程序相同
// 不会自动取消 - 这是最大的风险点

1.2 基本用法

// 基本的 GlobalScope 使用
fun basicGlobalScopeUsage() {
    // 启动一个全局协程
    val job = GlobalScope.launch {
        println("GlobalScope task started on thread: ${Thread.currentThread().name}")
        delay(1000)
        println("GlobalScope task completed")
    }
    
    // 带参数的启动
    val namedJob = GlobalScope.launch(CoroutineName("GlobalTask")) {
        println("Task name: ${coroutineContext[CoroutineName]?.name}")
        // 执行工作
    }
    
    // 使用不同的调度器
    GlobalScope.launch(Dispatchers.IO) {
        // IO 操作
    }
    
    GlobalScope.launch(Dispatchers.Main) {
        // UI 更新 (在支持UI的平台)
    }
}

2. GlobalScope 的特性

2.1 独立生命周期

// GlobalScope 协程独立运行,不受调用者生命周期影响
fun demonstrateIndependentLifecycle() {
    println("Main thread: ${Thread.currentThread().name}")
    
    GlobalScope.launch {
        println("GlobalScope task started at ${System.currentTimeMillis()}")
        repeat(5) { i ->
            println("GlobalScope iteration $i at ${System.currentTimeMillis()}")
            delay(1000)
        }
        println("GlobalScope task completed at ${System.currentTimeMillis()}")
    }
    
    // 主线程继续执行
    Thread.sleep(3000) // 等待3秒
    println("Main thread exiting after 3 seconds")
    
    // 即使主线程退出,GlobalScope 协程仍然继续运行
    // 在真正的应用程序中,只有当应用退出时才会停止
}

2.2 没有结构化并发

// GlobalScope 不提供结构化并发
fun demonstrateNonStructuredConcurrency() {
    val parentJob = GlobalScope.launch {
        println("Parent started")
        
        // 子协程1 - 不是真正的"子"协程
        val child1 = GlobalScope.launch {
            try {
                repeat(10) { i ->
                    delay(500)
                    println("Child1: iteration $i")
                }
            } finally {
                println("Child1: finally block")
            }
        }
        
        // 子协程2
        val child2 = GlobalScope.launch {
            try {
                repeat(5) { i ->
                    delay(1000)
                    println("Child2: iteration $i")
                }
            } finally {
                println("Child2: finally block")
            }
        }
        
        delay(1500)
        println("Parent cancelling...")
        // 取消父协程不会取消"子"协程
        cancel()
    }
    
    Thread.sleep(4000)
    println("Main: parent was cancelled, but children continue running")
    // 需要手动取消 child1 和 child2
}

2.3 异常处理特性

// GlobalScope 中的异常处理
fun demonstrateExceptionHandling() {
    // 方式1:使用 try-catch 在协程内部
    GlobalScope.launch {
        try {
            throw RuntimeException("Error inside GlobalScope")
        } catch (e: Exception) {
            println("Caught exception inside coroutine: ${e.message}")
        }
    }
    
    // 方式2:使用 CoroutineExceptionHandler
    val exceptionHandler = CoroutineExceptionHandler { _, exception ->
        println("GlobalScope caught exception: ${exception.message}")
    }
    
    GlobalScope.launch(exceptionHandler) {
        throw RuntimeException("Error with handler")
    }
    
    // 注意:GlobalScope 中的未捕获异常不会崩溃应用
    // 但会被打印到标准错误输出
    
    Thread.sleep(1000)
}

3. GlobalScope 的正确使用场景

3.1 真正的全局任务

// 适合 GlobalScope 的场景:应用程序级别的后台任务
object GlobalTaskManager {
    
    // 场景1:心跳检测 - 需要在应用整个生命周期运行
    private var heartbeatJob: Job? = null
    
    fun startHeartbeat() {
        heartbeatJob = GlobalScope.launch {
            while (isActive) {
                try {
                    sendHeartbeat()
                    delay(30000) // 每30秒发送一次心跳
                } catch (e: Exception) {
                    // 记录错误,继续尝试
                    logError("Heartbeat failed", e)
                    delay(60000) // 失败后等待更长时间
                }
            }
        }
    }
    
    fun stopHeartbeat() {
        heartbeatJob?.cancel()
        heartbeatJob = null
    }
    
    private suspend fun sendHeartbeat() {
        // 发送心跳到服务器
        withContext(Dispatchers.IO) {
            // 网络请求
        }
    }
    
    // 场景2:应用级别的缓存清理
    fun scheduleCacheCleanup() {
        GlobalScope.launch {
            while (true) {
                delay(3600000) // 每小时清理一次
                cleanExpiredCache()
            }
        }
    }
    
    private suspend fun cleanExpiredCache() {
        withContext(Dispatchers.IO) {
            // 清理过期缓存
        }
    }
    
    // 场景3:全局错误报告
    fun reportError(error: Throwable, context: Map<String, Any> = emptyMap()) {
        GlobalScope.launch(Dispatchers.IO) {
            try {
                // 异步发送错误报告,不阻塞调用者
                sendErrorReport(error, context)
            } catch (e: Exception) {
                // 静默失败,不影响应用主流程
                logError("Failed to send error report", e)
            }
        }
    }
    
    private suspend fun sendErrorReport(error: Throwable, context: Map<String, Any>) {
        // 发送到错误报告服务
    }
    
    // 场景4:性能监控
    fun trackPerformance(event: String, duration: Long) {
        GlobalScope.launch(Dispatchers.IO) {
            // 异步记录性能数据
            logPerformanceMetric(event, duration)
        }
    }
}

3.2 日志记录和监控

// 日志系统适合使用 GlobalScope
object AppLogger {
    
    private val logScope = CoroutineScope(
        Dispatchers.IO +
        SupervisorJob() + // 使用 SupervisorJob 防止一个日志失败影响其他
        CoroutineExceptionHandler { _, e ->
            // 日志系统自身的错误处理
            System.err.println("Logger error: $e")
        }
    )
    
    // 但也可以使用 GlobalScope,因为日志是全局的
    fun logGlobal(message: String, level: LogLevel = LogLevel.INFO) {
        GlobalScope.launch(Dispatchers.IO) {
            try {
                // 异步写入日志文件
                writeToLogFile("${level.name}: $message")
                
                // 同时发送到远程日志服务
                sendToRemoteLogService(message, level)
            } catch (e: Exception) {
                // 静默失败,不影响应用
                System.err.println("Logging failed: $e")
            }
        }
    }
    
    // 更好的做法:创建专门的日志作用域
    fun logStructured(message: String, level: LogLevel = LogLevel.INFO) {
        logScope.launch {
            try {
                writeToLogFile("${level.name}: $message")
                sendToRemoteLogService(message, level)
            } catch (e: Exception) {
                System.err.println("Logging failed: $e")
            }
        }
    }
    
    fun cleanup() {
        logScope.cancel()
    }
    
    enum class LogLevel {
        DEBUG, INFO, WARN, ERROR
    }
}

3.3 工具函数和扩展

// 工具函数中的 GlobalScope 使用
object AsyncUtils {
    
    // 异步执行并忽略结果
    fun executeAsync(block: suspend () -> Unit): Job {
        return GlobalScope.launch {
            try {
                block()
            } catch (e: Exception) {
                // 工具函数需要处理所有异常
                System.err.println("Async execution failed: $e")
            }
        }
    }
    
    // 带超时的异步执行
    fun executeWithTimeout(
        timeoutMillis: Long,
        block: suspend () -> Unit,
        onTimeout: () -> Unit = {},
        onError: (Throwable) -> Unit = { _ -> }
    ): Job {
        return GlobalScope.launch {
            try {
                withTimeout(timeoutMillis) {
                    block()
                }
            } catch (e: TimeoutCancellationException) {
                onTimeout()
            } catch (e: Exception) {
                onError(e)
            }
        }
    }
    
    // 定期执行任务
    fun scheduleAtFixedRate(
        initialDelay: Long,
        period: Long,
        unit: TimeUnit = TimeUnit.MILLISECONDS,
        block: suspend () -> Unit
    ): Job {
        return GlobalScope.launch {
            delay(unit.toMillis(initialDelay))
            while (isActive) {
                try {
                    block()
                } catch (e: Exception) {
                    // 处理异常,但继续执行
                    System.err.println("Scheduled task failed: $e")
                }
                delay(unit.toMillis(period))
            }
        }
    }
}

4. GlobalScope 的常见误用和风险

4.1 内存泄漏风险

// ❌ 错误示例:在 Android Activity 中使用 GlobalScope
class LeakyActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ❌ 错误:GlobalScope 协程不会随 Activity 销毁而取消
        GlobalScope.launch {
            // 长时间运行的任务
            val data = fetchDataFromNetwork()
            
            // Activity 可能已经被销毁,这里会导致崩溃或内存泄漏
            updateUI(data)
        }
        
        // ❌ 错误:捕获了 Activity 的引用
        GlobalScope.launch {
            delay(5000)
            // 5秒后,Activity 可能已经被销毁,但这里还在引用它
            this@LeakyActivity.title = "Updated Title"
        }
    }
}

// ✅ 正确示例:使用 lifecycleScope
class SafeActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ✅ 正确:使用 lifecycleScope
        lifecycleScope.launch {
            val data = withContext(Dispatchers.IO) {
                fetchDataFromNetwork()
            }
            // 如果 Activity 已经销毁,这里不会执行
            updateUI(data)
        }
        
        // ✅ 或者使用 viewLifecycleOwner(对于 Fragment)
        // viewLifecycleOwner.lifecycleScope.launch { ... }
    }
}

4.2 缺乏取消机制

// ❌ 错误示例:无法正确取消任务
class UserRepository {
    fun loadUserData(userId: String, callback: (User) -> Unit) {
        // 启动一个 GlobalScope 协程
        GlobalScope.launch {
            val user = fetchUser(userId)
            callback(user)
        }
        // 问题:无法从外部取消这个任务
    }
    
    // 调用方无法取消
    fun someOperation() {
        loadUserData("123") { user ->
            // 处理用户数据
        }
        
        // 如果用户很快离开了这个页面,请求仍然会继续
        // 并且可能调用回调,导致意外行为
    }
}

// ✅ 正确示例:提供取消机制
class SafeUserRepository {
    
    // 方法1:返回 Job 以便取消
    fun loadUserData(userId: String, callback: (User) -> Unit): Job {
        return GlobalScope.launch {
            val user = fetchUser(userId)
            callback(user)
        }
    }
    
    // 方法2:使用 CoroutineScope 参数
    fun loadUserData(scope: CoroutineScope, userId: String, callback: (User) -> Unit) {
        scope.launch {
            val user = fetchUser(userId)
            callback(user)
        }
    }
    
    // 方法3:使用 suspend 函数
    suspend fun loadUserData(userId: String): User {
        return withContext(Dispatchers.IO) {
            fetchUser(userId)
        }
    }
}

4.3 资源泄漏问题

// ❌ 错误示例:资源未正确释放
class ResourceManager {
    private val resources = mutableListOf<Closeable>()
    
    fun processData(data: String) {
        GlobalScope.launch {
            val resource = acquireExpensiveResource()
            resources.add(resource)
            
            try {
                // 使用资源
                resource.process(data)
            } finally {
                // 问题:如果协程被取消,finally 块可能不会执行
                resource.close()
                resources.remove(resource)
            }
        }
    }
    
    // 更大的问题:如果忘记调用 cleanup,资源永远不会释放
    fun cleanup() {
        resources.forEach { it.close() }
        resources.clear()
    }
}

// ✅ 正确示例:使用结构化并发确保资源释放
class SafeResourceManager {
    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    private val resources = ConcurrentHashMap<Job, Closeable>()
    
    fun processData(data: String): Job {
        return scope.launch {
            val resource = acquireExpensiveResource()
            resources[coroutineContext[Job]!!] = resource
            
            try {
                resource.process(data)
            } finally {
                // 使用 use 块确保资源关闭
                resource.use {
                    resources.remove(coroutineContext[Job])
                }
            }
        }
    }
    
    // 自动清理
    fun cleanup() {
        scope.cancel()
        resources.values.forEach { it.close() }
        resources.clear()
    }
}

5. GlobalScope 的最佳实践

5.1 创建安全的全局作用域包装器

// 创建安全的全局作用域替代品
object SafeGlobalScope {
    
    // 使用 SupervisorJob 防止一个协程失败影响其他
    private val supervisorJob = SupervisorJob()
    
    // 添加异常处理器
    private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
        System.err.println("SafeGlobalScope caught exception: $throwable")
        // 可以在这里添加错误报告
    }
    
    // 安全的作用域
    private val safeScope = CoroutineScope(
        Dispatchers.Default + 
        supervisorJob + 
        exceptionHandler +
        CoroutineName("SafeGlobalScope")
    )
    
    // 安全的启动方法
    fun launch(
        context: CoroutineContext = EmptyCoroutineContext,
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
    ): Job {
        return safeScope.launch(context, start, block)
    }
    
    // 特定类型的任务
    fun launchIO(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(Dispatchers.IO, block = block)
    }
    
    fun launchMain(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(Dispatchers.Main, block = block)
    }
    
    // 带生命周期的启动(模拟)
    fun launchWithLifecycle(
        lifecycleCheck: () -> Boolean,
        block: suspend CoroutineScope.() -> Unit
    ): Job {
        return launch {
            while (lifecycleCheck() && isActive) {
                try {
                    block()
                } catch (e: Exception) {
                    if (lifecycleCheck()) {
                        // 只有生命周期有效时才处理异常
                        throw e
                    }
                    // 否则静默取消
                    cancel()
                }
            }
        }
    }
    
    // 清理所有协程
    fun cancelAll() {
        supervisorJob.cancelChildren()
    }
    
    // 完全关闭
    fun shutdown() {
        safeScope.cancel()
    }
}

// 使用示例
fun demonstrateSafeGlobalScope() {
    // 启动任务
    val job1 = SafeGlobalScope.launchIO {
        // IO 操作
    }
    
    val job2 = SafeGlobalScope.launch {
        // 默认调度器的操作
    }
    
    // 带生命周期检查
    var isActive = true
    val job3 = SafeGlobalScope.launchWithLifecycle({ isActive }) {
        // 只在 isActive 为 true 时运行
    }
    
    // 稍后取消所有任务
    Thread.sleep(5000)
    SafeGlobalScope.cancelAll()
    
    // 或者取消特定任务
    job1.cancel()
}

5.2 限制 GlobalScope 的使用

// 通过代码审查和静态分析限制 GlobalScope 使用
object GlobalScopePolicy {
    
    // 允许使用 GlobalScope 的特定场景
    enum class AllowedScenario {
        APPLICATION_STARTUP,    // 应用启动时
        BACKGROUND_SERVICE,     // 后台服务
        LOGGING,               // 日志记录
        ANALYTICS,             // 分析统计
        GLOBAL_EVENT_HANDLER   // 全局事件处理
    }
    
    // 记录 GlobalScope 的使用
    private val usageLog = ConcurrentHashMap<String, AllowedScenario>()
    
    // 批准的启动方法
    fun launch(
        scenario: AllowedScenario,
        context: CoroutineContext = EmptyCoroutineContext,
        block: suspend CoroutineScope.() -> Unit
    ): Job {
        // 记录使用情况
        val stackTrace = Thread.currentThread().stackTrace
        val caller = stackTrace.getOrNull(2)?.toString() ?: "unknown"
        usageLog[caller] = scenario
        
        // 添加监控信息
        val monitoredContext = context + CoroutineName("GlobalScope-$scenario")
        
        return GlobalScope.launch(monitoredContext) {
            try {
                block()
            } catch (e: Exception) {
                handleException(scenario, e)
                throw e
            }
        }
    }
    
    private fun handleException(scenario: AllowedScenario, exception: Throwable) {
        // 根据场景处理异常
        when (scenario) {
            AllowedScenario.LOGGING -> {
                // 日志系统的异常静默处理
                System.err.println("Logging exception: $exception")
            }
            AllowedScenario.ANALYTICS -> {
                // 分析系统的异常可以忽略
                // 不记录到错误报告
            }
            else -> {
                // 其他场景记录错误
                System.err.println("GlobalScope exception in $scenario: $exception")
            }
        }
    }
    
    // 获取使用报告
    fun getUsageReport(): Map<String, AllowedScenario> {
        return usageLog.toMap()
    }
    
    // 清理不再需要的任务
    fun cleanup() {
        // 可以在这里实现清理逻辑
    }
}

// 使用批准的 GlobalScope
fun demonstratePolicy() {
    // 正确的使用方式
    GlobalScopePolicy.launch(GlobalScopePolicy.AllowedScenario.LOGGING) {
        // 日志操作
    }
    
    // 需要说明使用场景
    GlobalScopePolicy.launch(GlobalScopePolicy.AllowedScenario.ANALYTICS) {
        // 发送分析事件
    }
}

5.3 监控和调试 GlobalScope

// 监控 GlobalScope 协程的工具
object GlobalScopeMonitor {
    
    private val activeJobs = ConcurrentHashMap<Job, JobInfo>()
    
    data class JobInfo(
        val name: String?,
        val startTime: Long,
        val thread: String,
        val stackTrace: List<StackTraceElement>
    )
    
    // 包装 GlobalScope.launch 以进行监控
    fun monitoredLaunch(
        name: String? = null,
        context: CoroutineContext = EmptyCoroutineContext,
        block: suspend CoroutineScope.() -> Unit
    ): Job {
        val jobName = name ?: "GlobalScope-${System.currentTimeMillis()}"
        val monitoredContext = context + CoroutineName(jobName)
        
        val job = GlobalScope.launch(monitoredContext) {
            // 记录开始
            val jobInfo = JobInfo(
                name = jobName,
                startTime = System.currentTimeMillis(),
                thread = Thread.currentThread().name,
                stackTrace = Thread.currentThread().stackTrace.toList()
            )
            activeJobs[coroutineContext[Job]!!] = jobInfo
            
            try {
                block()
            } finally {
                // 记录结束
                activeJobs.remove(coroutineContext[Job])
            }
        }
        
        // 设置完成回调
        job.invokeOnCompletion { cause ->
            val duration = System.currentTimeMillis() - 
                (activeJobs[job]?.startTime ?: System.currentTimeMillis())
            
            if (cause != null) {
                println("Job '$jobName' failed after ${duration}ms: $cause")
            } else {
                println("Job '$jobName' completed successfully after ${duration}ms")
            }
            
            activeJobs.remove(job)
        }
        
        return job
    }
    
    // 获取活跃的 GlobalScope 任务
    fun getActiveJobs(): List<JobInfo> {
        return activeJobs.values.toList()
    }
    
    // 检查是否有长时间运行的任务
    fun checkForLongRunningTasks(timeoutMillis: Long = 60000): List<JobInfo> {
        val now = System.currentTimeMillis()
        return activeJobs.values.filter { jobInfo ->
            now - jobInfo.startTime > timeoutMillis
        }
    }
    
    // 取消所有监控的任务
    fun cancelAll() {
        activeJobs.keys.forEach { it.cancel() }
        activeJobs.clear()
    }
    
    // 生成监控报告
    fun generateReport(): String {
        val active = activeJobs.values
        val builder = StringBuilder()
        
        builder.appendLine("=== GlobalScope Monitor Report ===")
        builder.appendLine("Active jobs: ${active.size}")
        
        active.forEach { jobInfo ->
            builder.appendLine("\nJob: ${jobInfo.name}")
            builder.appendLine("Running for: ${System.currentTimeMillis() - jobInfo.startTime}ms")
            builder.appendLine("Thread: ${jobInfo.thread}")
            builder.appendLine("Created from:")
            jobInfo.stackTrace.take(5).forEach { element ->
                builder.appendLine("  $element")
            }
        }
        
        return builder.toString()
    }
}

// 使用监控的 GlobalScope
fun demonstrateMonitoring() {
    // 使用监控版本
    val job1 = GlobalScopeMonitor.monitoredLaunch("BackgroundTask") {
        delay(30000)
    }
    
    val job2 = GlobalScopeMonitor.monitoredLaunch {
        // 未命名的任务
        delay(60000)
    }
    
    // 检查报告
    Thread.sleep(5000)
    println(GlobalScopeMonitor.generateReport())
    
    // 检查长时间运行的任务
    val longRunning = GlobalScopeMonitor.checkForLongRunningTasks(10000)
    if (longRunning.isNotEmpty()) {
        println("Warning: ${longRunning.size} long running tasks detected")
    }
    
    // 清理
    job1.cancel()
    GlobalScopeMonitor.cancelAll()
}

6. 替代 GlobalScope 的方案

6.1 应用级作用域

// 创建应用级别的协程作用域
class ApplicationScope private constructor() {
    
    companion object {
        private lateinit var instance: ApplicationScope
        
        fun initialize(context: CoroutineContext = EmptyCoroutineContext) {
            instance = ApplicationScope(context)
        }
        
        fun get(): ApplicationScope {
            if (!::instance.isInitialized) {
                initialize()
            }
            return instance
        }
    }
    
    private val supervisorJob = SupervisorJob()
    private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
        handleApplicationException(throwable)
    }
    
    val applicationScope: CoroutineScope
    
    private constructor(context: CoroutineContext) : this() {
        applicationScope = CoroutineScope(
            Dispatchers.Default +
            supervisorJob +
            exceptionHandler +
            context +
            CoroutineName("ApplicationScope")
        )
    }
    
    fun launch(
        context: CoroutineContext = EmptyCoroutineContext,
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
    ): Job {
        return applicationScope.launch(context, start, block)
    }
    
    fun launchIO(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(Dispatchers.IO, block = block)
    }
    
    fun cancelAll() {
        supervisorJob.cancelChildren()
    }
    
    fun shutdown() {
        applicationScope.cancel()
    }
    
    private fun handleApplicationException(throwable: Throwable) {
        // 应用级别的异常处理
        System.err.println("ApplicationScope exception: $throwable")
        
        // 可以根据异常类型采取不同行动
        when (throwable) {
            is IOException -> {
                // 网络错误,可以重试或降级
            }
            is SecurityException -> {
                // 权限错误,需要用户干预
            }
            else -> {
                // 其他未预料错误
                // 可以发送到错误报告服务
            }
        }
    }
}

// 在应用启动时初始化
fun main() {
    // 初始化应用作用域
    ApplicationScope.initialize(
        Dispatchers.Default +
        CoroutineExceptionHandler { _, e ->
            println("App error: $e")
        }
    )
    
    // 使用应用作用域而不是 GlobalScope
    val appScope = ApplicationScope.get()
    
    appScope.launch {
        println("Running in application scope")
    }
    
    appScope.launchIO {
        // IO 操作
    }
    
    // 在应用关闭时清理
    Runtime.getRuntime().addShutdownHook(Thread {
        ApplicationScope.get().shutdown()
    })
}

6.2 功能模块作用域

// 为每个功能模块创建独立的作用域
abstract class FeatureScope(
    protected val featureName: String
) : CoroutineScope {
    
    protected open val supervisorJob = SupervisorJob()
    protected open val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
        handleFeatureException(throwable)
    }
    
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Default + supervisorJob + exceptionHandler + CoroutineName(featureName)
    
    abstract fun handleFeatureException(throwable: Throwable)
    
    fun cancelFeature() {
        supervisorJob.cancel()
    }
    
    fun launchIO(block: suspend CoroutineScope.() -> Unit): Job {
        return launch(Dispatchers.IO, block = block)
    }
}

// 具体功能模块
class AnalyticsScope : FeatureScope("Analytics") {
    
    override fun handleFeatureException(throwable: Throwable) {
        // 分析系统的异常可以静默处理
        System.err.println("Analytics error (non-critical): $throwable")
    }
    
    fun trackEvent(eventName: String, properties: Map<String, Any> = emptyMap()) {
        launchIO {
            // 异步发送分析事件
            sendAnalyticsEvent(eventName, properties)
        }
    }
    
    private suspend fun sendAnalyticsEvent(eventName: String, properties: Map<String, Any>) {
        // 实现发送逻辑
    }
}

class DatabaseScope : FeatureScope("Database") {
    
    override val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
        // 数据库错误需要特殊处理
        if (throwable is SQLException) {
            handleDatabaseError(throwable)
        } else {
            super.handleFeatureException(throwable)
        }
    }
    
    override fun handleFeatureException(throwable: Throwable) {
        System.err.println("Database error: $throwable")
        // 可能需要回滚事务或重试
    }
    
    private fun handleDatabaseError(error: SQLException) {
        // 特定的数据库错误处理
    }
    
    fun queryUsers(): Job {
        return launchIO {
            // 数据库查询
        }
    }
}

// 使用功能模块作用域
fun demonstrateFeatureScopes() {
    val analytics = AnalyticsScope()
    val database = DatabaseScope()
    
    // 分别在不同的作用域中执行任务
    analytics.trackEvent("app_started")
    
    database.queryUsers()
    
    // 可以独立取消
    analytics.cancelFeature()
    
    // 或者通过应用统一管理
}

7. 总结:GlobalScope 的指导原则

何时使用 GlobalScope:

  1. 真正的全局任务:应用生命周期内的后台服务
  2. 日志和监控:不依赖组件生命周期的记录操作
  3. 工具函数:独立、自包含的异步工具
  4. 快速原型:临时测试代码(但生产环境要替换)

何时避免 GlobalScope:

  1. UI 组件中:Activity、Fragment、Composable
  2. ViewModel 或 Presenter 中
  3. 有明确生命周期的对象中
  4. 需要结构化并发的场景

最佳实践:

  1. 优先使用生命周期感知的作用域lifecycleScopeviewModelScope
  2. 创建应用级作用域:替代 GlobalScope
  3. 总是提供取消机制:返回 Job 或使用可取消的接口
  4. 添加监控和日志:跟踪 GlobalScope 的使用
  5. 代码审查:限制团队中 GlobalScope 的使用
  6. 使用静态分析工具:检测不当的 GlobalScope 使用

记住:GlobalScope 是最后的备选方案,不是首选方案。在大多数情况下,都有更好的替代方案可以提供更安全、更可维护的并发代码。