Kotlin如何延时准确的循环执行事件,比如倒计时或每一秒执行一次事件

这篇具有很好参考价值的文章主要介绍了Kotlin如何延时准确的循环执行事件,比如倒计时或每一秒执行一次事件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

延时循环执行事件很简单,且有很多方式,但想要延时相对精确,就需要稍微设计一下了

普通的方案

线程内阻塞的方案

这种方案很简单,示例代码如下

    while (true){
        block()//执行逻辑
        Thread.sleep(1000)//延时1秒
    }

但缺点也是显而易见,其是线程阻塞的,比较浪费资源

异步或挂起的方案

我们可以使用handler,rxjava,定时线程池或协程等来实现异步方案,这样可以节省线程资源

我们以协程来做示例

    //suspend方法中
    while (true){
        block()//执行逻辑
        delay(1000)//延时1秒
    }

延时准确的方案

可能上面普通方案就能解决一般情况下的需求,但如果是要求延时准确或者需要循环很多次的话就会存在问题

比如众所周知我们常用的操作系统都不是实时操作系统,比如Windows,Linux,Android等,所以我们上面的延时操作不管是Thread.sleep(1000)还是delay(1000)都不一定会在1000毫秒后恢复,我们测试一下:

Kotlin如何延时准确的循环执行事件,比如倒计时或每一秒执行一次事件

 可以看到,Thread.sleep(1000)有时候会将线程睡眠1016毫秒之多,而这些是跟操作系统,编程语言,CPU线程相关的,我们几乎无法改变,ps:且执行逻辑可能也会占用时间

这也就导致了,如果你的循环要跑几个月的话(后端程序很正常),每次循环多个几毫秒,这样累加起来可能任务就会少执行很多次,且执行的时间点也会越偏缺远

我们可以使用自校准的方式,来使任务执行次数和时间尽量少出(或不出)偏差

阻塞,异步或挂起自校准方案

我们可以每次在执行逻辑和延时的时候记录当前使用了多少时间(多用了多少时间),然后在下次延时的时候少延时相应时间,这样就可以消除其时间偏差

伪代码如下:

    while (true) {
        //记录开始时间
        //执行逻辑
        delay(1000 - 多用的时间)//延时1秒
        //记录执行逻辑和延时多用了多长时间
    }

这个方案很好的解决了时间偏差的问题,但其实也有如下一些问题:

比如每1秒执行一次,但我的执行逻辑就用了一秒多,这就可能会出现问题了

或者如果此时cpu(操作系统)睡眠了,导致十秒没有cpu时间片,这样就会丢失10个事件

响应式自校准方案

我们可以使用Flow或者RxJava的来做响应式的自校准方案,我们已Flow为例:

/**
 * 延时准确的循环回调flow
 * [timeInterval]时间间隔
 * [callNow]是否执行时就先发送一次事件
 */
fun downtimeFlow(timeInterval: Long, callNow: Boolean = true) =
    flow {
        val startTime = System.currentTimeMillis()//@1
        var i = if (callNow) 0 else 1
        while (true) {
            emit(startTime + i * timeInterval)//@2
            i++
        }
    }.buffer(10)//@3
        .transform {
            //delay到指定时间发送,如果因cpu睡眠等原因导致超过了时间,则直接发送(delay内负数会直接放行)
            delay(it - System.currentTimeMillis())//@4
            emit(it)
        }.flowOn(Dispatchers.Default)//@5
  1.  我们先记录开始执行的时间
  2. 然后持续的发送要执行任务的时间戳
  3. 我们使用buffer操作符建立一个有10个位置的缓冲区,如果在@2的位置发送时发现缓冲区满了,就会挂起等待缓冲区有可用位置后再发送
  4. 通过计算并delay距离要执行的任务的时间,来达到指定时间发送的功能
  5. 通过flowOn来将上层flow转为异步的,这样能忽略执行逻辑的耗时

这样我们首先通过flowOn操作符将执行逻辑和发送分离,又通过发送时间戳+buffer的方式解决了cpu睡眠的问题

结语

上面我们就解决了精确延时循环执行事件(当然只是相对精确)的问题

不过一般可能也用不到这个需求emmm

如果有错误请大佬们指出

对Kotlin或KMP感兴趣的同学可以进Q群 101786950

如果这篇文章对您有帮助的话

可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)

