协程
Posted shubin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了协程相关的知识,希望对你有一定的参考价值。
引言
在使用socket编程时,我们会用到accept、connect、recv、send等函数,这些函数在没有数据到达时,会阻塞等待IO数据的到达。 这不利于我们处理多个连接并快速响应。一种方案是,服务端每accept一个连接,就创建一个新的线程用来处理这个连接。这会导致线程过多, 而且线程之前切换开销很大。这就可以使用到协程了。当然不止socket这种可以使用协程,IO密集型都可以使用协程,无论是网络IO还是其他IO。
协程
协程可以理解为用户态的非抢占线程。
特点
用户态:协程是在用户态实现调度。
轻量级:协程不用内核调度,内核态与用户态之间切换。
非抢占:协程是由用户自己实现调度,并且同一时间只能有一个协程在执行,协程自己主动交出CPU的。
优缺点
- 优点:
- 协程切换的时候开销小,用户态且轻量
- 非抢占式,不用加很多锁,减小复杂度,不用很复杂的处理线程同步问题。
- 缺点:
- 协程不能利用多核,只能使用单核,因为同时只有一个协程在运行。
适用场景
IO密集型。 在IO密集的情况下,协程的开销比线程小,能快速实现调度。 协程不适用于计算密集型,协程不能很好的利用多核cpu。
ucontext组件
linux下在头文件ucontext.h 提供了getcontext(),setcontext(),makecontext(),swapcontext()四个函数和mcontext_t和ucontext_t结构体。
其中mcontext_t与机器相关。ucontext_t结构体如下(一般在/usr/include下):
typedef struct ucontext
unsigned long int uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
mcontext_t uc_mcontext;
__sigset_t uc_sigmask;
struct _libc_fpstate __fpregs_mem;
ucontext_t;
其中uc_link指向下文,及当前上下文(可以理解为执行状态)执行完了,恢复运行的上下文;
uc_sigmask为该上下文中的阻塞信号集合;
uc_stack为该上下文中使用的栈;
uc_mcontext保存的上下文的特定机器表示,包括调用线程的特定寄存器等。
通过栈式计算机原理,我们可以知道,保存栈区和所有通用寄存器的值就可以保存程序运行的状态。这里uc_mcontext就是用来保存所有的寄存器的值的。而我们把栈设置到uc_stack所指向的内存, uc_stack就保存了栈的状态。
ucontext的4个函数介绍
int getcontext(ucontext_t *ucp);
获取当前上下文,初始化ucp结构体,将当前的上下文保存到ucp中。如果执行成功,返回0。执行失败返回-1。
int setcontext(const ucontext_t *ucp);
设置当前上下文,设置当前的上下文为ucp, 恢复ucp的执行状态。如果ucp执行完了,会恢复到uc_link所指向的上下文,若uc_link为NULL,则线程退出。如果执行成功,不返回。执行失败返回-1。
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);
创建上下文,修改通过getcontext取得的上下文ucp, 然后给该上下文指定一个栈空间ucp->stack,设置后继的上下文ucp->uc_link。
int swapcontext(ucontext_t *oucp, ucontext_t *ucp);
切换上下文,保存当前上下文到oucp结构体中,然后激活upc上下文。 如果执行成功,不返回。执行失败返回-1。
Kotlin 协程协程简介 ( 协程概念 | 协程作用 | 创建 Android 工程并进行协程相关配置开发 | 异步任务与协程对比 )
文章目录
一、协程概念
协程 Coroutine 是 Kotlin 语言 中新出现的概念 , 在 Java 语言中没有 ;
协程 是 基于 线程 的 , 是 轻量级 线程 ;
二、协程作用
协程主要作用如下 :
- 处理耗时任务 : 耗时任务 通常需要 阻塞主线程 , 线程量级太重 , 耗时任务 推荐在协程中执行 ;
- 保证主线程安全 : 从主线程中 安全地调用可能会挂起的函数 ;
异步任务 AsyncTask 也可以处理耗时操作 , 避免耗时任务阻塞线程 , 但是在 Android 11 中 , 官方规定 该 api 已过时 , 被标记为弃用状态 , 建议使用
- 协程
- java.util.concurrent 包下的 Executor,ThreadPoolExecutor,FutureTask
取代 AsyncTask ;
三、创建 Android 工程并进行协程相关配置
1、创建 Android 工程
创建 Android 工程 , 在 Android Studio 中 选择 " 菜单栏 | File | New | New Project " 选项 , 创建工程 ,
创建 Empty Activity ;
注意选择 Kotlin 语言 , Android Studio 会自动添加 Kotlin 语言支持 ;
2、配置协程环境
在 AndroidManifest.xml 清单文件 中 , 添加网络权限 :
<uses-permission android:name="android.permission.INTERNET"/>
Android 中访问网络 , 建议使用 https 协议 , 如果在 Android 中使用 http 协议 , 则需要加入如下网络声明 : 在 res/xml 目录下 , 配置 network_security_config.xml 配置文件 ;
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
然后在 清单文件中的 application 节点 配置 如下属性 :
android:networkSecurityConfig="@xml/network_security_config"
完整的清单文件配置示例 :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="kim.hsl.coroutine">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Coroutine"
android:networkSecurityConfig="@xml/network_security_config">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
在 build.gradle 中设置协程依赖 :
dependencies
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-RC-native-mt'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0-RC-native-mt'
3、布局文件
布局文件 :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/asyncTaskButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="异步任务方法"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"
app:layout_constraintHorizontal_bias="0.5"/>
<Button
android:id="@+id/coroutineButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="协程方法"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.4"
app:layout_constraintHorizontal_bias="0.5"/>
</androidx.constraintlayout.widget.ConstraintLayout>
4、异步任务代码示例
findViewById<Button>(R.id.asyncTaskButton).also
it.setOnClickListener
// 使用异步任务执行耗时操作,
// 使用匿名内部类形式定义异步任务 ,
// Java 匿名内部类 对应 Kotlin 对象表达式
object : AsyncTask<Void, Void, Void>()
override fun doInBackground(vararg params: Void?): Void?
// 在子线程执行任务
Log.i("MainActivity", "doInBackground : 子线程执行异步任务执行耗时操作")
return null
override fun onPostExecute(result: Void?)
super.onPostExecute(result)
// 主线程更新 UI
Log.i("MainActivity", "onPostExecute : 主线程更新 UI")
.execute()
5、协程代码示例
findViewById<Button>(R.id.coroutineButton).also
it.setOnClickListener
// 创建协程
GlobalScope.launch
// Dispatchers.IO 是协程任务调度器, 用于执行耗时操作
withContext(Dispatchers.IO)
Log.i("MainActivity", "withContext : 协程中执行耗时操作")
// 主线程更新 UI
Log.i("MainActivity", "GlobalScope : 主线程更新 UI")
6、完整代码示例
package kim.hsl.coroutine
import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.asyncTaskButton).also
it.setOnClickListener
// 使用异步任务执行耗时操作,
// 使用匿名内部类形式定义异步任务 ,
// Java 匿名内部类 对应 Kotlin 对象表达式
object : AsyncTask<Void, Void, Void>()
override fun doInBackground(vararg params: Void?): Void?
// 在子线程执行任务
Log.i("MainActivity", "doInBackground : 子线程执行异步任务执行耗时操作")
return null
override fun onPostExecute(result: Void?)
super.onPostExecute(result)
// 主线程更新 UI
Log.i("MainActivity", "onPostExecute : 主线程更新 UI")
.execute()
findViewById<Button>(R.id.coroutineButton).also
it.setOnClickListener
// 创建协程
GlobalScope.launch
// Dispatchers.IO 是协程任务调度器, 用于执行耗时操作
withContext(Dispatchers.IO)
Log.i("MainActivity", "withContext : 协程中执行耗时操作")
// 主线程更新 UI
Log.i("MainActivity", "GlobalScope : 主线程更新 UI")
四、异步任务与协程对比
异步任务与协程对比 :
- 相同点 : 都可以 处理耗时任务 , 保证主线程的安全性 ;
- 异步任务缺陷 : 不符合人类的思维逻辑 , 其先执行 doInBackground 方法在其中执行后台任务 , 然后再通过回调触发 onPostExecute 方法在主线程执行操作 ;
- 协程优点 : 符合人类思维习惯 , 借助编辑器实现了 异步任务同步化 , 没有回调操作 ; 可以在执行一段程序后 挂起 , 之后在挂起的地方 恢复执行 ;
以上是关于协程的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin 协程协程简介 ( 协程概念 | 协程作用 | 创建 Android 工程并进行协程相关配置开发 | 异步任务与协程对比 )
Kotlin 协程协程简介 ( 协程概念 | 协程作用 | 创建 Android 工程并进行协程相关配置开发 | 异步任务与协程对比 )
Kotlin 协程协程异常处理 ② ( SupervisorJob 协程 | supervisorScope 协程作用域构建器函数 )
Kotlin 协程协程异常处理 ② ( SupervisorJob 协程 | supervisorScope 协程作用域构建器函数 )
Kotlin 协程协程取消 ② ( CPU 密集型协程任务取消 | 使用 isActive 判定协程状态 | 使用 ensureActive 函数取消协程 | 使用 yield 函数取消协程 )