补篇协程:协程(Coroutine)里通过挂起suspend函数实现异步IO操作

2024-06-10 19:12

本文主要是介绍补篇协程:协程(Coroutine)里通过挂起suspend函数实现异步IO操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

异步IO的概念

异步IO是一种非阻塞的数据读写方法,异步IO与同步IO相对。 当一个异步过程调用发出后,调用者不能立刻得到结果。 实际的IO处理部件在完成操作后,会通过状态、通知或回调机制来通知调用者。

在一个CPU密集型的应用中,有一些需要处理的数据可能放在磁盘上。预先知道这些数 据的位置,所以预先发起异步IO读请求。等到真正需要用到这些数据的时候,再等待异步IO完成后获取数据。这种方式使用了异步IO允许程序在等待IO操作完成的同时继续执行其他任务,从而提高了系统的整体效率。

异步IO将比特分成小组进行传送,小组可以是8位的1个字符或更长。发送方可以在任何时刻发送这些比特组,而接收方从不知道它们会在什么时候到达。

异步传输存在一个潜在的问题,即接收方并不知道数据会在什么时候到达。在它检测到数据并做出响应之前,第一个比特已经过去了。这就像有人出乎意料地从后面走上来跟你说话,而你没来得及反应过来,漏掉了最前面的几个词。因此,每次异步传输的信息都以一个起始位开头,它通知接收方数据已经到达了,这就给了接收方响应、接收和缓存数据比特的时间;在传输结束时,一个停止位表示该次传输信息的终止。按照惯例,空闲(没有传送数据)的线路实际携带着一个代表二进制1的信号,异步传输的开始位使信号变成0,其他的比特位使信号随传输的数据信息而变化。最后,停止位使信号重新变回1,该信号一直保持到下一个开始位到达。例如在键盘上数字“1”,按照8比特位的扩展ASCII编码,将发送“00110001”,同时需要在8比特位的前面加一个起始位,后面一个停止位。

Android 实现异步IO操作:

在Android开发中,异步IO通常用于执行耗时的网络请求、文件读写等操作,避免UI线程被长时间运行的IO耗时任务阻塞(避免阻塞UI线程,保持应用的响应性)。但是,在使用异步IO时,也需要注意线程安全和资源管理的问题,确保不会出现内存泄漏或竞态条件等问题。

Android提供了多种机制来实现异步IO操作:使用AsyncTask,Thread,HandlerThread,IntentService,JobIntentService,RxJava等机制实现异步IO操作.它们本质上都是对线程或线程池的封装,该类可以将耗时的操作放在后台线程池来处理,而不需要人为地另开线程来处理。

使用AsyncTask实现异步IO操作:

这是一个轻量级的异步类,适合在后台执行简单的异步任务,如网络请求或文件读写。它包含doInBackground方法在后台线程执行耗时操作,onProgressUpdate在UI线程更新进度,以及onPostExecute在任务完成后在UI线程执行后续操作。使用AsyncTask来实现异步IO的优点就是简单便捷,各个过程都有明确的回调,过程可控。

使用HandlerThread实现异步IO操作:

HandlerThread是一种在单独的线程中处理消息和Runnable对象的机制。通过使用Handler与HandlerThread结合,可以在后台线程中处理耗时的操作,并通过Handler将结果发送回UI线程进行更新。

使用IntentService实现异步IO操作:

IntentService是一种在后台执行异步任务的服务。它会在一个单独的工作线程中处理传入的Intent,并自动处理线程间的通信。IntentService适用于执行不需要立即返回结果的长时间运行的操作。

使用JobIntentService实现异步IO操作:

在Android O及更高版本中,建议使用JobIntentService作为IntentService的替代方案。它提供了更多的灵活性和更好的电池效率。

使用RxJava实现异步IO操作:

RxJava是一个在Java VM上使用可观察序列来组成异步和基于事件的程序的库。它提供了一种声明式的方式来处理异步数据流。

Handler

 在Android中,Handler本身并不直接实现异步IO操作。

可以在后台子线程中执行IO操作(耗时任务), 然后通过Handler将数据结果,发送传递 给UI主线程进行更新,从而间接地支持异步IO的实现。

例子:使用Handler结合Thread实现异步IO:

