当前位置: 首页 > news >正文

【Kotlin】协程的字节码原理

前言

协程是Koltin语言最重要的特性之一,也是最难理解的特性。网上关于kotlin协程的描述也是五花八门,有人说它是轻量级线程,有人说它是无阻塞式挂起,有人说它是一个异步框架等等,众说纷芸。甚至还有人出了书籍专门介绍kotlin协程。

笔者刚开始接触这个概念也是一头雾水:什么叫轻量级线程?难道它是一个操作系统级别的任务调度器吗?闻所未闻呀。

后来才知道协程它其实不是线程,它只是一个语言层面的东西,确切地讲它是一个轻量级的线程框架,主要功能是可以实现简洁的线程切换,避免了直接使用Thread导致的回调地狱。也可以说它用同步的方式实现异步操作。

看别人怎么介绍,还不如亲眼看一看协程的字节码,其实没那么难。

在这里插入图片描述
笔者原创,转载请注明来源:https://blog.csdn.net/devnn/article/details/135610313

协程字节码

在MainActivity的onCreate中写一段协程的代码:

lifecycleScope.launchWhenResumed {Log.i("MainActivity", "launchWhenResumed,isMainThread:${Thread.currentThread().id == Looper.getMainLooper().thread.id}")//这里打印trueLog.i("MainActivity", "launchWhenResumed,threadId:${Thread.currentThread().id}")//这里threadId打印2也就是主线程//以下两个代码块是串行执行的withContext(Dispatchers.Main) {Thread.sleep(10000)Log.i("MainActivity", "launchWhenResumed,withContext1,threadId:${Thread.currentThread().id}")}withContext(Dispatchers.IO) {Log.i("MainActivity", "launchWhenResumed,withContext2,threadId:${Thread.currentThread().id}")}}

笔者用lifecycleScope创建了一个协程,用其它方式创建也是一样的,比如MainScope()、GlobalScope、viewModelScope等等,这些方式的区别不是本文介绍的重点。

以上代码的字节码内容如下:

 L33LINENUMBER 126 L33ALOAD 0CHECKCAST androidx/lifecycle/LifecycleOwnerINVOKESTATIC androidx/lifecycle/LifecycleOwnerKt.getLifecycleScope (Landroidx/lifecycle/LifecycleOwner;)Landroidx/lifecycle/LifecycleCoroutineScope;NEW com/devnn/demo/MainActivity$onCreate$6DUPACONST_NULLINVOKESPECIAL com/devnn/demo/MainActivity$onCreate$6.<init> (Lkotlin/coroutines/Continuation;)VCHECKCAST kotlin/jvm/functions/Function2INVOKEVIRTUAL androidx/lifecycle/LifecycleCoroutineScope.launchWhenResumed (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/Job;POP

协程代码块被封装成了一个匿名内部类,匿名内部类继承了SuspendLambda(它实现了Continuation接口),同时实现了Function2接口,匿名内部类的构造方法需要一个Continuation参数,以上传null。

这个匿名内部类com/devnn/demo/MainActivity\$onCreate\$6.class内容如下:

final class com.devnn.demo.MainActivity$onCreate$6 extends kotlin.coroutines.jvm.internal.SuspendLambda implements kotlin.jvm.functions.Function2<kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>, java.lang.Object> {int label;com.devnn.demo.MainActivity$onCreate$6(kotlin.coroutines.Continuation<? super com.devnn.demo.MainActivity$onCreate$6>);Code:0: aload_01: iconst_22: aload_13: invokespecial #13                 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V6: returnpublic final java.lang.Object invokeSuspend(java.lang.Object);Code:0: invokestatic  #39                 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;3: astore_24: aload_05: getfield      #43                 // Field label:I8: tableswitch   { // 0 to 20: 361: 1342: 176default: 186}36: aload_137: invokestatic  #49                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V40: ldc           #51                 // String MainActivity42: ldc           #53                 // String launchWhenResumed,isMainThread:44: invokestatic  #59                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;47: invokevirtual #63                 // Method java/lang/Thread.getId:()J50: invokestatic  #69                 // Method android/os/Looper.getMainLooper:()Landroid/os/Looper;53: invokevirtual #72                 // Method android/os/Looper.getThread:()Ljava/lang/Thread;56: invokevirtual #63                 // Method java/lang/Thread.getId:()J59: lcmp60: ifne          6763: iconst_164: goto          6867: iconst_068: invokestatic  #78                 // Method kotlin/coroutines/jvm/internal/Boxing.boxBoolean:(Z)Ljava/lang/Boolean;71: invokestatic  #84                 // Method kotlin/jvm/internal/Intrinsics.stringPlus:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;74: invokestatic  #89                 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I77: pop78: ldc           #51                 // String MainActivity80: ldc           #91                 // String launchWhenResumed,threadId:82: invokestatic  #59                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;85: invokevirtual #63                 // Method java/lang/Thread.getId:()J88: invokestatic  #95                 // Method kotlin/coroutines/jvm/internal/Boxing.boxLong:(J)Ljava/lang/Long;91: invokestatic  #84                 // Method kotlin/jvm/internal/Intrinsics.stringPlus:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;94: invokestatic  #89                 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I97: pop98: invokestatic  #101                // Method kotlinx/coroutines/Dispatchers.getMain:()Lkotlinx/coroutines/MainCoroutineDispatcher;101: checkcast     #103                // class kotlin/coroutines/CoroutineContext104: new           #105                // class com/devnn/demo/MainActivity$onCreate$6$1107: dup108: aconst_null109: invokespecial #107                // Method com/devnn/demo/MainActivity$onCreate$6$1."<init>":(Lkotlin/coroutines/Continuation;)V112: checkcast     #7                  // class kotlin/jvm/functions/Function2115: aload_0116: checkcast     #109                // class kotlin/coroutines/Continuation119: aload_0120: iconst_1121: putfield      #43                 // Field label:I124: invokestatic  #115                // Method kotlinx/coroutines/BuildersKt.withContext:(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;127: dup128: aload_2129: if_acmpne     139132: aload_2133: areturn134: aload_1135: invokestatic  #49                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V138: aload_1139: pop140: invokestatic  #119                // Method kotlinx/coroutines/Dispatchers.getIO:()Lkotlinx/coroutines/CoroutineDispatcher;143: checkcast     #103                // class kotlin/coroutines/CoroutineContext146: new           #121                // class com/devnn/demo/MainActivity$onCreate$6$2149: dup150: aconst_null151: invokespecial #122                // Method com/devnn/demo/MainActivity$onCreate$6$2."<init>":(Lkotlin/coroutines/Continuation;)V154: checkcast     #7                  // class kotlin/jvm/functions/Function2157: aload_0158: checkcast     #109                // class kotlin/coroutines/Continuation161: aload_0162: iconst_2163: putfield      #43                 // Field label:I166: invokestatic  #115                // Method kotlinx/coroutines/BuildersKt.withContext:(Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;169: dup170: aload_2171: if_acmpne     181174: aload_2175: areturn176: aload_1177: invokestatic  #49                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V180: aload_1181: pop182: getstatic     #128                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;185: areturn186: new           #130                // class java/lang/IllegalStateException189: dup190: ldc           #132                // String call to 'resume' before 'invoke' with coroutine192: invokespecial #135                // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V195: athrowpublic final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);Code:0: new           #2                  // class com/devnn/demo/MainActivity$onCreate$63: dup4: aload_25: invokespecial #145                // Method "<init>":(Lkotlin/coroutines/Continuation;)V8: checkcast     #109                // class kotlin/coroutines/Continuation11: areturnpublic final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>);Code:0: aload_01: aload_12: aload_23: invokevirtual #151                // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;6: checkcast     #2                  // class com/devnn/demo/MainActivity$onCreate$69: getstatic     #128                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;12: invokevirtual #153                // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;15: areturnpublic java.lang.Object invoke(java.lang.Object, java.lang.Object);Code:0: aload_01: aload_12: checkcast     #159                // class kotlinx/coroutines/CoroutineScope5: aload_26: checkcast     #109                // class kotlin/coroutines/Continuation9: invokevirtual #161                // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;12: areturn
}

这个匿名内部类只有一个字段就是int类型的label。同时它的主要业务逻辑代码在invokeSuspend函数中,这个函数里面有一个tableswitch的判断,根据label的值,判断跳转到哪一块代码执行。看这个有点类似有限状态机。

Function2接口内容:

public interface Function2<in P1, in P2, out R> : Function<R> {/** Invokes the function with the specified arguments. */public operator fun invoke(p1: P1, p2: P2): R
}

MainActivity的协程中有两段withContext{}代码块,它们也被封装成了匿名内部类,这个匿名内部类跟外部的协程代码块一样,继承了SuspendLambda类,同时实现了Function2接口。

第一个withContext代码块的匿名内部类是com/devnn/demo/MainActivity\$onCreate\$6\$1.class

第二个withContext代码块的匿名内部类是com/devnn/demo/MainActivity\$onCreate\$6\$2.class

转载请注明来源:
https://blog.csdn.net/devnn/article/details/135610313

com/devnn/demo/MainActivity\$onCreate\$6\$1.class的内容如下:

final class com.devnn.demo.MainActivity$onCreate$6$1 extends kotlin.coroutines.jvm.internal.SuspendLambda implements kotlin.jvm.functions.Function2<kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super java.lang.Integer>, java.lang.Object> {int label;com.devnn.demo.MainActivity$onCreate$6$1(kotlin.coroutines.Continuation<? super com.devnn.demo.MainActivity$onCreate$6$1>);Code:0: aload_01: iconst_22: aload_13: invokespecial #13                 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V6: returnpublic final java.lang.Object invokeSuspend(java.lang.Object);Code:0: invokestatic  #37                 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;3: pop4: aload_05: getfield      #41                 // Field label:I8: tableswitch   { // 0 to 00: 28default: 61}28: aload_129: invokestatic  #47                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V32: ldc2_w        #48                 // long 10000l35: invokestatic  #55                 // Method java/lang/Thread.sleep:(J)V38: ldc           #57                 // String MainActivity40: ldc           #59                 // String launchWhenResumed,withContext1,threadId:42: invokestatic  #63                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;45: invokevirtual #67                 // Method java/lang/Thread.getId:()J48: invokestatic  #73                 // Method kotlin/coroutines/jvm/internal/Boxing.boxLong:(J)Ljava/lang/Long;51: invokestatic  #79                 // Method kotlin/jvm/internal/Intrinsics.stringPlus:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;54: invokestatic  #84                 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I57: invokestatic  #88                 // Method kotlin/coroutines/jvm/internal/Boxing.boxInt:(I)Ljava/lang/Integer;60: areturn61: new           #90                 // class java/lang/IllegalStateException64: dup65: ldc           #92                 // String call to 'resume' before 'invoke' with coroutine67: invokespecial #95                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V70: athrowpublic final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);Code:0: new           #2                  // class com/devnn/demo/MainActivity$onCreate$6$13: dup4: aload_25: invokespecial #102                // Method "<init>":(Lkotlin/coroutines/Continuation;)V8: checkcast     #104                // class kotlin/coroutines/Continuation11: areturnpublic final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super java.lang.Integer>);Code:0: aload_01: aload_12: aload_23: invokevirtual #110                // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;6: checkcast     #2                  // class com/devnn/demo/MainActivity$onCreate$6$19: getstatic     #116                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;12: invokevirtual #118                // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;15: areturnpublic java.lang.Object invoke(java.lang.Object, java.lang.Object);Code:0: aload_01: aload_12: checkcast     #124                // class kotlinx/coroutines/CoroutineScope5: aload_26: checkcast     #104                // class kotlin/coroutines/Continuation9: invokevirtual #126                // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;12: areturn
}

com.devnn.demo.MainActivity$onCreate$6$2的内容如下:

final class com.devnn.demo.MainActivity$onCreate$6$2 extends kotlin.coroutines.jvm.internal.SuspendLambda implements kotlin.jvm.functions.Function2<kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>, java.lang.Object> {int label;com.devnn.demo.MainActivity$onCreate$6$2(kotlin.coroutines.Continuation<? super com.devnn.demo.MainActivity$onCreate$6$2>);Code:0: aload_01: iconst_22: aload_13: invokespecial #13                 // Method kotlin/coroutines/jvm/internal/SuspendLambda."<init>":(ILkotlin/coroutines/Continuation;)V6: returnpublic final java.lang.Object invokeSuspend(java.lang.Object);Code:0: invokestatic  #37                 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;3: pop4: aload_05: getfield      #41                 // Field label:I8: tableswitch   { // 0 to 00: 28default: 56}28: aload_129: invokestatic  #47                 // Method kotlin/ResultKt.throwOnFailure:(Ljava/lang/Object;)V32: ldc           #49                 // String MainActivity34: ldc           #51                 // String launchWhenResumed,withContext2,threadId:36: invokestatic  #57                 // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;39: invokevirtual #61                 // Method java/lang/Thread.getId:()J42: invokestatic  #67                 // Method kotlin/coroutines/jvm/internal/Boxing.boxLong:(J)Ljava/lang/Long;45: invokestatic  #73                 // Method kotlin/jvm/internal/Intrinsics.stringPlus:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;48: invokestatic  #78                 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I51: pop52: getstatic     #84                 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;55: areturn56: new           #86                 // class java/lang/IllegalStateException59: dup60: ldc           #88                 // String call to 'resume' before 'invoke' with coroutine62: invokespecial #91                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V65: athrowpublic final kotlin.coroutines.Continuation<kotlin.Unit> create(java.lang.Object, kotlin.coroutines.Continuation<?>);Code:0: new           #2                  // class com/devnn/demo/MainActivity$onCreate$6$23: dup4: aload_25: invokespecial #98                 // Method "<init>":(Lkotlin/coroutines/Continuation;)V8: checkcast     #100                // class kotlin/coroutines/Continuation11: areturnpublic final java.lang.Object invoke(kotlinx.coroutines.CoroutineScope, kotlin.coroutines.Continuation<? super kotlin.Unit>);Code:0: aload_01: aload_12: aload_23: invokevirtual #106                // Method create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;6: checkcast     #2                  // class com/devnn/demo/MainActivity$onCreate$6$29: getstatic     #84                 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;12: invokevirtual #108                // Method invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;15: areturnpublic java.lang.Object invoke(java.lang.Object, java.lang.Object);Code:0: aload_01: aload_12: checkcast     #114                // class kotlinx/coroutines/CoroutineScope5: aload_26: checkcast     #100                // class kotlin/coroutines/Continuation9: invokevirtual #116                // Method invoke:(Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;12: areturn
}

每次执行新的匿名内部类代码(就是withContext代码块)时,就把当前这个匿名内部类传递给了新的匿名内部类。注意每个匿名内部类都是Continuation的实现。看到这里就知道其实Continuation就是一个回调。这其实就跟Java的回调一样,只是Kotlin隐式地实现了回调,并且加了状态机机制。每次执行一段suspend代码之后,将状态值修改成新值,执行回调时就知道走哪一段代码块。

转载请注明来源:
https://blog.csdn.net/devnn/article/details/135610313

相关文章:

【Kotlin】协程的字节码原理

前言 协程是Koltin语言最重要的特性之一&#xff0c;也是最难理解的特性。网上关于kotlin协程的描述也是五花八门&#xff0c;有人说它是轻量级线程&#xff0c;有人说它是无阻塞式挂起&#xff0c;有人说它是一个异步框架等等&#xff0c;众说纷芸。甚至还有人出了书籍专门介…...

区间预测 | Matlab实现LSSVM-ABKDE的最小二乘支持向量机结合自适应带宽核密度估计多变量回归区间预测

区间预测 | Matlab实现LSSVM-ABKDE的最小二乘支持向量机结合自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现LSSVM-ABKDE的最小二乘支持向量机结合自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现…...

基于深度学习的实例分割的Web应用

基于深度学习的实例分割的Web应用 1. 项目简介1.1 模型部署1.2 Web应用 2. Web前端开发3. Web后端开发4. 总结 1. 项目简介 这是一个基于深度学习的实例分割Web应用的项目介绍。该项目使用PaddlePaddle框架&#xff0c;并以PaddleSeg训练的图像分割模型为例。 1.1 模型部署 …...

20240115如何在线识别俄语字幕?

20240115如何在线识别俄语字幕&#xff1f; 2024/1/15 21:25 百度搜索&#xff1a;俄罗斯语 音频 在线识别 字幕 Bilibili&#xff1a;俄语AI字幕识别 音视频转文字 字幕小工具V1.2 BING&#xff1a;音视频转文字 字幕小工具V1.2 https://www.bilibili.com/video/BV1d34y1F7…...

Flink 处理函数(1)—— 基本处理函数

在 Flink 的多层 API中&#xff0c;处理函数是最底层的API&#xff0c;是所有转换算子的一个概括性的表达&#xff0c;可以自定义处理逻辑 在处理函数中&#xff0c;我们直面的就是数据流中最基本的元素&#xff1a;数据事件&#xff08;event&#xff09;、状态&#xff08;st…...

Linux系统下编译MPlayer

一、编译MPlayer 在 http://www.mplayerhq.hu/design7/dload.html 下载MPlayer源码 执行命令&#xff1a; tar -xf MPlayer-1.5.tar.xz cd MPlayer-1.5 ./configure --prefix$(pwd)/install --yasm make make install 然后在install/bin目录下即会生成mplayer的可执行文件 二…...

事务的ACID属性是什么?为什么它们很重要?

引言 在现代的数据库和事务处理系统中&#xff0c;事务处理是一项非常重要的技术。在数据库中&#xff0c;事务是指一组被视为单个逻辑操作单元的SQL语句序列&#xff0c;它们要么全部成功执行&#xff0c;要么全部不执行。事务可以确保数据库在执行时保持一致性和可靠性。ACI…...

计算机毕业设计 基于Java的手机销售网站的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

Redis相关命令详解及其原理

Redis概念 Redis&#xff0c;英文全称是remote dictionary service&#xff0c;也就是远程字典服务。这是kv存储数据库。Redis&#xff0c;包括所有的数据库&#xff0c;都是请求-回应模式&#xff0c;通俗来说就是数据库不会主动地要给前台推送数据&#xff0c;只有前台发送了…...

go语言中的GoMock

GoMock是一个Go框架。它与内置的测试包整合得很好&#xff0c;并在单元测试时提供了灵活性。正如我们所知&#xff0c;对具有外部资源&#xff08;数据库、网络和文件&#xff09;或依赖关系的代码进行单元测试总是很麻烦。 安装 为了使用GoMock&#xff0c;我们需要安装gomo…...

DIFFWAVE: A VERSATILE DIFFUSION MODEL FOR AUDIO SYNTHESIS (Paper reading)

DIFFWAVE: A VERSATILE DIFFUSION MODEL FOR AUDIO SYNTHESIS Zhifeng Kong, Computer Science and Engineering, UCSD, ICLR2021, Code, Paper 1. 前言 在这项工作中&#xff0c;我们提出了DiffWave&#xff0c;这是一种用于条件和无条件波形生成的多功能扩散概率模型。该模…...

排序算法8----归并排序(非递归)(C)

1、介绍 归并排序既可以是内排序&#xff08;在内存上的数据排序&#xff09;&#xff0c;也可以是外排序&#xff08;磁盘上&#xff09;&#xff08;硬盘&#xff09;&#xff08;在文件中的数据排序&#xff09;。 其他排序一般都是内排序。 区别于快速排序的非递归&#xf…...

Golang 里的 context

context 的作用 go 的编程中&#xff0c;常常会在一个 goroutine 中启动多个 goroutine&#xff0c;然后有可能在这些 goroutine 中又启动多个 goroutine。 如上图&#xff0c;在 main 函数中&#xff0c;启动了一个 goroutine A 和 goroutine B&#xff0c;然后 goroutine A …...

PHP短链接url还原成长链接

在开发过程中&#xff0c;碰到了需要校验用户回填的短链接是不是系统所需要的&#xff0c;于是就需要还原找出短链接所对应的长链接。 长链接转短链接 在百度上搜索程序员&#xff0c;跳转页面后的url就是一个长链接。当然你可以从任何地方复制一个长链接过来。 长链接 http…...

redis原理(三)redis命令

一、字符串命令&#xff1a; 1、字符串基本操作&#xff1a; 2、自增自减 &#xff1a;如果一个值可以被解释为十进制整数或者浮点数&#xff0c;redis允许用户对这个字符串进行INCR*、DECR*操作。 &#xff08;1&#xff09;INCR key&#xff1a;将键存储的值的值加1。 &a…...

教程:在Django中实现微信授权登录

教程&#xff1a;在Django中实现微信授权登录 本教程将引导您如何在Django项目中实现微信授权登录。在本教程中&#xff0c;我们将使用自定义的用户模型User&#xff0c;并通过微信提供的API来进行用户认证。 在进行以下教程之前&#xff0c;请确保你已经在微信开放平台添加了…...

YOLOv5改进 | 主干篇 | 12月份最新成果TransNeXt特征提取网络(全网首发)

一、本文介绍 本文给大家带来的改进机制是TransNeXt特征提取网络,其发表于2023年的12月份是一个最新最前沿的网络模型&#xff0c;将其应用在我们的特征提取网络来提取特征&#xff0c;同时本文给大家解决其自带的一个报错&#xff0c;通过结合聚合的像素聚焦注意力和卷积GLU&…...

【java八股文】之计算机网络系列篇

1、TCP/IP和UDP模型 TCP/IP分层&#xff08;4层&#xff09;&#xff1a;应用层&#xff0c;传输层&#xff0c;网络层&#xff0c;数据链路层 网络的七层架构 &#xff08;7层&#xff09;&#xff1a;应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff…...

SpringAMQP的使用

1. 简介&#xff1a; SpringAMQP是基于RabbitMQ封装的一套模板&#xff0c;并且还利用SpringBoot对其实现了自动装配&#xff0c;使用起来非常方便。 SpringAmqp的官方地址&#xff1a;https://spring.io/projects/spring-amqp SpringAMQP提供了三个功能&#xff1a; 自动声…...

MATLAB - 使用运动学 DH 参数构建机械臂

系列文章目录 前言 一、 使用 Puma560 机械手机器人的 Denavit-Hartenberg (DH) 参数&#xff0c;逐步建立刚体树形机器人模型。在连接每个关节时&#xff0c;指定其相对 DH 参数。可视化机器人坐标系&#xff0c;并与最终模型进行交互。 DH 参数定义了每个刚体通过关节与其父…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...