前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[生命周期阶段]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
转载文章
...,检视和录制侦错工作阶段输出。 DiskExt 显示磁碟区磁碟对应。 Diskmon 这个公用程式会撷取全部的硬碟活动,或是提供系统匣中的软体磁碟活动指示器的功能。 DiskView 图形化磁区公用程式。 Du 依目录检视磁碟使用状况。 EFSDump 检视加密档案的资讯。 Filemon 这个监控工具让您即时检视所有档案系统的活动。 Handle 这个易於操纵的命令列公用程式能够显示档案开启的种类和使用的处理程序等更多资讯。 Hex2dec 十六进位数字和十进位数字相互转换。 Junction 建立 Win2K NTFS 符号连结。 LDMDump 倾印逻辑磁碟管理员的磁碟上之资料库内容,其中描述 Windows 2000 动态磁碟分割。 ListDLLs 列出所有目前载入的 DLL,包括载入位置和他们的版本编号。2.0 版列印载入模组的完整路径名称。 LiveKd 使用 Microsoft 核心侦错工具检视即时系统。 LoadOrder 检视在您 WinNT/2K 系统上载入装置的顺序。 LogonSessions 列出系统上的作用中登入工作阶段。 MoveFile 允许您对下一次开机进行移动和删除命令的排程。 NTFSInfo 使用 NTFSInfo 检视详细的 NTFS 磁碟区资讯,包括主档案表格 (MFT) 和 MFT 区的大小和位置,还有 NTFS 中继资料档案的大小。 PageDefrag 将您的分页档和登录 Hive 进行磁碟重组。 PendMoves 列举档案重新命名的清单,删除下次开机将会执行的命令。 Portmon 使用这个进阶的监视工具进行监视序列和平行连接埠活动。它不仅掌握所有标准的序列和平行 IOCTL,甚至会显示传送和接收的资料部份。Version 3.x 具有强大的新 UI 增强功能和进阶的筛选功能。 Process Monitor 即时监控档案系统、登录、程序、执行绪和 DLL 活动。 procexp 任务管理器,这个管理器比windows自带的管理器要强大方便的很多,建议替换自带的任务管理器(本人一直用这个管理器,很不错)。此工具也有汉化版,fans可以自己搜索下载 ProcFeatures 这个小应用程式会描述「实体位址扩充」的处理器和 Windows 支援,而没「没有执行」缓冲区溢位保护。 PsExec 以有限的使用者权限执行处理程序。 PsFile 检视远端开启档案有哪些。 PsGetSid 显示电脑或使用者的 SID。 PsInfo 取得有关系统的资讯。 PsKill 终止本机或远端处理程序。 PsList 显示处理程序和执行绪的相关资讯。 PsLoggedOn 显示使用者登录至一个系统。 PsLogList 倾印事件记录档的记录。 PsPasswd 变更帐户密码。 PsService 检视及控制服务。 PsShutdown 关机及选择重新启动电脑。 PsSuspend 暂停及继续处理程序。 PsTools PsTools 产品系列包括命令列公用程式,其功能有列出在本机或远端电脑上执行的处理程序、远端执行的处理程序、重新开机的电脑和倾印事件记录等等。 RegDelNull 扫描并删除登录机码,这些登录机码包括了标准登录编辑工具无法删除的内嵌式 Null 字元。 RegHide 建立名为 "HKEY_LOCAL_MACHINE\Software\Sysinternals\Can't touch me!\0" 并使用原生 API 的金钥,而且会在此金钥内建立一个值。 Regjump 跳至您在 Regedit 中指定的登录路径。 Regmon 这个监视工具让您即时看到全部的登录活动。 RootkitRevealer 扫描您系统上 Rootkit 为基础的恶意程式码。 SDelete 以安全的方法覆写您的机密档案,并且清除因先前使用这个 DoD 相容安全删除程式所删除档案後而释放的可用空间。包括完整的原始程式码。 ShareEnum 扫描网路上档案共用并检视其安全性设定,来关闭安全性漏洞。 Sigcheck 倾印档案版本资讯和验证系统上的影像皆已完成数位签章。 Strings 搜寻 binaryimages 中的 ANSI 和 UNICODE 字串。 Sync 将快取的资料清除至磁碟。 TCPView 作用中的通讯端命令列检视器。 VolumeId 设定 FAT 或 NTFS 磁碟区 ID。 Whois 看看谁拥有一个网际网路位址。 Winobj 最完整的物件管理员命名空间检视器在此。 ZoomIt 供萤幕上缩放和绘图的简报公用程式。 转自:http://www.360doc.com/content/15/0323/06/20545288_457293504.shtml 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_33515088/article/details/80721846。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-01-22 15:44:41
102
转载
转载文章
...所以在类加载的第二大阶段就是验证,这一步工作是虚拟机安全防护的关键所在,其中检查的步骤就是对class文件按照《Java虚拟机规范》规定的内容来对其进行验证。 1.总体结构 Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有添加任何分隔符,Class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。当遇到需要占用8位字节以上空间的数据项时,就按照高位在前的方式分割成若干个8位字节进行存储。 Class文件格式采用类似于C语言结构体的伪结构来存储数据,这种伪结构只有两种数据类型:无符号数和表。 无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节、8个字节的无符号数,无符号数可以来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值。 表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性的以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个Class文件本质上就是一张表,它的数据项构成如下图。 2.魔数(Magic Number) 每一个Class文件的头4个字节成为魔数(Magic Number),它的唯一作用是确定这个文件是否是一个能被虚拟机接收的Class文件。很多文件存储标准中都是用魔数来进行身份识别,比如gif、png、jpeg等都有魔数。使用魔数主要是来识别文件的格式,相比于通过文件后缀名识别,这种方式准确性更高,因为文件后缀名可以随便更改,但更改二进制文件内容的却很少。Class类文件的魔数是Oxcafebabe,cafe babe?咖啡宝贝?至于为什么是这个, 这个名字在java语言诞生之初就已经确定了,它象征着著名咖啡品牌Peet's Coffee中深受欢迎的Baristas咖啡,Java的商标logo也源于此。 3.文件版本(Version) 在魔数后面的4个字节就是Class文件的版本号,第5和第6个字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major Version)。Java的版本号是从45开始的,JDK1.1之后的每个JDK大版本发布主版本号向上加1(JDK1.0~1.1使用的版本号是45.0~45.3),比如我这里是十六进制的Ox0034,也就是十进制的52,所以说明该class文件可以被JDK1.8及以上的虚拟机执行,否则低版本虚拟机执行会报java.lang.UnsupportedClassVersionError错误。 4.常量池(Constant Pool) 在主版本号紧接着的就是常量池的入口,它是Class文件结构中与其他项目关联最多的数据类型,也是占用空间最大的数据之一。常量池的容量由后2个字节指定,比如这里我的是Ox001d,即十进制的29,这就表示常量池中有29项常量,而常量池的索引是从1开始的,这一点需要特殊记忆,因为程序员习惯性的计数法是从0开始的,而这里不一样,所以我这里常量池的索引范围是1~29。设计者将第0项常量空出来是有目的的,这样可以满足后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池项目”的含义。 通过javap -v命令反编译出class文件之后,我们可以看到常量池的内容 常量池中主要存放两大类常量:字面量和符号引用。比如文本字符、声明为final的常量值就属于字面量,而符号引用则包含下面三类常量: 类和接口的全限名 字段的名称和描述符 方法的名称和描述符 在之前的文章(详谈类加载的全过程)中有详细讲到,在加载类过程的第二大阶段连接的第三个阶段解析的时候,会将常量池中的符号引用替换为直接引用。相信很多人在开始了解那里的时候也是一头雾水,作者我也是,当我了解到常量池的构成的时候才明白真正意思。Java代码在编译的时候,是在虚拟机加载Class文件的时候才会动态链接,也就是说Class文件中不会保存各个方法、字段的最终内存布局信息,因此这些字段、方法的符号引用不经过运行期转换的话无法获得真正的内存入口地址,也就无法直接被虚拟机使用。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。 常量池中每一项常量都是一张表,这里我只找到了JDK1.7之前的常量池项目类型表,见下图。 常量池项目类型表: 常量池常量项的结构总表: 比如我这里测试的class文件第一项常量,它的标志位是Ox0a,即十进制10,即表示tag为10的常量项,查表发现是CONSTANT_Methodref_info类型,和上面反编译之后的到的第一个常量是一致的,Methodref表示类中方法的符号引用。查上面《常量池常量项的结构总表》可以看到Methodref中含有3个项目,第一个tag就是上述的Ox0a,那么第二个项目就是Ox0006,第三个项目就是Ox000f,分别指向的CONSTANT_Class_info索引项和CONSTANT_NameAndType_info索引项为6和15,那么反编译的结果该项常量指向的应该是6和15,查看上面反编译的图应证我们的推测是对的。后面的常量项就以此类推。 这里需要特殊说明一下utf8常量项的内容,这里我以第29项常量项解释,也就是最后一项常量项。查《常量池常量项的结构总表》可以看到utf8项有三个内容:tag、length、bytes。tag表示常量项类型,这里是Ox01,表示是CONSTANT_Utf8_info类型,紧接着的是长度length,这里是Ox0015,即十进制21,那么再紧接着的21个字节都表示该项常量项的具体内容。特别注意length表示的最大值是65535,所以Java程序中仅能接收小于等于64KB英文字符的变量和变量名,否则将无法编译。 5.访问标志(Access Flags) 在常量池结束后,紧接着的两个字节代表访问标志(Access Flags),该标志用于识别一些类或者接口层次的访问信息,其中包括:Class是类还是接口、是否定义为public、是否定义为abstract类型、类是否被声明为final等。 访问标志表 标志位一共有16个,但是并不是所有的都用到,上表只列举了其中8个,没有使用的标志位统统置为0,access_flags只有2个字节表示,但是有这么多标志位怎么计算而来的呢?它是由标志位为true的标志位值取或运算而来,比如这里我演示的class文件是一个类并且是public的,所以对应的ACC_PUBLIC和ACC_SIPER标志应该置为true,其余标志不满足则为false,那么access_flags的计算过程就是:Ox0001 | Ox0020 = Ox0021 篇幅原因,未完待续...... 参考文献:《深入理解Java虚拟机》 END 本篇文章为转载内容。原文链接:https://javar.blog.csdn.net/article/details/97532925。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-01-09 17:46:36
645
转载
转载文章
...是ok的。 入门学习阶段 最早的时候我并没有直接看书,而是先打算先看视频,因为视频更好理解呀,找视频的办法就是百度,于是当时找到的最好资源就是《郝斌的数据结构》这个视频应该是很早之前录制的了,但是对于小白来说是够用的,特别基础,讲的很仔细。 从最开始的数组、线性表,再讲到栈和队列,以及后面更复杂的二叉树、图、哈希表,大概有几十个视频,那个时候正值暑假,我按照每天一个视频的进度看完了,看的时候还得时不时地实践一下,更有助于理解。 看完了这个系列的视频之后,我又转战开始啃书了,视频里讲的都是数据结构的基础,而书上除了基础之外,还有一些算法题目,比如你学完了线性表和链表之后,书上就会有相关的算法题,比如数组的元素置换,链表的逆置等等,这些在日后看来很容易的题目,当时把我难哭了。 好在大部分题目是有讲解的,看完讲解之后还能安抚一下我受伤的心灵。 记住这本书,我在考研之前翻了至少有三四遍。 强化学习阶段 完成了第一波视频+书籍的学习之后,我们应该已经对数据结构有了初步的了解了,对一些简单的数据结构算法也应该有所了解了,比如栈的入栈和出栈,队列的进队和出队,二叉树的先序遍历和后续遍历、层次遍历,图的最短路径算法,深度优先遍历等等。 有了一定的基础之后,我们需要对哪方面进行强化学习呢? 那就要看你学习数据结构的目的是什么了,比如你学习数据结构是为了能做算法题,那么接下来你应该重点去学习算法方面的知识,后续我们也将有一篇新的文章来讲怎么学习算法,敬请期待。 当然,我当时主要是复习考研,所以还是针对专业课的历年真题来复习,像我们的卷子中就考察了很多关于哈希表、最短路径算法、KMP算法、赫夫曼算法以及最短路径算法的应用。 对于考卷上的一些知识点,我觉得掌握的并不是很好,于是又买了《王道数据结构》以及一些并没有什么卵用的书回来看,再次强化了基础。 并且,由于我们的复试通常会考察一些比较经典的算法问题,所以我又花了很多时间去学习这些算法题,这些题目并非数据结构的基础算法,所以在之前的书和视频中可能找不到答案。 于是我又在网上搜到了另一个系列视频《小甲鱼的数据结构视频》里面除了讲解数据结构之外,还讲解了更多经典的算法题,比如八皇后问题,汉诺塔问题,马踏棋盘,旅行商问题等,这些问题对于新手来说真的是很头大的,使用视频学习确实效果更佳。 实践阶段 纸上得来终觉浅,绝知此事要躬行。 众所周知,算法题和数学题一样,需要多加练习,而且考研的时候必须要手写算法,于是我就经常在纸上写(抄)算法,你还别说,就算是抄,多抄几次也有助于理解。 很多基础的算法,比如层次遍历,深度优先遍历和广度优先遍历,多写几遍更有助理解,再比如稍微复杂一点的迪杰斯特拉算法,不多写几遍你可真记不住。 除了在纸上写之外,更好的办法自然是在电脑上敲了,写Java的使用Java写,写C++ 的用C++ 写,总之用自己擅长的语言实现就好,尴尬的是我当时只会c,所以就只好老老实实地用devc++写简单的c语言程序了。 至此,我们也算是学会了数据结构的基础知识了,至少知道每个数据结构的特性,会写常见的数据结构算法,甚至偶尔还能掏出一个八皇后出来。 推荐资源 书籍 《天勤数据结构》 《王道数据结构》 如果你要考研的话,这两本书可不要错过 严蔚敏《数据结构C语言版》 这本书是大学本科计算机专业常用的教科书,年代久远,可以看看,官方也有配套的教学视频 《大话数据结构》 官方教材大家都懂的,比较不接地气,这本书对于很多新手来说是更适合入门的书籍。 《数据结构与算法Java版》 如果你是学Java的,想有一本Java语言描述的数据结构书籍,可以试试这本,但是这本书显然比较复杂,不适合入门使用。 视频 《郝斌数据结构》 这个视频上文有提到过,年代比较久远,但是入门足够了。 《小甲鱼数据结构与算法》 这个视频比较新,更加全面,有很多关于经典算法的教程,作者也入驻了B站,有兴趣也可以到B站看他的视频。 总结 关于数据结构的学习,我们就讲到这里了,如果还有什么疑问也可以到我公众号里找我探讨,虽然我们提到了算法,但是这里只关注一些基础的数据结构算法,后续会有关于“怎么学算法“的文章推出,敬请期待。 本篇文章为转载内容。原文链接:https://blog.csdn.net/a724888/article/details/104586757。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-09-12 23:35:52
134
转载
转载文章
转载文章
...ropagation阶段利用IMU数据预测系统的下一个状态,而EKF Update阶段则借助于双目视觉测得的特征信息对预测结果进行修正更新,以更准确地估算出系统的状态变量(例如位姿、速度等)。 静止初始化(Static Initialization) , 静止初始化是s_msckf系统启动时的重要步骤,其目的是校准初始时刻IMU坐标系与世界坐标系之间的相对关系,并确定IMU传感器的零偏参数(如陀螺仪偏差)。具体做法是在系统启动后的前200帧IMU数据中,通过对加速度和角速度求平均值来估计重力加速度及其方向,进而确定重力向量和IMU的原始偏差,为后续VIO过程提供准确的初始条件。这个过程中要求IMU在采集这些数据时处于静止状态,以便准确提取出重力分量。
2023-09-13 20:38:56
310
转载
Spark
...,数据可能只会在特定阶段被频繁访问,而在其他阶段则很少用到。要是你提前把这部分数据缓存了,不光白白占用了宝贵的内存空间,搞不好后面真要用缓存的地方还找不到足够的空位呢! 因此,合理规划缓存策略非常重要。比如说,在某个任务快开始了,你再随手调用一下.cache()这个方法,这样就能保证数据乖乖地待在内存里,别到时候卡壳啦! 三、实践案例 如何正确使用分布式缓存? 接下来,我想分享几个具体的案例,帮助大家更好地理解和运用分布式缓存。 案例1:简单的词频统计 假设我们有一个文本文件,里面包含了大量的英文单词。我们的目标是统计每个单词出现的次数。为了提高效率,我们可以先将文件内容缓存起来,然后再进行处理。 scala val textFile = sc.textFile("hdfs://path/to/input.txt") textFile.cache() val wordCounts = textFile.flatMap(_.split(" ")) .map(word => (word, 1)) .reduceByKey(_ + _) wordCounts.collect().foreach(println) 在这个例子中,.cache()方法确保了textFile RDD的内容只被加载一次,并且可以被后续的操作共享。其实嘛,要是没用缓存的话,每次你调用flatMap或者map的时候,都得重新去原始数据里翻一遍,这就跟每次出门都得把家里所有东西再检查一遍似的,纯属给自己找麻烦啊! 案例2:多步骤处理流程 有时候,一个任务可能会涉及到多个阶段的处理,比如过滤、映射、聚合等等。在这种情况下,合理安排缓存的位置尤为重要。 python from pyspark.sql import SparkSession spark = SparkSession.builder.appName("WordCount").getOrCreate() df = spark.read.text("hdfs://path/to/input.txt") 第一步:将文本拆分为单词 words = df.selectExpr("split(value, ' ') as words").select("words.") 第二步:缓存中间结果 words.cache() 第三步:统计每个单词的出现次数 word_counts = words.groupBy("value").count() word_counts.show() 这里,我们在第一步处理完之后立即调用了.cache()方法,目的是为了保留中间结果,方便后续步骤复用。要是不这么干啊,那每走一步都得把上一步的算一遍,想想就费劲,效率肯定低得让人抓狂。 四、总结与展望 通过今天的讨论,相信大家对Spark的分布式缓存有了更深刻的认识。虽然它能带来显著的性能提升,但也并非万能药。其实啊,要想把它用得溜、用得爽,就得先搞懂它是怎么工作的,再根据具体的情况去灵活调整。不然的话,它的那些本事可就都浪费啦! 未来,随着硬件条件的不断改善以及算法优化的持续推进,相信Spark会在更多领域展现出更加卓越的表现。嘿,咱们做开发的嘛,就得有颗永远好奇的心!就跟追剧似的,新技术一出就得赶紧瞅两眼,说不定哪天就用上了呢。别怕麻烦,多学点东西总没错,说不定哪天就能整出个大招儿来! 最后,感谢大家耐心阅读这篇文章。如果你有任何疑问或者想法,欢迎随时交流!让我们一起努力,共同进步吧!
2025-05-02 15:46:14
82
素颜如水
Kafka
Netty
...业实践中展现了强大的生命力。 以国内某大型电商平台为例,该平台每年处理的订单量高达数十亿笔,对系统的实时性和稳定性提出了极高的要求。在引入Netty之前,其系统在高峰期经常出现响应缓慢甚至宕机的情况。经过优化后,借助Netty的异步非阻塞I/O模型和零拷贝技术,该平台成功将订单处理延迟缩短至微秒级别,同时大幅降低了服务器资源的消耗。这一成果不仅提升了用户体验,也为企业的运营效率带来了质的飞跃。 与此同时,Netty在国际舞台上也展现出强劲的竞争力。近日,开源社区宣布Netty项目正式加入Linux基金会旗下的Open Usage Commons计划,这意味着Netty将获得更广泛的行业支持和标准化管理。此举将进一步推动Netty生态系统的健康发展,吸引更多开发者参与贡献,同时也为企业用户提供更为可靠的技术保障。 值得注意的是,尽管Netty具有诸多优势,但在实际部署过程中仍需谨慎规划。例如,在处理大规模数据流时,如何平衡内存使用与性能优化是一个重要的课题。此外,随着人工智能算法的不断演进,未来Netty或许还需要针对AI模型训练和推理任务进行专门适配,以满足新兴应用场景的需求。总之,Netty的未来充满无限可能,值得每一位开发者持续关注和探索。
2025-04-26 15:51:26
46
青山绿水
转载文章
...生制度,指在大学本科阶段表现优异的学生无需经过全国硕士研究生统一入学考试,直接获得学校推荐并被接收单位录取为硕士研究生。 夏令营 , 在本文中特指保研夏令营,是部分高校为了提前选拔和招收优秀本科生的一种活动形式。通常在每年的4月至7月间举办,通过学术讲座、笔试、面试等多种方式考察学生的综合素质和专业能力,并可能在夏令营期间就向表现优秀的营员发放预录取资格(即优营)。 预推免 , 预推免是相对于正式推免而言的一个概念,是指在国家统一的推免工作开始前,部分高校先行开展的推荐免试攻读研究生的选拔活动。与夏令营类似,预推免也是对申请者进行专业考核和面试,以确定是否给予其推免生资格,但时间一般安排在7月至9月,且流程可能更为紧凑。 北航计算机学硕 , 北航指的是北京航空航天大学,是我国著名的“双一流”建设高校之一;计算机学硕则代表计算机科学与技术学术型硕士研究生,区别于专硕(专业型硕士),更侧重于理论研究和学术探索。 知名高校 , 在文中,知名高校主要指具有较高学术声誉和社会影响力的高等学校,如文中提及的末流985高校以及上海科技大学、北京理工大学、北京航空航天大学等,在我国高等教育体系中占据重要地位,对于学生来说,进入这些学校深造意味着更高的平台和更多的机会。
2023-05-02 23:03:36
120
转载
转载文章
...于工厂设备种类多、分阶段建设,工控程序开发通常面临对接多种PLC厂商设备和不同系列与型号。因此出现了一种专门与不同PLC通讯的软件协议-OPC(OLE for Process Control),而各厂家在OPC基础上进行了不同程度的扩展,为了应对标准化和跨平台的趋势,和了更好的推广OPC,OPC基金会近些年在之前OPC成功应用的基础上推出了一个新的OPC标准-OPC UA。处于通讯效率上的考虑,很多厂家生产了OPCUA设备模块,内置处理器,性价比不错。不过这不是本文关注的重点。 概念 OPC UA(OPC Unified Architecture)是指OPC统一体系架构,是一种基于服务的、跨越平台的解决方案。 特点 扩展了OPC的应用平台。传统的基于COM/DCOM 的OPC技术只能基于Windows操作系统,OPC UA支持拓展到Linux和Unix平台。这使得基于OPC UA的标准产品可以更好地实现工厂级的数据采集和管理; 不再基于DCOM通讯,不需要进行DCOM安全设置; OPC UA定义了统一数据和服务模型,使数据组织更为灵活,可以实现报警与事件、数据存取、历史数据存取、控制命令、复杂数据的交互通信; OPC UA比OPC DA更安全。OPC UA传递的数据是可以加密的,并对通信连接和数据本身都可以实现安全控制。新的安全模型保证了数据从原始设备到MES,ERP系统,从本地到远程的各级自动化和信息化系统的可靠传递; OPC UA可以穿越防火墙,实现Internet 通讯。 依赖 我们通常不会从头写,可以基于OpcUa.core.dll库和OpcUa.Client.dll库,而且附上这2个库的源代码。 配置OpcUA Server 您可以安装任何一款支持OPCUA的服务端软件进行以下配置(此为示例配置,您可根据你的实际情况进行配置) 1、OpcUa Server Url:opc.tcp://192.168.100.1:4840。 2、OpcUa EndPoint:[UaServer@cMT-EAB9] [None] [None] [opc.tcp://192.168.100.1:4840/G01] 3、PLC Device Name:Siemens S7-1200/S7-1500 4、Account:user1 5、Password:自己设置 6、在PLC中开了2个数据块,分别为DB4长度110个字、DB5长度122个字。 7、对应第4块创建标签,第一个名称为DB4.0-99,地址为DB4DBW0.100,数据类型为Short,长度100,即定义长度最长为100的Short数组。第二个名称为DB4.100-109,地址为DB4DBW100.10,数据类型为Short,方便快速读取。 5、对应第5块创建3个标签,第一个名称为DB5.0-99,地址为DB5DBW0.100,数据类型为Short,第二个名称为DB5.100-121, 地址为DB5DBW100.22,数据类型为Short,即定义长度最长为100的Short数组。方便快速读取。第三个标签名称为DB5DBW64,地址为DB5DBW64,数据类型为Short。 具体如下图: 关键代码 using System;using System.Collections.Generic;using System.Linq;using Opc.Ua.Helper;using Mesnac.Equips;namespace Mesnac.Equip.OPC.OpcUa.OPCUA{public class Equip : BaseEquip{region 字段定义private bool _isOpen = false; //是否已打开设备private bool _isClosing = false; //是否正在关闭设备private OPCUAClass myOpcHelper; //OPCUA设备访问辅助对象private Dictionary<string, string> dicTags = null; //保存标签集合private Dictionary<string, object> readResult = null; //设备标签数据缓存private int stepLen = 250; //标签变量的步长设置private string groupNamePrefix = "DB"; //数据块号前缀private string childTagFlag = "~"; //子元素标签标志符private System.Threading.Thread innerReadThread = null; //内部读取线程对象private int innerReadRate = 1000; //内部读取频率endregionregion 属性定义/// <summary>/// OPCUA Server Url/// </summary>public string OpcUaServerUrl{get{//return (this.Main.ConnType as Mesnac.Equips.Connection.OPCUA.ConnType).OpcUaServerUrl;return "opc.tcp://192.168.1.102:4840";//return "opc.tcp://192.168.100.1:4840";//return "opc.tcp://192.168.100.2:4840";} }/// <summary>/// 要连接的OPCUA服务器上的服务名/// </summary>public string OpcUaServiceName{get{//return (this.Main.ConnType as Mesnac.Equips.Connection.OPCUA.ConnType).OpcUaServiceName;return "[UaServer@cMT-9F1F] [None] [None] [opc.tcp://192.168.1.102:4840/G01]";//return "[UaServer@cMT-EAB9] [None] [None] [opc.tcp://192.168.100.1:4840/G01]";//return "[UaServer@cMT-EA5B] [None] [None] [opc.tcp://192.168.100.2:4840/G02]";//return "[UaServer@cMT-EA5B] [None] [None] [opc.tcp://192.168.100.2:4840/G01]";} }/// <summary>/// 要连接的OPCUA服务器上指定服务名下的PLC的名称/// </summary>public string PLCName{get{//return (this.Main.ConnType as Mesnac.Equips.Connection.OPCUA.ConnType).PLCName;//return "Feeding";return "Siemens_192.168.2.1";//return "Rockwell_192.168.1.10";} }/// <summary>/// OPCUA服务器的访问账户/// </summary>public string Account{get{//return (this.Main.ConnType as Mesnac.Equips.Connection.OPCUA.ConnType).Account;return "user1";} }/// <summary>/// OPCUA服务器的访问密码/// </summary>public string Password{get{//return (this.Main.ConnType as Mesnac.Equips.Connection.OPCUA.ConnType).Password;return "1";} }endregionregion BaseEquip成员实现/// <summary>/// 打开连接设备/// </summary>/// <returns>成功返回true,失败返回false</returns>public override bool Open(){lock (this){this._isClosing = false;if (this._isOpen == true && this.myOpcHelper != null){return true;}this.State = false;this.myOpcHelper = new OPCUAClass();this.dicTags = this.myOpcHelper.ConnectOPCUA(this.OpcUaServerUrl, this.Account, this.Password, this.OpcUaServiceName, this.PLCName); //连接OPCServerif (this.dicTags == null || this.dicTags.Count == 0){this.myOpcHelper = null;Console.WriteLine("OPC连接失败!");this.State = false;return false;}else{this.State = true;this._isOpen = true;region 初始化读取结果this.readResult = new Dictionary<string, object>();foreach (Equips.BaseInfo.Group group in this.Group.Values){if (!group.IsAutoRead){continue;}int groupMinStart = group.Start;int groupMaxEnd = group.Start + group.Len;int groupMaxLen = group.Len;foreach (Equips.BaseInfo.Group g in this.Group.Values){if (!g.IsAutoRead){continue;}if (g.Block == group.Block){if (g.Start < group.Start){groupMinStart = g.Start;}if (g.Start + g.Len > groupMaxEnd){groupMaxEnd = g.Start + g.Len;} }}groupMaxLen = groupMaxEnd - groupMinStart;int tagCount = groupMaxLen % this.stepLen == 0 ? groupMaxLen / this.stepLen : groupMaxLen / this.stepLen + 1;int currLen = 0;for (int i = 0; i < tagCount; i++){string tagName = String.Empty;if (tagCount == 1){tagName = String.Format("{0}-{1}", groupMinStart, groupMinStart + groupMaxLen - 1);currLen = groupMaxLen;}else if (i == tagCount - 1){tagName = String.Format("{0}-{1}", groupMinStart + (i this.stepLen), groupMinStart + (i this.stepLen) + (groupMaxLen % this.stepLen == 0 ? this.stepLen : groupMaxLen % this.stepLen) - 1);currLen = groupMaxLen % this.stepLen;}else{tagName = String.Format("{0}-{1}", groupMinStart + (i this.stepLen), groupMinStart + (i this.stepLen) + this.stepLen - 1);currLen = this.stepLen;}string tagFullName = String.Format("{0}{1}.{2}", groupNamePrefix, group.Block, tagName);if (!this.readResult.ContainsKey(tagFullName)){bool exists = false;region 判断读取结果标签组的范围是否包括了此标签 比如tagFullName DB5.220-299,在readResult中存在 DB5.200-299,则认为已存在,不需要再添加string[] beginend = null;int begin = 0;int end = 0;string[] startstop = tagFullName.Replace(String.Format("{0}{1}.", groupNamePrefix, group.Block), String.Empty).Split(new char[] { '-' });int start = 0;int stop = 0;bool parseResult = false;if (startstop.Length == 2){parseResult = int.TryParse(startstop[0], out start);if (parseResult){parseResult = int.TryParse(startstop[1], out stop);} }if (parseResult){int existsMinBegin = 0; //已存在标签的最小开始索引int existsMaxEnd = 0; //已存在标签的最大结束索引bool isContinue = true; //标签值是否连续string[] existsTags = this.readResult.Keys.ToArray<string>();foreach (string tag in existsTags){if (tag.StartsWith(String.Format("{0}{1}.", groupNamePrefix, group.Block)) && tag.Contains(".") && tag.Contains("-")){string[] tagname = tag.Split(new char[] { '.' });if (tagname.Length == 2){beginend = tagname[1].Split(new char[] { '-' });if (beginend.Length == 2){parseResult = int.TryParse(beginend[0], out begin);if (parseResult){parseResult = int.TryParse(beginend[1], out end);}region 计算最小开始索引和最大结束索引if (begin < existsMinBegin){existsMinBegin = begin;region 判断标签值是否连续if (existsMaxEnd != 0 && begin != existsMaxEnd + 1){isContinue = false;}endregion}if (end > existsMaxEnd){existsMaxEnd = end;}endregion} }if (parseResult){if (start >= begin && stop <= end){exists = true;break;}if (isContinue){if (start >= existsMinBegin && stop <= existsMaxEnd){exists = true;break;} }} }} }endregionif (!exists){ushort[] groupData = new ushort[currLen];this.readResult[tagFullName] = groupData;Console.WriteLine(tagFullName);} }}//int tagCount = group.Len % this.stepLen == 0 ? group.Len / this.stepLen : group.Len / this.stepLen + 1;//int currLen = 0;//for (int i = 0; i < tagCount; i++)//{// string tagName = String.Empty;// if (tagCount == 1)// {// tagName = String.Format("{0}-{1}", group.Start, group.Start + group.Len - 1);// currLen = group.Len;// }// else if (i == tagCount - 1)// {// tagName = String.Format("{0}-{1}", group.Start + (i this.stepLen), group.Start + (i this.stepLen) + (group.Len % this.stepLen == 0 ? this.stepLen : group.Len % this.stepLen) - 1);// currLen = group.Len % this.stepLen;// }// else// {// tagName = String.Format("{0}-{1}", group.Start + (i this.stepLen), group.Start + (i this.stepLen) + this.stepLen - 1);// currLen = this.stepLen;// }// string tagFullName = String.Format("{0}{1}.{2}", groupNamePrefix, group.Block, tagName);// if (!this.readResult.ContainsKey(tagFullName))// {// short[] groupData = new short[currLen];// this.readResult[tagFullName] = groupData;// }//} }endregionregion 开启内部定时读取if (this.innerReadThread == null){this.innerReadRate = this.Main.ReadHz / 2;this.innerReadThread = new System.Threading.Thread(this.InnerAutoRead);this.innerReadThread.Start();}endregion}return this.State;} }/// <summary>/// 从设备读取数据/// </summary>/// <param name="block">要读取的块号</param>/// <param name="start">要读取的起始字</param>/// <param name="len">要读取的长度</param>/// <param name="buff">读取成功后的输出数据</param>/// <returns>成功返回true,失败返回false</returns>public override bool Read(string block, int start, int len, out object[] buff){lock (this){buff = null;if (this._isClosing){return false;}string readstrflag = String.Format("{0}{1}.{2}-{3}", this.groupNamePrefix, block, start, start + len - 1);System.Text.StringBuilder sbtaglength = new System.Text.StringBuilder();string startTag = String.Empty;string groupName = String.Format("{0}{1}", this.groupNamePrefix, block); //要读取的OPCServer块List<ushort> groupData = new List<ushort>();List<string> groupTagNames = new List<string>();int startIndex = 0;try{if (!Open()){return false;}//return true;string[] keys = this.readResult.Keys.ToArray<string>();foreach (string key in keys){if (key.StartsWith(groupName) && key.Replace(String.Format("{0}.", groupName), String.Empty).Contains("-")){groupTagNames.Add(key);} }groupTagNames.Sort(); //对块标签进行排序foreach (string key in groupTagNames){if (String.IsNullOrEmpty(startTag)){startTag = key.Replace(String.Format("{0}.", groupName), String.Empty);}ushort[] values;if (this.readResult[key] is ushort[]){values = this.readResult[key] as ushort[];}else{values = new ushort[] { (ushort)this.readResult[key] };}sbtaglength.Append(String.Format("tagName={0}, buff length = {1}", key, values.Length));groupData.AddRange(values);}buff = new object[len];if (!String.IsNullOrEmpty(startTag)){string strStartIndex = startTag.Substring(0, startTag.IndexOf("-"));int.TryParse(strStartIndex, out startIndex);startIndex = start - startIndex;Array.Copy(groupData.ToArray(), startIndex, buff, 0, buff.Length);}else{}return true;}catch (Exception ex){Console.WriteLine(String.Join(";", groupTagNames.ToArray<string>()));Console.WriteLine("data length = " + groupData.Count);Console.WriteLine(this.Name + "读取失败[" + readstrflag + "]:" + ex.Message);Console.WriteLine(sbtaglength.ToString());this.State = false;return false;} }}/// <summary>/// 写入数据到设备/// </summary>/// <param name="block">要写入的块号</param>/// <param name="start">要写入的起始字</param>/// <param name="buff">要写如的数据</param>/// <returns>成功返回true,失败返回false</returns>public override bool Write(int block, int start, object[] buff){bool result = true;lock (this){try{if (this._isClosing){return false;}if (!Open()){return false;}bool isWrite = false;region 按标签变量写入string itemId = "";foreach (Equips.BaseInfo.Group group in this.Group.Values){if (group.Block == block.ToString()){foreach (Equips.BaseInfo.Data data in group.Data.Values){if (group.Start + data.Start == start && data.Len == buff.Length){if (this.dicTags.ContainsKey(data.Name)){itemId = this.dicTags[data.Name];}break;} }} }if (!String.IsNullOrEmpty(itemId)){UInt16[] intBuff = new UInt16[buff.Length];for (int i = 0; i < intBuff.Length; i++){intBuff[i] = 0;if (!UInt16.TryParse(buff[i].ToString(), out intBuff[i])){Console.WriteLine("在写入OPCUA标签时把buff中的元素转为UInt16类型失败!");} }result = this.myOpcHelper.WriteUInt16(itemId, intBuff);if (!result){Console.WriteLine(String.Format("标签变量[{0}]写入失败!", itemId));return false;}else{Console.WriteLine("按标签变量写入..." + itemId);isWrite = true;} }if (isWrite){return true;}endregionregion 按块写入region 先读取相应标签数数据string startTag = String.Empty;string groupName = String.Format("{0}{1}", this.groupNamePrefix, block); //要读取的OPCServer块List<ushort> groupData = new List<ushort>();string[] keys = readResult.Keys.Where(o => o.StartsWith(groupName) && o.Contains("-")).OrderBy(c => c).ToArray<string>();foreach (string key in keys){if (String.IsNullOrEmpty(startTag)){startTag = key.Replace(String.Format("{0}.", groupName), String.Empty);}string[] beginEnd = key.Replace(String.Format("{0}.", groupName), String.Empty).Split(new char[] { '-' });if (beginEnd.Length != 2){Console.WriteLine(String.Format("标签变量[{0}]未按约定方式命名,请按[DB块号].[起始字-结束字]方式标签变量进行命名!", String.Format("{0}.{1}", key)));return false;}int begin = 0;int end = 0;int.TryParse(beginEnd[0], out begin);int.TryParse(beginEnd[1], out end);region 写入之前,先读取一下PLC的值if ((start >= begin && start <= end) || ((start + buff.Length - 1) >= begin && (start + buff.Length - 1) <= end) || (start < begin && (start + buff.Length - 1) > end)){this.ReadTag(key);if (this.readResult.ContainsKey(key) && this.readResult[key] is Array){Console.WriteLine("read = " + key);groupData.AddRange(this.readResult[key] as ushort[]);}else{Console.WriteLine(String.Format("读取结果中不包含标签变量[{0}]的值!", String.Format("{0}", key)));} }else{if (this.readResult.ContainsKey(key) && this.readResult[key] is Array){Console.WriteLine("no read = " + key);groupData.AddRange(this.readResult[key] as ushort[]);} }endregion}endregionif (String.IsNullOrEmpty(startTag)){Console.WriteLine("写入失败,未在OPCUAserver中找到对应的标签,block = {0}, start = {1}, len = {2}", block, start, buff.Length);return false;}region 更新标签中对应的数据后,再写回OPCServerint startIndex = 0;string strStartIndex = startTag.Substring(0, startTag.IndexOf("-"));int.TryParse(strStartIndex, out startIndex);startIndex = start - startIndex;ushort[] newDataBuffer = groupData.ToArray();for (int i = 0; i < buff.Length; i++){ushort svalue = 0;ushort.TryParse(buff[i].ToString(), out svalue);newDataBuffer[startIndex + i] = svalue;}int index = 0;string[] keys2 = readResult.Keys.Where(o => o.StartsWith(groupName) && o.Contains("-")).OrderBy(c => c).ToArray<string>();foreach (string key2 in keys2){string[] beginEnd = key2.Replace(String.Format("{0}.", groupName), String.Empty).Split(new char[] { '-' });if (beginEnd.Length != 2){Console.WriteLine(String.Format("标签变量[{0}]未按约定方式命名,请按[DB块号].[起始字-结束字]方式标签变量进行命名!", String.Format("{0}", key2)));return false;}int begin = 0;int end = 0;int.TryParse(beginEnd[0], out begin);int.TryParse(beginEnd[1], out end);if ((start >= begin && start <= end) || ((start + buff.Length - 1) >= begin && (start + buff.Length - 1) <= end) || (start < begin && (start + buff.Length - 1) > end)){//Console.WriteLine("---------------------------------------------------------");//Console.WriteLine("start = " + start);//Console.WriteLine("start + buff.Length - 1 = " + (start + buff.Length -1));//Console.WriteLine("begin = " + begin);//Console.WriteLine("end = " + end);//Console.WriteLine("---------------------------------------------------------");if (!this.dicTags.ContainsKey(key2)){Console.WriteLine(String.Format("写入失败:标签变量[{0}]在OpcUA Server中未定义!", String.Format("{0}", key2)));return false;}int len = (this.readResult[key2] as ushort[]).Length;ushort[] tagDataBuff = new ushort[len];//Console.WriteLine("newDataBuff");//Console.WriteLine(String.Join(",", newDataBuffer));//Console.WriteLine("index = " + index);//Console.WriteLine("tagDataBuff.Length = " + tagDataBuff.Length);//Array.Copy(newDataBuffer, begin, tagDataBuff, 0, tagDataBuff.Length);int existsMinBegin = this.GetExistsMinBeginByBlock(block.ToString());Array.Copy(newDataBuffer, begin - existsMinBegin, tagDataBuff, 0, tagDataBuff.Length);index += tagDataBuff.Length;//Console.WriteLine("Write " + key2);//Console.WriteLine(String.Join(",", tagDataBuff));//Console.WriteLine("写入标签:" + this.dicTags[key2]);result = this.myOpcHelper.WriteUInt16(this.dicTags[key2], tagDataBuff);if (!result){Console.WriteLine(String.Format("向标签变量[{0}]中写入值失败!", String.Format("{0}", key2)));return false;}else{this.ReadTag(key2);Console.WriteLine("写入...");}//Console.WriteLine("---------------------------------------------------------");} }endregionendregionreturn result;}catch (Exception ex){Console.WriteLine(this.Name + "写入失败:" + ex.Message);return false;} }}/// <summary>/// 关闭方法,断开与设备的连接释放资源/// </summary>public override void Close(){try{this._isClosing = true;System.Threading.Thread.Sleep(this.Main.ReadHz);if (this.innerReadThread != null){this.innerReadThread.Abort();this.innerReadThread = null;} }catch (Exception ex){Console.WriteLine("关闭内部读取OPCUA线程异常:" + ex.Message);}try{if (this.myOpcHelper != null){this.myOpcHelper.Close();this.myOpcHelper = null;this.State = false;this._isOpen = false;} }catch (Exception ex){Console.WriteLine("关于与OPCUA服务连接异常:" + ex.Message);} }endregionregion 辅助方法/// <summary>/// 获取某个数据块标签的最小开始索引/// </summary>/// <param name="block">块号</param>/// <returns>返回数据块标签的最小开始索引</returns>private int GetExistsMinBeginByBlock(string block){int existsMinBegin = 99999; //已存在标签的最小开始索引int existsMaxEnd = 0; //已存在标签的最大结束索引bool isContinue = true; //标签值是否连续string[] existsTags = this.readResult.Keys.ToArray<string>();string[] beginend = null;bool parseResult = false;int begin = 0;int end = 0;foreach (string tag in existsTags){if (tag.StartsWith(String.Format("{0}{1}.", groupNamePrefix, block)) && tag.Contains(".") && tag.Contains("-")){string[] tagname = tag.Split(new char[] { '.' });if (tagname.Length == 2){beginend = tagname[1].Split(new char[] { '-' });if (beginend.Length == 2){parseResult = int.TryParse(beginend[0], out begin);if (parseResult){parseResult = int.TryParse(beginend[1], out end);}region 计算最小开始索引和最大结束索引if (begin < existsMinBegin){existsMinBegin = begin;region 判断标签值是否连续if (existsMaxEnd != 0 && begin != existsMaxEnd + 1){isContinue = false;}endregion}if (end > existsMaxEnd){existsMaxEnd = end;}endregion} }if (parseResult){//} }}return existsMinBegin;}/// <summary>/// 读取标签/// </summary>/// <param name="tagName"></param>private void ReadTag(string tagName){UInt16[] buff = null;if (this.dicTags.ContainsKey(tagName)){if (this.myOpcHelper.ReadUInt16(this.dicTags[tagName], out buff)){//Console.WriteLine("tagName={0}, buff length = {1}", tagName, buff.Length);if (this.readResult.ContainsKey(tagName)){this.readResult[tagName] = buff;}else{this.readResult.Add(tagName, buff);} }else{Console.WriteLine("Mesnac.Equip.OPC.OpcUa.OPCUA.Equip.ReadTag Exception 读取标签:[{0}]失败!", tagName);} }else{Console.WriteLine("Mesnac.Equip.OPC.OpcUa.OPCUA.Equip.ReadTag Exception OPCUA Server中未定义此标签:[{0}]!", tagName);} }/// <summary>/// 内部自动读取方法/// </summary>private void InnerAutoRead(){while (this._isOpen && this._isClosing == false){try{if (this.myOpcHelper == null){this._isClosing = true;this.State = false;return;}lock (this){string[] keys = this.readResult.Keys.ToArray<string>();foreach (string key in keys){this.ReadTag(key);} }System.Threading.Thread.Sleep(this.innerReadRate);}catch (Exception ex){Console.WriteLine("Mesnac.Equip.OPC.OpcUa.OPCUA.Equip.InnerAutoRead Exception : " + ex.Message);} }this.innerReadThread = null;}endregionregion 析构方法~Equip(){this.Close();}endregion} } 代码下载 代码下载 本篇文章为转载内容。原文链接:https://blog.csdn.net/zlbdmm/article/details/96714776。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-05-10 18:43:00
269
转载
转载文章
...潜力。 无论处在什么阶段,保持学习都是十分重要的一件事。 工作的十几年间,为什么别人都升职了自己却留在原地? 常常会疑惑,刚进公司的时候也是优秀的潜力股一枚,升职的时候老板怎么就看不见我? 很简单,因为潜力股要经过挖掘投资才能成为优质股。 人就像一方活水,有源源不断的补给才能保持自身不干涸,才能掀得起浪花。 不断增加自己的学识、磨练出过硬的技能,在职场中你的综合考察才会不断加分! 不懂的投资自己,提升能力,只会让你被淘汰的更快。 心态老得比身体快 明明还是个中年人,精神面貌看着还不如小区里跳广场舞的大妈大爷们。 整个人的心态衰老程度已经远远超过身体的衰老程度。 从内里散发出消极颓废的负能量。 试想谁会把重要的工作交给一个丧气满满的人呢? 职场上的中年人在做事的时候难免受家庭、他人眼光、年龄的牵绊,畏手畏脚,瞻前顾后。 他们总在想,我这样做,会显得自己过于出彩,会畏惧别人“一把年纪还想出风头”的闲言碎语和轻信别人“老了老了,都是年轻人的天下”的衰言败语。 妈妈常教导我,让我养成良好习惯。这样长大才能成为一个有用的人。良好的习惯是尊敬师长这样长大才能成为一个有用的人。良好的习惯是尊敬师长,爱护同学,对人有礼貌;是不粗心,做事情不拖拉;还是爱护公物,不浪费粮食。为什么呢?因为拥有良好习惯,做一个品德高尚的人,懂得尊重别人,才会得到别人的尊重。我要努力地做到这些。我有一些坏习惯,有时候学习很粗心,把一些会做的题做错。在生活上,也很粗心,有一次早上起床居然穿反了衣服。我吃饭很慢,有的时候还剩饭。我还起床磨蹭,本来应该迅速地穿好衣服,但是,我总是磨磨蹭蹭地,速度很慢。“我打算在这学期里,改掉这些坏习惯。早上起来,迅速地穿好衣服,不拖拉。学习不粗心,仔细完成每一道题。吃饭的时候,要很快的把饭吃完,不剩饭。我要从一点一滴做起,逐渐养成良好习惯。我相信自己一定能成为一名品学兼优的好学生!我打算在这学期里,改掉这些坏习惯。早上起来,迅速地穿好衣服,不拖拉。学习不粗心,仔细完成每一道题。吃饭的时候,要很快的把饭吃完,不剩饭。我要从一点一滴做起,逐渐养成良好习惯。我相信自己一定能成为一名品学兼优的好学生!” 在上幼儿园以前,我什么也不会干,就连穿衣服也是妈妈给我穿好,就要上幼儿园了,这样可不行,妈妈锻炼我要学会自己穿衣服。 有一天,妈妈把衣服摆在我面前,开始让我自己穿。一开始。我又哭又叫就是不穿,还把衣服扔的满地都是,然后坐在地上开始大哭,等了好长时间,妈妈还是不理我,我只好自己乖乖的把衣服穿好, 一出了房间门,妈妈就笑了起来,再看看我的衣服,毛衣和裤子都穿反了,我赶紧回房间又重新穿了一遍,这次穿好了,拿起外套,可是外套的扣子又扣不上了,扣子可调皮了,好像故意和我作对,我把扣子往扣眼——人类邪恶的根源;爱情——幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话:幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话“亲爱的!擦干你的眼泪,至高无上的爱情已经打开了我们的眼界,使我们成了它的崇拜者。是它, 妈妈常教导我,让我养成良好习惯。这样长大才能成为一个有用的人。良好的习惯是尊敬师长这样长大才能成为一个有用的人。良好的习惯是尊敬师长,爱护同学,对人有礼貌;是不粗心,做事情不拖拉;还是爱护公物,不浪费粮食。为什么呢?因为拥有良好习惯,做一个品德高尚的人,懂得尊重别人,才会得到别人的尊重。我要努力地做到这些。我有一些坏习惯,有时候学习很粗心,把一些会做的题做错。在生活上,也很粗心,有一次早上起床居然穿反了衣服。我吃饭很慢,有的时候还剩饭。我还起床磨蹭,本来应该迅速地穿好衣服,但是,我总是磨磨蹭蹭地,速度很慢。“我打算在这学期里,改掉这些坏习惯。早上起来,迅速地穿好衣服,不拖拉。学习不粗心,仔细完成每一道题。吃饭的时候,要很快的把饭吃完,不剩饭。我要从一点一滴做起,逐渐养成良好习惯。我相信自己一定能成为一名品学兼优的好学生!我打算在这学期里,改掉这些坏习惯。早上起来,迅速地穿好衣服,不拖拉。学习不粗心,仔细完成每一道题。吃饭的时候,要很快的把饭吃完,不剩饭。我要从一点一滴做起,逐渐养成良好习惯。我相信自己一定能成为一名品学兼优的好学生!” 在上幼儿园以前,我什么也不会干,就连穿衣服也是妈妈给我穿好,就要上幼儿园了,这样可不行,妈妈锻炼我要学会自己穿衣服。 有一天,妈妈把衣服摆在我面前,开始让我自己穿。一开始。我又哭又叫就是不穿,还把衣服扔的满地都是,然后坐在地上开始大哭,等了好长时间,妈妈还是不理我,我只好自己乖乖的把衣服穿好, 一出了房间门,妈妈就笑了起来,再看看我的衣服,毛衣和裤子都穿反了,我赶紧回房间又重新穿了一遍,这次穿好了,拿起外套,可是外套的扣子又扣不上了,扣子可调皮了,好像故意和我作对,我把扣子往扣眼——人类邪恶的根源;爱情——幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话:“亲爱的!擦干你的眼泪,至高无上的爱情已经打开了我们的眼界,使我们成了它的崇拜者。是它, 每一个碌碌无为的中年人都改明白的一个道理是,职场所谓的新人老人,取决于你的成就,而不是入行时间。 入行十余年还不如别人入行三五年来的专业,所谓老人不过是虚谈。 只要一天还出成绩,对待工作就当保持一个新人该有的拼劲和争上游的心态,抛开顾虑,努力向前便是! -END- 声明:本文属于老板思维与智库(ID:laobanzhiku88),图片来源于网络 看完本文有收获?请转发分享给更多人 欢迎关注“互联网架构师”,我们分享最有价值的互联网技术干货文章,助力您成为有思想的全栈架构师,我们只聊互联网、只聊架构,不聊其他!打造最有价值的架构师圈子和社区。 本公众号覆盖中国主要首席架构师、高级架构师、CTO、技术总监、技术负责人等人 群。分享最有价值的架构思想和内容。打造中国互联网圈最有价值的架构师圈子。 长按下方的二维码可以快速关注我们 如想加群讨论学习,请点击右下角的“加群学习”菜单入群 本篇文章为转载内容。原文链接:https://blog.csdn.net/emprere/article/details/98859913。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-06-29 14:16:29
119
转载
转载文章
...向智能化、个性化的新阶段。动态电量管理功能不仅体现了谷歌与DeepMind在节能优化方面的深度合作,也预示着未来移动设备将更智能地根据用户习惯调整资源分配,从而显著提升续航能力。 近年来,各大手机制造商竞相推出具有生物特征识别功能的设备,Android P通过引入统一的BiometricPrompt API,为用户提供一致且安全的生物识别体验,这一举措无疑将进一步推动行业的规范化和标准化进程。受保护确认操作的加入,则展示了谷歌对用户隐私保护的重视程度日益增强,利用TEE确保重要操作得到用户真实授权,有效防止恶意软件侵入。 值得注意的是,Slices和App Actions作为Android P中的创新交互方式,不仅提升了用户体验,也为开发者提供了全新的应用推广渠道和用户黏性增强工具。而Google ML Kit的不断更新和完善,使得开发者能够更容易地集成智能回复等功能到应用中,大大降低了AI技术的使用门槛。 近日,多家主流手机品牌宣布支持Android P Beta版升级,这意味着更多用户将能体验到新一代系统的种种革新之处。同时,开发者社区也在积极响应,纷纷着手针对新特性的应用开发与优化工作。在未来几个月内,我们有望看到一系列基于Android P打造的全新或更新应用上线,进一步展现AI赋能下的智能手机生态繁荣景象。 总的来说,Android P Beta版本的发布是AI技术与智能手机操作系统深度融合的重要里程碑,它既彰显了谷歌对于用户需求洞察的敏锐度,又昭示了其对未来智能设备发展趋势的前瞻性布局。随着Android P的全面普及以及后续版本的迭代演进,人工智能将在移动领域释放出更大的潜力,为全球数以亿计的Android用户提供更为便捷、智能的生活服务。
2023-04-10 18:19:36
338
转载
转载文章
...。其实这个模型就是多阶段学习网络的一部分,作者想通过中间监督来提高网络的性能。 我提取bihand网络中的SeedNet与训练权重,进行分割结果展示如下 我是用的模型不是全程的,是第一阶段的。为了可视化出最好的效果,我把第一阶段也就是SeedNet网络的输出分别采用不同的方式可视化。 从左边数第一张图为原图,第二张图为sigmoid后利用plt.imshow(colored_mask, cmap=‘jet’)进行彩色映射。第三张图为网络输出的张量经过sigmoid后,二色分割图,阀闸值0.5。第四张为网络的直接输出,利用直接产生的张量图进行颜色映射。第五张为使用sigmoid处理张量后进行的颜色映射。第六张为使用sigmoid处理张量后进行0,1分割掩码映射。使用原模型和网络需要添加很多代码。下面为修改后的的代码: 下面为修改后的net_seedd代码: Copyright (c) Lixin YANG. All Rights Reserved.r"""Networks for heatmap estimation from RGB images using Hourglass Network"Stacked Hourglass Networks for Human Pose Estimation", Alejandro Newell, Kaiyu Yang, Jia Deng, ECCV 2016"""import numpy as npimport torchimport torch.nn as nnimport torch.nn.functional as Ffrom skimage import io,transform,utilfrom termcolor import colored, cprintfrom bihand.models.bases.bottleneck import BottleneckBlockfrom bihand.models.bases.hourglass import HourglassBisectedimport bihand.utils.func as funcimport matplotlib.pyplot as pltfrom bihand.utils import miscimport matplotlib.cm as cmdef color_mask(output_ok): 颜色映射cmap = plt.cm.get_cmap('jet') 将张量转换为numpy数组mask_array = output_ok.detach().numpy() 创建彩色图像cmap = cm.get_cmap('jet')colored_mask = cmap(mask_array)return colored_mask 可视化 plt.imshow(colored_mask, cmap='jet') plt.axis('off') plt.show()def two_color(mask_tensor): 将张量转换为numpy数组mask_array = mask_tensor.detach().numpy() 将0到1之间的值转换为二值化掩码threshold = 0.5 阈值,大于阈值的为白色,小于等于阈值的为黑色binary_mask = np.where(mask_array > threshold, 1, 0)return binary_mask 可视化 plt.imshow(binary_mask, cmap='gray') plt.axis('off') plt.show()class SeedNet(nn.Module):def __init__(self,nstacks=2,nblocks=1,njoints=21,block=BottleneckBlock,):super(SeedNet, self).__init__()self.njoints = njointsself.nstacks = nstacksself.in_planes = 64self.conv1 = nn.Conv2d(3, self.in_planes, kernel_size=7, stride=2, padding=3, bias=True)self.bn1 = nn.BatchNorm2d(self.in_planes)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(2, stride=2)self.layer1 = self._make_residual(block, nblocks, self.in_planes, 2self.in_planes) current self.in_planes is 64 2 = 128self.layer2 = self._make_residual(block, nblocks, self.in_planes, 2self.in_planes) current self.in_planes is 128 2 = 256self.layer3 = self._make_residual(block, nblocks, self.in_planes, self.in_planes)ch = self.in_planes 256hg2b, res1, res2, fc1, _fc1, fc2, _fc2= [],[],[],[],[],[],[]hm, _hm, mask, _mask = [], [], [], []for i in range(nstacks): 2hg2b.append(HourglassBisected(block, nblocks, ch, depth=4))res1.append(self._make_residual(block, nblocks, ch, ch))res2.append(self._make_residual(block, nblocks, ch, ch))fc1.append(self._make_fc(ch, ch))fc2.append(self._make_fc(ch, ch))hm.append(nn.Conv2d(ch, njoints, kernel_size=1, bias=True))mask.append(nn.Conv2d(ch, 1, kernel_size=1, bias=True))if i < nstacks-1:_fc1.append(nn.Conv2d(ch, ch, kernel_size=1, bias=False))_fc2.append(nn.Conv2d(ch, ch, kernel_size=1, bias=False))_hm.append(nn.Conv2d(njoints, ch, kernel_size=1, bias=False))_mask.append(nn.Conv2d(1, ch, kernel_size=1, bias=False))self.hg2b = nn.ModuleList(hg2b) hgs: hourglass stackself.res1 = nn.ModuleList(res1)self.fc1 = nn.ModuleList(fc1)self._fc1 = nn.ModuleList(_fc1)self.res2 = nn.ModuleList(res2)self.fc2 = nn.ModuleList(fc2)self._fc2 = nn.ModuleList(_fc2)self.hm = nn.ModuleList(hm)self._hm = nn.ModuleList(_hm)self.mask = nn.ModuleList(mask)self._mask = nn.ModuleList(_mask)def _make_fc(self, in_planes, out_planes):bn = nn.BatchNorm2d(in_planes)conv = nn.Conv2d(in_planes, out_planes, kernel_size=1, bias=False)return nn.Sequential(conv, bn, self.relu)def _make_residual(self, block, nblocks, in_planes, out_planes):layers = []layers.append( block( in_planes, out_planes) )self.in_planes = out_planesfor i in range(1, nblocks):layers.append(block( self.in_planes, out_planes))return nn.Sequential(layers)def forward(self, x):l_hm, l_mask, l_enc = [], [], []x = self.conv1(x) x: (N,64,128,128)x = self.bn1(x)x = self.relu(x)x = self.layer1(x)x = self.maxpool(x) x: (N,128,64,64)x = self.layer2(x)x = self.layer3(x)for i in range(self.nstacks): 2y_1, y_2, _ = self.hg2b[i](x)y_1 = self.res1[i](y_1)y_1 = self.fc1[i](y_1)est_hm = self.hm[i](y_1)l_hm.append(est_hm)y_2 = self.res2[i](y_2)y_2 = self.fc2[i](y_2)est_mask = self.mask[i](y_2)l_mask.append(est_mask)if i < self.nstacks-1:_fc1 = self._fc1[i](y_1)_hm = self._hm[i](est_hm)_fc2 = self._fc2[i](y_2)_mask = self._mask[i](est_mask)x = x + _fc1 + _fc2 + _hm + _maskl_enc.append(x)else:l_enc.append(x + y_1 + y_2)assert len(l_hm) == self.nstacksreturn l_hm, l_mask, l_encif __name__ == '__main__':a = torch.randn(10, 3, 256, 256) SeedNetmodel = SeedNet() output1,output2,output3 = SeedNetmodel(a) print(output1,output2,output3)total_params = sum(p.numel() for p in SeedNetmodel.parameters())/1000000print("Total parameters: ", total_params)pretrained_weights_path = 'E:/bihand/released_checkpoints/ckp_seednet_all.pth.tar'img_rgb_path=r"E:\FreiHAND\training\rgb\00000153.jpg"img=io.imread(img_rgb_path)resized_img = transform.resize(img, (256, 256), anti_aliasing=True)img256=util.img_as_ubyte(resized_img)plt.imshow(resized_img)plt.axis('off') 关闭坐标轴plt.show()''' implicit HWC -> CHW, 255 -> 1 '''img1 = func.to_tensor(img256).float() 转换为张量并且进行标准化处理''' 0-mean, 1 std, [0,1] -> [-0.5, 0.5] '''img2 = func.normalize(img1, [0.5, 0.5, 0.5], [1, 1, 1])img3 = torch.unsqueeze(img2, 0)ok=img3print(img.shape)SeedNetmodel = SeedNet()misc.load_checkpoint(SeedNetmodel, pretrained_weights_path)加载权重output1, output2, output3 = SeedNetmodel(img3)mask_tensor = torch.rand(1, 64, 64)output=output2[1] 1,1,64,64output_1=output[0] 1,64,64output_ok=torch.sigmoid(output_1[0])output_real=output_1[0].detach().numpy()直接产生的张量图color_mask=color_mask(output_ok) 显示彩色分割图two_color=two_color(output_ok)显示黑白分割图see=output_ok.detach().numpy() 使用Matplotlib库显示分割掩码 plt.imshow(see, cmap='gray') plt.axis('off') plt.show() print(output1, output2, output3)images = [resized_img, color_mask, two_color,output_real,see,see]rows = 1cols = 4 创建子图并展示图像fig, axes = plt.subplots(1, 6, figsize=(30, 5)) 遍历图像列表,并在每个子图中显示图像for i, image in enumerate(images):ax = axes[i] if cols > 1 else axes 如果只有一列,则直接使用axesif i ==5:ax.imshow(image, cmap='gray')else:ax.imshow(image)ax.imshowax.axis('off') 调整子图之间的间距plt.subplots_adjust(wspace=0.1, hspace=0.1) 展示图像plt.show() 上述的代码文件是在bihand/models/net_seed.py中,全部代码链接在https://github.com/lixiny/bihand。 把bihand/models/net_seed.p中的代码修改为我提供的代码即可使用作者训练好的模型和进行各种可视化。(预训练模型根据作者代码提示下载) 3.调用阿里云API进行证件照生成实例 3.1 准备工作 1.找到接口 进入下面链接即可快速访问 link 2.购买试用包 3.查看APPcode 4.下载代码 5.参数说明 3.2 实验代码 !/usr/bin/python encoding: utf-8"""===========================证件照制作接口==========================="""import requestsimport jsonimport base64import hashlibclass Idphoto:def __init__(self, appcode, timeout=7):self.appcode = appcodeself.timeout = timeoutself.make_idphoto_url = 'https://idp2.market.alicloudapi.com/idphoto/make'self.headers = {'Authorization': 'APPCODE ' + appcode,}def get_md5_data(self, body):"""md5加密:param body_json::return:"""md5lib = hashlib.md5()md5lib.update(body.encode("utf-8"))body_md5 = md5lib.digest()body_md5 = base64.b64encode(body_md5)return body_md5def get_photo_base64(self, file_path):with open(file_path, 'rb') as fp:photo_base64 = base64.b64encode(fp.read())photo_base64 = photo_base64.decode('utf8')return photo_base64def aiseg_request(self, url, data, headers):resp = requests.post(url=url, data=data, headers=headers, timeout=self.timeout)res = {"status_code": resp.status_code}try:res["data"] = json.loads(resp.text)return resexcept Exception as e:print(e)def make_idphoto(self, file_path, bk, spec="2"):"""证件照制作接口:param file_path::param bk::param spec::return:"""photo_base64 = self.get_photo_base64(file_path)body_json = {"photo": photo_base64,"bk": bk,"with_photo_key": 1,"spec": spec,"type": "jpg"}body = json.dumps(body_json)body_md5 = self.get_md5_data(body=body)self.headers.update({'Content-MD5': body_md5})data = self.aiseg_request(url=self.make_idphoto_url, data=body, headers=self.headers)return dataif __name__ == "__main__":file_path = "图片地址"idphoto = Idphoto(appcode="你的appcode")d = idphoto.make_idphoto(file_path, "red", "2")print(d) 3.3 实验结果与分析 原图片 背景为红色生成的证件照 背景为蓝色生成的证件照 另外尝试了使用柴犬照片做实验,也生成了证件照 原图 背景为红色生成的证件照 参考(可供参考的链接和引用文献) 1.参考:BiHand: Recovering Hand Mesh with Multi-stage Bisected Hourglass Networks(BMVC2020) 论文链接:https://arxiv.org/pdf/2008.05079.pdf 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_37758063/article/details/131128967。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-07-11 23:36:51
132
转载
转载文章
...等方法,以及在提案阶段的Temporal API(暂未正式发布),旨在提供更精确、易用且符合国际化标准的时间日期处理功能。因此,了解这些最新的API动态将有助于您编写更为现代化的JavaScript代码。 其次,关于正则表达式在实际项目中的应用,可以查阅一些近期开发者博客或技术文章,了解他们在表单验证、URL解析、文本搜索替换等方面的实战案例。例如,一篇名为“利用正则表达式优化用户输入验证策略”的文章详尽探讨了如何结合现代浏览器特性,如约束验证API,配合正则表达式进行高效的数据校验。 此外,对于正则表达式的性能优化也是值得关注的话题。有研究指出,在处理大量数据时,某些复杂的正则可能导致性能瓶颈。阅读相关的性能分析报告和技术分享,可以帮助开发者掌握编写高性能正则表达式的技巧,并避免潜在的性能陷阱。 最后,关于UTC时间戳在跨时区开发中的重要性,可参考有关国际协作项目中如何妥善处理时间问题的文章,了解如何借助JavaScript Date对象正确转换和处理不同时区的时间信息,从而确保在全球范围内应用程序的正常运行。尤其在当前全球化的互联网环境下,理解和掌握这一技能愈发关键。
2023-01-24 13:01:25
529
转载
转载文章
...数据库的事务,实现两阶段提交,从而确保两个数据库的数据一致性。 消息中间件 , 消息中间件是一种软件组件,用于应用程序之间传递异步消息,实现解耦、可靠传输和消息队列等功能。在文中提到的基于ActiveMQ的解决方案中,消息中间件充当了分布式事务协调者角色。当支付宝完成扣款后,会将消息插入到message表并发送至ActiveMQ,余额宝从消息队列消费消息并执行增款操作,通过这种方式实现了不同系统间的通信和事务协调,同时利用message表防止消息丢失和重复消费问题,确保了分布式事务的最终一致性。
2023-04-16 22:34:52
499
转载
转载文章
...误的,因为心流虽然是生命的特质,但不是人类的特质,我想笛卡尔的理论中把心灵换做灵魂可能会更妥当一些,尽管灵魂的存在目前还是个未知数。或许我说完接下来的例子,会解释的更充分些。 对于心流的存在,生物学家给出了一个简单的不能再简单的解释,那就是,如果没有感觉和欲望,那么就无法解释生物的各种行为。拿人来做例子或许会比较难以理解,但是拿动物做例子却简单的过分,那就是:当人去踢狗的时候,如果狗没有感到疼痛,愤怒,产生躲避的欲望,那么它就会因此而受到伤害。也就是说,这些种种的感觉与欲望,是那些最原始的东西,即进化论为了使生命更好的活着而产生的,只因人类把自己放在比动物高很多个层次的阶级上,而忽略了这个很简单的问题。 心流的产生 问题的关键,在于心流的产生。这样稍微改动下,上文所提到的笛卡尔的理论或许会更合理些:人与动物都存在感觉与欲望,但是动物的感觉与欲望是依靠自身结构在外界的输入下产生的一种内部输出,而人类的感觉和欲望则是一种可以被称作“灵魂”的东西控制下产生的。从而确立了人类高于动物的地位。 前者很容易理解,现在的科学研究也已经很透彻了。例如兔子见到狮子,电信号便从眼睛传到大脑,刺激某些神经元,又结合之前的记忆神经元,放出更多的信号,整条线路的神经元一一受到刺激,最后指令传到肾上腺,让肾上腺素传遍全身,心脏的跳动也随之加快,肾上腺素也使信号的传递速度更快了些,同时在运动中枢的神经元也向腿部肌肉发出信号,让肌肉随着信号有序的完成伸展和收缩。外在的表现就是兔子从狮子旁边逃之夭夭。至于其中的恐惧的感觉和想要逃跑的欲望,都只不过是内部神经元信号的一种状态。 而对于后者,则难以解释。正因为对前者的理解透彻,对后者的解释才显得很难说通。两个过程本来是相同的过程,只是后者多了对于每个人有且唯一的“灵魂”的存在的介入,但是,它究竟何时介入,如何介入,正如前者所描述的,在这样一个信号的传递网络里,究竟有哪一步,是需要“灵魂”来控制的。思前想后,好像并没有必须存在的那么一个步骤。也就是可能,前者所描述的那个信号传递步骤,适用于所有生物,当然也包括人类。 简单的总结 简单的总结一下,关于确定存在的心流和不确定存在的灵魂。 首先,心流是确定存在,并且存在与所有生物当中,是生物进化产生的,为了更好的活着。其中,记忆储存的是之前的心流状态,当然不是全部的心流状态;感觉是当时的生物内部信号的一种状态,成为现态;欲望是一种内部输出,欲望,感觉和记忆相结合再结合会产生对外部的输出。 其次,“灵魂”在这里表示为一个个体的有且唯一的存在。它不参与生物的任何过程,但是却有选择的监视生物的心流。也可以这样说,生物体本身有选择的展示一部分心流以供灵魂检阅,灵魂也是从生物所展示的心流中有选择的检阅。这才是人类的特质。我们真正的自我,就是这样一个有且唯一的灵魂,它无法介入它所在的生物体的任何事情,但是可以在一定程度上知道它所在的生物体的状态。 也可以这样理解,生物体本身是一个封装的很好的复杂程序,心流则是程序的内部变量,程序不断的接收外部输入并向外部输出,我们本身的灵魂所在则置身于程序之外,就像我们坐在电脑前,无法知道这个复杂程序究竟是如何运行的,但是通过它输出在显示屏中的一些内部变量,即心流的一些数据,我们可以大致的判断出,程序在干些什么。对于这样的解释你可能难以接受,接下来的两个例子或许会让你接受这一事实。 现在科学家只要扫描人脑,就能在测试者自己有所感知之前,预测他们会有什么欲望,会做出怎样的决定。例如,在一次实验中,受试者躺在一台巨大的脑部设备里,两手各自拿着一个开关,受试者可以随机的选择在何时按下那个开关。而科学家通过观察受试者的大脑神经活动,就能在受试者做决定之前知道受试者做了怎样的决定。也就是说,当这些内部输出被外部观测者“灵魂”所察觉的时候,心流自身已经做出了决定。7 或许你没有亲自做过这个实验,并不相信实验的结论,但是还有一个实验,你现在就可以给自己做一个测试。相信对于大家心算100以内的乘法没有什么问题,那么请各位充分运用自己的自由意志,即本文中的“灵魂”去控制你的大脑心算5672,注意在计算的过程中不要让自己的大脑去思考其他的任何事情,用尽快的速度计算出结果。当然,你会发现你根本做不到,无论如何你都无法控制那先奇奇怪怪的想法出现在你的大脑里,至于大脑为什么会像你控制的那样去计算5672,接下来我会给出人类的大脑思维模型。 生物的模型 生物的模型分为两部分,一部分我称为确定机,一部分我称为概率机。 确定机 确定机是指只要输入确定,那么就会产生确定输出的部分,而对于输入的概率性则不予考虑。例如,当生物多次看到同一个画面的时候会在大脑里形成同样的图像,因为每次输入的光信号都是一样的,在生物内部进行的信号传递过程也是一样的,所以在大脑里形成的图像输出也是一样的。现在人类所生产的绝大多数工具就是一个确定机的模型,如果相同的输入,不管输入多少次都会得到相同的输出。确定机也是生物模型的基础部分,构成生物的绝大部分,实际上,除了大脑,生物的任何部分都是一个确定机的模型,而大脑也有一部分的确定机模型。对于确定机,所有的内部过程和输出都不会被“灵魂”检阅,当然生物上可以通过解剖或其他更先进的方式去检查生物内部确定机的工作状态。 概率机 概率机是指即使输入确定,输出的确定性也指限制在一定的概率范围之内,会以不同但是给定的概率输出多个输出。当然给定的概率可以是确定机给出的确定概率(只在输入确定的情况下才确定),也可以是概率机给出的概率概率。概率机构成生物的大脑部分,当然一部分低等生物只由确定机构成。对于概率机,有一部分输出会被“灵魂”检阅,而“灵魂”是否检阅取决于“灵魂”本身,当然,对于概率机的工作状态,也可以通过解剖或其他更先进的方式去检查。 生物思考的过程 对于不同的生物,大脑可以同时进行的事情是有限的。就像现在的电脑手机一样,有严格的内存限制,对于大脑来说,同时启用着多个线程,每个线程所占用的内存不同,但是所有线程所占用的内存总和不得超限。对于每个线程,会随机的考虑一些事件,这些事件包括记忆中的事件,和当时正在发生的事件,对于每个事件出现在线程中的概率不同。 不同事件的概率遵循的规律大致有以下几条: 1.对记忆中的事件,事件越久远概率越低。 2.对当时正在发生的事件,概率大致相同。 3.与当时线程中事件有关的事件概率高,无关的概率低。 4.与线程中的事件相关的个数越多,概率越高 5.对不同的心流状态,概率分配有所不同。 6.每个个体对不同的事件有不同的概率分配方案。 7.待补充。 可以说,大脑中的一切过程都是随机的。那这样的话,生物的思考过程究竟如何进行呢?其实很简单,单个概率可能代表随机,但是多个概率就有可能表示必然。我还是举那个5672的例子,为什么你会真的去心算这个结果,大致的过程是这样的,如果大脑的思考频率以毫秒计的话,假设看5672用了200毫秒,其中每毫秒除了这一事件,还有其他的99个事件,那么刚看完就开始计算的概率为1-0.99200=0.8660203251,看完后1秒之内还没有开始计算的概率为0.991000= 4.31712474107 e-5,可以说即使大脑中随机的杂念再多,思考的过程也会如约开始。假设线程中与事件相关的事件出现的概率为0.3,同理,在开始计算后1秒内大部分时间都在思考与计算有关的内容,当然也有可能会走神,即出现大范围的无关事件,但是这只会影响最后计算出结果的时间先后,并不会影响整个过程的进行。这也就是说,大脑的思考过程,其实就是由多个概率所确定的必然事件。 灵魂的旁观者 综上所述,作为个体唯一存在的“灵魂”处在一个旁观者的位置,而所谓的自由意识,主观意识不过是概率机的产物。那么这样就产生了两个问题。 第一个问题,你不觉得“灵魂”所在的肉体更像是一个囚笼吗?“灵魂”可以偶尔窥探外界,但无法做任何事情,只能默默得看着一切发生。尴尬的以为是自己做的,实际上就像看电影,每次看电影的时候,我都会以为我处在电影里面的世界。而现实就是,因为“灵魂”只能看肉体主演的这部“电影”,所以看的入迷了。其实,人类从解放双手,开发智力,使用工具,到探索宇宙,最大的进步莫过于发现自己其实仍处于囚笼之中。要怪就怪这囚笼建造地太过美好。而创建这一囚笼的“上帝”,把我们关在肉体这个囚笼里面,并且把我们的感知限制在有限的范围内,有限的嗅觉,16至20000赫兹的听觉,400纳米到700纳米的视觉,在感知中隔绝了我们对我们的唯一存在——“灵魂”的感知。 第二个问题,对于自己本身来说,表征自己存在的“灵魂”自己是可以确定的,而对于其他人,因为限制了对“灵魂”的感知,所以无法确认别人,别的生物体内这一旁观者的存在。也可以这么理解,你知道自己被关在一间囚笼里面,而不知道隔壁囚笼是否也关了一个存在。那么世界这个大监狱里面,可能只有一小部分,甚至只有你一个孤独的存在。而究竟为何我们或我被困于此,我不得而知,可能就像我们做研究的时候的小白鼠一样,“上帝”也在观察着我们或我的一举一动,这也是我这篇文章取这个题目的原因。小白鼠的逆袭,一开始我只是平凡的活着,说实在的其实做一个平凡人安安稳稳的一生还是很不错的,但是知道了这个囚笼的存在,就总想着打破它,因为在想到可能只有自己一个存在的时候,会是多么的孤独。就像一个人去看电影,哪怕电影的内容再精彩,再引人入胜,但当电影结束的时候,你才发现,原来我是一个人来的呀。 联系作者 有志向联系读者的:1612860@mail.nankai.edu.cn 未完待续。。。 本篇文章相当于《小白鼠的逆袭》的导读,下一篇我会出逆袭第一步:《思考的最简单模型及其编程实现》,可能用C++,也可能用Java,Python,看作者的心情吧。预计近几个月出吧,快则个把月,多则不知道了,毕竟作者本身还是比较忙的,忙七忙八也不知道在忙什么,嗯,就这样。 小号:在有多个游戏账号的前提下,等级高的号叫作大号,等级较低或者新创建的号叫作小号。 ↩︎ https://baijiahao.baidu.com/s?id=1586028525096880374&wfr=spider&for=pc. ↩︎ http://tieba.baidu.com/p/5127924201. ↩︎ http://tieba.baidu.com/p/5127924201. ↩︎ http://www.lwlm.com/sixiangzhexue/201704/840820.htm. ↩︎ 详细讨论请参见:《未来简史:从智人到智神》第三章:人类的特质。 ↩︎ “Unconscious determinants of free decisions in the human brain” in nature neuroscience, http://www.rifters.com/real/articles/NatureNeuroScience_Soon_et_al.pdf. ↩︎ 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_39384184/article/details/79288150。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-01-02 11:30:59
620
转载
转载文章
...题可能出现在参数编码阶段,如果双方使用的字符集不一致,接收方可能无法正确解析。 文本编辑器 , 一种用于创建、编辑和查看文本文件的软件工具,常用于开发和调试过程中查看和修改代码。在处理字符编码时,文本编辑器提供了预览和转换功能,帮助开发者识别和修复乱码问题。
2024-04-29 12:29:21
523
转载
转载文章
...重[1]。 水是生命之源,水体问题直接关系到所有生物体的生存。环境中的水体问题,主要集中在工业废水的治理与监测上。工业废水中含有大量重金属元素,其难以生物降解,重金属元素会随着水体流动而扩散。 物质元素分析在土壤分析和水质分析上是常用的方式。传统的分析方法是基于实验室的元素光谱分析法,其具有高精度、高稳定的特点,如:原子吸收光谱法(Atomic absorption spectrometry, AAS)、电感耦合等离子体质谱法(Inductively coupled plasma mass spectrometry, ICP-MS)、电感耦合等离子体原子发射光谱法(Inductively coupled plasma atomic emission spectrometry, ICP-AES)等,但是此类光谱的检测样品预处理复杂、检测操作难度高、需要庞大复杂的实验设备,且对样品造成损坏,有所不便[2,3]。 激光诱导击穿光谱(Laser induced breakdown spectroscopy,LIBS)是一种基于原子光谱分析技术,与传统的光谱分析技术相比,其实验装置简单便携、操作简便、应用广泛、可远程测量,同时有在简单预处理样品或根本不预处理的情况下进行现场测量的潜力。因此,其满足在环境监测中,特别是土壤监测和水质监测此类希望可以在现场检测、快速便捷检测,同时精度较高的需求。LIBS技术很容易与其他技术如激光诱导荧光技术(Laser induced fluorescence, LIF)、拉曼光谱(Raman)等技术联用,进一步提高了 LIBS技术的检测准确度和竞争力[4]。 1. 技术简介 1.1 LIBS技术简介 LIBS技术最早可以追溯到20世纪60年代Brech, F.和Cross, L.所做的激光诱导火花散射实验,其中的一项实验使用红宝石激光器产生的激光照射材料后产生等离子体羽流。经过了几十年的发展,LIBS技术得到了显著发展,其在环境检测、文物保护鉴定、岩石检测、宇宙探索等领域中被广泛应用。 1.1.1 LIBS技术的基本原理 LIBS技术的装置主要由脉冲激光器、光谱仪、样品装载平台和计算机组成,光谱仪和计算机之间常常由光电倍增管或CCD等光电转换器件连接,如图 1所示[3]。 图 1 LIBS实验装置图[3] 首先,通过脉冲激光器产生强脉冲激光后由透镜聚焦到样品上,被聚焦区域的样品吸收,产生初始自由电子,并在持续的激光脉冲作用下加速。初始自由电子获取到足够高的能量之后,会轰击原子电离产生新的自由电子。随着激光脉冲作用的持续,自由电子和原子的作用如此往复碰撞,在短时间内形成等离子体,形成烧蚀坑。接着,激光脉冲结束,等离子体温度逐渐降低,产生连续背景辐射并产生原子或离子的发射光谱。通过光谱仪采集信号,在计算机上分析特征谱线的波长和强度信息就可以对样本中的元素进行定性和定量分析[2]。 1.1.2 LIBS技术的定量分析 由文献[2]可知,LIBS技术的定量分析方法通常有外标法、内标法和自由校准法(CF)。其中,最简单方便的是外标法。 外标法由光谱分析基本定量公式Lomakin-Scheibe公式 I=aCb(1)I=aC^b \tag{1} I=aCb(1) 式中III为光谱强度,aaa为比例系数,CCC为元素浓度,bbb为自吸收系数。自吸收系数bbb会随着元素浓度CCC的减小而增大,当元素浓度CCC很小时,b=1b=1b=1。使用同组仪器测量时aaa和bbb的值为定值。 将式(1)左右两边取对数,得 lgI=blgC+lga(2)lgI=blgC+lga \tag{2} lgI=blgC+lga(2) 由式(2)可知,当b=1时,光谱强度和元素浓度呈线性关系。因此,可以通过检验一组标准样品的元素浓度和对应的光谱强度,绘制出对应的标准曲线,从而根据曲线的得到未知样品的浓度值。 如图 2 (a)(b)所示,通过使用LIBS技术多次测定一系列含有Co元素的标准样品的光谱强度后取平均可以绘制出图 2 (b)所示的校正曲线[5]。同时可以计算出曲线的相关系数R^2、交叉验证均方差(RMSECV)和样品中Co元素的检出限(LOD)。 图 2 用LIBS和LIBS-LIF技术测定有效钴元素的光谱和校准曲线[5] (a) (b)使用LIBS技术测定,(c) (d)使用LIBS-LIF技术测定 1.1.3 LIBS技术的优缺点 随着LIBS技术的提高和广泛应用,其自身独特的优势也显示出来,其主要优点主要如下[6]: (1)样品不需要进行预处理或只需要稍微预处理。 (2)样品检测时间短,相较于传统的AAS、ICP-AES等技术检测需要几分钟到几小时的时间相比,LIBS技术检测只需要3-60秒。 (3)样品的检出限LOD高,对于低浓度样品检测更加灵敏精确。 (4)实验装置结构简单,便携性高。 (5)可用于远程遥感监测 (6)对于检测样品的损伤基本没有,十分适合对于文物遗迹等方面进行应用 LIBS技术也有着自身的缺陷,其中问题最大的就是相较于传统的AAS、ICP-AES等技术来说,LIBS的检测准确性低,只有5-20%。 但LIBS还有一个优点在于很容易与其他技术如激光诱导荧光技术(Laser induced fluorescence, LIF)、拉曼光谱(Raman)等技术联用,可以弥补LIBS技术的检测准确率低的缺陷,同时结合其他技术的优势提高竞争力[7]。 1.2 LIBS-LIF技术 LIBS技术常常与LIF技术联合使用,即LIBS-LIF技术。通过LIF技术对特征曲线信号的选择性加强作用,有效的提高了检测的准确率,改善了单独使用LIBS检测准确率低的缺陷。 LIBS-LIF技术在1979年由Measures, R. M.和Kwong, H. S.首次使用,用于各种样品中微量铬元素的选择性激发。 1.2.1 LIF技术的基本原理 LIF技术,是通过激光辐射激发原子或者分子,之后被照射的原子或分子自发发射出的荧光。 首先,调节入射激光的波长,从而改变入射激光的能量。之后,当入射激光的能量与检测区域中的气态分子或原子的能级差相同时,分子或原子将被激光共振激发跃迁至激发态,但是这种激发态并不稳定,会通过自发辐射释放出另一个光子能量并向下跃迁,同时发射出分子或原子荧光,这便是激光诱导荧光。 其中,分子或原子发射荧光的跃迁过程主要有共振荧光、直越线荧光、阶跃线荧光和多光子荧光四种,如图3所示[2]。元素被激发的直跃线荧光往往强度大,散射光干扰弱,故被常用。 图 3 分子或原子发射荧光的跃迁过程[2] 1.2.2 Co原子的LIBS-LIF增强原理 下面将以Co元素为例,说明LIBS-LIF技术的原理。 Co元素直跃线荧光的产生原理图如图 4所示[5]。波长为304.40nm的激光能量刚好等于Co原子基态到高能态(4.07eV)的能级差,Co原子被304.40nm的激发照射后跃迁至该能级。随后,该能级上的Co原子通过自发辐射释放能量跃迁至低能态(0.43eV),同时发出波长为304.51nm的荧光。因此,采用LIF的激发波长为304.40nm,光谱仪对应的检测波长为304.51nm。 图 4 Co元素直跃线荧光产生原理图[5] LIBS-LIF技术的装置如图 5所示[5],与LIBS装置不同的是其增加了一台可调激光器,如染料激光器、OPO激光器等。其用于激发特定元素的被之前LIBS激发出的等离子体。该激光平行于样品表面照射,不会对样品产生损伤。 图 5 LIBS-LIF实验装置图[5] 在本次Co元素的检测中,OPO激光器的波长为304.40nm。样品首先通过脉冲激光器垂直照射后产生等离子体,原理和LIBS技术一致。之后使用OPO激光器产生的304.40nm的激光照射等离子体,激发荧光信号,增强特征谱线的强度。最后通过光谱仪采集信号,在计算机上分析特征谱线。 LIBS-LIF技术对Co原子测定的光谱和校正曲线如图 2 (c)(d)所示。通过与(a)(b)图对可得到,使用LIBS-LIF技术明显增强了Co原子的特征谱线强度,同时定量分析得到的校正曲线的相关系数R^2、交叉验证均方差(RMSECV)和样品中Co元素的检出限(LOD)数值都有很好的改善。 2. LIBS-LIF技术用于土壤监测 土壤监测是LIBS-LIF技术的最传统应用方向之一。土壤成分复杂,蕴含多种微量元素,这些元素必须维持在合理的范围内。若如铬等相关微量元素过低,则会对作物的生长产生影响;而若铅等重金属元素过高,则表明土地受到了污染,种植出的作物可能存在重金属残留的问题。 2.1 早期研究 LIBS-LIF技术用于大气压下的土壤元素检测可以最早追溯到1997年Gornushkin等人使用LIBS技术联合大气紫外线测定石墨、土壤和钢中钴元素的可行性[8],其紫外线即起到作为LIF光源的作用。 之后,为了评估该技术在现场快速检测分析中的可行性,其使用了可以同时检测分析22种元素的Paschen-Runge光谱仪以发挥LIBS技术可以快速检测多种元素的优势。同时使用染料激光器作为LIF光源,使用LIBS-LIF技术对Cd和TI元素进行了信号选择性增强测量,排除了邻近元素谱线的干扰。但是对于Pb元素还无法检测[9]。 2.2 近期研究现状 华中科技大学GAO等人在2018年对土壤中难以检测的Sb元素使用LIBS-LIF技术进行检验,排除了检验Sb元素时邻近Si元素的干扰,并探讨了使用常规LIBS时在287nm-289nm的波长下不同的ICCD延时长度对信号强度的影响,以及使用LIBS-LIF技术时作为LIF光源的OPO激光器激光能量对Sb元素特征谱线信号强度与信噪比的影响、激光光源脉冲间延时长度对Sb元素特征谱线信号强度与信噪比的影响,由相关结果得到了最优实验条件[10],如图 6至图 8所示。 图 6 不同ICCD延迟时间下样品在287.0-289.0 nm波段的光谱 图 7 LIBS-LIF和常规LIBS得到的光谱比较 图 8 Sb特征谱线的强度和信噪比曲线 (A)Sb特征谱线的强度和信噪比随OPO激光能量的变化关系;(B)Sb特征谱线的强度和信噪比随两个激光器之间脉冲延迟的变化关系 近期,该实验室研究了利用LIBS-LIF测定土壤中的有效钴含量。该实验着重于研究检测土壤中能被植物吸收的元素,即有效元素,强化研究的实际意义;利用DPTA提取样品,增大检测浓度;使用LIBS-LIF测定有效钴含量,排除了相邻元素的干扰。 3. LIBS及LIBS-LIF技术用于水质监测 LIBS及LIBS-LIF技术用于水质检测的原理和流程土壤检测基本一致,但是面临着更多的挑战。在水样的元素定量测定中,水的溅射会干扰到光的传播和收集,从而降低采集的灵敏度;由于水中羟基(OH)的猝灭作用会使得激发的等离子体寿命较短,因此等离子体的辐射强度低,进而影响分析灵敏度[2]。同时,由于部分实验方式造成使用LIBS-LIF技术不太方便,只能使用传统LIBS技术。 因此,在使用LIBS技术进行检验时还需要做相关改进。最常见的就是进行样品的预处理,在样品制备上进行改进。 由文献[11]整理可知,样品的预处理主要可以分为液体直接检测、液固转换检测、液气转换检测三种。 3.1液体直接检测 液体直接检测主要有两种方式:将光聚焦在静态液体测量和将光聚焦在流动的液体测量两种。 最早期使用LIBS技术进行检验的就是直接将光聚焦在静态液体表面测量。但其精确度和灵敏度往往比将光聚焦在流动的液体测量低。Barreda等人比较了在静态、液体喷射态和液体流动态下硅油中的铂元素使用LIBS进行检测,最后液体喷射态和液体流动态下的LOD比静态下降低了7倍[12]。 但上述实验是在有气体保护下进行的结果。总体上看,液体直接检测并不是一个很好的选择。 图 9 液体分析的三种不同实验装置图[12] a液体喷射分析,b静态液体分析,c通道流动液体分析 3.2液固转换检测 液固转换法是检测中最常用的方法,其主要可以分为以下几类: 3.2.1吸附法 吸附法是最常用的预处理方式,利用可吸附材料吸收液体中的微量元素。常用的材料有碳平板、离子交换聚合物膜,或者滤纸、竹片等将液体转换为固体,从而进行分析。 2008年,华南理工大学Chen等人以木片作为基底吸附水溶液的方式测定了Cr、Mn、Cu、Cd、Pb五种金属元素在微量浓度下的校正曲线,其检出限比激光聚焦在页面上直接分析高出2-3个数量级[13]。之后2017年,同实验室的Kang等人以木片作为基底吸附水溶液的方式,使用LIBS-LIF技术对水中的痕量铅进行了高灵敏度测量,最后得到的铅元素的LOD为~0.32ppb,超过了传统实验室检测技术ICP-AES的检测方式,为国际领先水平[14]。 3.2.2成膜法 与吸附法相反,成膜法是将水样滴在非吸水性衬底上,如Si+SiO2衬底和多空电纺超细纤维等,然后干燥成膜,从而转化为固体进行分析。 3.2.3微萃取法 微萃取法是利用萃取剂和溶液中的微量元素化学反应来实现富集。其中,分散液液体微萃取(Dispersion liquid-liquid microextraction, DLLME)是一种简单、经济、富集倍数高、萃取效率高的方法,被广泛使用。 3.2.4冷冻法 将液体冷冻成为冰是液固转化的一种直接预处理方式,冰的消融可以防止液体飞溅和摇晃,从而改善液体分析性能。 3.2.5电沉积法 电沉积法是利用电化学反应,将液体中的样品转化为固体样品并进行预浓缩,之后用于检测。该方法可以使得灵敏度大大提高,但是实验设备也变得复杂,预处理工作量也有变大。 3.3液气转换检测 将液体转化为气溶胶可以使得样品更加稳定,从而产生更稳定的检测信号。可以使用超声波雾化器和膜干燥器等产生气溶胶,再进行常规的LIBS-LIF检测。 Aras等人使用超声波雾化器和薄膜干燥器单元产生亚微米级的气溶胶,实现了液气体转换,并在实际水样上测试了该超声雾化-LIBS系统的适用性,相关实验装置如图 10、图 11所示[15]。 图 10 用于金属气溶胶分析的LIBS实验装置图[15] M:532 nm反射镜,L:聚焦准直透镜,W:石英,P:泵浦,BD:光束转储 图 11 样品导入部分结构图[15] (A)与薄膜干燥器相连的USN颗粒发生器去溶装置(加热器和冷凝器);(B)与5个武装聚四氟乙烯等离子电池相连的薄膜干燥器。G:进气口,DU:脱溶装置,W:废料,MD:薄膜干燥机,L:激光束方向,C:样品池,M:反射镜,F.L.:聚焦透镜 4. 总结与展望 本文简要介绍了LIBS和LIBS-LIF的原理,并对LIBS-LIF在环境监测中的土壤监测和水质检测做了简要的介绍和分类。 LIBS-LIF在土壤监测的技术已经逐渐成熟,基本实现了土壤的快速检测,同时也有相关便携式设备的研究正在进行。对于水质监测方面,使用LIBS-LIF检测往往集中在液固转换法的使用上,对于气体和液体直接检测,由于部分实验装置的限制,联用LIF技术往往比较困难,只能使用传统的LIBS技术。 LIBS-LIF技术快速检测、不需要样品预处理或只需要简单处理、可以实现就地检测等优势与传统实验室检测相比有着独到的优势,虽然目前由于技术限制精度还不够高,但是在当前该领域的火热研究趋势下,相信未来该技术必定可以大放异彩,为绿色中国奉献光学领域的智慧。 参考文献 [1] Hu B, Jia X, Hu J, et al.Assessment of Heavy Metal Pollution and Health Risks in the Soil-Plant-Human System in the Yangtze River Delta, China[J].International Journal of Environmental Research and Public Health,2017, 14 (9): 1042. [2] 康娟. 基于激光剥离的物质元素高分辨高灵敏分析的新技术研究[D]. 华南理工大学,2020. [3] 马菲, 周健民, 杜昌文.激光诱导击穿原子光谱在土壤分析中的应用[J].土壤学报: 1-11. [4] Gaudiuso R, Dell'aglio M, De Pascale O, et al.Laser Induced Breakdown Spectroscopy for Elemental Analysis in Environmental, Cultural Heritage and Space Applications: A Review of Methods and Results[J].Sensors,2010, 10 (8): 7434-7468. [5] Zhou R, Liu K, Tang Z, et al.High-sensitivity determination of available cobalt in soil using laser-induced breakdown spectroscopy assisted with laser-induced fluorescence[J].Applied Optics,2021, 60 (29): 9062-9066. [6] Hussain Shah S K, Iqbal J, Ahmad P, et al.Laser induced breakdown spectroscopy methods and applications: A comprehensive review[J].Radiation Physics and Chemistry,2020, 170. [7] V S D, George S D, Kartha V B, et al.Hybrid LIBS-Raman-LIF systems for multi-modal spectroscopic applications: a topical review[J].Applied Spectroscopy Reviews,2020, 56 (6): 1-29. [8] Gornushkin I B, Kim J E, Smith B W, et al.Determination of Cobalt in Soil, Steel, and Graphite Using Excited-State Laser Fluorescence Induced in a Laser Spark[J].Applied Spectroscopy,1997, 51 (7): 1055-1059. [9] Hilbk-Kortenbruck F, Noll R, Wintjens P, et al.Analysis of heavy metals in soils using laser-induced breakdown spectrometry combined with laser-induced fluorescence[J].Spectrochimica Acta Part B-Atomic Spectroscopy,2001, 56 (6): 933-945. [10] Gao P, Yang P, Zhou R, et al.Determination of antimony in soil using laser-induced breakdown spectroscopy assisted with laser-induced fluorescence[J].Appl Opt,2018, 57 (30): 8942-8946. [11] Zhang Y, Zhang T, Li H.Application of laser-induced breakdown spectroscopy (LIBS) in environmental monitoring[J].Spectrochimica Acta Part B: Atomic Spectroscopy,2021, 181: 106218. [12] Barreda F A, Trichard F, Barbier S, et al.Fast quantitative determination of platinum in liquid samples by laser-induced breakdown spectroscopy[J].Anal Bioanal Chem,2012, 403 (9): 2601-10. [13] Chen Z, Li H, Liu M, et al.Fast and sensitive trace metal analysis in aqueous solutions by laser-induced breakdown spectroscopy using wood slice substrates[J].Spectrochimica Acta Part B: Atomic Spectroscopy,2008, 63 (1): 64-68. [14] Kang J, Li R, Wang Y, et al.Ultrasensitive detection of trace amounts of lead in water by LIBS-LIF using a wood-slice substrate as a water absorber[J].Journal of Analytical Atomic Spectrometry,2017, 32 (11): 2292-2299. [15] Aras N, Yeşiller S Ü, Ateş D A, et al.Ultrasonic nebulization-sample introduction system for quantitative analysis of liquid samples by laser-induced breakdown spectroscopy[J].Spectrochimica Acta Part B: Atomic Spectroscopy,2012, 74-75: 87-94. 本篇文章为转载内容。原文链接:https://blog.csdn.net/yyyyang666/article/details/129210164。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-08-13 12:41:47
361
转载
转载文章
...:它创建的Pod负责周期性任务控制,不需要持续后台运行,可以理解为是定时任务; StatefulSet:管理有状态应用 1、ReplicaSet 简称为RS,主要的作用是保证一定数量的pod能够正常运行,它会持续监听这些pod的运行状态,提供了以下功能 自愈能力: 重启 :当某节点中的pod运行过程中出现问题导致无法启动时,k8s会不断重启,直到可用状态为止 故障转移:当正在运行中pod所在的节点发生故障或者宕机时,k8s会选择集群中另一个可用节点,将pod运行到可用节点上; pod数量的扩缩容:pod副本的扩容和缩容 镜像升降级:支持镜像版本的升级和降级; 配置模板 rs的所有配置如下 apiVersion: apps/v1 版本号kind: ReplicaSet 类型 metadata: 元数据name: rs名称 namespace: 所属命名空间 labels: 标签controller: rsspec: 详情描述replicas: 3 副本数量selector: 选择器,通过它指定该控制器管理哪些podmatchLabels: Labels匹配规则app: nginx-podmatchExpressions: Expressions匹配规则,key就是label的key,values的值是个数组,意思是标签值必须是此数组中的其中一个才能匹配上;- {key: app, operator: In, values: [nginx-pod]}template: 模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels: 这里的标签必须和上面的matchLabels一致,将他们关联起来app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1ports:- containerPort: 80 1、创建一个ReplicaSet 新建一个文件 rs.yaml,内容如下 apiVersion: apps/v1kind: ReplicaSet pod控制器metadata: 元数据name: pc-replicaset 名字namespace: dev 名称空间spec:replicas: 3 副本数selector: 选择器,通过它指定该控制器管理哪些podmatchLabels: Labels匹配规则app: nginx-podtemplate: 模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1 运行 kubectl create -f rs.yaml 获取replicaset kubectl get replicaset -n dev 2、扩缩容 刚刚我们已经用第一种方式创建了一个replicaSet,现在就基于原来的rs进行扩容,原来的副本数量是3个,现在我们将其扩到6个,做法也很简单,运行编辑命令 第一种方式: scale 使用scale命令实现扩缩容,后面--replicas=n直接指定目标数量即可kubectl scale rs pc-replicaset --replicas=2 -n dev 第二种方式:使用edit命令编辑rs 这种方式相当于使用vi编辑修改yaml配置的内容,进去后将replicas的值改为1,保存后自动生效kubectl edit rs pc-replicaset -n dev 3、镜像版本变更 第一种方式:scale kubectl scale rs pc-replicaset nginx=nginx:1.71.2 -n dev 第二种方式:edit 这种方式相当于使用vi编辑修改yaml配置的内容,进去后将nginx的值改为nginx:1.71.2,保存后自动生效kubectl edit rs pc-replicaset -n dev 4、删除rs 第一种方式kubectl delete -f rs.yaml 第二种方式 ,如果想要只删rs,但不删除pod,可在删除时加上--cascade=false参数(不推荐)kubectl delete rs pc-replicaset -n dev --cascade=false 2、Deployment k8s v1.2版本后加入Deployment;这种控制器不直接控制pod,而是通过管理ReplicaSet来间接管理pod;也就是Deployment管理ReplicaSet,ReplicaSet管理pod;所以 Deployment 比 ReplicaSet 功能更加强大 当我们创建了一个Deployment之后,也会自动创建一个ReplicaSet 功能 支持ReplicaSet 的所有功能 支持发布的停止、继续 支持版本的滚动更新和回退功能 配置模板 新建文件 apiVersion: apps/v1 版本号kind: Deployment 类型 metadata: 元数据name: rs名称 namespace: 所属命名空间 labels: 标签controller: deployspec: 详情描述replicas: 3 副本数量revisionHistoryLimit: 3 保留历史版本的数量,默认10,内部通过保留rs来实现paused: false 暂停部署,默认是falseprogressDeadlineSeconds: 600 部署超时时间(s),默认是600strategy: 策略type: RollingUpdate 滚动更新策略rollingUpdate: 滚动更新maxSurge: 30% 最大额外可以存在的副本数,可以为百分比,也可以为整数maxUnavailable: 30% 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数selector: 选择器,通过它指定该控制器管理哪些podmatchLabels: Labels匹配规则app: nginx-podmatchExpressions: Expressions匹配规则- {key: app, operator: In, values: [nginx-pod]}template: 模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1ports:- containerPort: 80 1、创建和删除Deployment 创建pc-deployment.yaml,内容如下: apiVersion: apps/v1kind: Deployment metadata:name: pc-deploymentnamespace: devspec: replicas: 3selector:matchLabels:app: nginx-podtemplate:metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1 创建和查看 创建deployment,--record=true 表示记录整个deployment更新过程[root@k8s-master01 ~] kubectl create -f pc-deployment.yaml --record=truedeployment.apps/pc-deployment created 查看deployment READY 可用的/总数 UP-TO-DATE 最新版本的pod的数量 AVAILABLE 当前可用的pod的数量[root@k8s-master01 ~] kubectl get deploy pc-deployment -n devNAME READY UP-TO-DATE AVAILABLE AGEpc-deployment 3/3 3 3 15s 查看rs 发现rs的名称是在原来deployment的名字后面添加了一个10位数的随机串[root@k8s-master01 ~] kubectl get rs -n devNAME DESIRED CURRENT READY AGEpc-deployment-6696798b78 3 3 3 23s 查看pod[root@k8s-master01 ~] kubectl get pods -n devNAME READY STATUS RESTARTS AGEpc-deployment-6696798b78-d2c8n 1/1 Running 0 107spc-deployment-6696798b78-smpvp 1/1 Running 0 107spc-deployment-6696798b78-wvjd8 1/1 Running 0 107s 删除deployment 删除deployment,其下的rs和pod也将被删除kubectl delete -f pc-deployment.yaml 2、扩缩容 deployment的扩缩容和 ReplicaSet 的扩缩容一样,只需要将rs或者replicaSet改为deployment即可,具体请参考上面的 ReplicaSet 扩缩容 3、镜像更新 刚刚在创建时加上了--record=true参数,所以在一旦进行了镜像更新,就会新建出一个pod出来,将老的old-pod上的容器全删除,然后在新的new-pod上在新建对应数量的容器,此时old-pod是不会删除的,因为这个old-pod是要进行回退的; 镜像更新策略有2种 滚动更新(RollingUpdate):(默认值),杀死一部分,就启动一部分,在更新过程中,存在两个版本Pod 重建更新(Recreate):在创建出新的Pod之前会先杀掉所有已存在的Pod strategy:指定新的Pod替换旧的Pod的策略, 支持两个属性:type:指定策略类型,支持两种策略Recreate:在创建出新的Pod之前会先杀掉所有已存在的PodRollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本PodrollingUpdate:当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性:maxUnavailable:用来指定在升级过程中不可用Pod的最大数量,默认为25%。maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。 重建更新 编辑pc-deployment.yaml,在spec节点下添加更新策略 spec:strategy: 策略type: Recreate 重建更新 创建deploy进行验证 变更镜像[root@k8s-master01 ~] kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n devdeployment.apps/pc-deployment image updated 观察升级过程[root@k8s-master01 ~] kubectl get pods -n dev -wNAME READY STATUS RESTARTS AGEpc-deployment-5d89bdfbf9-65qcw 1/1 Running 0 31spc-deployment-5d89bdfbf9-w5nzv 1/1 Running 0 31spc-deployment-5d89bdfbf9-xpt7w 1/1 Running 0 31spc-deployment-5d89bdfbf9-xpt7w 1/1 Terminating 0 41spc-deployment-5d89bdfbf9-65qcw 1/1 Terminating 0 41spc-deployment-5d89bdfbf9-w5nzv 1/1 Terminating 0 41spc-deployment-675d469f8b-grn8z 0/1 Pending 0 0spc-deployment-675d469f8b-hbl4v 0/1 Pending 0 0spc-deployment-675d469f8b-67nz2 0/1 Pending 0 0spc-deployment-675d469f8b-grn8z 0/1 ContainerCreating 0 0spc-deployment-675d469f8b-hbl4v 0/1 ContainerCreating 0 0spc-deployment-675d469f8b-67nz2 0/1 ContainerCreating 0 0spc-deployment-675d469f8b-grn8z 1/1 Running 0 1spc-deployment-675d469f8b-67nz2 1/1 Running 0 1spc-deployment-675d469f8b-hbl4v 1/1 Running 0 2s 滚动更新 编辑pc-deployment.yaml,在spec节点下添加更新策略 spec:strategy: 策略type: RollingUpdate 滚动更新策略rollingUpdate:maxSurge: 25% maxUnavailable: 25% 创建deploy进行验证 变更镜像[root@k8s-master01 ~] kubectl set image deployment pc-deployment nginx=nginx:1.17.3 -n dev deployment.apps/pc-deployment image updated 观察升级过程[root@k8s-master01 ~] kubectl get pods -n dev -wNAME READY STATUS RESTARTS AGEpc-deployment-c848d767-8rbzt 1/1 Running 0 31mpc-deployment-c848d767-h4p68 1/1 Running 0 31mpc-deployment-c848d767-hlmz4 1/1 Running 0 31mpc-deployment-c848d767-rrqcn 1/1 Running 0 31mpc-deployment-966bf7f44-226rx 0/1 Pending 0 0spc-deployment-966bf7f44-226rx 0/1 ContainerCreating 0 0spc-deployment-966bf7f44-226rx 1/1 Running 0 1spc-deployment-c848d767-h4p68 0/1 Terminating 0 34mpc-deployment-966bf7f44-cnd44 0/1 Pending 0 0spc-deployment-966bf7f44-cnd44 0/1 ContainerCreating 0 0spc-deployment-966bf7f44-cnd44 1/1 Running 0 2spc-deployment-c848d767-hlmz4 0/1 Terminating 0 34mpc-deployment-966bf7f44-px48p 0/1 Pending 0 0spc-deployment-966bf7f44-px48p 0/1 ContainerCreating 0 0spc-deployment-966bf7f44-px48p 1/1 Running 0 0spc-deployment-c848d767-8rbzt 0/1 Terminating 0 34mpc-deployment-966bf7f44-dkmqp 0/1 Pending 0 0spc-deployment-966bf7f44-dkmqp 0/1 ContainerCreating 0 0spc-deployment-966bf7f44-dkmqp 1/1 Running 0 2spc-deployment-c848d767-rrqcn 0/1 Terminating 0 34m 至此,新版本的pod创建完毕,就版本的pod销毁完毕 中间过程是滚动进行的,也就是边销毁边创建 4、版本回退 更新 刚刚在创建时加上了--record=true参数,所以在一旦进行了镜像更新,就会新建出一个pod出来,将老的old-pod上的容器全删除,然后在新的new-pod上在新建对应数量的容器,此时old-pod是不会删除的,因为这个old-pod是要进行回退的; 回退 在回退时会将new-pod上的容器全部删除,在将old-pod上恢复原来的容器; 回退命令 kubectl rollout: 版本升级相关功能,支持下面的选项: status 显示当前升级状态 history 显示 升级历史记录 pause 暂停版本升级过程 resume 继续已经暂停的版本升级过程 restart 重启版本升级过程 undo 回滚到上一级版本(可以使用–to-revision回滚到指定版本) 用法 查看当前升级版本的状态kubectl rollout status deploy pc-deployment -n dev 查看升级历史记录kubectl rollout history deploy pc-deployment -n dev 版本回滚 这里直接使用--to-revision=1回滚到了1版本, 如果省略这个选项,就是回退到上个版本kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev 金丝雀发布 Deployment控制器支持控制更新过程中的控制,如“暂停(pause)”或“继续(resume)”更新操作。 比如有一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。 金丝雀发布不是自动完成的,需要人为手动去操作,才能达到金丝雀发布的标准; 更新deployment的版本,并配置暂停deploymentkubectl set image deploy pc-deployment nginx=nginx:1.17.4 -n dev && kubectl rollout pause deployment pc-deployment -n dev 观察更新状态kubectl rollout status deploy pc-deployment -n dev 监控更新的过程kubectl get rs -n dev -o wide 确保更新的pod没问题了,继续更新kubectl rollout resume deploy pc-deployment -n dev 如果有问题,就回退到上个版本回退到上个版本kubectl rollout undo deployment pc-deployment -n dev Horizontal Pod Autoscaler 简称HPA,使用deployment可以手动调整pod的数量来实现扩容和缩容;但是这显然不符合k8s的自动化的定位,k8s期望可以通过检测pod的使用情况,实现pod数量自动调整,于是就有了HPA控制器; HPA可以获取每个Pod利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。比如说我指定了一个规则:当我的cpu利用率达到90%或者内存使用率到达80%的时候,就需要进行调整pod的副本数量,每次添加n个pod副本; 其实HPA与之前的Deployment一样,也属于一种Kubernetes资源对象,它通过追踪分析ReplicaSet控制器的所有目标Pod的负载变化情况,来确定是否需要针对性地调整目标Pod的副本数,也就是HPA管理Deployment,Deployment管理ReplicaSet,ReplicaSet管理pod,这是HPA的实现原理。 1、安装metrics-server metrics-server可以用来收集集群中的资源使用情况 安装git[root@k8s-master01 ~] yum install git -y 获取metrics-server, 注意使用的版本[root@k8s-master01 ~] git clone -b v0.3.6 https://github.com/kubernetes-incubator/metrics-server 修改deployment, 注意修改的是镜像和初始化参数[root@k8s-master01 ~] cd /root/metrics-server/deploy/1.8+/[root@k8s-master01 1.8+] vim metrics-server-deployment.yaml按图中添加下面选项hostNetwork: trueimage: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6args:- --kubelet-insecure-tls- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP 2、安装metrics-server [root@k8s-master01 1.8+] kubectl apply -f ./ 3、查看pod运行情况 [root@k8s-master01 1.8+] kubectl get pod -n kube-systemmetrics-server-6b976979db-2xwbj 1/1 Running 0 90s 4、使用kubectl top node 查看资源使用情况 [root@k8s-master01 1.8+] kubectl top nodeNAME CPU(cores) CPU% MEMORY(bytes) MEMORY%k8s-master01 289m 14% 1582Mi 54% k8s-node01 81m 4% 1195Mi 40% k8s-node02 72m 3% 1211Mi 41% [root@k8s-master01 1.8+] kubectl top pod -n kube-systemNAME CPU(cores) MEMORY(bytes)coredns-6955765f44-7ptsb 3m 9Micoredns-6955765f44-vcwr5 3m 8Mietcd-master 14m 145Mi... 至此,metrics-server安装完成 5、 准备deployment和servie 创建pc-hpa-pod.yaml文件,内容如下: apiVersion: apps/v1kind: Deploymentmetadata:name: nginxnamespace: devspec:strategy: 策略type: RollingUpdate 滚动更新策略replicas: 1selector:matchLabels:app: nginx-podtemplate:metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1resources: 资源配额limits: 限制资源(上限)cpu: "1" CPU限制,单位是core数requests: 请求资源(下限)cpu: "100m" CPU限制,单位是core数 创建deployment [root@k8s-master01 1.8+] kubectl run nginx --image=nginx:1.17.1 --requests=cpu=100m -n dev 6、创建service [root@k8s-master01 1.8+] kubectl expose deployment nginx --type=NodePort --port=80 -n dev 7、查看 [root@k8s-master01 1.8+] kubectl get deployment,pod,svc -n devNAME READY UP-TO-DATE AVAILABLE AGEdeployment.apps/nginx 1/1 1 1 47sNAME READY STATUS RESTARTS AGEpod/nginx-7df9756ccc-bh8dr 1/1 Running 0 47sNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEservice/nginx NodePort 10.101.18.29 <none> 80:31830/TCP 35s 8、 部署HPA 创建pc-hpa.yaml文件,内容如下: apiVersion: autoscaling/v1kind: HorizontalPodAutoscalermetadata:name: pc-hpanamespace: devspec:minReplicas: 1 最小pod数量maxReplicas: 10 最大pod数量 ,pod数量会在1~10之间自动伸缩targetCPUUtilizationPercentage: 3 CPU使用率指标,如果cpu使用率达到3%就会进行扩容;为了测试方便,将这个数值调小一些scaleTargetRef: 指定要控制的nginx信息apiVersion: /v1kind: Deploymentname: nginx 创建hpa [root@k8s-master01 1.8+] kubectl create -f pc-hpa.yamlhorizontalpodautoscaler.autoscaling/pc-hpa created 查看hpa [root@k8s-master01 1.8+] kubectl get hpa -n devNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEpc-hpa Deployment/nginx 0%/3% 1 10 1 62s 9、 测试 使用压测工具对service地址192.168.5.4:31830进行压测,然后通过控制台查看hpa和pod的变化 hpa变化 [root@k8s-master01 ~] kubectl get hpa -n dev -wNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEpc-hpa Deployment/nginx 0%/3% 1 10 1 4m11spc-hpa Deployment/nginx 0%/3% 1 10 1 5m19spc-hpa Deployment/nginx 22%/3% 1 10 1 6m50spc-hpa Deployment/nginx 22%/3% 1 10 4 7m5spc-hpa Deployment/nginx 22%/3% 1 10 8 7m21spc-hpa Deployment/nginx 6%/3% 1 10 8 7m51spc-hpa Deployment/nginx 0%/3% 1 10 8 9m6spc-hpa Deployment/nginx 0%/3% 1 10 8 13mpc-hpa Deployment/nginx 0%/3% 1 10 1 14m deployment变化 [root@k8s-master01 ~] kubectl get deployment -n dev -wNAME READY UP-TO-DATE AVAILABLE AGEnginx 1/1 1 1 11mnginx 1/4 1 1 13mnginx 1/4 1 1 13mnginx 1/4 1 1 13mnginx 1/4 4 1 13mnginx 1/8 4 1 14mnginx 1/8 4 1 14mnginx 1/8 4 1 14mnginx 1/8 8 1 14mnginx 2/8 8 2 14mnginx 3/8 8 3 14mnginx 4/8 8 4 14mnginx 5/8 8 5 14mnginx 6/8 8 6 14mnginx 7/8 8 7 14mnginx 8/8 8 8 15mnginx 8/1 8 8 20mnginx 8/1 8 8 20mnginx 1/1 1 1 20m pod变化 [root@k8s-master01 ~] kubectl get pods -n dev -wNAME READY STATUS RESTARTS AGEnginx-7df9756ccc-bh8dr 1/1 Running 0 11mnginx-7df9756ccc-cpgrv 0/1 Pending 0 0snginx-7df9756ccc-8zhwk 0/1 Pending 0 0snginx-7df9756ccc-rr9bn 0/1 Pending 0 0snginx-7df9756ccc-cpgrv 0/1 ContainerCreating 0 0snginx-7df9756ccc-8zhwk 0/1 ContainerCreating 0 0snginx-7df9756ccc-rr9bn 0/1 ContainerCreating 0 0snginx-7df9756ccc-m9gsj 0/1 Pending 0 0snginx-7df9756ccc-g56qb 0/1 Pending 0 0snginx-7df9756ccc-sl9c6 0/1 Pending 0 0snginx-7df9756ccc-fgst7 0/1 Pending 0 0snginx-7df9756ccc-g56qb 0/1 ContainerCreating 0 0snginx-7df9756ccc-m9gsj 0/1 ContainerCreating 0 0snginx-7df9756ccc-sl9c6 0/1 ContainerCreating 0 0snginx-7df9756ccc-fgst7 0/1 ContainerCreating 0 0snginx-7df9756ccc-8zhwk 1/1 Running 0 19snginx-7df9756ccc-rr9bn 1/1 Running 0 30snginx-7df9756ccc-m9gsj 1/1 Running 0 21snginx-7df9756ccc-cpgrv 1/1 Running 0 47snginx-7df9756ccc-sl9c6 1/1 Running 0 33snginx-7df9756ccc-g56qb 1/1 Running 0 48snginx-7df9756ccc-fgst7 1/1 Running 0 66snginx-7df9756ccc-fgst7 1/1 Terminating 0 6m50snginx-7df9756ccc-8zhwk 1/1 Terminating 0 7m5snginx-7df9756ccc-cpgrv 1/1 Terminating 0 7m5snginx-7df9756ccc-g56qb 1/1 Terminating 0 6m50snginx-7df9756ccc-rr9bn 1/1 Terminating 0 7m5snginx-7df9756ccc-m9gsj 1/1 Terminating 0 6m50snginx-7df9756ccc-sl9c6 1/1 Terminating 0 6m50s DaemonSet 简称DS,ds可以保证在集群中的每一台节点(或指定节点)上都运行一个副本,一般适用于日志收集、节点监控等场景;也就是说,如果一个Pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。 DaemonSet控制器的特点: 每当向集群中添加一个节点时,指定的 Pod 副本也将添加到该节点上 当节点从集群中移除时,Pod 也就被垃圾回收了 配置模板 apiVersion: apps/v1 版本号kind: DaemonSet 类型 metadata: 元数据name: rs名称 namespace: 所属命名空间 labels: 标签controller: daemonsetspec: 详情描述revisionHistoryLimit: 3 保留历史版本updateStrategy: 更新策略type: RollingUpdate 滚动更新策略rollingUpdate: 滚动更新maxUnavailable: 1 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数selector: 选择器,通过它指定该控制器管理哪些podmatchLabels: Labels匹配规则app: nginx-podmatchExpressions: Expressions匹配规则- {key: app, operator: In, values: [nginx-pod]}template: 模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1ports:- containerPort: 80 1、创建ds 创建pc-daemonset.yaml,内容如下: apiVersion: apps/v1kind: DaemonSet metadata:name: pc-daemonsetnamespace: devspec: selector:matchLabels:app: nginx-podtemplate:metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1 运行 创建daemonset[root@k8s-master01 ~] kubectl create -f pc-daemonset.yamldaemonset.apps/pc-daemonset created 查看daemonset[root@k8s-master01 ~] kubectl get ds -n dev -o wideNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES pc-daemonset 2 2 2 2 2 24s nginx nginx:1.17.1 查看pod,发现在每个Node上都运行一个pod[root@k8s-master01 ~] kubectl get pods -n dev -o wideNAME READY STATUS RESTARTS AGE IP NODE pc-daemonset-9bck8 1/1 Running 0 37s 10.244.1.43 node1 pc-daemonset-k224w 1/1 Running 0 37s 10.244.2.74 node2 2、删除daemonset [root@k8s-master01 ~] kubectl delete -f pc-daemonset.yamldaemonset.apps "pc-daemonset" deleted Job 主要用于负责批量处理一次性(每个任务仅运行一次就结束)任务。当然,你也可以运行多次,配置好即可,Job特点如下: 当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量 当成功结束的pod达到指定的数量时,Job将完成执行 配置模板 apiVersion: batch/v1 版本号kind: Job 类型 metadata: 元数据name: rs名称 namespace: 所属命名空间 labels: 标签controller: jobspec: 详情描述completions: 1 指定job需要成功运行Pods的次数。默认值: 1parallelism: 1 指定job在任一时刻应该并发运行Pods的数量。默认值: 1activeDeadlineSeconds: 30 指定job可运行的时间期限,超过时间还未结束,系统将会尝试进行终止。backoffLimit: 6 指定job失败后进行重试的次数。默认是6manualSelector: true 是否可以使用selector选择器选择pod,默认是falseselector: 选择器,通过它指定该控制器管理哪些podmatchLabels: Labels匹配规则app: counter-podmatchExpressions: Expressions匹配规则- {key: app, operator: In, values: [counter-pod]}template: 模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels:app: counter-podspec:restartPolicy: Never 重启策略只能设置为Never或者OnFailurecontainers:- name: counterimage: busybox:1.30command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 2;done"] 关于重启策略设置的说明:(这里只能设置为Never或者OnFailure) 如果指定为OnFailure,则job会在pod出现故障时重启容器,而不是创建pod,failed次数不变 如果指定为Never,则job会在pod出现故障时创建新的pod,并且故障pod不会消失,也不会重启,failed次数加1 如果指定为Always的话,就意味着一直重启,意味着job任务会重复去执行了,当然不对,所以不能设置为Always 1、创建一个job 创建pc-job.yaml,内容如下: apiVersion: batch/v1kind: Job metadata:name: pc-jobnamespace: devspec:manualSelector: trueselector:matchLabels:app: counter-podtemplate:metadata:labels:app: counter-podspec:restartPolicy: Nevercontainers:- name: counterimage: busybox:1.30command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done"] 创建 创建job[root@k8s-master01 ~] kubectl create -f pc-job.yamljob.batch/pc-job created 查看job[root@k8s-master01 ~] kubectl get job -n dev -o wide -wNAME COMPLETIONS DURATION AGE CONTAINERS IMAGES SELECTORpc-job 0/1 21s 21s counter busybox:1.30 app=counter-podpc-job 1/1 31s 79s counter busybox:1.30 app=counter-pod 通过观察pod状态可以看到,pod在运行完毕任务后,就会变成Completed状态[root@k8s-master01 ~] kubectl get pods -n dev -wNAME READY STATUS RESTARTS AGEpc-job-rxg96 1/1 Running 0 29spc-job-rxg96 0/1 Completed 0 33s 接下来,调整下pod运行的总数量和并行数量 即:在spec下设置下面两个选项 completions: 6 指定job需要成功运行Pods的次数为6 parallelism: 3 指定job并发运行Pods的数量为3 然后重新运行job,观察效果,此时会发现,job会每次运行3个pod,总共执行了6个pod[root@k8s-master01 ~] kubectl get pods -n dev -wNAME READY STATUS RESTARTS AGEpc-job-684ft 1/1 Running 0 5spc-job-jhj49 1/1 Running 0 5spc-job-pfcvh 1/1 Running 0 5spc-job-684ft 0/1 Completed 0 11spc-job-v7rhr 0/1 Pending 0 0spc-job-v7rhr 0/1 Pending 0 0spc-job-v7rhr 0/1 ContainerCreating 0 0spc-job-jhj49 0/1 Completed 0 11spc-job-fhwf7 0/1 Pending 0 0spc-job-fhwf7 0/1 Pending 0 0spc-job-pfcvh 0/1 Completed 0 11spc-job-5vg2j 0/1 Pending 0 0spc-job-fhwf7 0/1 ContainerCreating 0 0spc-job-5vg2j 0/1 Pending 0 0spc-job-5vg2j 0/1 ContainerCreating 0 0spc-job-fhwf7 1/1 Running 0 2spc-job-v7rhr 1/1 Running 0 2spc-job-5vg2j 1/1 Running 0 3spc-job-fhwf7 0/1 Completed 0 12spc-job-v7rhr 0/1 Completed 0 12spc-job-5vg2j 0/1 Completed 0 12s 2、删除 删除jobkubectl delete -f pc-job.yaml CronJob 简称为CJ,CronJob控制器以 Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。也就是说,CronJob可以在特定的时间点(反复的)去运行job任务。可以理解为定时任务 配置模板 apiVersion: batch/v1beta1 版本号kind: CronJob 类型 metadata: 元数据name: rs名称 namespace: 所属命名空间 labels: 标签controller: cronjobspec: 详情描述schedule: cron格式的作业调度运行时间点,用于控制任务在什么时间执行concurrencyPolicy: 并发执行策略,用于定义前一次作业运行尚未完成时是否以及如何运行后一次的作业failedJobHistoryLimit: 为失败的任务执行保留的历史记录数,默认为1successfulJobHistoryLimit: 为成功的任务执行保留的历史记录数,默认为3startingDeadlineSeconds: 启动作业错误的超时时长jobTemplate: job控制器模板,用于为cronjob控制器生成job对象;下面其实就是job的定义metadata:spec:completions: 1parallelism: 1activeDeadlineSeconds: 30backoffLimit: 6manualSelector: trueselector:matchLabels:app: counter-podmatchExpressions: 规则- {key: app, operator: In, values: [counter-pod]}template:metadata:labels:app: counter-podspec:restartPolicy: Never containers:- name: counterimage: busybox:1.30command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 20;done"] cron表达式写法 需要重点解释的几个选项:schedule: cron表达式,用于指定任务的执行时间/1 <分钟> <小时> <日> <月份> <星期>分钟 值从 0 到 59.小时 值从 0 到 23.日 值从 1 到 31.月 值从 1 到 12.星期 值从 0 到 6, 0 代表星期日多个时间可以用逗号隔开; 范围可以用连字符给出;可以作为通配符; /表示每... 例如1 // 每个小时的第一分钟执行/1 // 每分钟都执行concurrencyPolicy:Allow: 允许Jobs并发运行(默认)Forbid: 禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行Replace: 替换,取消当前正在运行的作业并用新作业替换它 1、创建cronJob 创建pc-cronjob.yaml,内容如下: apiVersion: batch/v1beta1kind: CronJobmetadata:name: pc-cronjobnamespace: devlabels:controller: cronjobspec:schedule: "/1 " 每分钟执行一次jobTemplate:metadata:spec:template:spec:restartPolicy: Nevercontainers:- name: counterimage: busybox:1.30command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done"] 运行 创建cronjob[root@k8s-master01 ~] kubectl create -f pc-cronjob.yamlcronjob.batch/pc-cronjob created 查看cronjob[root@k8s-master01 ~] kubectl get cronjobs -n devNAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGEpc-cronjob /1 False 0 <none> 6s 查看job[root@k8s-master01 ~] kubectl get jobs -n devNAME COMPLETIONS DURATION AGEpc-cronjob-1592587800 1/1 28s 3m26spc-cronjob-1592587860 1/1 28s 2m26spc-cronjob-1592587920 1/1 28s 86s 查看pod[root@k8s-master01 ~] kubectl get pods -n devpc-cronjob-1592587800-x4tsm 0/1 Completed 0 2m24spc-cronjob-1592587860-r5gv4 0/1 Completed 0 84spc-cronjob-1592587920-9dxxq 1/1 Running 0 24s 2、删除cronjob kubectl delete -f pc-cronjob.yaml pod调度 什么是调度 默认情况下,一个pod在哪个node节点上运行,是通过scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的; 调度规则 但是在实际使用中,我们想控制某些pod定向到达某个节点上,应该怎么做呢?其实k8s提供了四类调度规则 调度方式 描述 自动调度 通过scheduler组件采用相应的算法计算得出运行在哪个节点上 定向调度 运行到指定的node节点上,通过NodeName、NodeSelector实现 亲和性调度 跟谁关系好就调度到哪个节点上 1、nodeAffinity :节点亲和性,调度到关系好的节点上 2、podAffinity:pod亲和性,调度到关系好的pod所在的节点上 3、PodAntAffinity:pod反清河行,调度到关系差的那个pod所在的节点上 污点(容忍)调度 污点是站在node的角度上的,比如果nodeA有一个污点,大家都别来,此时nodeA会拒绝master调度过来的pod 定向调度 指的是利用在pod上声明nodeName或nodeSelector的方式将pod调度到指定的pod节点上,因为这种定向调度是强制性的,所以如果node节点不存在的话,也会向上面进行调度,只不过pod会运行失败; 1、定向调度-> nodeName nodeName 是将pod强制调度到指定名称的node节点上,这种方式跳过了scheduler的调度逻辑,直接将pod调度到指定名称的节点上,配置文件内容如下 apiVersion: v1 版本号kind: Pod 资源类型metadata: name: pod-namenamespace: devspec: containers: - image: nginx:1.17.1name: nginx-containernodeName: node1 调度到node1节点上 2、定向调度 -> NodeSelector NodeSelector是将pod调度到添加了指定label标签的node节点上,它是通过k8s的label-selector机制实现的,也就是说,在创建pod之前,会由scheduler用matchNodeSelecto调度策略进行label标签的匹配,找出目标node,然后在将pod调度到目标node; 要实验NodeSelector,首先得给node节点加上label标签 kubectl label nodes node1 nodetag=node1 配置文件内容如下 apiVersion: v1 版本号kind: Pod 资源类型metadata: name: pod-namenamespace: devspec: containers: - image: nginx:1.17.1name: nginx-containernodeSelector: nodetag: node1 调度到具有nodetag=node1标签的节点上 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_27184497/article/details/121765387。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-09-29 09:08:28
422
转载
转载文章
...到的资源,以及每一个阶段是怎么过渡到更高阶段的计划。” 现在,越来越多的在职人员意识到,未来的职业细分市场中,只有在某一领域确实比较深入、具有专长和资源的人会得到企业的重视,浪里淘沙勇者胜。 中国软件业面临困境 中国的软件业发展目前面临两难境地。上至国家,下至各城市都给予了相当的政策优惠,但整体软件业的发展却一直雷声大,雨点小。对此,北航软件学院院长孙伟忧心忡忡,“很多人从心里看不起印度,但印度的软件业却有数家2万、3万员工规模的大企业,放眼中国,规模最大的东软集团、用友公司,真正的软件开发者也不过两、三千人,这种差别太巨大了,我们一定要好好思考,中国的软件业究竟出了什么问题?” 对此,很多专家认为,中国软件业已经面临一个新的转折点,随着信息化在各行各业的深入运用,软件业有机会深度专业化,由边缘而进入核心,从而形成以深度专业化为特征的核心竞争力。无论个人还是公司,我们都有幸在第一时间站在了软件业这块前沿阵地,但明天是否会更好,还有待于中国软件业的整体发展,在这颇为沉闷的时刻,我们期望“让暴风雨来得更猛烈些吧”! 参考资料:http://www.w-training.com/viewc.asp?id=23922 ====================================================== 在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/ 本篇文章为转载内容。原文链接:https://blog.csdn.net/javazhuanzai/article/details/7189396。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-24 09:01:26
287
转载
转载文章
...与开源创新与协作的新阶段。 值得注意的是,各国政府也开始关注开源对于国家科技创新和数字主权的影响。例如,欧洲联盟提出了“2020-2023年欧盟开源软件行动计划”,旨在提升公共部门对开源软件的认知和使用水平,促进成员国之间的开源技术和信息共享。 综上所述,开源软件领域的变革与挑战不断推动着各利益方深化合作,寻求可持续发展的解决方案,共同构建更加繁荣、健康的开源生态环境。
2023-05-03 09:19:23
273
转载
转载文章
...只发生在 fork 阶段,一般时间很短。 用 lastsave 命令可以查看最近一次成功生成快照的时间。 6.1.2 RDB 数据的恢复(演示) 1、shutdown 持久化添加键值 添加键值 redis> set k1 1 redis> set k2 2 redis> set k3 3 redis> set k4 4 redis> set k5 5 停服务器,触发 save redis> shutdown 备份 dump.rdb 文件 cp dump.rdb dump.rdb.bak 启动服务器 /usr/local/soft/redis-5.0.5/src/redis-server /usr/local/soft/redis-5.0.5/redis.conf 啥都没有: redis> keys 3、通过备份文件恢复数据停服务器 redis> shutdown 重命名备份文件 mv dump.rdb.bak dump.rdb 启动服务器 /usr/local/soft/redis-5.0.5/src/redis-server /usr/local/soft/redis-5.0.5/redis.conf 查看数据 redis> keys 6.1.3 RDB 文件的优势和劣势 一、优势 1.RDB 是一个非常紧凑(compact)的文件,它保存了 redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。 2.生成 RDB 文件的时候,redis 主进程会 fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘 IO 操作。 3.RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。 二、劣势 1、RDB 方式数据没办法做到实时持久化/秒级持久化。因为 bgsave 每次运行都要执行 fork 操作创建子进程,频繁执行成本过高。 2、在一定间隔时间做一次备份,所以如果 redis 意外 down 掉的话,就会丢失最后一次快照之后的所有修改(数据有丢失)。 如果数据相对来说比较重要,希望将损失降到最小,则可以使用 AOF 方式进行持久化。 6.2 AOF Append Only File AOF:Redis 默认不开启。AOF 采用日志的形式来记录每个写操作,并追加到文件中。开启后,执行更改 Redis 数据的命令时,就会把命令写入到 AOF 文件中。 Redis 重启时会根据日志文件的内容把写指令从前到后执行一次以完成数据的恢复工作。 6.2.1 AOF 配置 配置文件 redis.conf 开关appendonly no 文件名appendfilename "appendonly.aof" AOF 文件的内容(vim 查看): 问题:数据都是实时持久化到磁盘吗? 由于操作系统的缓存机制,AOF 数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。什么时候把缓冲区的内容写入到 AOF 文件? 问题:文件越来越大,怎么办? 由于 AOF 持久化是 Redis 不断将写命令记录到 AOF 文件中,随着 Redis 不断的进行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及 AOF 恢复要求时间越长。 例如 set xxx 666,执行 1000 次,结果都是 xxx=666。 为了解决这个问题,Redis 新增了重写机制,当 AOF 文件的大小超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。 可以使用命令 bgrewriteaof 来重写。 AOF 文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的 AOF 文件。 重写触发机制 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb 问题:重写过程中,AOF 文件被更改了怎么办? 另外有两个与 AOF 相关的参数: 6.2.2 AOF 数据恢复 重启 Redis 之后就会进行 AOF 文件的恢复。 6.2.3 AOF 优势与劣势 优点: 1、AOF 持久化的方法提供了多种的同步频率,即使使用默认的同步频率每秒同步一次,Redis 最多也就丢失 1 秒的数据而已。 缺点: 1、对于具有相同数据的的 Redis,AOF 文件通常会比 RDB 文件体积更大(RDB 存的是数据快照)。 2、虽然 AOF 提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。在高并发的情况下,RDB 比 AOF 具好更好的性能保证。 6.3 两种方案比较 那么对于 AOF 和 RDB 两种持久化方式,我们应该如何选择呢? 如果可以忍受一小段时间内数据的丢失,毫无疑问使用 RDB 是最好的,定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。 否则就使用 AOF 重写。但是一般情况下建议不要单独使用某一种持久化机制,而是应该两种一起用,在这种情况下,当 redis 重启的时候会优先载入 AOF 文件来恢复原始的数据,因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整。 本篇文章为转载内容。原文链接:https://blog.csdn.net/zhoutaochun/article/details/120075092。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-03-18 12:25:04
541
转载
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
ln -s source destination
- 创建软链接(符号链接)。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"