关于Kotlin协程的一些应用_kotlin 协程在其他地方使用,2024年最新面试常识

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新HarmonyOS鸿蒙全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img

img
img
htt

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注鸿蒙)
img

正文

fun runMethodTask(callback: OnSingleMethodCallback) {
Thread {
Thread.sleep(1000)
callback.onValueCallback(“abc”)
}.start()
}

fun runMethodTask(){
runMethodTask(object : OnSingleMethodCallback {
override fun onValueCallback(value: String) {
YYLogUtils.w(“value:$value”)
}
})
}

如果我们使用 suspendCoroutine:

suspend fun runMethodTaskWithSuspend(): String {

return suspendCoroutine { continuation ->

runMethodTask(object : OnSingleMethodCallback {
override fun onValueCallback(value: String) {
continuation.resume(value)
}
})

}
}

但是我们也需要注意,这是协程的写法,方法也标明了 suspend ,所以只能在协程中使用。

如果是一个网络请求有成功与失败的回调,那么我们也能使用 suspendCancellableCoroutine 来达到效果:

interface ICallBack {
fun onSuccess(data: String)
fun onFailure(t: Throwable)
}

private fun request(callback: ICallBack) {
thread {
try {
callback.onSuccess(“success”)
} catch (e: Exception) {
callback.onFailure(e)
}
}
}

private fun requestDefault() {
request(object : ICallBack {
override fun onSuccess(data: String) {
// …
}

override fun onFailure(t: Throwable) {
// …
}

})
}

如果使用 suspendCancellableCoroutine 的话就变成这样:

private suspend fun requestWithSuspend(): String {
return suspendCancellableCoroutine { cancellableContinuation->
request(object : ICallBack {
override fun onSuccess(data: String) {
cancellableContinuation.resume(data)
}

override fun onFailure(t: Throwable) {
cancellableContinuation.resumeWithException(t)
}
})
}
}

同样需要注意是,这是协程的写法,方法也标明了 suspend ,所以只能在协程中使用。

其实为什么Retrofit的请求看似把异步的网络请求用成了同步一样,Retrofit的内部也是同样的处理。

Retrofit最终的处理逻辑在此:KotlinExtensions.awaitResponse

所以我们照着Retrofit学就行了。

三、Kotlin协程分发器

有没有同学全部用 Dispatchers.IO 切换线程调度的。

Dispatchers.IO / Dispatchers.Default 的异同:

两者都是协程分发器,Dispatchers.IO 侧重于任务本身是阻塞型的,比如文件、数据库、网络等操作等。并不那么占用CPU

而Dispatchers.Default 则偏向那些可能会长时间占用CPU的任务。比如人脸特征提取,图片压缩处理,视频的合成等。

他们的线程池的实现也是不同的

协程线程池在设计的时候,针对两者在线程的调度策略上有所不同。

所有任务分成纯CPU任务和非纯CPU任务两种,对应着核心线程和非核心线程。

入队的逻辑是 Dispatchers.IO 的任务放入 globalBlockingQueue 队列,而 Dispatchers.Default 的任务放入的是 globalBlockingQueue 队列。

所有线程在执行前都先尝试成为核心线程,核心线程可以从两种任务中任意选择执行,非核心线程只能执行非纯CPU任务。核心线程如果选择执行非纯CPU任务会变成非核心线程。

所以真的有人从来没用过 Dispatchers.Default 吗?

四、使用协程有什么好处?怎么用?

看到过网上的一些Java线程池比协程线程池执行逻辑更快的文章,其实意义不大,协程最大的优势是会更加的方便,可以很方便的把一些碎片化的方法加入协程,同时它可以去掉回调地狱还能更加方便的实现并发与排队执行的效果。

比如这样的一个场景,在主线程计算薪水,我们根据时薪与工作时长计算总共的薪水,内部有复杂的判断,是否是签约员工,是否迟到了,迟到了扣钱,扣除五险一金,连续工作的奖励,推荐的奖励,顾客打赏,等等一系列的复杂逻辑,我们就可以随意加入协程中。

private fun calculateSalary(): String {
// 省略100行代码
return “1000”
}

private suspend fun calculateSalary2() = withContext(Dispatchers.Default) {
// 省略100行代码
“2000”
}

private suspend fun calculateSalary3() = coroutineScope {
// 省略100行代码
“3000”
}

下面看看代码的优化:

