补篇协程:协程(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操作完成,我们使用
Handler的post方法将一个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 的 关键。
挂起函数 原理:
挂起函数必须在一个协程上下文中执行,通常是通过
launch、async等协程构建器创建的。此外,挂起函数只能被其他挂起函数或协程调用,以确保正确的执行顺序和线程安全性。挂起函数通过非阻塞性和协作式调度的原理,实现了在 Kotlin 协程中执行异步 IO 操作的高效流程。它们允许代码以同步的方式编写,而实际上却是在底层执行异步操作,从而简化了异步编程的复杂性。❶非阻塞性:挂起函数允许协程在遇到耗时的操作时(IO 操作), 而不会阻塞当前(主)线程。这使得(主)线程可以继续执行其他任务,从而提高了整体的并发性能。
❷协作式调度:协程不是由操作系统来调度的,而是由用户代码(或者库代码)来显式地调度和挂起。挂起函数是这种协作式调度的关键部分。当这个挂起函数被调用执行时,它会暂停当前协程的执行,并释放当前(主)线程的控制权。当异步操作完成或条件满足时,协程会恢复执行,恢复对当前(主)线程的控制权。
❸轻量级:由于挂起函数并不涉及线程的切换,因此它们相比于传统的线程或回调机制更加轻量级。这减少了系统资源的消耗,提高了程序的性能。
2.协程构建器(Coroutine Builder):
Kotlin 标准库提供了多个协程构建器,如 launch、async 和 runBlocking 等。这些构建器用于创建协程并启动它们的执行。
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.launch 或 viewModelScope.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 对象来管理协程的生命周期。launch 和 async 构建器都会返回一个 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操作
异步IO的概念 异步IO是一种非阻塞的数据读写方法,异步IO与同步IO相对。 当一个异步过程调用发出后,调用者不能立刻得到结果。 实际的IO处理部件在完成操作后,会通过状态、通知或回调机制来通知调用者。 在一个CPU密集型的应用中,…...
qmt量化交易策略小白学习笔记第16期【qmt编程之获取北向南向资金(沪港通,深港通和港股通)】
qmt编程之获取北向南向资金 qmt更加详细的教程方法,会持续慢慢梳理。 也可找寻博主的历史文章,搜索关键词查看解决方案 ! 北向南向资金(沪港通,深港通和港股通) #北向南向资金交易日历 获取交易日列表…...
开源项目学习——vnote
一、介绍 vnote是一款免费且开源的markdown编辑器,用C开发,基于Qt框架,windows/linux/mac都能用。 二、编译 $ git clone --recursive https://github.com/vnotex/vnote.git $ cd vnote && mkdir build $ cd build $ cmake ../ $ …...
5_1 Linux 计划任务
5_1 Linux 计划任务 文章目录 5_1 Linux 计划任务[toc]1. crontab 命令2. 计划任务书写格式 用途:按照设置的时间间隔,为用户反复执行某一固定的系统任务 软件包:cronie、crontabs 系统服务:crond 日志文件:/var/log/c…...
接口框架项目实战-pytest(六)csv数据驱动
csv 数据驱动 为了解决数据量大 导致yaml文件重复太多 yaml_util.py import osimport jsonpath import yamlfrom pytestdemo.common.base_util import get_path from pytestdemo.common.csv_util import analysis_parametersdef read_config_file(one_node,two_node):with ope…...
【Apache Doris】周FAQ集锦:第 5 期
【Apache Doris】周FAQ集锦:第 5 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目! 在这个栏目中,每周将筛选社区反馈的热门问题和话题,重点回答并进行深入探讨。旨在为广大用户和…...
再读高考作文题
新课标I卷:讨论了随着互联网和人工智能的普及,问题是否会变得越来越少,要求考生写一篇文章,表达自己对于这一现象的联想和思考。 从来就没有什么救世主 AI也不是 一直不会写作文,直到高中,才堪堪…...
小程序中实现自定义头部导航组件
在页面中实现自定义头部导航的组件,如果仅是单个页面中需要自定义可在页面的json文件中配置"navigationStyle": “custom”,如果是项目中所有页面都想使用自定义的组件,可在app.json的window中全局配置"navigationStyle"…...
算数运算符与表达式(打印被10整除的数)
打印100以内(包含100)能被10整除的正整数 #include <stdio.h>#define UPPER 100int main() {int i 1;while (i < UPPER)if (i % 10 0)printf("%d\n", i);return 0; } 自增运算符 i 用于递增变量 i 的值。在 while 循环中…...
kv视频如何转码mp4格式,kv转换mp4最简单方法
在数字化时代,视频格式转换成为了一项日常需求。有时候我们需要把kv格式转换为MP4格式。下面将详细介绍kv转MP4的方法 方法一、 1、使用 "小白兔视频格式在线转换网站" 2、地址发给"小白兔视频格式在线转换网站"的客服,客服下载即可…...
哈夫曼树详解
哈夫曼树 例题 有n堆果子,每堆果子的质量已知,现在需要把这些果子合并成一堆,但是每次只能把两堆果子合并到一起,同时会消耗与两堆果子质量之和等值的体力。显然,在进行n-1次合并之后,就只剩下一堆了。为…...
LangChain4j实战
基础 LangChain4j模型适配: Provider Native Image Sync Completion Streaming Completion Embedding Image Generation Scoring Function Calling OpenAI ✅ ✅ ✅ ✅ ✅ ✅ Azure OpenAI ✅ ✅ ✅ ✅ ✅ Hugging Face ✅ ✅ Amazon Bedrock ✅ ✅…...
57.Semaphore信号量
用来限制能同时访问共享资源的线程上限。只是适合限制单机线程数量。 Slf4j public class SemaphoreDemo {public static void main(String[] args) {Semaphore semaphore new Semaphore(3);for (int i 0; i < 10; i) {new Thread(() -> {try {semaphore.acquire();//…...
生成式人工智能 - 文本反转(Textual Inversion):一种微调稳定扩散模型的方法
一、简述 大型文本到图像稳定扩散模型已经展示了前所未有的能力,可以使用文本提示合成新场景。这些文本到图像模型提供了通过自然语言指导创作的自由。然而,它们的使用受到用户描述特定或独特场景、艺术创作或新实体产品的能力的限制。很多时候,用户被限制行使她的艺术自由来…...
minio的一个基础使用案例:用户头像上传
文章目录 一、minio下载安装(Windows)二、案例需求分析三、后端接口开发 一、minio下载安装(Windows) 1. 下载minio服务端和客户端 minio下载地址 2. 手动搭建目录 /minio/binmc.exeminio.exe/data/logs手动创建minio应用程序目…...
Linux用户和用户组的管理
目录 前言一、系统环境二、Linux用户组的管理2.1 新增用户组2.2 删除用户组2.3 修改用户组2.4 查看用户组 三、Linux用户的管理3.1 新增用户3.2 删除用户3.3 修改用户3.4 查看用户3.5 用户口令(密码)的管理 总结 前言 本篇文章介绍如何在Linux系统上实现…...
项目-五子棋双人对战:游戏房间的管理(5)
完整代码见: 邹锦辉个人所有代码: 测试仓库 - Gitee.com 之前我们已经实现了玩家匹配的功能, 我们都知道, 匹配完过后就可以进入游戏房间进行对战了, 所以我们下一步关注的重点就是对于游戏房间的管理. 模块详细讲解 功能需求 通过匹配的方式, 自动给玩家加入到一个游戏房间…...
LocalDate和Date有什么区别?两者如何转换?
LocalDate与Date 在Java中,LocalDate和Date是用来处理日期的两种不同的类。 区别: Date是Java早期的日期类,它包含了日期和时间的信息。但是在Java 8之后,Date类被标记为过时的,推荐使用新的日期时间API,…...
铝合金货物运输鉴定书办理 货物危险性鉴定
货物运输鉴定书/货物危险性鉴定 项目背景: 为了运输的安全,航空运输、公路运输、铁道运输、水路运输都必须了解货物的运输危险性。货物运输条件鉴定就是对货物的运输适宜性作出评价和建议。 货物运输条件鉴定一般依据IATA危险货物规章(DGR)2005、联合国危…...
php操作数据库
<?php session_start(); #面向过程 function create_connection(){ $conn mysqli_connect(127.0.0.1,root,123456,learn_2) or die("数据库连接失败"); mysqli_query($conn,"set names utf8"); return $conn; } #面向对象 function create_connection…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
高效的后台管理系统——可进行二次开发
随着互联网技术的迅猛发展,企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心,成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统,它不仅支持跨平台应用,还能提供丰富…...
aurora与pcie的数据高速传输
设备:zynq7100; 开发环境:window; vivado版本:2021.1; 引言 之前在前面两章已经介绍了aurora读写DDR,xdma读写ddr实验。这次我们做一个大工程,pc通过pcie传输给fpga,fpga再通过aur…...