Kotlin如何延时准确的循环执行事件,比如倒计时或每一秒执行一次事件Kotlin如何延时准确的循环执行事件,比如倒计时或每一秒执行一次事件文章来源地址https://www.toymoban.com/news/detail-401156.html

到了这里,关于Kotlin如何延时准确的循环执行事件,比如倒计时或每一秒执行一次事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JavaScript中的事件循环机制,包括事件循环的原理、宏任务和微任务、事件队列和调用栈、以及如何优化事件循环

    JavaScript中的事件循环机制是JavaScript运行引擎的核心之一,它决定了代码的执行方式和效率。本文将从几个方面介绍JavaScript中的事件循环机制,包括事件循环的原理、宏任务和微任务、事件队列和调用栈、以及如何优化事件循环。 一、事件循环的原理 事件循环是JavaScript中实

    2024年02月05日
    浏览(34)
  • 如何循环执行windows和linux上的控制台指令

    linux以centos为例做介绍 将以下脚本复制到并命名为repeat.sh 执行指令 ps -ef,执行1000次 先考虑脚本的形式 将以下代码复制仅repeat.bat中 以下指令是通过curl向某个服务器的8866端口发送10000次图片的请求 使用方法,具体结果就是不同的服务器不同了 我们改一个可以在本地之心并看现

    2024年02月13日
    浏览(32)
  • 嵌入式_常见延时方式的差异与选择(for循环延时、定时器延时、汇编延时....)

    这里整理几种常见的延时方式,并做简单测试供大家参考,如果有什么不对的地方,欢迎指正,共同探讨。 测试基于GD32F103CBT6硬件平台,标准的72MHz系统时钟, 使用标准库GD32F10x_Firmware_Library_V1.0.0 提示:(提示:此库坑多、慎用!) 测试方法为: 1:在Debug模式下延时开始于

    2024年02月02日
    浏览(73)
  • Android: alarm定时很短时,比如500ms,测试执行mPowerManager.forceSuspend()后,系统不会suspend

    参考文档: https://blog.csdn.net/weixin_35691921/article/details/124961404 Android: alarm定时很短时,比如500ms,然后执行mPowerManager.forceSuspend()后,系统不会suspend,原因分析:

    2024年01月22日
    浏览(23)
  • 汇编实现LED循环点亮(延时子程序模板)

    在单片机P2口外接8个发光二极管(低电平驱动)。试编写一个汇编程序,实现LED循环点亮功能:P2.0-P2.1-P2.2-P2.3-…-P2.7-P2.6-P25-…-P2.0的顺序,无限循环。要求采用软件延时方式控制闪烁时间间隔(约50ms)。 首先进行电路设计 利用 Proteus 软件的ISIS 模块绘制原理图。虑到 LED低电平驱动

    2024年02月03日
    浏览(30)
  • uniapp中延时执行任务的方法

    在 uniapp 中,可以使用 JavaScript 内置的 setTimeout 函数来延时执行任务。 具体用法如下: 上面的代码中,setTimeout 函数的第一个参数是一个匿名函数,表示要延时执行的代码。第二个参数是延时的时间,单位是毫秒。 使用 setTimeout 函数,就可以在 uniapp 中延时执行任务了。 注意

    2024年02月13日
    浏览(27)
  • JavaScript:延迟访问和延时执行函数

    在java中线程有sleep函数可以延迟执行,但是在js中并没有这样的函数。 唯一有的就是setTimeout延迟执行函数,但是这个函数也是有很多坑。 场景:由于js是单线程异步执行的,当调用第三方API接口时,如果对方没有提供批量操作的接口,我们就需要多次请求相同的API,但是在

    2024年02月12日
    浏览(25)
  • unity几种延时执行程序的方法

    一,使用Invoke Invoke方法可以很方便的将程序延迟执行,但是使用有一定的局限性,只能用于不带参数的函数 二,使用InvokeRepeatin

    2024年02月16日
    浏览(26)
  • Unity——延时执行的几种方法

    延时执行的函数,可以自己设定延时要执行的函数和具体延时的时间,是Monobehaviour基类中实现好的方法 在Update等刷新函数内计时,timer += Time.deltaTime 当时间达到预期,执行需要延时的方法。需要注意的是,增量时间Time.deltaTime是每帧都不同的浮点数。计时器不能用 == 去判断

    2024年02月11日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包