class CalculateFaceUtil private constructor() : CoroutineScope by MainScope() {

//… 单例

/**
* 计算并找到最匹对的人脸信息
*
* 使用协程异步的并发的双端遍历查询最大值
*/
fun getTopFace(
list: List,
faceEngine: FaceEngine,
faceFeature: FaceFeature,
action: (similar: Float, index: Int) -> Unit
) {

// 、、、其他逻辑

val middlePosition = list.size / 2

launch(Dispatchers.IO) {

val topface1 = async {
val tempFaceFeature = FaceFeature()
val faceSimilar = FaceSimilar()
var maxSimilar = 0f
var maxSimilarIndex = -1

for (i in 0 until middlePosition) {
tempFaceFeature.featureData = list[i].featureData
//调用SDK比对两个 FaceFeature 人脸特征,返回相似度
faceEngine.compareFaceFeature(faceFeature, tempFaceFeature, faceSimilar)
//拿到相似度的对象,获取得分(每一次都会全部遍历,如果有相同的图片还是会取到最后的)
if (faceSimilar.score > maxSimilar) {
maxSimilar = faceSimilar.score
maxSimilarIndex = i
}
}

TopFace(maxSimilar, maxSimilarIndex)
}

val topface2 = async {
val tempFaceFeature = FaceFeature()
val faceSimilar = FaceSimilar()
var maxSimilar = 0f
var maxSimilarIndex = -1

for (i in middlePosition until list.size) {
tempFaceFeature.featureData = list[i].featureData
//调用SDK比对两个 FaceFeature 人脸特征,返回相似度
faceEngine.compareFaceFeature(faceFeature, tempFaceFeature, faceSimilar)
//拿到相似度的对象,获取得分(每一次都会全部遍历,如果有相同的图片还是会取到最后的)
if (faceSimilar.score > maxSimilar) {
maxSimilar = faceSimilar.score
maxSimilarIndex = i
}
}

TopFace(maxSimilar, maxSimilarIndex)
}

//并发查找并找到最大值
val face1 = topface1.await()
val face2 = topface2.await()

if (face1 != null && face2 != null) {
//回调到主线程
withContext(Dispatchers.Main) {
//优先返回后面的数据
if (face2.similar > face1.similar) {
action(face2.similar, face2.index)
} else {
action(face1.similar, face1.index)
}
}

}
}

}

}

场景:ViewModel中调用这个工具类,查找较大集合中最匹配的人脸,使用头尾双端遍历找到最大值。

我们以这一个使用场景为例,逻辑没问题,但是协程的使用有优化的空间。

1.计算最好使用 Dispatchers.Default , 这是小问题。 2.viewModel中viewModelScope协程作用域中调用全局的协程作用域,这…感觉不太好,推荐使用下面的方式,继承父布局的协程作用域。

suspend fun getTopFace() = coroutineScope {

async(Dispatchers.Default) {

}

async(Dispatchers.Default) {

}

// 。。。
}

3.使用高阶函数回调,如果是协程中最好是可以铺平回调

suspend fun getTopFace(
list: List,
faceEngine: FaceEngine,
faceFeature: FaceFeature,
): TopFace = suspendCoroutine { continuation ->

async(Dispatchers.Default) {

}

async(Dispatchers.Default) {

}

// 。。。
continuation.resume(TopFace(maxSimilar, maxSimilarIndex))
}

之前的viewModel中使用:

private fun searchFace(
frFace: FaceFeature, requestId: Int,
orignData: ByteArray?, faceInfo: FaceInfo?, width: Int, height: Int
) {

viewModelScope.launch {

//通过FaceServer找到最匹配的人脸
CalculateFaceUtil.getInstance().getTopFace(frFace) { compareResult ->

// 。。。逻辑
}
}
}

在回调里面写逻辑,后面的逻辑就破坏了协程作用域,那么又要使用工具类开启一个新的协程,这样就很不好。

现在的viewModel中使用:

private fun searchFace(
frFace: FaceFeature, requestId: Int,
orignData: ByteArray?, faceInfo: FaceInfo?, width: Int, height: Int
) {

viewModelScope.launch {

//通过FaceServer找到最匹配的人脸
val topFace = CalculateFaceUtil.getInstance().getTopFace(frFace)

// 。。。逻辑

withContext(Dispatchers.IO){
//上传到网络逻辑
}

}
}

修改之后就可以直接在一个作用域中切换线程的调度。

还有一个比较典型的例子就是网络请求用的很多的协程处理类,很多人喜欢把网络请求的结果再封装一层,指定成功或失败。例如:

sealed class OkResult {

data class Success(val data: T) : OkResult()
data class Error(val exception: Exception) : OkResult()

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

{

data class Success(val data: T) : OkResult()
data class Error(val exception: Exception) : OkResult()

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
[外链图片转存中…(img-bRZJYaY7-1713175316901)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值