没有要开车,参赛规定有写不能污言秽语,等我有空再去其他平台写个开车系列的coroutine
这里给个快转,android开发者从1开始看,ktor从2开始看
如标题所诉,有时在客户端会因为对方重复点击按钮,在结果还没出来就发多一次请求,导致最後结果出错,~~就坏掉了~~ 就有bug了
而实际上发生什麽事呢? 预期的工作顺序应该是
但在多次请求的时候,将不是回传排序结果
,而是最後一个排序工作完成的结果
,中间大概就是divide and conquer的过程一直被打乱,导致结果不如预期
而这其实跟排序的逻辑没有关系,排序的逻辑是正确的,也和coroutine本身没有关系,在任何多执行绪的程序,都有可能发生这个问题,而其实只是没有妥善处理触发机制
那它其实有四种解法
对的,最简单也最方便的方法就是在过程中让按钮不能按,这种设计其实很常见,限购产品呀、无效登入呀、防止洗版等等,(当然前端後端都挡是最好的),而我们通常会设一个条件,让按钮变成可按
而且这个方法的优点不只解决我们的问题,测试写起来也方便
viewModelScope.launch{
_sortButtonsEnabled.value = false
try{
sortByAlphabet()
} catch(e:Exception){
} finally {
_sortButtonsEnabled.value = true
}
}
这边用liveData示范,非常简单却又实际的解法
这边提醒一个小细节,在launch预设是在main执行,这里也充分利用这个特性,如果你切换了dispatcher,有可能disenable的速度感不上某些使用者的触发
------哔哔,难易度分隔线,如果上述方法已经解决问题,可以有空了在了解其他解法,以ktor来说,直接来後面找答案吧,後端又没按纽-----
由大大提供的gist,剩下的要搭配着看
有时我们在某个条件达成後,会执行某个动作,而我们永远以最新的要求为主,所以会取消前面的请求
跟着大大写起来就会是这样
var controlledRunner = ControlledRunner<List<ProductListing>>()
...
suspend fun ...
{
return controlledRunner.cancelPreviousThenRun {
//someThing
}
}
而这个cancelPreviousThenRun和ControlledRunner不是原生的,都在那个gist里面,我这边简单介绍一下,为什麽他能确保取消前一个病执行最新的任务呢
在他的cancelPreviousThenRun里面是这麽写的
suspend fun cancelPreviousThenRun(block: suspend() -> T): T {
// fast path: if we already know about an active task, just cancel it right away.
activeTask.get()?.cancelAndJoin()
而这个activeTask是
private val activeTask = AtomicReference<Deferred<T>?>(null)
AtomicReference翻过来应该叫原子性引用,而这个原子性保证了在多个线程中修改,不会使结果不一致
直接开门,不然又要讲很多 AtomicReference原子性引用
Important: This pattern is not well suited for use in global singletons, since unrelated callers shouldn’t cancel each other.
这个方式会以旧的请求为主,毕竟如果工作一样,何必再多做新的呢?
比如,对同个api发出5次请求,你明知每次都会拿到一样的结果,何必让客户端做重工
var controlledRunner = ControlledRunner<List<ProductListing>>()
...
suspend fun ... {
return controlledRunner.joinPreviousOrRun {
//something
}
}
那他是如何做到放弃新请求的
suspend fun joinPreviousOrRun(block: suspend () -> T): T {
// fast path: if there's already an active task, just wait for it and return the result
activeTask.get()?.let {
return it.await()
}
...
}
听着困难,但其实大家应该都写过了,就是如果activeTask存在,就return它
val singleRunner = SingleRunner()
suspend fun ... {
return singleRunner.afterPrevious {
//someThing
}
}
如果你希望每个任务都会发生,但是要照请求的顺序执行,大大的SingleRunner是以mutex去实作
mutex是一个锁,文档,你可以想像成水上乐园的滑水道,会有一个人在把关,等前一个人出了滑水道(任务结束),再让下一个排队的人进滑水道,代码长这样,mutex会在return时自动释放
mutex.withLock {
return block()
}
mutex有lock和unlock,而withLock几本上就是取代
mutex.lock(); try { …… } finally { mutex.unlock() }
<<: 【Day28】Git 版本控制 - GitBook 简介
>>: Youtube Reports API 教学 - 频道中出报表
大家好! 我们今天要实作能和使用者互动的视窗。 我们进入今天的主题吧! 互动视窗 如果要和使用者互动...
在进到 " Shading " 之前,我们必须先调整 " Partic...
今天我们来写一个简单的form来当作测试吧,首先我们刻出一个简单的画面 const App: FC ...
上一篇提到图片汇入方式最重要环节就是src属性,相对路径及绝对路径使用方式 要注意相对路径档案及绝...
Virtual Judge ZeroJudge 题意 输入 a、b 两字串,输出皆为两者的子字串 ...