kotlin协程
Kotlin协程是一种轻量级的并发机制,它基于线程而不是进程,使得开发者能够更加高效地管理异步任务,避免了回调地狱的问题。协程是在一种非抢占式的多任务环境中运行,它是一种将并发代码以同步的方式进行编写的方法。Kotlin协程的使用步骤包括:创建协程作用域:可以使用或创建协程作用域。创建挂起函数:使用suspend关键字来定义挂起函数。在协程作用域中调用挂起函数:使用launch或async函数来启
文章目录
前言
Kotlin协程是一种轻量级的并发机制,它基于线程而不是进程,使得开发者能够更加高效地管理异步任务,避免了回调地狱的问题。协程是在一种非抢占式的多任务环境中运行,它是一种将并发代码以同步的方式进行编写的方法。
Kotlin协程的使用步骤包括:
-
创建协程作用域:可以使用
coroutineScope或GlobalScope创建协程作用域。 -
创建挂起函数:使用
suspend关键字来定义挂起函数。 -
在协程作用域中调用挂起函数:使用
launch或async函数来启动协程,这些函数都是挂起函数。 -
挂起函数的使用:在挂起函数中可以使用
delay等挂起函数或调用其他挂起函数。 -
协程的取消:可以使用
Job.cancel()函数来取消协程,也可以使用withTimeout等函数来限制协程的执行时间。
总的来说,Kotlin协程是一种非常强大和高效的异步编程方式,使用它可以大大简化异步编程的复杂性,使得代码更加清晰和易于理解。
提示:以下是本篇文章正文内容,下面案例可供参考
一、kotlin协程优点和基本概念
a.Kotlin协程的优点在于:
-
异步编程更加简洁:Kotlin协程提供了一种基于语言层面的异步编程模型,让异步编程更加简洁和易于理解。
-
避免回调地狱:使用协程可以避免回调地狱的问题,将异步任务看做是普通的函数调用,使得代码的结构更加清晰。
-
代码风格统一:协程可以在不同的线程中执行,但代码的风格始终保持同步的样式,避免了异步编程的复杂性。
-
更加高效的并发:协程的运行不需要创建新的线程,可以复用已有的线程,提高了并发代码的效率。
b.Kotlin协程的基本概念包括:
-
挂起函数(Suspending Function):这是一个能够暂停执行并且可以在之后恢复执行的函数,可以在函数前面使用
suspend关键字来定义。 -
CoroutineScope:协程作用域,它定义了协程的生命周期和所运行的线程。
-
Job:协程的任务,可以用来取消协程。
-
Deferred:异步计算的结果,可以通过它获取异步计算的结果。
-
Dispatcher:协程的执行上下文,定义了协程在哪个线程或线程池中执行。
二、使用步骤
1.阻塞主线程的使用
import kotlinx.coroutines.*
fun main() = runBlocking {
println("Start")
val job = launch {
delay(1000)
println("Coroutine")
}
println("End")
job.join()
}
在 runBlocking 中创建了一个协程作用域,它会等待其中所有协程执行完毕才会结束。在 launch 中创建了一个协程,其中执行了一个 delay 操作,它会挂起协程一段时间,这里是 1000ms。在 delay 操作完成后,输出了一段字符串。 在主线程中输出了 "Start" 和 "End" 字符串,这说明在协程执行过程中主线程并不会阻塞,可以继续执行其他任务。 最后通过 job.join() 等待协程执行完毕,这会阻塞主线程,直到协程执行完成后才会继续执行主线程。
launch是Kotlin协程库中用于启动新协程的关键字之一。它是一种简单的协程构建器,可以快速创建一个新的协程并在后台执行异步任务。使用launch可以在不阻塞当前线程的情况下执行异步任务,提高程序的响应性和并发性。
2.不阻塞主线程的使用
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = async {
delay(1000L)
println("Hello")
}
println("World")
job.await()
}
我们使用 async 函数创建了一个异步协程。异步协程的执行与普通协程的执行方式类似,但是在异步协程中使用 await() 函数来获取协程执行的结果。 与使用 launch 函数不同的是,我们不需要在主线程中等待异步协程执行完成。在这个示例中,我们首先创建了一个异步协程 job,然后立即在主线程中打印了 World。接着,我们调用 job.await() 等待协程执行完成。当异步协程执行完毕后,我们打印了 Hello。 通过使用异步操作,我们可以在协程执行的同时执行其他任务,不会阻塞主线程。
工作上的应用
在工作中,协程通常用于异步操作,例如网络请求或者IO操作。
1.网络请求
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 启动一个协程进行网络请求
CoroutineScope(Dispatchers.Main).launch {
try {
// 发起网络请求
val response = withContext(Dispatchers.IO) {
Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(GitHubApi::class.java)
.getRepositories()
}
// 更新UI界面
showRepositories(response)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
// 显示数据
private fun showRepositories(repositories: List<Repository>) {
recyclerView.adapter = RepositoryAdapter(repositories)
}
}
上面的代码中,我们首先创建一个协程作用域,指定协程运行在主线程(Dispatchers.Main)。然后在协程中,我们使用 withContext 函数切换协程上下文到 IO 线程,执行 Retrofit 网络请求,然后返回结果。最后在协程中,我们通过 showRepositories 函数更新UI界面,这样可以避免在主线程中进行耗时操作。
需要注意的是,上面的代码中协程使用了 withContext 函数切换了协程上下文,这样就避免了在主线程中执行耗时操作。另外,协程也可以使用 async 函数启动多个并发任务,然后使用 await 函数等待任务执行完成,这样可以提高并发效率。
2.异步任务:
import kotlinx.coroutines.*
suspend fun getResultA(): Int {
delay(1000) // 模拟耗时操作
return 10
}
suspend fun getResultB(): Int {
delay(2000) // 模拟耗时操作
return 20
}
suspend fun getResultC(): Int {
delay(3000) // 模拟耗时操作
return 30
}
suspend fun main() {
val jobA = GlobalScope.async { getResultA() }
val jobB = GlobalScope.async { getResultB() }
val jobC = GlobalScope.async { getResultC() }
val resultA = jobA.await()
val resultB = jobB.await()
val resultC = jobC.await()
println("Result: ${resultA + resultB + resultC}")
}
在上面的示例中,我们使用 async 函数并发启动了三个协程,分别执行 getResultA、getResultB 和 getResultC 函数,并将它们的返回值封装成 Deferred 对象。然后,我们使用 await 函数等待每个任务的执行结果,并将结果赋值给 resultA、resultB 和 resultC 变量。最后,我们将这三个结果相加并输出。
由于使用了 async 函数启动多个并发任务,并使用 await 函数等待所有任务执行完成后再处理结果,所以可以提高程序的并发效率。
注:上面的result A,result B,result C,并不是同时执行的,是并发启动的。多个协程之间的执行顺序是不确定的,因为它们是并发执行的,受到多个因素影响,例如计算资源、调度算法等等。在上面的例子中,虽然我们启动了三个协程,但它们的执行顺序是无法预测的。
当 await() 方法被调用时,协程会被挂起,等待异步计算结果返回。由于三个协程是并发执行的,因此它们的执行结果可以被立即返回。当三个异步计算结果都被返回后,程序会继续执行 println(“Result: $result1, $result2, $result3”) 语句,打印出三个计算结果。
因此,虽然使用了 await() 方法等待协程执行完成,但它并不会阻塞主线程。这样可以充分利用多核处理器的并行计算能力,提高程序的并发性能。
但是如果三个任务有阻塞操作,因为协程被挂起,会直接执行println语句,但是当任务执行完毕后返回结果,这个println也已经执行了,这是我们可以加一段代码:
fun main() = runBlocking<Unit> {
val result1 = async { getResult1() }
val result2 = async { getResult2() }
val result3 = async { getResult3() }
println("Result: ${result1.await()}, ${result2.await()}, ${result3.await()}")
}
runBlocking函数会在主线程中创建一个新的协程并执行,直到所有子协程执行完成后才会返回。这样就可以确保println语句在协程执行完成之后才会被执行。
总结:
更多协程知识查阅工具书
更多推荐


所有评论(0)