【问题标题】:Asynchronous scheduled job in KotlinKotlin 中的异步计划作业
【发布时间】:2019-02-24 14:21:15
【问题描述】:

我试图了解在 Kotlin 中以预定速率触发异步作业的最佳方式,而应用程序通常运行它是正常任务。假设我有一个简单的应用程序,它每秒只打印出“...”,但每 5 秒我想要另一个作业/线程/协程(最适合)打印“你有一条消息!”。对于异步作业,我有一个类 NotificationProducer,它看起来像这样。

class NotificationProducer {

    fun produce() {
        println("You have a message!")
    }
} 

那么,我的main方法是这样的。

    while (true) {
        println("...")
        sleep(1000)
    }

我应该使用GlobalScope.asyncTimer().schedule(...) 还是一些 Quartz 工作来实现我想要的?任何建议都将受到高度赞赏。关键是通知必须来自另一个类(例如 NotificationProducer)

【问题讨论】:

  • 我建议使用 Java 标准方法 - 使用 Executors.newScheduledThreadPool() 创建执行程序,然后使用 scheduleWithFixedDelay 创建任务。注意,Runnable 任务的异常会取消执行,可能需要 try/catch
  • @EugenePetrenko,为什么不用delay 函数执行协程?

标签: asynchronous kotlin quartz-scheduler


【解决方案1】:

对于简单的调度需求,可以考虑使用协程:

class NotificationProducerScheduler(val service: NotificationProducer, val interval: Long, val initialDelay: Long?) :
    CoroutineScope {
    private val job = Job()

    private val singleThreadExecutor = Executors.newSingleThreadExecutor()

    override val coroutineContext: CoroutineContext
        get() = job + singleThreadExecutor.asCoroutineDispatcher()


    fun stop() {
        job.cancel()
        singleThreadExecutor.shutdown()
    }

    fun start() = launch {
        initialDelay?.let {
            delay(it)
        }
        while (isActive) {
            service.produce()
            delay(interval)
        }
        println("coroutine done")
    }
}

否则,Java 并发 API 也相当可靠:

class NotificationProducerSchedulerJavaScheduler(
    val service: NotificationProducer,
    val interval: Long,
    val initialDelay: Long = 0
) {

    private val scheduler = Executors.newScheduledThreadPool(1)
    private val task = Runnable { service.produce() }

    fun stop() {
        scheduler.shutdown()
    }

    fun start() {
        scheduler.scheduleWithFixedDelay(task, initialDelay, interval, TimeUnit.MILLISECONDS)
    }
}

【讨论】:

    【解决方案2】:

    如果我正确理解了这个问题,您可以使用 Kotlin Coroutines 来实现它:

    class Presenter : CoroutineScope { // implement CoroutineScope to create local scope
        private var job: Job = Job()
        override val coroutineContext: CoroutineContext
            get() = Dispatchers.Default + job 
    
        // this method will help to stop execution of a coroutine. 
        // Call it to cancel coroutine and to break the while loop defined in the coroutine below    
        fun cancel() {
            job.cancel()
        }
    
        fun schedule() = launch { // launching the coroutine
            var seconds = 1
            val producer = NotificationProducer()
            while (true) {
                println("...")
                delay(1000)
    
                if (seconds++ == 5) {
                    producer.produce()
                    seconds = 1
                }
            }
        }
    }
    

    然后您可以使用Presenter 类的实例来启动和停止协程:

    val presenter = Presenter()
    presenter.schedule() // calling `schedule()` function launches the coroutine
    
    //...
    
    presenter.cancel() // cancel the coroutine when you need
    

    【讨论】:

      猜你喜欢
      • 2016-08-27
      • 1970-01-01
      • 2010-09-19
      • 2013-12-14
      • 2022-01-01
      • 2017-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多