首页 文章 精选 留言 我的

精选列表

搜索[全模态模型],共10000篇文章
优秀的个人博客,低调大师

得物视频编辑工具优化全指南

一、背景介绍 随着4G网络的推广和网络带宽的提升,视频成为互联网用户主要的消费载体,用户通过短视频来分享和浏览信息。由此视频的编辑功能越来越重要、越来越普遍。视频编辑的App也如雨后春笋般涌现。 为更好地推动得物App社区业务的发展,得物也自研符合得物需求的视频编辑工具。我们致力于打造一个“更快、更强”的视频编辑工具。 二、视频编辑工具介绍 为了让大家更好地了解得物App的视频编辑工具,我们先简单介绍一下视频编辑工具的主要功能。 下面是得物App视频编辑工具的主要功能: 视频编辑工具的重点如下: 视频编辑工具需要操作的资源: 文字:包括普通的文字、特殊的艺术字、花字等等; 图片:包括静态图,如JPEG/PNG等等,也包括HEIC/GIF等动态图; 视频:包括各种各样的视频(各种编码和封装格式),主流的格式一般是MP4的封装格式、H264视频编码格式、AAC音频编码格式等等; 音频:包括各种各样的音频(各种编码和封装格式),当然视频当然也是包含音频轨道的。 视频编辑工具主要的操作方式: 操作图片、视频帧:我们知道视频是一帧一帧的图片组成的,所以操作视频帧和操作图片是一样的道理,我们通过添加一些特效在图片和视频帧上面,实现一些有趣的效果来吸引用户。 操作音频:主流的操作音频方式如倍速、调整音量、变调等等,都是现今短视频的主要玩法。 视频编辑工具最终生成的是一个新的视频,这个视频将特定的资源应用一些特效生成一个新的视频。 下面的流程图可以很方便地让大家了解视频编辑的工作流程。为了方便,我们输入一个视频,加上一些特效,生成一个新的视频。 从上面的流程可以看出来,原始视频A.mp4经过解封装分离出音频轨道和视频轨道,对它们解码之后,对音频数据应用音频特效、对视频帧数据应用视频特效,然后编码封装合成一个新的视频。当然解码和编码都是有一个队列控制的,流程图上标注了,没有深入展开,大家了解即可。 经过上面的介绍,大家对视频编辑工具有了大概得了解,其实衡量一个视频编辑工具做得好不好,主要从下面这几个方面着手: 内存占用情况 导出视频的速度如何 导出视频的清晰度如何 下面从这三方面详细展开给大家阐述得物App的视频编辑工具优化的心路历程。 三、内存优化 性能是所有程序好不好的首要指标,一个工具即使功能再强大,但是一点就崩溃,或者用着用着内存暴涨、应用卡死,估计这个应用不能称为一个优秀的应用,下面我们具体谈一谈视频编辑工具的优化检测方案。 优化内存从良好的编码习惯开始,尤其对音视频这种对内存需求非常高的应用而言。例如一个1080 * 1920的视频,解码出来原始数据一帧图片大小也是1080 * 1920,占用内存是1080 * 1920 * (8 * 3 ) / 8 = 5.93 MB,一个视频帧就占用这么大,1秒一般有30帧,那得占用177.9MB,如果不加控制,那不管多高性能的手机也经不住这样的折腾。希望下面的内存检测和优化方案可以给你带来一些帮助。 3.1 合理设计队列 上面我们在介绍视频编辑流程的视频谈到了解码队列和编码队列的概念。其实队列这个概念在音视频中使用非常频繁,正是因为内存的限制,所以才引入队列这个控制方式。大家可能还有点懵,但是看完下面的流程图,我相信你一定会豁然开朗。 我们仅选取解码的部分来分析一下队列的重要应用。 在视频编辑工具中有几个重要的队列: 解码过程中: Video Packet Queue:视频解码之前Packet存放的队列,一般建议的队列大小是100 Audio Packet Queue:音频解码之前Packet存放的队列,一般建议的队列大小是150 Video Frame Queue:视频解码之后Frame存放的队列,一般建议的队列大小是3 Audio Frame Queue:音频解码之后Frame存放的队列,一般建议的队列大小是8 编码过程中: Encode Video Packet Queue:视频编码之后Packet存放的队列,一般建议的大小是100 Encode Audio Packet Queue:音频编码之后的Packet存放的队列,一般建议的大小是150 按照上面的方式设计队列的大小,可以在保证功能正常的情况下最大程度的降低内存占用,提升用户体验。 3.2 排查内存泄漏 Android上排查内存泄漏的方式有很多,这里介绍两种: Asan检测 Profile检测 Asan全称是AddressSanitizer是一种基于编译器的快速检测的工具,用于检测原生代码中的内存错误问题,Asan可以解决如下四种核心问题: 堆栈和堆缓冲区上溢、下溢 释放之后堆重新使用问题 超过范围的堆栈使用情况 重复释放、错误释放问题 Asan的使用方式建议参考google官方文档,这儿就不多作介绍了: https://github.com/google/sanitizers/wiki/AddressSanitizer 关于Profile的使用,如果需要检测Native内存使用情况,需要满足API>=29,大家在使用的时候需要非常注意。 下面是我们在demo中应用Asan抓取的堆栈: 20042-20042/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 20042-20042/? A/DEBUG: Build fingerprint: 'samsung/t2qzcx/t2q:11/RP1A.200720.012/G9960ZCU2AUGE:user/release-keys' 20042-20042/? A/DEBUG: Revision: '13' 20042-20042/? A/DEBUG: ABI: 'arm64' 20042-20042/? A/DEBUG: Timestamp: 2021-09-17 00:32:31+0800 20042-20042/? A/DEBUG: pid: 19946, tid: 20011, name: AudioTrack >>> com.jeffmony.audioplayer <<< 20042-20042/? A/DEBUG: uid: 10350 20042-20042/? A/DEBUG: signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- 2021-09-17 00:32:31.157 20042-20042/? A/DEBUG: Abort message: '================================================================= ==19946==ERROR: AddressSanitizer: heap-use-after-free on address 0x004ac1e41080 at pc 0x007157f69580 bp 0x00705c0bb350 sp 0x00705c0bab08 READ of size 1792 at 0x004ac1e41080 thread T32 (AudioTrack) #0 0x7157f6957c (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libclang_rt.asan-aarch64-android.so+0x9f57c) #1 0x706549c228 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x14228) #2 0x706549bcd4 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x13cd4) #3 0x70654994f0 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x114f0) #4 0x70654a9cbc (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x21cbc) #5 0x70654a91d4 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x211d4) #6 0x715af9d188 (/system/lib64/libwilhelm.so+0x1c188) #7 0x71570ea290 (/system/lib64/libaudioclient.so+0x8b290) #8 0x71570e9480 (/system/lib64/libaudioclient.so+0x8a480) #9 0x7156b664d4 (/system/lib64/libutils.so+0x154d4) #10 0x71593e9974 (/system/lib64/libandroid_runtime.so+0xa5974) #11 0x7156b65db0 (/system/lib64/libutils.so+0x14db0) #12 0x7156ace234 (/apex/com.android.runtime/lib64/bionic/libc.so+0xb6234) #13 0x7156a68e64 (/apex/com.android.runtime/lib64/bionic/libc.so+0x50e64) 0x004ac1e41080 is located 0 bytes inside of 1792-byte region [0x004ac1e41080,0x004ac1e41780) freed by thread T32 (AudioTrack) here: #0 0x7157f74c64 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libclang_rt.asan-aarch64-android.so+0xaac64) #1 0x70654a6d2c (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x1ed2c) #2 0x70654a6af0 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x1eaf0) #3 0x706549bf4c (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x13f4c) #4 0x706549bcd4 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x13cd4) #5 0x70654994f0 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x114f0) #6 0x70654a9cbc (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x21cbc) #7 0x70654a91d4 (/data/app/~~G094WKQQj7KZvdhvGYDLDA==/com.jeffmony.audioplayer-kcu1nmgzpBIQDRJDxCJDOQ==/lib/arm64/libltpaudio.so+0x211d4) #8 0x715af9d188 (/system/lib64/libwilhelm.so+0x1c188) #9 0x71570ea290 (/system/lib64/libaudioclient.so+0x8b290) 显示message是:heap-use-after-free on address 0x004ac1e41080 说明是使用了已经释放掉的内存了,再继续看,这个内存具体在什么地方被释放的?0x004ac1e41080 is located 0 bytes inside of 1792-byte region [0x004ac1e41080,0x004ac1e41780) Asan一个很大的优势就是可以追踪内存释放的路径,防止出现内存泄漏和野指针问题,特别是野指针,一旦出现特别难排查,简直是C++开发的噩梦,希望大家用好工具,同时培养良好的C++编码习惯。 3.3 优化线程 另一个影响内存的重要因素是线程,视频编辑工具涉及到的线程非常多,线程的使用得遵循一些基本的原则: 尽量少创建线程 尽量少使用pthread_mutex_t 本着功能隔绝原则使用线程 能同步就别异步 以编辑模块为例,这儿列一下我们使用到的所有线程: GL处理线程 视频解封装线程 视频中视频轨道解码线程 视频音频轨道解码线程 抽取缩略图线程 音频编码线程 视频编码线程 视频封装线程 如果插入了独立的音频文件,还需要添加两个额外的线程: 音乐文件播放线程 音乐文件解码线程 上面列出的是一个视频编辑工具能正常工作所必备的最少线程,如果你的视频编辑工具中多了什么线程,我们建议可以适当优化一下,毕竟少一个线程,可以少一分开销,而且少一分线程同步的工作。 我们在底层也按照Android的消息机制重写了一套C++层的消息分发SDK,这个我们后续会另外分享文章阐释我们定制的消息分发SDK,这儿点到为止。 四、提升导出视频的速度 我们使用视频编辑工具,最终是希望导出一个视频,如果这个导出的过程很慢,那肯定是无法忍受的,从上面的介绍我们已知视频的导出需要经过“解码——应用特效——编码”的过程,其中解码和编码这两个过程对速度的影响至关重要。因为解码和编码视频需要耗费大量的资源,目前主要有两种方式——“软解/编码”和“硬解/编码”。 如果你使用过FFmpeg或者其他使用CPU进行视频编解码的来处理视频的话,你可能已经遇到了处理速度慢的问题。这主要是因为软编码和软解码使用CPU进行运算,而CPU在处理视频上的速度远低于DSP芯片;简而言之“软解/编码”主要通过CPU来工作,通过CPU来主导大量的计算工作,是原始的处理方式,当然耗费的时间也比较长;“硬解/编码”是通过GPU来处理,GPU是专用的图形处理芯片,对视频的解码和编码有专门的优化,所以编码和解码的速度非常快。 Android上使用MediaCodec来实现“硬解/编码”,iOS上使用VideoToolBox来实现“硬解/编码”,这里着重介绍Android上编码解码的速度优化。 从上面的流程我们可以看出,编码在解码的后面,一个时长60s(30fps)的视频,需要解码1800帧,然后编码1800帧视频才能完整生成另外一个视频,这样串行的等待是耗时的主要原因。 这时候我们参考多线程方案,将一个60s的视频均分为两段,然后这两段视频同时进行解码操作,生成导出了两个30s的临时缓存视频文件,随后将这两个30s的视频合并为一个60s的B.mp4视频,最后删除临时缓存文件,这样我们只需要同时处理900帧的数据,理论上可以提升一倍的导出速度。 这就是并行导出,下面是得物App并行导出的基本流程。 首先我们要明确导出视频是需要消耗资源的,这个资源就是MediaCodec,最终是送入到GPU中处理,一个手机中的MediaCodec实例是有限的,正常情况下,一个手机可以提供的MediaCodec实例最多有16个,如果当前使用的MediaCodec实例超过16个,那么手机将无法正常工作。MediaCodec资源是手机中的所有App共同持有。所以并行分段的个数不是越多越好。 只有一段,需要两个MediaCodec(一个用来解码视频,一个用来编码视频),注意:音频的解码和编码可以不要用MediaCodec,毕竟音频的耗时少多了,不是瓶颈。 分成两段需要四个MediaCodec,分成三段需要六个MediaCodec,分成四段需要八个MediaCodec,以此类推。 下面是并行导出的测试结果: 两段并行速度提升50% ~ 70%,内存增加20%, 三段并行速度提升60% ~ 90%,内存增加80%;并行超过三段的话就无法明显提升速度了。我们比较建议并行两段,在一些性能很好的机型上并行三段。 如果有些同学对视频导出过程中文件操作还有疑问的,下面的示意图可以比较清楚地看出并行导出操作本地文件的过程: 并行导出的过程中,生成了两个临时文件 并行导出完成后,这两个临时文件合并为一个新的文件,两个临时生成的文件被删除了(节省用户宝贵的存储空间) 原始文件jeffmony_out.mp4并没有被删除/修改 Tips:目前我们在处理过程中生成的临时文件和最终的适配文件都会保存在/sdcard/Pictures/duapp/Compile/下,而在处理完成后的临时文件清理过程会触发在某些机型上的保护机制,建议后续调整到App的私有目录下。 当然还有其他的提升导出速度的建议,例如在视频帧特效处理的过程中,我们建议: 尽量采用FBO/EBO/ABO方式处理texture 纹理如果过大要进行压缩 严禁采用glFinish() 这些做法都是我们在视频编辑开发过程中的切实经验,希望能给大家带来一些帮助。 五、提升导出视频的清晰度 一个视频编辑功能是否足够优秀,其中的一个重要指标就是同等条件下导出的视频是否足够清楚,通常而言,衡量视频是否清晰的有两种方式: 主观标准:找一些用户观看不同的视频,根据用户的观感输出视频清晰度的对比结果,用户一般根据色彩、画面亮度、柔和度等来评估清晰度。 客观标准:利用算法计算视频画面质量分,目前比较推荐Netflix推出的开源库VMAF来计算视频帧的质量分。 实际上主观标准是比较准确的,但是可操作性比较差,特别是处理海量视频的时候,需要大量的人力,无法有效开展,因此日常工作中还是推荐客观标准进行海量计算,主观标准进行重点判断。具体的可以结合业务的重要程度来开展。 下面结合我们实际的工作给出具体提升视频清晰度的方式: 视频基础编码信息优化 Profile优化:Profile有三种Level,分别是Baseline、Main、High,其中Baseline Profile对应清晰度最低,Android 3.0之后的版本都支持的,Main Profile清晰度比Baseline Profile清晰度要好,但是从Android 7.0之后才支持,High Profile清晰度最高,也是从Android 7.0之后才支持。我们在设置Encoder Profile Level之前,需要判断一下当前是否支持。 Bitrate码率设置: 视频码率是视频数据传输时单位时间内传送的数据位数。单位是kbps,望文生义,码率越大,单位时间填充的数据就越多,视频质量就越高。但码率也不是设置的越大越好,超过必要限度,对视频画质的提升已不明显,建议采用合适的factor来调整码率。Bitrate = width * height * frameRate * factor,其中factor=0.15。 Bitrate Mode: 有三种通过的编码模式——VBR(可变码率)、CBR(固定码率)、ABR(平均码率),其中ABR是最好的方式,可以兼顾质量和视频大小。 B帧设置: 视频有I帧、P帧、B帧构成,其中I帧最大,P帧次之,B帧最小,我们在编码时尽量多设置B帧(在合理的范围内),并不会降低清晰度,但是可以大大降低视频的大小,这样我们就可以相应地调大码率,最终实现了提升清晰度的目标。 HEVC编码优化: 使用HEVC编码,可以保证在不增加文件大小的情况下,大大提升视频的清晰度。在相同的图像质量下,HEVC编码的视频比H.264编码的视频约减少40% 色彩调优 综合调整亮度、对比度、色温、饱和度、锐度等颜色参数,进而优化整体的视频画面,让视频画面看上去“更清晰”。 **超分算法 **: 采用ESRGAN算法,利用机器学习的优势对图片和视频进行去模糊、Resize、降噪、锐化等处理,重建图片,实现对图片的超分辨率处理。 特征提取:计算噪点 非线性映射:放大,模糊化噪点 图像重建:差分,平滑过度,去噪 下面是使用超分算法处理前后的对比图,可以很明显地看出右边的图更加清晰,少了很多噪点、图片更亮、过度更平滑。 如果大家想了解视频清晰度优化的技术细节,可以参考文章--视频清晰度优化指南 六、总结 本文开篇从介绍得物App的主要功能展开,提出了视频编辑工具优化的三个维度: 优化内存占用 提升视频导出速度 提升导出视频的清晰度 其中在“提升视频导出速度”时重点谈到了“并行导出”的技术方案,从最终的结果来看,视频导出速度的提升非常明显,同时也非常清楚地解释了“并行导出”过程中为什么生成临时文件?为什么有必要在导出完成之后删除临时文件?尽力给用户带来较好的体验。 最后在“提升导出视频的清晰度”中重点提到的超分算法应用效果提升明显,超分之后的视频帧相比原帧图更加清晰、噪点更少,而且细节部分更加真实。 后续我们还会结合AR特效输出更多有意义的技术分享,敬请期待。 *文 /JeffMony 关注得物技术,每周一三五晚18:30更新技术干货 要是觉得文章对你有帮助的话,欢迎评论转发点赞~