1.我们首先初始化了一个Handler对象,它绑定到主线程的Looper上,这样我们就可以在主线程中执行Runnable对象。

2.然后,我们创建并启动了一个新的Thread来执行耗时的IO操作。

3.在后台线程中,我们调用performIOOperation()方法模拟了一个耗时的IO操作。

4.一旦IO操作完成,我们使用Handlerpost方法将一个Runnable对象发送回主线程。这个Runnable对象包含了更新UI或处理IO操作结果的逻辑。

5.最后,在updateUIWithResult()方法中,我们执行了必须在主线程中完成的UI更新操作。

public class AsyncIOActivity extends AppCompatActivity {private static final String TAG = "AsyncIOActivity";private Handler mainHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_async_io);// 初始化主线程的HandlermainHandler = new Handler(Looper.getMainLooper());// 启动后台线程执行IO操作new Thread(new Runnable() {@Overridepublic void run() {// 模拟耗时IO操作,比如网络请求或文件读写final String result = performIOOperation();// 使用Handler将结果发送回主线程mainHandler.post(new Runnable() {@Overridepublic void run() {// 在主线程中更新UI或处理结果updateUIWithResult(result);}});}}).start();}private String performIOOperation() {// 在这里执行实际的IO操作,例如网络请求或文件读写// 这个操作是耗时的,因此应该在后台线程中执行// 模拟耗时操作try {Thread.sleep(2000); // 假设耗时2秒} catch (InterruptedException e) {e.printStackTrace();}return "IO操作完成";}private void updateUIWithResult(String result) {// 在这里更新UI或处理从IO操作中获取的结果// 这个操作必须在主线程中执行,因为Android不允许在非主线程中更新UILog.d(TAG, "UI updated with result: " + result);// 例如:textView.setText(result);}
}

 在主线程也可以通过 Handler发消息给子线程,不过在子线程接收数据,需要轮训Handler,需要初始化Looper.prepare()和Looper.loop()。

public class LooperThreadActivity extends Activity {private Handler mHandler = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);new MyThread().start();//发消息到目标子线程mHandler.obtainMessage(0).sendToTarget();}class MyThread extends Thread{@Overridepublic void run() {super.run();//1.建立消息循环,初始化LooperLooper.prepare();mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);int what = msg.what;if(what == 0){//}}};//启动消息循环Looper.loop();}}
}

使用协程(Coroutine)实现异步IO操作

Kotlin 协程(Coroutine)是一种轻量级的线程,它允许我们以同步的方式编写异步代码,从而极大地简化了异步编程的复杂性。协程不是真正的线程,它们是在单个线程上通过协作调度来执行的,这避免了线程切换的开销,提高了效率。下面将详细讲解 Kotlin 使用协程实现异步 IO 的原理和流程。

使用协程实现异步 IO 的原理

1.挂起函数(Suspend Function)

Kotlin 协程的核心是suspend挂起函数。这些suspend挂起函数可以在执行过程中暂停(挂起),等待某个异步任务(IO操作,网络请求)完成后再恢复执行。这使得协程能够在不阻塞主线程的情况下执行耗时的操作。

  挂起函数(Suspend Functions)在 Kotlin 协程中扮演着至关重要的角色,它们是实现异步 IO 的  关键。 

 挂起函数 原理:

挂起函数必须在一个协程上下文中执行,通常是通过 launchasync 等协程构建器创建的。此外,挂起函数只能被其他挂起函数或协程调用,以确保正确的执行顺序和线程安全性。挂起函数通过非阻塞性和协作式调度的原理,实现了在 Kotlin 协程中执行异步 IO 操作的高效流程。它们允许代码以同步的方式编写,而实际上却是在底层执行异步操作,从而简化了异步编程的复杂性。

非阻塞性:挂起函数允许协程在遇到耗时的操作时(IO 操作), 而不会阻塞当前(主)线程。这使得(主)线程可以继续执行其他任务,从而提高了整体的并发性能。

协作式调度:协程不是由操作系统来调度的,而是由用户代码(或者库代码)来显式地调度和挂起。挂起函数是这种协作式调度的关键部分。当这个挂起函数被调用执行时,它会暂停当前协程的执行,并释放当前(主)线程的控制权。当异步操作完成或条件满足时,协程会恢复执行,恢复对当前(主)线程的控制权。

