Kotlin协程详解——协程取消与超时
目录
一、协程取消
1.取消协程的执行
2.使计算代码可取消
3.在finally中释放资源
4.运行不能取消的代码块
二、协程超时
异步超时与资源管理
一、协程取消
1.取消协程的执行
在一个长时间运行的应用程序中,你也许需要对你的后台协程进行细粒度的控制。 比如说,
一个用户也许关闭了一个启动了协程的界面,那么现在协程的执行结果已经不再被需要了,
这时,它应该是可以被取消的。 该 launch 函数返回了一个可以被用来取消运行中的协程的
Job:
runBlocking {val job = launch {Log.d(TAG,"job: I'm sleeping ...")}delay(100L)Log.d(TAG,"main: I'm tired of waiting!")job.cancel() // 取消该作业job.join() // 等待作业执行结束Log.d(TAG,"main: Now I can quit.")}
一旦 main 函数调用了 job.cancel ,我们在其它的协程中就看不到任何输出,因为它被取消
了。 这里也有一个可以使 Job 挂起的函数 cancelAndJoin 它合并了对 cancel 以及 join 的调用。
2.取消是协作的
协程的取消是协作的。一段协程代码必须协作才能被取消。 所有 kotlinx.coroutines 中的
挂起函数都是 可被取消的 。它们检查协程的取消, 并在取消时抛出 CancellationException。
然而,如果协程正在执行计算任务,并且没有检查取消的话,那么它是不能被取消的,就如
如下示例代码所示:
runBlocking {
//sampleStart
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (i < 5) { // 一个执行计算的循环,只是为了占用 CPU
// 每秒打印消息两次
if (System.currentTimeMillis() >= nextPrintTime) {
println("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // 等待一段时间
println("main: I'm tired of waiting!")
job.cancelAndJoin() // 取消一个作业并且等待它结束
println("main: Now I can quit.")
//sampleEnd
}
运行示例代码,并且我们可以看到它连续打印出了“I'm sleeping”,甚至在调用取消后, 作业
仍然执行了五次循环迭代并运行到了它结束为止。
可以通过捕获CancellationException
而不重新抛出它来观察到相同的问题。
runBlocking {//sampleStartval job = launch(Dispatchers.Default) {repeat(5) { i ->try {Log.d(TAG,"job: I'm sleeping $i ...")delay(500)} catch (e: CancellationException) {Log.d(TAG,"CancellationException")Log.d(TAG,e.toString())}}}delay(1300L) // delay a bitLog.d(TAG,"main: I'm tired of waiting!")job.cancelAndJoin() // cancels the job and waits for its completionLog.d(TAG,"main: Now I can quit.")}
虽然捕获异常(Exception)被视为一种反模式(anti-pattern),但这个问题可能会以更微妙的方式出现,比如在使用runCatching
函数时,该函数不会重新抛出CancellationException
。
为什么取消协程是协作的?
在编程中,特别是在涉及并发和异步操作的上下文中,"协程"(Coroutine)是一种可以暂停和恢复执行的函数或方法。协程允许程序在等待某些操作(如I/O操作)完成时释放执行权,从而允许其他任务运行,这提高了程序的效率和响应性。
当我们说“一段协程代码必须协作才能被取消”时,意味着协程本身需要包含一些机制或代码,以响应外部的取消请求。这不同于传统的线程或进程,后者可以通过操作系统层面的信号或中断直接强制终止。协程的取消需要更加细致和协作的处理,因为协程的运行是在用户态管理的,而不是由操作系统直接控制。
以下是一些关键点,解释了为什么协程的取消需要协作:
-
状态管理:协程可能处于多种状态(如运行中、等待中、已完成等)。要安全地取消协程,需要确保它不会在取消过程中处于不一致的状态。
-
资源清理:协程可能会分配资源(如内存、文件句柄、网络连接等)。取消协程时,需要确保这些资源被适当地释放或回收,以避免资源泄漏。
-
取消点:协程需要在其执行路径上明确设置“取消点”,这些点是检查取消请求的地方。如果在这些点检测到取消请求,协程将停止执行并适当地清理资源。
-
异常处理:取消协程通常通过抛出或传播异常来实现。这意味着协程需要能够捕获并处理这些异常,以避免程序崩溃。
-
用户态控制:由于协程的调度和执行是在用户态进行的,没有操作系统的直接干预,因此取消操作需要协程代码本身的支持和配合。
总之,协程的取消机制依赖于协程内部的协作,这意味着协程需要编写成能够响应取消请求的形式,包括在适当的时候检查取消状态、清理资源、以及适当地处理取消操作引发的异常。这种设计使得协程的取消更加灵活和安全,但同时也要求开发者在编写协程时更加注意取消逻辑的实现。
2.使计算代码可取消
我们有两种方法来使执行计算的代码可以被取消。第一种方法是定期调用挂起函数来检查取
消。对于这种目的 yield 是一个好的选择。 另一种方法是显式的检查取消状态。让我们试试第
二种方法。
将前一个示例中的 while (i < 5) 替换为 while (isActive) 并重新运行它。
runBlocking {//sampleStartval startTime = System.currentTimeMillis()val job = launch(Dispatchers.Default) {var nextPrintTime = startTimevar i = 0while (isActive) { // 可以被取消的计算循环if (System.currentTimeMillis() >= nextPrintTime) {println("job: I'm sleeping ${i++} ...")nextPrintTime += 500L}}}delay(1300L) // 等待一段时间println("main: I'm tired of waiting!")job.cancelAndJoin() // 取消该作业并等待它结束println("main: Now I can quit.")}
你可以看到,现在循环被取消了。isActive 是一个可以被使用在 CoroutineScope 中的扩展属
性。
3.在finally中释放资源
我们通常使用如下的方法处理在被取消时抛出 CancellationException 的可被取消的挂起函数。
比如说, try {……} finally {……} 表达式以及 Kotlin 的 use 函数一般在协程被取消的时候执
行它们的终结动作:
runBlocking {//sampleStartval job = launch {try {repeat(1000) { i ->println("job: I'm sleeping $i ...")delay(500L)}} catch (e:CancellationException){println("CancellationException:"+e.message)} finally {println("job: I'm running finally")}}delay(1300L) // 延迟一段时间println("main: I'm tired of waiting!")job.cancelAndJoin() // 取消该作业并且等待它结束println("main: Now I can quit.")}
join 和 cancelAndJoin 等待了所有的终结动作执行完毕, 所以运行示例得到了下面的输出:
job: I'm sleeping 0 ...
job: I'm sleeping 1 ...
job: I'm sleeping 2 ...
main: I'm tired of waiting!
job: I'm running finally
main: Now I can quit.
4.运行不能取消的代码块
在前一个例子中任何尝试在 finally 块中调用挂起函数的行为都会抛出
CancellationException,因为这里持续运行的代码是可以被取消的。通常,这并不是一个问
题,所有良好的关闭操作(关闭一个文件、取消一个作业、或是关闭任何一种通信通道)通
常都是非阻塞的,并且不会调用任何挂起函数。然而,在真实的案例中,当你需要挂起一个
被取消的协程,你可以将相应的代码包装在 withContext(NonCancellable) {……} 中,并使用
withContext 函数以及 NonCancellable 上下文,见如下示例所示:
runBlocking {//sampleStartval job = launch {try {repeat(1000) { i ->println("job: I'm sleeping $i ...")delay(500L)}} finally {withContext(NonCancellable) {println("job: I'm running finally")delay(1000L)//如果不用withContext,则此句话不会被打印println("job: And I've just delayed for 1 sec because I'm non-cancella ble")}}}delay(1300L) // 延迟一段时间println("main: I'm tired of waiting!")job.cancelAndJoin() // 取消该作业并等待它结束println("main: Now I can quit.")}
关于 Kotlin 协程(Coroutines)中处理取消操作和异常情况的说明:
-
协程和取消操作:在 Kotlin 协程中,协程可以被取消以释放资源或响应超时等情况。当协程被取消时,它会尽可能快地抛出一个
CancellationException
异常来通知调用者或相关代码,当前操作已被取消。 -
finally 块中的挂起函数:在 try-catch-finally 结构中,finally 块用于执行清理操作,无论 try 块中的代码是否成功执行或抛出异常。如果在 finally 块中调用了挂起函数(即一个可能挂起执行的函数,如网络请求或延迟操作),并且此时协程已被取消,那么尝试执行这个挂起函数将会导致
CancellationException
被抛出。 -
为什么通常不是问题:通常,finally 块中的清理操作(如关闭文件、取消作业、关闭通信通道等)都是非阻塞的,意味着它们不需要等待其他操作完成。因此,这些操作通常不会调用挂起函数,从而避免了在协程被取消时抛出
CancellationException
的问题。 -
处理被取消的协程中的挂起函数:然而,在某些情况下,你可能需要在已被取消的协程中执行挂起函数。例如,你可能需要在取消操作时执行一些清理工作,这些工作本身包含挂起操作。为了在这种情况下避免
CancellationException
,Kotlin 协程提供了withContext(NonCancellable) { ... }
结构。 -
withContext(NonCancellable) { ... }:这个函数允许你在一个不会被取消的上下文中执行代码块。这意味着,即使外部协程已被取消,
withContext(NonCancellable) { ... }
内部的代码仍然会执行,而不会抛出CancellationException
。这对于执行必须完成的清理操作特别有用,即使这些操作包含挂起函数。
综上所述,这段话是在说明如何在 Kotlin 协程中处理取消操作和异常,特别是在需要执行挂起函数作为清理操作时,如何使用 withContext(NonCancellable) { ... }
来确保这些操作能够安全执行,而不会因协程被取消而失败。
二、协程超时
在实践中绝大多数取消一个协程的理由是它有可能超时。 当你手动追踪一个相关 Job 的引用
并启动了一个单独的协程在延迟后取消追踪,这里已经准备好使用 withTimeout 函数来做这件
事。 来看看示例代码:
runBlocking {//sampleStarttry {var result = withTimeout(4000L){repeat(1000){i->println("I am sleep $i...")delay(500L)}}Log.d(TAG,"result:"+result.toString())}catch (e:TimeoutCancellationException){Log.d(TAG,"TimeoutCancellationException:"+e.message)}}
withTimeout 抛出了 TimeoutCancellationException ,它是 CancellationException 的子类。 我
们之前没有在控制台上看到堆栈跟踪信息的打印。这是因为在被取消的协程中
CancellationException 被认为是协程执行结束的正常原因。 然而,在这个示例中我们在
main 函数中正确地使用了 withTimeout 。
由于取消只是一个例外,所有的资源都使用常用的方法来关闭。 如果你需要做一些各类使用
超时的特别的额外操作,可以使用类似 withTimeout 的 withTimeoutOrNull 函数,并把这些会
超时的代码包装在 try {...} catch (e: TimeoutCancellationException) {...} 代码块中,而
withTimeoutOrNull 通过返回 null 来进行超时操作,从而替代抛出一个异常:
runBlocking {//sampleStarttry {var result = withTimeoutOrNull(4000L){repeat(1000){i->println("I am sleep $i...")delay(500L)}}Log.d(TAG,"result:"+result.toString())}catch (e:TimeoutCancellationException){Log.d(TAG,"TimeoutCancellationException:"+e.message)}}
运行这段代码时不再抛出异常,输出为:
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
Result is null
异步超时与资源管理
withTimeout
中的超时事件相对于其代码块内运行的代码是异步的,并且可能随时发生,甚至在从超时块内部返回之前立即发生。如果你在该代码块内部打开或获取了一些需要在代码块外部关闭或释放的资源,请牢记这一点。
例如,这里我们使用Resource
类来模拟一个可关闭的资源,该类仅通过递增获取计数器并在其close
函数中递减计数器来跟踪它被创建了多少次。现在,让我们创建大量协程,每个协程在withTimeout
块的末尾创建一个Resource
并在块外部释放该资源。我们添加了一个小的延迟,以便更有可能在withTimeout
块刚好完成时发生超时,这将导致资源泄漏。
这段话是关于Kotlin协程中withTimeout
函数行为的一个重要说明。让我们一步步解析它的含义:
-
withTimeout
中的超时事件是异步的:这意味着超时不是由withTimeout
代码块内部的代码直接控制的。它不是在该代码块执行到某个特定点时触发的,而是由协程调度器根据指定的超时时间来管理的。因此,即使代码块内部的代码正在运行,超时也可能在任何时候发生。 -
可能随时发生,甚至在从超时块内部返回之前立即发生:这句话进一步强调了超时的异步性。它表明,即使代码块内部的代码看起来即将完成并准备返回,超时也可能在返回操作实际发生之前的一瞬间触发。这种情况可能导致一些棘手的问题,特别是当涉及到资源管理时。
-
如果你在代码块内部打开或获取了一些资源:这里提到的“资源”可以是任何需要在使用完毕后关闭或释放的东西,比如文件句柄、数据库连接、网络连接等。在
withTimeout
代码块内部打开或获取这些资源是常见的做法,但你需要意识到超时的异步性可能导致这些资源在未被正确关闭或释放的情况下被遗弃。 -
请牢记这一点:这是一个警告,提醒开发者在使用
withTimeout
时需要特别注意资源管理。由于超时的异步性,你不能简单地假设代码块内部的代码总是会执行到末尾并有机会关闭或释放所有资源。因此,你需要采取额外的措施来确保资源的正确管理,比如使用try-finally
结构来确保资源在发生超时或其他异常时也能被正确关闭或释放。
综上所述,这段话是在强调在使用withTimeout
时需要注意资源管理的异步性和潜在的风险,以及需要采取适当的措施来确保资源的正确管理。
runBlocking {//sampleStartrepeat(10000){launch {var res = withTimeout(60){delay(50)Resource()}res.close()}}}Log.d(TAG,"aq:$aq")class Resource{var aq = 0init{aq++}fun close(){aq--}}
如果你运行上面的代码,你会发现它并不总是打印零,尽管这可能会取决于你机器的时序。你可能需要调整这个示例中的超时时间,以便实际看到非零值。
请注意,这里从10K个协程中对已获取的计数器进行增减操作是完全线程安全的,因为这一操作总是在同一个线程中执行,即runBlocking
所使用的线程。关于这一点的更多信息,将在关于协程上下文的章节中解释。
为了解决这个问题,你可以将资源的引用存储在一个变量中,而不是从withTimeout
块中返回它。
runBlocking {//sampleStartrepeat(10000){launch {var res: Resource? = nulltry {res = withTimeout(60){delay(50)Resource()}}finally {res?.close()}}}}Log.d(TAG,"aq:$aq")class Resource{var aq = 0init{aq++}fun close(){aq--}
}
输出结果一直为0,Resource没有泄露。
推荐文章
取消与超时 · Kotlin 官方文档 中文版
相关文章:
Kotlin协程详解——协程取消与超时
目录 一、协程取消 1.取消协程的执行 2.使计算代码可取消 3.在finally中释放资源 4.运行不能取消的代码块 二、协程超时 异步超时与资源管理 一、协程取消 1.取消协程的执行 在一个长时间运行的应用程序中,你也许需要对你的后台协程进行细粒度的控制。 比如…...
双向链表、内核链表和gdb(20250208)
单向链表 节点 数据域 指针域(后继节点) 双向链表 相比于单项指针,双向指针存有前驱节点的地址,使链表的灵活性更高。 内核链表 在内核中 offsetof:获取结构体某个成员到结构体开头的偏移量container_of:根据结…...
全程Kali linux---CTFshow misc入门(38-50)
第三十八题: ctfshow{48b722b570c603ef58cc0b83bbf7680d} 第三十九题: 37换成1,36换成0,就得到长度为287的二进制字符串,因为不能被8整除所以,考虑每7位转换一个字符,得到flag。 ctfshow{5281…...
MySQL 8.0.41安装教程(2025年2月8号)
下载网址:https://www.mysql.com/cn/downloads/ 点击 我选择的是第二个离线安装 点击之后,选择直接下载: 下载完成双击: 我选择的是自定义安装: 右边默认已经存在我选择的8.0.41 点击红框中的,自定义安装路…...
【自学笔记】Deepseek的基础知识点总览-持续更新
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 Deepseek知识点总览一、Deepseek简介二、Deepseek的三大适用模式1. 基础模型(V3)2. 深度思考(R1)3. 联网搜索模式 三…...
10N10-ASEMI中低压N沟道MOS管10N10
编辑:ll 10N10-ASEMI中低压N沟道MOS管10N10 型号:10N10 品牌:ASEMI 封装:TO-252 最大漏源电流:10A 漏源击穿电压:100V 批号:最新 RDS(ON)Max:135mΩ …...
2025年2月8日(Adafruit_PCA9685详细使用)
Adafruit_PCA9685 是一个 Python 模块,用于与 PCA9685 驱动芯片进行通信,该芯片常用于控制多个伺服电机。PCA9685 是一个 16 通道的 PWM(脉宽调制)驱动器,常用于需要精确控制多个伺服电机的应用。 以下是详细的使用方…...
MR30分布式IO模块:驱动智能制造工厂的工业互联与高效控制新范式
在工业4.0与智能制造浪潮的推动下,传统制造业正经历着从“机械驱动”向“数据驱动”的深刻转型。作为工业数据连接领域的领军者,明达技术凭借其自主研发的MR30分布式IO模块,以创新的技术架构与卓越的性能表现,为全球制造企业构建了…...
Reqable使用实践
一、背景 日常开发中,难免要抓取请求数据,查看接口数据,从而更好定位问题,基于这个原因,查找了一些抓包工具,例如: HttpCanary、 Steam 、Fiddler等,不是要钱,就是只对苹…...
数据可视化基本套路总结
首先从维基百科上搬出数据可视化的概念: 数据可视化是关于数据之视觉表现形式的研究;其中,这种数据的视觉表现形式被定义为一种以某种概要形式抽提出来的信息,包括相应信息单位的各种属性和变量。 用人话简单来说,数据…...
TensorFlow域对抗训练DANN神经网络分析MNIST与Blobs数据集梯度反转层提升目标域适应能力可视化...
全文链接:https://tecdat.cn/?p39656 本文围绕基于TensorFlow实现的神经网络对抗训练域适应方法展开研究。详细介绍了梯度反转层的原理与实现,通过MNIST和Blobs等数据集进行实验,对比了不同训练方式(仅源域训练、域对抗训练等&am…...
DNS劫持和HTTPDNS
DNS 劫持是一种网络攻击手段,攻击者通过篡改域名系统(DNS)解析过程,将用户请求的域名重定向到恶意网站或其他不正确的地址。这种攻击可以用于多种目的,例如窃取用户数据、传播恶意软件或进行钓鱼攻击。 举个例子 假设…...
云原生微服务
能够认识到云原生微服务对应用程序设计的影响,描述无状态微服务,并比较单体和微服务架构。要充分利用运营模式,您需要以不同的方式思考应用程序设计。您需要考虑云原生微服务。此图像显示了一个应用程序,该应用程序被设计为小型微…...
【deepSeek R1】Ollama 更改模型安装位置 以及应用安装位置
【deepSeek R1】Ollama 更改模型安装位置 以及应用安装位置 本地版部署deepSeek R1 可以参考文章 3分钟教你搭建属于自己的本地大模型 DeepSeek R1 Ollama 是一个开源工具,旨在帮助用户轻松在本地计算机上运行、部署和管理大型语言模型(LLMs)…...
windows + visual studio 2019 使用cmake 编译构建静、动态库并调用详解
环境 windows visual studio 2019 visual studio 2019创建cmake工程 1. 静态库.lib 1.1 静态库编译生成 以下是我创建的cmake工程文件结构,只关注高亮文件夹部分 libout 存放编译生成的.lib文件libsrc 存放编译用的源代码和头文件CMakeLists.txt 此次编译CMak…...
使用Feign代替RestTemplet
Feign RestTemplet存在的问题 String url "http: //userservice/user/" order.getUserId(); User user restTemplate.getFor0bject(url, User.class);可读性差参数复杂URL难以维护 Feign声明式的Http客户端,官方地址:https://github.com…...
苹果笔记本安装jmeter
下载并安装jmeter即可,jmeter官网下载地址:Apache JMeter - Download Apache JMeter 参考以下文章:“https://blog.csdn.net/weixin_51664828/article/details/145008755”...
设备通过国标GB28181接入EasyCVR,显示在线但视频无法播放的原因排查
安防监控EasyCVR平台支持多种视频源接入,包括但不限于IP摄像头、NVR、编码器、流媒体服务器等。平台采用高效的视频流接入技术,支持大规模视频流的并发接入,确保视频流的稳定性和流畅性。 有用户反馈,项目现场使用国标GB28181接入…...
为什么我喜欢在 CSS 中使用 RegEx
说到正则(RegEx),我们第一反应往往是“在编程中用来匹配或验证字符串”,比如做表单验证。但其实在 CSS 中,也能用到与正则类似的选择器特性,为我们的样式管理带来诸多便利。别怀疑,以下就是如何…...
深度剖析 Redisson 分布式锁:原理、实现与应用实践
文章目录 写在文章开头详解Redisson 分布式锁使用和实现前置准备工作分布式锁的基本使用公平锁的使用联锁的使用读写锁基本使用常见问题Redisson和Jedis有什么区别redisson如何实现分布式锁redisson如何实现分布式锁的可重入redisson如何实现公平锁Redisson的watchdog机制是什么…...
今日AI和商界事件(2025-02-08)
今日AI领域的重大事件主要包括以下几个方面: 一、DeepSeek引发的行业震动 事件概述:DeepSeek作为近期崛起的AI模型,以其低成本、高性能的推理能力引发了广泛关注。其开源策略、独特的出身以及强大的算力表现,使得微软、英伟达等…...
Mac 基于Ollama 本地部署DeepSeek离线模型
最近节日期间最火的除了《哪吒》就是deepseek了,毕竟又让西方各个层面都瑟瑟发抖的产品。DeepSeek凭借其强大的AI能力真的是在全球多个领域展现出强大的影响力。由于受到外部势力的恶意攻击倒是deepseek官方服务不稳定,国内其他厂家的适配版本也不是很稳…...
Python截图轻量化工具
这是用Python做到截图工具,不过由于使用了ctypes调用了Windows的API, 同时访问了Windows中"C:/Windows/Cursors/"中的.cur光标样式文件, 这个工具只适用于Windows环境; 如果要提升其跨平台性的话,需要考虑替换ctypes的一些专属于W…...
怎麼在Chrome中設置代理伺服器?
出於隱私、安全或者訪問特定網路資源的需求,設置代理伺服器顯得尤為重要。本文將詳細介紹如何在Chrome流覽器中進行代理伺服器的設置。 代理伺服器是介於電腦和互聯網之間的一道“中間牆”。幫助間接訪問互聯網資源,這樣實際的IP地址被代理伺服器的IP地…...
【数据结构中链表常用的方法实现过程】
线性表 线性表包括:顺序表、链表、栈,队列等,本节我们先学习顺序表。 顺序表 利用新的数据类型——顺序表,操作数组 顺序表的本质就是对数组的增删改查。 /*** 打印顺序表中的所有元素*/Overridepublic void display() {for (int i 0; i…...
语言月赛 202308【小粉兔处理题解审核志愿者轮换】题解(AC)
》》》点我查看「视频」详解》》》 [语言月赛 202308] 小粉兔处理题解审核志愿者轮换 题目背景 又到了一周的周日,扶苏又像催命一样开始催促小粉兔处理题解审核志愿者的轮换。但是懒狗小粉兔总是把这项工作拖到第二天凌晨。 【这里有一张内部群聊图,…...
第二十二章:游戏结缘与现实的相遇
“终于结束了……” 小冷的手微微颤抖,笔在纸上划过,签下放弃 985 高校研究生入学资格的名字,那一刻,数月来压在心头沉甸甸的巨石轰然崩塌,扬起的尘埃渐渐消散。曾经,学术巅峰犹如夜空中遥不可及却又熠熠生…...
(ICLR=2025)生成的表征对齐:训练扩散Transformer比你想象的更简单
生成的表征对齐:训练扩散Transformer比你想象的更简单 paper是KAIST发表在ICLR 2025的工作 paper title:REPRESENTATION ALIGNMENT FOR GENERATION: TRAINING DIFFUSION TRANSFORMERS IS EASIER THAN YOU THINK Code:链接 ABSTRACT 最近的研究表明&…...
保姆级教程--DeepSeek部署
以DeepSeek-R1或其他类似模型为例,涵盖环境配置、代码部署和运行测试的全流程: 准备工作 1. 注册 Cloud Studio - 访问 [Cloud Studio 官网](https://cloudstudio.net/),使用腾讯云账号登录。 - 完成实名认证(如需长期使用…...
[css] 黑白主题切换
link动态引入 类名切换 css滤镜 var 类名切换 v-bind css预处理器mixin类名切换 【前端知识分享】CSS主题切换方案...
C语言练习题
文章目录 1. 递归实现将字符串str中的元素逆序2. 对数组arr进行冒泡排序(升序)3. 对数组从下标low到下标hihg区间内的元素进行快速排序(升序)4. 在数组中利用二分查找(折半查找)目标关键字5. 求n的阶乘6. 判断year是否为闰年7. 求…...
Lambda 表达式
一、Lambda 表达式简介 Lambda 表达式是一种简洁的函数式编程方式,用于实现只有一个方法的接口(例如函数式接口)。 基本语法 (parameters) -> expression (parameters) -> { statements; } 参数:可以有零个或多个参数。…...
Vue 鼠标事件合集,关于鼠标右键的处理方法(改写鼠标右键方法、自定义鼠标右键)
鼠标事件使用 mousedown"canvasDown($event)"按下事件合集 click 点击某个对象时触发 mousedown 鼠标按钮被按下时触发 mouseup 鼠标按钮被松开时触发 mouseleave 当鼠标指针移出元素时触发 dblclick 双击时触发 mousemove 鼠标移动时触发,…...
go语言中的接口
接口简介 现实生活中的接口 现实生活中手机、相机、U 盘都可以和电脑的 USB 接口建立连接。我们不需要关注 usb 卡槽大小是否一样,因为所有的 USB 接口都是按照统一的标准来设计的。 Golang 中的接口(interface) Golang 中的接口是一种抽象…...
如何在Android Studio中开发一个简单的Android应用?
Android Studio是开发Android应用的官方集成开发环境(IDE),它提供了许多强大的功能,使得开发者能够高效地创建Android应用。如果你是Android开发的初学者,本文将引导你如何在Android Studio中开发一个简单的Android应用…...
启明星辰发布MAF大模型应用防火墙产品,提升DeepSeek类企业用户安全
2月7日,启明星辰面向DeepSeek等企业级大模型业务服务者提供的安全防护产品——天清MAF(Model Application Firewall)大模型应用防火墙产品正式发布。 一个新赛道将被开启…… DeepSeek的低成本引爆赛道规模 随着DeepSeek成为当前最热的现象级…...
开箱即用的.NET MAUI组件库 V-Control 发布了!
之前写过挺多的MAUI Sample,其中有很多代码可以打包成组件,当组件完善到一定程度,我会把控件封装起来放到控件库中。 今天,在这个仓库建立一年零八个月后,我觉得可以考虑将其作为开源库发布。 有很多网友在观望.NET …...
android skia渲染介绍
Android AOSP 的渲染系统主要使用 Skia 图形库。Skia 是一个开源的 2D 图形库,它被广泛应用于 Android 的图形渲染中,负责绘制 UI 元素、文本、图像以及其他 2D 图形内容。 以下是 Android AOSP 中 Skia 的作用和它在渲染系统中的位置: 1. 什…...
MySQL的底层原理与架构
前言 了解MySQL的架构和原理对于很多的后续很多的操作会有很大的帮助与理解。并且很多知识都与底层架构相关联。 了解MySQL架构 通过上面的架构图可以得知,Server层中主要由 连接器、查询缓存、解析器/分析器、优化器、执行器 几部分组成的,下面将主要…...
GB/T 43698-2024 《网络安全技术 软件供应链安全要求》标准解读
一、43698-2024标准图解 https://mmbiz.qpic.cn/sz_mmbiz_png/rwcfRwCticvgeBPR8TWIPywUP8nGp4IMFwwrxAHMZ9Enfp3wibNxnfichT5zs7rh2FxTZWMxz0je9TZSqQ0lNZ7lQ/640?wx_fmtpng&fromappmsg 标准在线预览: 国家标准|GB/T 43698-2024 相关标准: &a…...
Vue(4)
一.组件的三大组成部分-注意点说明 (1)scoped样式冲突 默认情况:写在组件中的样式会全局生效 → 因此很容易造成多个组件之间的样式冲突 ①全局样式:默认组件中的样式会作用到全局 ②局部样式:可以给组件加上scoped属…...
实验3 词法分析(二)
实验3 词法分析(二) [实验目的]: 1 . 熟悉给定的词法分析程序; 2 . 改进词法分析程序。 [实验内容]: 1.尝试多方面改进TEST语言的文法,参考教材附录B词法分析程序TESTscan.c,在此词法分析程序的基础上改进程序&#x…...
MYSQL第四次
目录 题目分析 代码实现 一、修改 Student 表中年龄(sage)字段属性,数据类型由 int 改变为 smallint 二、为 Course 表中 Cno 字段设置索引,并查看索引 三、为 SC 表建立按学号(sno)和课程号ÿ…...
CentOS 7配置samba服务设置文件共享
CentOS 7配置samba服务设置文件共享 一、生成另一个Linux系统,名为Linux-client,作为测试系统。 [rootliunx-client ~]# hostnamectl set-hostname Liunx-client二、如果没有则安装Samba服务,如果已经安装则省略此步。 yum install samba…...
分布式微服务系统架构第91集:系统性能指标总结
加群联系作者vx:xiaoda0423 仓库地址:https://webvueblog.github.io/JavaPlusDoc/ 系统性能指标总结 系统性能指标包括哪些? 业务指标、资源指标、中间件指标、数据库指标、前端指标、稳定性指标、批量处理指标、可扩展性指标、可靠性指标。 …...
【算法】动态规划专题⑦ —— 多重背包问题 + 二进制分解优化 python
目录 前置知识进入正题优化方法:二进制分解实战演练 前置知识 【算法】动态规划专题⑤ —— 0-1背包问题 滚动数组优化 python 【算法】动态规划专题⑥ —— 完全背包问题 python 进入正题 多重背包问题I https://www.acwing.com/problem/content/4/ 题目描述 有…...
Node.js学习指南
一、模块化规范 nodejs使用的模块化规范 叫做 common.js 规范: 每一个模块都有独立的作用域 代码在各自模块中执行 不会造成全局污染 每一个模块都是一个独立的文件(module对象) 模块可以被多次加载(module.exports 属性) 但是仅…...
Mybatis篇
1,什么是Mybatis ( 1 )Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁…...
微信小程序案例1——制作猫眼电影底部标签导航栏
文章目录 一、项目步骤1 新建一个无AppID的movie项目2将准备好的底部标签导航图标拷贝到movie项目下面(将图标文件夹image放到项目文件夹里)3 打开App.json配置文件,在pages数组里添加4个页面路径:电影“pages/movie/movie”、影院“pages/cinema/cinema…...
Docker 数据卷(Volume)详细介绍
Docker 数据卷(Volume)详细介绍 1. 什么是 Docker 数据卷? Docker 数据卷(Volume)是一种用于 持久化数据 和 容器间数据共享 的机制。由于容器的存储是临时的,容器删除后其中的数据会丢失,因此…...