优秀的个人博客,低调大师

Hanami 2.0 发布,全栈 Ruby Web 框架

经过三年多的努力,Hanami 2.0 正式发布,随着这个版本的发布,Hanami 进入了框架成熟的新阶段,并为 Ruby 社区开启了新的篇章。 更好 Hanami 2.0 的核心是现在的 app/ 目录,在这里,你可以随心所欲地组织你的代码,同时还可以享受常见组件的合理默认值。随着你的应用程序的增长,你可以利用切片的优势,将你的代码分成若干域。 Hanami 2.0 提供了一个既简单又强大的框架: 新的应用程序核心提供了以容器和组件为中心的高级代码加载功能 代码自动加载帮助你以最小的代价工作 新的内置切片随着你的应用程序的增长而逐渐提供模块化。 一个始终存在的依赖关系混合器帮助你在你的应用程序的组件之间建立更清晰的联系 重新设计的 action 类与你的应用程序的业务逻辑无缝集成 带有 dotenv 集成的类型安全的应用程序设置,确保你的应用程序在每个环境中都有它所需要的东西。 新的供应商管理你的应用程序的关键组件和集成的生命周期 自上而下的模块化使您能够构建各种类型的应用程序,包括非 Web 应用程序 我们重写的入门指南可以帮助你开始使用上述所有内容 更快 Hanami 2.0 完全重写了 HTTP 路由引擎,基准显示它超过了几乎所有其他引擎。 当在开发中使用 Hanami 时,由于我们的智能代码加载,你的应用程序将立即启动和重新加载。无论你的应用程序有多大,你的控制台将在几毫秒内加载,你的测试将保持快速。 更多详情可查看:https://hanamirb.org/blog/2022/11/22/announcing-hanami-200/