轻量级:由于挂起函数并不涉及线程的切换,因此它们相比于传统的线程或回调机制更加轻量级。这减少了系统资源的消耗,提高了程序的性能。

2.协程构建器(Coroutine Builder)

Kotlin 标准库提供了多个协程构建器,如 launchasyncrunBlocking 等。这些构建器用于创建协程并启动它们的执行。

3.调度器(Dispatcher)

协程的调度器决定了协程在哪个线程或线程池上执行任务。如果你要更新UI,就让调度器把协程调度到UI主线程Dispatchers.Main(或许默认就在UI主线程);如果你要做异步IO耗时任务,就让调度器把协程调度到IO子线程Dispatchers.IO

 Kotlin 提供了默认的调度器,如 Dispatchers.Default(用于计算密集型任务)、Dispatchers.IO(用于 IO 密集型任务)和 Dispatchers.Main(用于在 Android 的主线程上执行 UI 更新)。

4.延续(Continuation)

协程的挂起和恢复是通过 Continuation 机制实现的

当一个挂起函数被调用时,它会将当前的执行状态保存到一个 Continuation 对象中,并释放当前线程的控制权(不在当前线程里了)。

当异步操作完成时,它会恢复该 Continuation,从而使挂起函数继续执行,重新掌控当前线程的控制权(又回到当前线程里了)。

使用协程实现异步 IO 的流程

以下是一个使用 Kotlin 协程实现异步 IO 的典型流程:

1.添加依赖

 首先,你需要在项目的 build.gradle 文件中添加 Kotlin 协程的依赖。

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:<version>"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:<version>" // 对于 Android 项目

2.创建一个协程

使用协程构建器(如 GlobalScope.launchviewModelScope.launch 对于 Android ViewModel)来创建协程。

//协程调度器调度到IO子线程
GlobalScope.launch(Dispatchers.IO) {// 在这里执行异步 IO 操作
}

3.调用挂起函数:

在协程中,你可以调用挂起函数来执行异步 IO 操作。这些挂起函数通常是异步 API 的封装,它们使用协程的挂起和恢复机制来处理异步性。

使用挂起函数withContext,   指定一个不同的调度器(Dispatchers.IO )调度到IO子线程里,在代码块里执行异步IO操作。

释放对当前主线程的控制权(不在当前主线程里了)。 

/**
使用挂起函数withContext,   指定一个不同的调度器(Dispatchers.IO )调度到IO子线程里,在代码块里执行异步IO操作
*/val result = withContext(Dispatchers.IO) {// 执行网络请求或文件读写等异步操作// 返回操作结果
}

4.挂起协程

当挂起函数被调用时,它会检查当前是否处于可以立即执行的状态。如果不能立即执行(比如需要等待网络响应),挂起函数就会暂停协程的执行,并释放当前(主)线程的控制权。此时,协程的状态会被保存,以便稍后恢复。

5.执行异步 IO操作

挂起函数withContext内部会开始执行异步IO操作。这通常涉及到底层库或框架的异步 API,比如使用 kotlinx.coroutines 提供的网络请求库。这些 API 在后台线程上执行实际的 IO 操作,而不会阻塞主线程。

6.恢复协程

当异步操作完成(比如网络请求返回了结果),挂起函数withContext会接收到通知。此时,它会检查之前挂起的协程是否还存活,并尝试恢复该协程的执行。恢复过程包括重新获取对(主)线程的控制权,并从上一次挂起的位置继续执行代码。

7.更新 UI

 一旦协程恢复执行,挂起函数withContext会返回异步IO操作的结果(或异常)。你可以在协程中处理这个结果,比如更新 UI 或进行进一步的计算。

如果需要在 UI 线程上更新数据结果,你可以使用 withContext(Dispatchers.Main),指定一个不同的调度器(Dispatchers.Main )调度到Main线程里(切换到UI主线程),在代码块里执行更新数据结果  。

//返回数据结果result 
val result=withContext(Dispatchers.Main) {// 更新 UI,如设置文本、显示图像等
}

 在协程中,你可以使用 try-catch 块来处理可能出现的异常。

try {//返回数据结果result val result = withContext(Dispatchers.IO) {// 更新 UI,如设置文本、显示图像等// 执行可能抛出异常的异步操作}
} catch (e: Exception) {// 处理异常
}

 8.取消协程

