在一定时间内重复执行一项任务,但有延迟
Repeat a task within a duration with delay
我必须在一个时间范围内移动进度条,例如在 6 秒内。我正在使用协程和 "repeat" 函数。代码执行除了总执行时间不是指定的。下面是我的代码。
val progressJob = Job()
var startTime = 0L
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
repeat(1000) {
progressBar.progress += 1
delay(6)
}
Log.d(TAG, "total time= ${System.currentTimeMillis() - startTime}")
}
我预计 "total time" 会是 6000,但我得到的值比 6000 至少大了 500。
基本上我只是想在一个时间范围内重复递增进度条,因为性能问题我没有使用动画。
有什么我遗漏的吗?
协程不提供精确计时。如果处理器同时忙 运行 其他事情,协程很容易被延迟。使用 Timer Class 进行精确计时。这是一个例子。我每秒记录一次时间,并在 6 秒后取消计时器。结果仅相差几毫秒。
var startTime = 0L
val timer : Timer = Timer()
val task = object : TimerTask()
{
var lastTime = 0L
override fun run() {
val now = System.currentTimeMillis()
if(now/1000 > lastTime/1000 )
{
Log.d("timer","total time= ${now - startTime}")
lastTime = now
}
if(now - startTime >= 6000)
{
timer.cancel()
}
}
startTime = System.currentTimeMillis()
timer.scheduleAtFixedRate(task,0,6)
所以你在这里做的是模拟进度。理想情况下,会有一些方法来检查你的栏的实际进度,并更新它,当它完成时,结束。但是,如果这不可能,那么你可以选择模拟。
因此,对于协程,我们正在处理一个线程环境,并且在其中,我们有我们的协程,当移交执行控制时需要继续执行。在您的实现中,这发生在 delay
调用中。因此,很难保证您的协程会在您期望的时间内完成。延迟所能做的就是说它不会在 "at least" 指定的时间过去之前恢复,而且可能经常会过去更多的时间,而不是确切的时间。
那么,我们如何让它在尽可能接近您期望的时间范围内执行?我们需要做的是删除 repeat
,而是检查经过的时间来决定我们是否完成。这是一个粗略的实现,希望能有所帮助。
class Bar(val barLength: Int = 1000) {
var progress = 0
}
suspend fun simulateProgress(bar: Bar, job: Job, totalDurationMillis: Long, incrementsMills: Long): Job {
var startTime = System.currentTimeMillis()
return CoroutineScope(Dispatchers.Default + job).launch {
var totalElapsed = 0L
while (totalElapsed < totalDurationMillis) {
totalElapsed = System.currentTimeMillis() - startTime
val progressRatio = totalElapsed.toDouble()/totalDurationMillis.toDouble()
bar.progress = (progressRatio * bar.barLength.toDouble()).toInt()
delay(incrementsMills)
}
println("Elapsed: $totalElapsed, Progress: ${bar.progress}")
}
}
fun main() = runBlocking {
val job = Job()
val bar = Bar()
val progressJob = simulateProgress(bar, job, 6000, 10)
progressJob.join()
}
您不仅要测量 6 毫秒的延迟,还要测量执行 for
循环(隐藏在 repeat
中)所需的时间,加上 progressBar.progress += 1
的时间和delay
本身的成本。
例如:
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
repeat(1000){
delay(6)
}
val endTime = System.currentTimeMillis() - startTime
println("total time= $endTime")
}
在我的机器上需要 6751 毫秒(平均 100 次运行)。
如果我使用 Thread.sleep
而不是延迟:
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
repeat(1){
delay(6)
}
val endTime = System.currentTimeMillis() - startTime
println("total time= $endTime")
}
需要 6701 毫秒。
如果我只执行一次重复:
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
repeat(1){
Thread.sleep(6)
}
val endTime = System.currentTimeMillis() - startTime
println("total time= $endTime")
}
8 毫秒
如果我删除重复:
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
Thread.sleep(6)
val endTime = System.currentTimeMillis() - startTime
println("total time= $endTime")
}
我会这样做:
withTimeout(1300L) {
repeat(1000) { i ->
println("Blip Blop $i ...")
delay(500L)
}
}
更多例子见官方文档:
https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html
我必须在一个时间范围内移动进度条,例如在 6 秒内。我正在使用协程和 "repeat" 函数。代码执行除了总执行时间不是指定的。下面是我的代码。
val progressJob = Job()
var startTime = 0L
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
repeat(1000) {
progressBar.progress += 1
delay(6)
}
Log.d(TAG, "total time= ${System.currentTimeMillis() - startTime}")
}
我预计 "total time" 会是 6000,但我得到的值比 6000 至少大了 500。
基本上我只是想在一个时间范围内重复递增进度条,因为性能问题我没有使用动画。
有什么我遗漏的吗?
协程不提供精确计时。如果处理器同时忙 运行 其他事情,协程很容易被延迟。使用 Timer Class 进行精确计时。这是一个例子。我每秒记录一次时间,并在 6 秒后取消计时器。结果仅相差几毫秒。
var startTime = 0L
val timer : Timer = Timer()
val task = object : TimerTask()
{
var lastTime = 0L
override fun run() {
val now = System.currentTimeMillis()
if(now/1000 > lastTime/1000 )
{
Log.d("timer","total time= ${now - startTime}")
lastTime = now
}
if(now - startTime >= 6000)
{
timer.cancel()
}
}
startTime = System.currentTimeMillis()
timer.scheduleAtFixedRate(task,0,6)
所以你在这里做的是模拟进度。理想情况下,会有一些方法来检查你的栏的实际进度,并更新它,当它完成时,结束。但是,如果这不可能,那么你可以选择模拟。
因此,对于协程,我们正在处理一个线程环境,并且在其中,我们有我们的协程,当移交执行控制时需要继续执行。在您的实现中,这发生在 delay
调用中。因此,很难保证您的协程会在您期望的时间内完成。延迟所能做的就是说它不会在 "at least" 指定的时间过去之前恢复,而且可能经常会过去更多的时间,而不是确切的时间。
那么,我们如何让它在尽可能接近您期望的时间范围内执行?我们需要做的是删除 repeat
,而是检查经过的时间来决定我们是否完成。这是一个粗略的实现,希望能有所帮助。
class Bar(val barLength: Int = 1000) {
var progress = 0
}
suspend fun simulateProgress(bar: Bar, job: Job, totalDurationMillis: Long, incrementsMills: Long): Job {
var startTime = System.currentTimeMillis()
return CoroutineScope(Dispatchers.Default + job).launch {
var totalElapsed = 0L
while (totalElapsed < totalDurationMillis) {
totalElapsed = System.currentTimeMillis() - startTime
val progressRatio = totalElapsed.toDouble()/totalDurationMillis.toDouble()
bar.progress = (progressRatio * bar.barLength.toDouble()).toInt()
delay(incrementsMills)
}
println("Elapsed: $totalElapsed, Progress: ${bar.progress}")
}
}
fun main() = runBlocking {
val job = Job()
val bar = Bar()
val progressJob = simulateProgress(bar, job, 6000, 10)
progressJob.join()
}
您不仅要测量 6 毫秒的延迟,还要测量执行 for
循环(隐藏在 repeat
中)所需的时间,加上 progressBar.progress += 1
的时间和delay
本身的成本。
例如:
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
repeat(1000){
delay(6)
}
val endTime = System.currentTimeMillis() - startTime
println("total time= $endTime")
}
在我的机器上需要 6751 毫秒(平均 100 次运行)。
如果我使用 Thread.sleep
而不是延迟:
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
repeat(1){
delay(6)
}
val endTime = System.currentTimeMillis() - startTime
println("total time= $endTime")
}
需要 6701 毫秒。
如果我只执行一次重复:
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
repeat(1){
Thread.sleep(6)
}
val endTime = System.currentTimeMillis() - startTime
println("total time= $endTime")
}
8 毫秒
如果我删除重复:
CoroutineScope(Dispatchers.Default + progressJob).launch {
startTime = System.currentTimeMillis()
Thread.sleep(6)
val endTime = System.currentTimeMillis() - startTime
println("total time= $endTime")
}
我会这样做:
withTimeout(1300L) {
repeat(1000) { i ->
println("Blip Blop $i ...")
delay(500L)
}
}
更多例子见官方文档: https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html