优秀的个人博客,低调大师

常见的初级排序算法,这次全搞懂

本文已被Github仓库收录 https://github.com/silently9527/JavaCore 程序员常用的IDEA插件:https://github.com/silently9527/ToolsetIdeaPlugin 完全开源的淘客项目:https://github.com/silently9527/mall-coupons-server 微信公众号:贝塔学Java 前言 相信所有的程序员刚开始接触到的算法都会是排序算法,因为排序在对数据处理和计算有这重要的地位,排序算法往往是其他算法的基础;本文我们就先从初级排序算法开始学习算法。 排序算法的模板 在开始之前我们先定义一个排序算法通用的模板,在后面的排序算法都会实现这个模板 public interface SortTemplate { void sort(Comparable[] array); default void print(Comparable[] array) { for (Comparable a : array) { System.out.print(a + " "); } } default boolean less(Comparable a, Comparable b) { return a.compareTo(b) < 0; } default void exch(Comparable[] array, int i, int j) { Comparable tmp = array[i]; array[i] = array[j]; array[j] = tmp; } } Comparable: 为了让我们实现的排序算法更加的通用,可以排序任意的对象,所以我们这里使用了Comparable数组 sort: 不同的排序算法实现的方式不一样,子类自己去实现 less: 定义的公用方法,如果a < b就返回true exch: 定义的公用方法,交换数组中的两个对象 print: 打印出数据中的每个元素 选择排序 算法实现的思路: 首先找到数组中的最小元素, 其实将它和数组中的第一个元素进行交换,这样就排定了一个元素; 再次找出剩余元素中最小的元素与数组中的第二个元素进行交换,如此反复直到所有元素都是有序的 代码实现: public class SelectionSort implements SortTemplate { @Override public void sort(Comparable[] array) { int length = array.length; for (int i = 0; i < length; i++) { int min = i; for (int j = i + 1; j < length; j++) { if (less(array[j], array[min])) { min = j; } } exch(array, i, min); } } } 假如输入的数组是有序的,我们会发现选择排序运行的时候和未排序的时间一样长! 对于N个元素的数组,使用选择排序的时间复杂度是O(n²) 选择排序的是数据移动最少的,交换的次数与数组的大小是线性关系,N个元素的数组需要N次交换 冒泡排序 算法实现的思路: 比较相邻的两个元素,如果前一个比后一个大,那么就交换两个元素的位置 对每一组相邻的元素执行同样的操作,直到最后一个元素,操作完成之后就可以排定一个最大的元素 如此往复,直到数组中所有的元素都有序 代码实现: public class BubbleSort implements SortTemplate { @Override public void sort(Comparable[] array) { int length = array.length - 1; for (int i = 0; i < length; i++) { for (int j = 0; j < length - i; j++) { if (less(array[j + 1], array[j])) { exch(array, j, j + 1); } } } } } 对于N个元素的数组,使用冒泡排序的时间复杂度是O(n²) 插入排序 想象我们在玩扑克牌时,整理扑克牌都是把每一张插入到左边已经排好序的牌中适当的位置。插入排序的思路类似 算法实现的思路: 初始默认第一个元素就是有序的,当前索引的位置从0开始 先后移动当前索引的位置,当前索引位置左边的元素是有序的,从后往前开始扫码与当前索引位置元素进行比较 当确定当前索引位置上的元素在左边有序适合的位置之后,插入到该位置上 如果当确定当前索引位置上的元素大于了已排序的最后一个元素,那么当前索引位置直接往后移动 如此反复,直到所有元素有序 代码实现: public class InsertionSort implements SortTemplate { @Override public void sort(Comparable[] array) { int length = array.length; for (int i = 1; i < length; i++) { for (int j = i; j > 0 && less(array[j], array[j - 1]); j--) { exch(array, j, j - 1); } } } } 从代码的实现我们可以看出,当遇到了当前索引的元素大于了左边有序数组的最后一个元素时,内层循环就直接结束了,所以所我们排序的数组中存在着部分有序,那么插入排序算法会很快。 考虑最糟糕的情况,如果输入数组是一个倒置的,那么插入排序的效率和选择排序一样,时间复杂度是O(n²) 希尔排序 对于大规模的乱序数组插入排序很慢,是因为它只交换相邻的元素,元素只能一点一点的从数组中移动到正确的位置;插入排序对于部分有序的数组排序是的效率很高; 希尔排序基于这两个特点对插入排序进行了改进; 算法实现的思路 首先设置一个步长h用来分隔出子数组 用插入排序将h个子数组独立排序 减小h步长继续排序子数组,直到h步长为1 当步长为1时就成了普通的插入排序,这样数组一定是有序的 希尔排序高效的原因,在排序之初,各个子数组都很短,子数组排序之后都是部分有序的,这两种情况都很适合插入排序。 代码实现: public class ShellSort implements SortTemplate { @Override public void sort(Comparable[] array) { int gap = 1; int length = array.length; while (gap < length / 3) { gap = 3 * gap + 1; } while (gap >= 1) { for (int i = gap; i < length; i++) { for (int j = i; j >= gap && less(array[j], array[j - gap]); j -= gap) { exch(array, j, j - gap); } } gap = gap / 3; } } } 最后(点关注,不迷路) 文中或许会存在或多或少的不足、错误之处,有建议或者意见也非常欢迎大家在评论交流。 最后,写作不易,请不要白嫖我哟,希望朋友们可以点赞评论关注三连,因为这些就是我分享的全部动力来源