如果需要取消协程的执行,你可以使用 Job 对象来管理协程的生命周期。launchasync 构建器都会返回一个 Job 对象,你可以调用它的 cancel 方法来取消协程。

val job = GlobalScope.launch {// 协程代码
}// 在某个时刻取消协程
job.cancel()

协程任务异步任务区别在哪里?

协程任务和异步任务都是处理并发和异步操作的重要手段,但它们在执行方式、并发执行、任务调度与使用场景等方面存在明显的区别。选择使用哪种方式取决于具体的应用需求和场景。在实际开发中,应根据项目的具体需求和团队的技能水平来选择合适的方案。

协程任务和异步任务在多个方面存在显著的区别。以下是它们之间的主要差异:

1.执行方式不同

  异步任务(Asynchronous Task):异步任务不进入主线程,而是进入任务队列。只有当主线程的任务执行完毕后,任务队列才会通知主线程请求执行任务,这时该任务才会进入主线程执行1。异步任务通常需要自己不断轮询,条件不满足就返回特定值(如EAGAIN),然后重新尝试2。

协程任务(Coroutine Task):协程任务是基于事件驱动的,它使用库封装好的API,这些API会往事件驱动模块(如epoll)订阅事件,并记录一些上下文(如回调)。当条件满足时,它会执行相应的回调。协程任务结合了同步和异步的优点,允许用户以同步的方式编写异步代码,从而简化了异步编程的复杂性124。

2.并发执行不同

异步任务:异步任务通常用于执行不会阻塞程序执行的任务,如网络请求、定时器、事件处理或异步函数1。

协程任务:协程在单线程下通过用户自己控制任务调度来实现并发。当遇到IO阻塞时,协程会切换到另一个任务执行,以此来提升效率3。协程的切换开销更小,属于程序级别的切换,因此更加轻量级3。

3.任务调度与状态保存不同

协程任务:协程允许用户程序自己控制任务调度,可以检测IO操作并在遇到IO操作时进行切换。同时,协程可以控制多个任务之间的切换,并在切换之前保存任务的状态,以便重新运行时可以从暂停的位置继续执行3。

4.使用场景不同:

异步任务:更适用于那些天然就是异步性质的操作,比如网络请求,这些操作本身就支持异步处理,因此使用异步任务可以更有效地利用系统资源。

协程任务:更适用于那些需要精细控制并发和IO操作的场景,特别是在需要编写复杂异步逻辑的代码时,协程可以大大简化代码结构,提高代码的可读性和可维护性。

挂起函数异步任务区别在哪里?

挂起函数和异步任务都是处理异步操作的重要手段,但它们在实现机制、编程模型、错误处理和性能开销方面存在明显的区别。Kotlin 协程的挂起函数提供了一种更加直观和高效的异步编程方式,适用于需要简化异步逻辑和提高代码可读性的场景。而异步任务则更适合于需要利用多线程并行处理任务的场景。在选择使用哪种方式时,需要根据具体的应用需求和场景来做出决策。

挂起函数(Suspend Function)和异步任务(Asynchronous Task)在异步编程中有不同的实现方式和应用场景,它们之间的主要区别如下:

1.执行机制不同

挂起函数:在 Kotlin 协程中,挂起函数允许程序在执行过程中暂停并恢复,而不需要阻塞线程。当挂起函数被调用时,它会将当前协程的执行状态保存起来,并释放线程的执行权,以便其他协程或任务能够运行。当挂起的原因(如IO操作完成)消失时,协程会恢复执行,从挂起点继续执行后续的代码。挂起函数通常用于封装那些可能阻塞的异步操作,如网络请求或文件读写。

异步任务:异步任务通常指的是在单独的线程或线程池中执行的任务,它们与主线程并行运行,不会阻塞主线程的执行。异步任务通过回调函数、Promise、Future 或其他机制来处理异步操作的结果。异步任务的执行和结果处理通常分散在多个方法或回调中,使得代码结构相对复杂。

2.编程模型不同

挂起函数:Kotlin 协程提供了一种更直观的编程模型,使得异步代码看起来像是同步执行的。挂起函数的使用使得异步逻辑可以更加自然地融入代码结构中,减少了回调嵌套和代码分散的问题,提高了代码的可读性和可维护性。