优秀的个人博客,低调大师

使用Kubectl管理Kubernetes的全解教程

kubectl主要用于与K8s API服务器通信,以在K8s中创建、更新和删除工作负载。不少IT人员通过kubectl与K8s交互。本文将介绍如何安装kubectl、与K8s环境进行通信以及一些常用命令,给您提供管理K8s的良好起点。 对不少IT人员来说,每天与Kubernetes交互的机制一般是通过kubectl——一种命令行工具。kubectl主要用于与Kubernetes API服务器通信,以在Kubernetes中创建、更新和删除工作负载。本教程的目的是概述您可以使用的一些常用命令,并提供管理Kubernetes的良好起点。 我们将介绍如何在您的计算机上安装kubectl,如何与您的Kubernetes环境进行通信并执行一些常见操作。大多数常见的kubectl命令会提供某特定的操作,如创建、删除等。此方法通常需要解释描述Kubernetes中的对象(如POD、服务、资源等)的文件(YAML或JSON)。这些文件通常被用作模板以及环境的持续文档,并有助于保留Kubernetes对声明性配置的关注。命令行上给出的操作将传递给API服务器,然后根据需要与Kubernetes中的后端服务进行通信。 我们将介绍一些最常见的kubectl命令并提供一些示例。有关每个命令的更多详细信息,包括所有支持的标志和子命令,请查看kubectl参考文档: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands。 安装kubectl kubectl是一个独立的程序,因此不需要复杂的安装过程。它是一个需要位于操作系统PATH中的单个文件。有许多方法可以获得kubectl二进制文件,例如通过操作系统的本机包管理器或通过curl。下表中的一些示例就是如何为各种操作系统安装kubectl: 注意: 随着新版本的发布,最佳版本的kubectl for Windows将随着时间的推移而发生变化。要查找当前最佳二进制文件,请点击此链接查找最新的稳定版本,并根据需要调整上述URL: https://storage.googleapis.com/kubernetes-release/release/stable.txt 环境中使用的kubectl版本,需要与Kubernetes服务器的版本保持一致。您可以通过键入以下内容来查看正在使用的kubectl客户端的版本: kubectl在各方面都会保持与一个版本的兼容性。其中客户端版本会比服务器版本领先一步。这为服务器版本:v1.13.4中提供的功能和命令提供了支持。如果客户端版本不是服务器版本之后的各版本中的一个,那么在尝试访问相应服务器版本中可用的功能时,可能会遇到错误或不兼容。 kubectl语法 kubectl 的语法使用如下: Command(命令):指你想要执行的操作(创建、删除等等) Type(类别):指你正在执行命令的资源类型(Pod、Service等) Name(名称):对象的名称(需区分大小写)。如果未指定名称,则可以获取有关命令匹配的所有资源的信息(例如Pod) Flags(标志):这个可以按需选择(非必须),不过它在查找特定资源时非常有用。例如,--namespacespace可以让你指定要在哪个特定的命名空间中执行操作。 kubeconfig kubectl使用配置文件来访问Kubernetes集群。默认的kubectl配置文件位于〜/ .kube / config,称为kubeconfig文件。 kubeconfig文件组织有关集群、用户、命名空间和身份验证机制的信息。kubectl命令使用这些文件来查找它在选择集群并与之通信时所需要的信息。 加载顺序遵循以下规则: 如果设置了--kubeconfig标志,则仅加载给定文件。该标志只能设置一次,不会发生合并。 如果设置了$ KUBECONFIG环境变量,则根据系统的正常路径分隔规则,将其解析为文件系统路径列表。 否则,如果上述两项都未设置,则使用${HOME}/.kube/config 文件,不进行任何合并。 如果您看到类似于以下内容的消息,则意味着kubectl配置不正确或无法连接到Kubernetes集群 The connection to the server <server-name: port> was refused - did you specify the right host or port? 你可以通过多种方式创建配置文件,具体取决于你使用何种Kubernetes发行版。以下列出的是不同的K8S发行版及其位置: RKE 使用RKE创建Kubernetes集群时,RKE会在本地目录中创建一个kube_config_rancher-cluster.yml文件,该文件包含使用kubectl等工具连接到新集群所需的凭据。 您可以将此文件复制到$ HOME / .kube / config,或者,如果您正在使用多个Kubernetes集群,请将KUBECONFIG环境变量设置为kube_config_rancher-cluster.yml的路径,如下所示: Rancher统一管理的Kubernetes集群 在Rancher中,您可以通过Web UI下载kubeconfig文件,并使用它通过kubectl连接到Kubernetes环境。 在Rancher UI中,单击要通过kubectl连接的集群。在页面的右上角,单击Kubeconfig File按钮: 单击按钮以详细查看配置文件以及放置在~/.kube/config中的方向。 将配置复制到~/.kube/config后,你无需指定--kube-config文件位置,就可以运行kubectl命令: 一些基本命令的示例 以下我将重点介绍在典型环境中会用到的许多命令。我们将从概述集群开始,一直到探索Kubernetes环境中当前正在运行的内容的各种场景。 相信下文的内容将帮助您熟悉kubectl和典型输出的命令。 管理kubectl配置 kubectl命令包含一些不同的命令,可用来帮助查看和管理自己的配置。这些在初始设置期间,或在你需要处理的集群集发生变化时,将非常有用。 要查看当前配置,请键入: apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https://www.<yoururl>.com/k8s/clusters/<cluster> name: gcpcluster - cluster: certificate-authority-data: DATA+OMITTED server: https://10.240.0.41:6443 name: gcpcluster-k8s-1 - cluster: certificate-authority-data: DATA+OMITTED server: https://10.240.0.42:6443 name: gcpcluster-k8s-2 - cluster: certificate-authority-data: DATA+OMITTED server: https://10.240.0.43:6443 name: gcpcluster-k8s-3 contexts: - context: cluster: gcpcluster namespace: rancher user: user-qkvpz name: gcpcluster 你将能看到的输出内容汇总展现了你所配置的集群和及上下文。cluster键包含每个可用集群的列表,以及相关的连接和验证详细信息。contexts键将用户、集群和可选的命名空间组合在一起,以形成用于与集群交互的唯一标识和使用上下文。 要获得每个可用上下文的更简洁摘要,你可以键入: 输出的内容显示了每个已定义上下文的详细信息以及当前选定的上下文,由星号(*)表示。 要快速检查当前使用的上下文,请键入: 虽然我们不会在本摘要中介绍它,但除此之外你还可以使用kubectl set-cluster、kubectl set-credentials和kubectl set-context以及各种标志来定义集群和上下文,不过我们在本文中就不赘述了。 要更改要连接的上下文,请使用use-context命令: 检查集群组件的状态 为集群选择好适当的上下文后,可以使用get componentstatuses(缩写为get cs)命令检查核心主组件的状态: 输出的内容将显示调度程序、控制器管理器和etcd节点的状态以及从每个服务收集的最新消息和错误。如果你的集群运行不正常,这是一个很好的、进行第一次诊断检查的机会。 可以使用cluster-info命令收集其他连接和服务信息: Kubernetes master is running at https://www.<yoururl>.com/k8s/clusters/<cluster> KubeDNS is running at https://www.<yoururl>.com/k8s/clusters/<cluster>/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. 这里,输出显示了我们的Kubernetes master的端点以及KubeDNS服务端点的端点。 要查看有关作为集群成员的每个单个节点的信息,需使用get nodes命令: NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME k8s-1 Ready controlplane,etcd,worker 34d v1.13.5 <IP> <none> Ubuntu 18.10 4.18.0-1011-gcp docker://18.9.5 k8s-2 Ready controlplane,etcd,worker 34d v1.13.5 <IP> <none> Ubuntu 18.10 4.18.0-1011-gcp docker://18.9.5 k8s-3 Ready controlplane,etcd,worker 34d v1.13.5 <IP> <none> Ubuntu 18.10 4.18.0-1011-gcp docker://18.9.5 这列出了在每个节点上运行的核心软件的状态、角色、连接信息和版本号。如果需要在集群节点上执行维护或登录以调试问题,此命令可以帮助您提供所需的信息。 查看资源和事件信息 要概述集群中可用的命名空间,请使用get namespaces命令: 这显示了当前集群中定义的命名空间分区。 要跨所有命名空间概述集群上运行的所有资源,使用以下命令: 输出的内容会显示部署了每个资源的命名空间信息,以及加上了资源类型前缀的资源名称(例如上面显示的示例中的pod)。之后,有关每个资源的就绪和运行状态的信息将有助于确定进程是否运行正常。 要查看与资源关联的事件,请使用get events命令: NAMESPACE LAST SEEN TYPE REASON KIND MESSAGE cattle-system 9m31s Normal BackOff Pod Back-off pulling image "miguelgt/k8s-demo:v2" cattle-system 24m Warning Failed Pod Error: ImagePullBackOff cattle-system 14m Normal BackOff Pod Back-off pulling image "miguelgt/k8s-demo:v2" cattle-system 9m30s Warning Failed Pod Error: ImagePullBackOff 输出内容将列出资源记录的最新事件,包括事件消息及其触发的原因。 示 例 为了更具体地演示您在使用kubectl时可能参与的工作流程,我们将在这一部分介绍将容器部署到集群的快速方案,并将其部署到非默认命名空间中。 默认情况下,如果在未指定命名空间的情况下部署集群,kubectl会将资源放在名为default的命名空间中。如果要部署到其他名称空间,则需要指定所需的替代项。 虽然我们可以为创建命令提供命名空间,但如果我们要使用命名空间来处理多个命令,更改上下文的方法会更为容易。更改与上下文关联的命名空间将自动将命名空间规范应用于任何其他命令,直到更改上下文。 要更改当前上下文的命名空间,请使用带有--currentand --namespace标志的set-context命令: 这将改变当前上下文,以自动将未来的操作应用于rancher命名空间。 接下来,我们可以创建一个名为nginx的部署,它基于默认的nginx容器镜像运行容器。因为我们改变了我们的上下文,所以它会在rancher命名空间中运行: 您可以通过列出当前部署的pod来检查部署是否成功: 在这里,我们可以看到Nginx部署正常运行。READY那一列显示容器已就绪,状态是“正在运行”,没有出现故障。 虽然我们已经验证了pod正在运行,但我们还没有得到关于它部署到了哪个命名空间的信息。但是,我们可以通过添加--all-namespaces标志来稍微改变输出: 这将显示在每个命名空间中运行的pod,并另外添加一个NAMESPACE列,列出每个资源部署到了哪个命名空间。在这里,我们看到Nginx pod已正确部署到我们的rancher命名空间而不是通常的default命名空间。 这表明我们的上下文操作和我们的部署都按预期工作了。 你还可以通过键入以下内容来清理已部署的资源: 其他参考信息 虽然本章中深入讨论这些内容可能超出了本文原意的范围,但我们还是为大家列出了一些非常有用的命令。 Pod 资源删除 服务 事件&指标 命名空间&安全 中级命令 其他资源 kubectl的官方概述: https://kubernetes.io/docs/reference/kubectl/overview/ kubectl的官方命令文档: https://kubernetes.io/docs/reference/kubectl/kubectl/ kubectl的官方备忘单: https://kubernetes.io/docs/reference/kubectl/cheatsheet/ Rancher kubeconfig文档: https://rancher.com/docs/rancher/v2.x/en/cluster-admin/kubeconfig/ 有关使用kubectl访问集群的Rancher文档: https://rancher.com/docs/rancher/v2.x/en/cluster-admin/kubectl/ kubectl配置命令: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#config 使用kubeconfig文件组织集群: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册