异步任务:异步任务的编程模型通常涉及更多的回调和状态管理。开发者需要显式地处理异步操作的启动、结果监听和异常处理。这种模型在复杂的异步逻辑中容易导致代码结构混乱和错误处理困难。

3.错误处理不同

挂起函数:在 Kotlin 协程中,错误处理通常使用 try-catch 语句来捕获和处理异常。挂起函数中的异常会冒泡到调用栈的顶层,使得错误处理更加集中和方便。

异步任务:异步任务的错误处理通常需要在回调函数中显式处理。这要求开发者在每个回调中都要考虑异常处理的情况,增加了代码的复杂性和出错的可能性。

4.上下文切换和开销不同

挂起函数:挂起函数在协程间的上下文切换通常比线程切换开销要小得多,因为它们是在用户空间内完成的,不涉及内核态的切换。这使得协程在处理大量轻量级任务时更加高效。

异步任务:异步任务通常使用线程或线程池来执行,线程切换涉及到内核态的切换,因此开销相对较大。在处理大量异步任务时,线程的管理和调度可能会成为性能瓶颈。

挂起函数协程的关系(区别)

挂起函数是协程中实现异步IO操作和执行流程控制的关键组成部分。它们允许我们以同步的方式编写异步代码,提高程序的并发性能,并简化复杂的异步逻辑。在Kotlin等语言中,通过使用挂起函数和协程,我们可以更加高效地处理异步IO和其他异步任务。

挂起函数只能在协程环境中被调用,它们不能在普通的同步代码块中直接使用。这是因为挂起函数的实现依赖于协程的运行时系统,该系统负责管理协程的挂起和恢复操作。

挂起函数与协程之间存在着紧密的关系,主要体现在以下几个方面:

1.协程的定义与特性

 协程是一种用户态的轻量级线程,它可以在单线程中实现非阻塞的并发执行。协程具有可中断和可恢复的特性,这意味着它可以在执行过程中被挂起,并在稍后的某个时刻恢复执行。这种中断和恢复的能力使得协程可以非常高效地处理异步操作,如IO操作,而不会阻塞线程。

2.挂起函数的作用

 挂起函数是协程中用于实现挂起和恢复操作的关键函数。当调用一个挂起函数时,当前协程会暂停执行,并释放线程的控制权,以便其他任务可以执行。

挂起函数内部通常包含一些可能阻塞的耗时的异步IO操作,如网络请求或文件读写。当这些异步操作完成时,挂起函数会恢复执行,并继续执行后续的代码。

3.实现异步IO

挂起函数允许我们以同步的方式编写异步代码,这对于实现异步IO特别有用。通过挂起函数,我们可以避免阻塞线程,从而提高程序的并发性能。挂起函数内部通常封装了对底层异步API的调用,如网络请求或文件读写,使得异步操作看起来像是同步执行的2。

4.协作式调度

协程的调度是协作式的,这意味着协程的挂起和恢复是由用户代码(或库代码)显式控制的,而不是由操作系统调度的。挂起函数在这种协作式调度中起着关键作用,它们决定了何时挂起协程以及何时恢复协程的执行。

5.简化异步逻辑

通过使用挂起函数,我们可以将复杂的异步逻辑封装在简单的函数中,使得代码更加清晰和易于维护。这有助于减少回调地狱和提高代码的可读性。

挂起函数和协程的例子

下面例子,演示了如何使用 Kotlin 的协程和挂起函数来实现异步 IO操作:

1.在 Gradle 构建文件中添加以下依赖:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1" // 使用最新版本
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1" // 如果你在 Android 项目中使用

2.创建一个挂起函数来模拟异步 IO 操作(网络请求):

class SuspendActivity  : ComponentActivity() {override   fun onCreate(savedInstanceState: Bundle?){lifecycleScope.launch(context=Dispatchers.Main,block={Log.e(TAG, "当前所处的线程1:  ${Thread.currentThread().name} ") //当前所处的线程1:  mainLog.e(TAG, "获取 协程在上下文指定的调度器1:${this.coroutineContext}") //获取 协程在上下文指定的调度器1:[StandaloneCoroutine{Active}@8872fef, Dispatchers.Main]//在launch协程里调用挂起函数findBigPrime(),执行异步 IO 操作  它不会阻塞当前线程val bigIntegerResult:BigInteger=findBigPrime()Log.e(TAG,  "输出bigIntegerResult=$bigIntegerResult")Log.e(TAG, "当前所处的线程3:  ${Thread.currentThread().name} ") //当前所处的线程3:  mainLog.e(TAG, "获取 协程在上下文指定的调度器3:${this.coroutineContext}") //获取 协程在上下文指定的调度器3:[StandaloneCoroutine{Active}@8872fef, Dispatchers.Main]//在主线程更新显示请求的数据bigIntegerResultfindViewById<TextView>(R.id.textview).text= bigIntegerResult.toString()})}/** 改进正确的做法:*  借助 withContext 我们把BigInteger.probablePrime()的耗时CPU 计算操作   从当前主线程(切换到一个子线程里去)挪到了一个默认的后台线程池。不会阻塞当前的主线程,主线程能够进行其他的初始化操作*  当耗时操作完成计算出结果数据后,再在主线程更新显示请求的数据** */suspend fun  findBigPrime():BigInteger{val bigIntegerResult:BigInteger=withContext(context=Dispatchers.Default,block={Log.e(TAG, "当前所处的线程2:  ${Thread.currentThread().name} ") //当前所处的线程2:  DefaultDispatcher-worker-1Log.e(TAG, "获取 协程在上下文指定的调度器2:${this.coroutineContext}") //获取 协程在上下文指定的调度器2:[DispatchedCoroutine{Active}@4046afc, Dispatchers.Default]BigInteger.probablePrime(4096, Random()) //lambda最后一行结果值作为返回值})return  bigIntegerResult}}

这篇关于补篇协程:协程(Coroutine)里通过挂起suspend函数实现异步IO操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1049023

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

RedHat运维-Linux文本操作基础-AWK进阶

你不用整理,跟着敲一遍,有个印象,然后把它保存到本地,以后要用再去看,如果有了新东西,你自个再添加。这是我参考牛客上的shell编程专项题,只不过换成了问答的方式而已。不用背,就算是我自己亲自敲,我现在好多也记不住。 1. 输出nowcoder.txt文件第5行的内容 2. 输出nowcoder.txt文件第6行的内容 3. 输出nowcoder.txt文件第7行的内容 4. 输出nowcode

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

【操作系统】信号Signal超详解|捕捉函数

🔥博客主页: 我要成为C++领域大神🎥系列专栏:【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞👍收藏⭐评论✍️ 本博客致力于知识分享,与更多的人进行学习交流 ​ 如何触发信号 信号是Linux下的经典技术,一般操作系统利用信号杀死违规进程,典型进程干预手段,信号除了杀死进程外也可以挂起进程 kill -l 查看系统支持的信号

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

java中查看函数运行时间和cpu运行时间

android开发调查性能问题中有一个现象,函数的运行时间远低于cpu执行时间,因为函数运行期间线程可能包含等待操作。native层可以查看实际的cpu执行时间和函数执行时间。在java中如何实现? 借助AI得到了答案 import java.lang.management.ManagementFactory;import java.lang.management.Threa

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

基于Springboot + vue 的抗疫物质管理系统的设计与实现

目录 📚 前言 📑摘要 📑系统流程 📚 系统架构设计 📚 数据库设计 📚 系统功能的具体实现    💬 系统登录注册 系统登录 登录界面   用户添加  💬 抗疫列表展示模块     区域信息管理 添加物资详情 抗疫物资列表展示 抗疫物资申请 抗疫物资审核 ✒️ 源码实现 💖 源码获取 😁 联系方式 📚 前言 📑博客主页:

探索蓝牙协议的奥秘:用ESP32实现高质量蓝牙音频传输

蓝牙(Bluetooth)是一种短距离无线通信技术,广泛应用于各种电子设备之间的数据传输。自1994年由爱立信公司首次提出以来,蓝牙技术已经经历了多个版本的更新和改进。本文将详细介绍蓝牙协议,并通过一个具体的项目——使用ESP32实现蓝牙音频传输,来展示蓝牙协议的实际应用及其优点。 蓝牙协议概述 蓝牙协议栈 蓝牙协议栈是蓝牙技术的核心,定义了蓝牙设备之间如何进行通信。蓝牙协议