前端技术
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
[即时通信工具公众信息服务发展管理暂行规定]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
Tornado
...如何在云环境中更好地管理和保护敏感数据。就在上周,谷歌云宣布了一项新的隐私增强技术——Homomorphic Encryption(同态加密)。这项技术允许数据在不解密的情况下进行计算,这意味着企业可以在不暴露数据具体内容的前提下,利用云服务商提供的分析工具进行深度挖掘。这对于像Tornado这样的Web框架开发者来说尤其重要,因为未来的Web应用可能会更多地依赖于云端的数据处理能力,而不仅仅是本地计算。 与此同时,欧盟最近更新了《通用数据保护条例》(GDPR)的执法指南,明确指出即使是加密后的数据,也需要符合特定的安全标准。这一变化提醒所有开发者,即使采用了先进的加密技术,也不能忽视数据生命周期中的其他环节,比如访问控制、审计日志等。这也意味着,仅仅依靠Google Cloud Secret Manager可能还不够,还需要结合更全面的安全策略来应对日益复杂的网络威胁环境。 此外,针对Tornado框架本身,社区内正热议如何进一步优化其在高并发场景下的表现。有开发者提出,通过引入gRPC协议,可以显著降低客户端和服务端之间的通信延迟,这对于需要实时交互的应用尤为重要。值得注意的是,gRPC不仅支持多种编程语言,还内置了强大的负载均衡机制,这与Tornado的异步架构高度契合。 总之,在追求技术创新的同时,开发者必须时刻牢记数据安全与合规性的重要性。无论是采用新型加密技术,还是优化现有架构,都需要综合考虑业务需求和技术可行性,确保每一步都走在合法合规的道路上。未来,随着量子计算的发展,传统加密算法或将面临新的挑战,因此提前布局相关研究显得尤为必要。
2025-04-09 15:38:23
43
追梦人
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 2021年8月16日,《2020年北京市外来新生代农民工监测报告》发布,为了进一步做好农民工服务工作,了解外来农民工在京工作、生活需要,国家统计局北京调查总队在全市范围开展了农民工市民化进程动态监测调查。 2020年监测数据显示,新生代农民工占比达到50.1%,男性占比高于女性。新生代农民工中男性占比为66.3%,比上年提高4.6个百分点;男性占比高于女性32.5个百分点,比上年提高9.1个百分点。 就业集中于劳动密集型行业,从事信息传输、软件和信息技术服务业的新生代农民工占比大幅提高。 2020年就业人数前五位的行业依次为居民服务、修理和其他服务业,制造业,建筑业,批发和零售业,住宿和餐饮业,共吸纳67.2%的新生代农民工就业。 2020年北京市外来新生代农民工监测报告 为了进一步做好农民工服务工作,了解外来农民工在京工作、生活需要,国家统计局北京调查总队在全市范围开展了农民工市民化进程动态监测调查,2020年监测数据显示,新生代农民工(出生于20世纪80年代以后,年龄在16周岁及以上,在异地以非农就业为主的农业户籍人口)占比达到50.1%,已经成为农民工的主体。 一、新生代农民工总体特征 男性占比高于女性,差距进一步加大。新生代农民工中男性占比为66.3%,比上年提高4.6个百分点;男性占比高于女性32.5个百分点,比上年提高9.1个百分点。 31-40岁农民工占比提高。新生代农民工平均年龄31.4岁,比上年增加0.4岁。其中,31-40岁的占比为57.9%,比上年提高3.2个百分点;21-30岁的占比为39.9%,16-20岁的占比为2.2%,分别比上年下降2.6个和0.6个百分点。 大学本科以上学历新生代农民工占比增加。新生代农民工中大学本科以上学历占比为21.2%,比上年提高7.9个百分点。其中,大学本科学历的占比为20.0%,研究生学历的占比为1.2%。 外来新生代农民工主要来自北京周边地区。其中,河北、河南两省占比最大,河北省占比为37.3%,比上年同期提高3.5个百分点,河南省占比为12.3%,比上年同期下降3.3个百分点。 二、新生代农民工就业情况 (一)就业集中于劳动密集型行业,从事信息传输、软件和信息技术服务业的新生代农民工占比大幅提高 调查样本中,2020年就业人数前五位的行业与上年一致,依次为居民服务、修理和其他服务业,制造业,建筑业,批发和零售业,住宿和餐饮业,共吸纳67.2%的新生代农民工就业。 除上述五大行业外,从事信息传输、软件和信息技术服务业的新生代农民工比例为7.9%,比上年提高3.7个百分点,在所有行业中增幅最大。 (二)收入水平整体提高,内部差距拉大 调查样本中,新生代农民工月均收入6214元,比上年增加364元,增长6.2%。其中,66.5%月均收入在5000元及以上,比上年高8.6个百分点。 1.不同行业差距较大 新生代农民工从业人数最多的七个行业按照收入水平排序依次为:信息传输、软件和信息技术服务业,建筑业,交通运输、 仓储和邮政业,制造业,批发零售业,住宿和餐饮业,居民服务、修理和其他服务业。月均收入分别为10571元、6587元、6489元、6017元、5888元、5668元和5195元。其中,收入最高的信息传输、软件和信息技术服务业从业人员月均收入比上年同期增长15.5%;从业人数最多、收入最低的居民服务、修理和其他服务业从业人员月均收入比上年同期降低2.6%。 2.不同收入段间收入差距加大 高收入段人员收入增速高于中低收入段。月均收入5000元及以上人员平均月收入为7507元,比上年同期提高2.8个百分点;月均收入4000-5000元人员平均月收入为4175元,比上年同期降低3.4个百分点;月均收入4000元以下人员平均月收入为3064元,比上年同期提高1.1个百分点。 (三)自营人员收入高,工作强度大 自营就业的新生代农民工月均收入6716元,比务工就业人员高568元;自营就业的新生代农民工平均每周工作6.5天,每天工作9.5小时,分别比务工就业人员多0.9天和0.7小时。 三、新生代农民工生活情况 (一)消费支出下降,吃穿住消费占新生代农民工总消费支出的7成以上 受疫情影响,未来收入的不确定性增加,新生代农民工户均消费支出降低。2020年,新生代农民工家庭户均生活消费支出42395元,比上年减少1833元,下降4.1%。 按照金额排序,新生代农民工消费支出排在前三位的依次为:食品烟酒、居住、衣着及其他日用品和服务,分别为14032元、10861元和5141元,前三位消费支出占总消费支出的70.8%。 (二)居住性质略有改变,居住满意度小幅提升 租赁私房人员占比减少,单位提供住房比例提升。从住房性质来看,新生代农民工主要以租赁私房为主,租赁私房的占60.5%,比上年同期降低3.2个百分点;单位提供住房的占33.1%,比上年同期提高4.7个百分点。 单位提供住房,居住消费支出减少,新生代农民工对现在居住条件表示满意的占66.5%,比上年提高3.0个百分点,其中,表示非常满意的占18.6%,比较满意的占47.9%。 (三)网络依赖增加,自我提升类活动减少 上网已经成为新生代农民工业余时间的主要休闲活动。新生代农民工业余时间的主要活动排在前三位的依次是:上网、休息和朋友聚会,其中上网占60.1%,比上年同期提高4.7个百分点。 自我提升类活动减少。业余时间参加学习培训、读书看报的新生代农民工占比分别为3.8%和7.6%,比上年同期分别下降2.5个和1.3个百分点。 四、“90后”农民工工作和生活特点 (一)“90后”农民工工作特点 1.“90后”农民工从事行业略有不同 “90后”农民工喜好略有不同,就业人数最多的七个行业依次为:制造业,建筑业,居民服务、修理和其他服务业,信息传输、软件和信息技术服务业,住宿和餐饮业,文化和娱乐服务业,批发和零售业。与新生代农民工群体差距最大的两个行业是信息传输、软件和信息技术服务业,批发和零售业,其中,从事信息传输、软件和信息技术服务业的占11.6%,比新生代农民工群体高3.7个百分点;从事批发和零售业的占5.8%,比新生代农民工群体低6.3个百分点。 2.“90后”农民工收入略高 调查样本中,“90后”农民工月均收入6424元,比新生代农民工群体平均水平高210元。其中,月均收入在5000元及以上的占68.4%,比新生代农民工群体高1.9个百分点。 3.自营人员占比较低 由于年纪尚轻,积累不够,“90后”农民工中的96.3%以受雇就业为主,自营就业人员仅占3.7%,低于新生代农民工群体7.9个百分点。 (二)“90后”农民工生活特点 1.消费支出略低,更偏重于衣着及教育文化娱乐方面 “90后”农民工家庭户均生活消费支出42009元,比新生代农民工群体低386元。其中,衣着及其他日常用品和服务、教育文化娱乐支出占总消费支出的比重分别为14.0%和5.9%,分别比新生代农民工群体高1.9个和1.0个百分点;居住和交通通信费支出占总消费支出的比重分别为23.9%和9.2%,分别比新生代农民工群体低1.8个和1.0个百分点。 2.业余生活更注重休息和自我提升 “90后”农民工业余时间的主要活动排在前三位的依旧是上网、休息和朋友聚会,但与整个新生代农民工群体不同的是,“90后”农民工更注重休息和自我提升,其中,业余时间休息的占34.5%,比新生代农民工群体高5.6个百分点;业余时间参加文娱体育活动、学习培训和读书看报的占27.5%,分别比新生代农民工群体、全部外来农民工整体高5.7个和11.8个百分点。 新生代农民工定义:出生于20世纪80年代以后,年龄在16周岁及以上,在异地以非农就业为主的农业户籍人口 推荐阅读: 世界的真实格局分析,地球人类社会底层运行原理 不是你需要中台,而是一名合格的架构师(附各大厂中台建设PPT) 企业IT技术架构规划方案 论数字化转型——转什么,如何转? 华为干部与人才发展手册(附PPT) 企业10大管理流程图,数字化转型从业者必备! 【中台实践】华为大数据中台架构分享.pdf 华为的数字化转型方法论 华为如何实施数字化转型(附PPT) 超详细280页Docker实战文档!开放下载 华为大数据解决方案(PPT) 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_45727359/article/details/119745674。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-06-28 17:16:54
62
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 sysinternals的网站创立于1996年由Mark russinovich和布赖科格斯韦尔主办其先进的系统工具和技术资料.微软于 2006年7月收购sysinternals公司 . 不管你是一个IT高级工作者还是一个开发者,你都会发现sysinternals工具可以帮助您管理、故障分析和诊断你的Windows系统和应用程序. 如果您有关于如何使用这些工具的问题,请访问sysinternals论坛从其他用户和我们的团队获取解答和帮助. 该工具包括: AccessChk 这个工具为您显示指定至档案、登录机码或 Windows 服务的使用者或群组之存取。 AccessEnum 这个简单又具有超高安全性的工具,会让您知道拥有对您系统目录、档案及登录机码的存取之对象和方式。用它来寻找您权限下的安全性漏洞。 AdRestore 取消删除 Server 2003 Active Directory 物件。 BgInfo 这个可完全设定的程式,会自动产生包括含有 IP 位址、电脑名称,和网路介面卡等等重要资讯的桌面背景。 BlueScreen 这个萤幕保护程式不只将「蓝色萤幕」(Blue Screens) 模仿得维妙维肖,也能模仿重新开机 (需使用 CHKDSK 完成),而且在 Windows NT 4、Windows 2000、Windows XP、Server 2003 和 Windows 9x 中皆能执行。 CacheSet CacheSet 是一种能让您使用 NT 提供的功能来控制 Cache Manager 的工作组大小。除了和 NT 所有版本相容之外,还提供原始程式码。 检视系统时钟的解析度,同时也是计时器解析度的最大值。 Contig 希望能够快速地将常用的档案进行磁碟重组吗?使用 Contig 最佳化个别档案,或是建立新的连续档案。 Ctrl2cap 这是一种核心模式驱动程式,展示键盘输入筛选只在键盘类别驱动程式之上,目的是为了将大写锁定按键转换至控制按键。这个层级的筛选允许在 NT 「发现」按键之前,先进行转换和隐藏按键。包括完整的来源。此外,Ctrl2cap 还会显示如何使用 NtDisplayString() 将讯息列印至初始化的蓝色萤幕。 DebugView Sysinternals 的另一个首开先例:这个程式会拦截分别由 DbgPrint 利用装置驱动程式,和 OutputDebugString 利用 Win32 程式所做的呼叫。它能够在您的本机上或跨往际往路,在不需要作用中的侦错工具情况下,检视和录制侦错工作阶段输出。 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
转载
Javascript
...Web开发领域的快速发展,AbortError的概念再次引起了广泛关注。特别是在大型在线平台如社交媒体和电商网站中,高效的请求管理变得尤为重要。例如,Facebook最近在其新版应用程序中引入了基于AbortError的优化策略,以减少不必要的后台数据同步操作。这一举措显著降低了移动端设备的能耗和内存占用,得到了用户的普遍好评。 与此同时,Google Chrome团队也在最新版本中加强了对AbortError的支持,新增了一项名为“智能取消”的功能。这项功能可以根据用户的操作习惯动态调整未完成请求的优先级,从而提升整体浏览体验。例如,在用户快速切换页面时,系统会自动取消低优先级的任务,确保核心功能的流畅运行。这种技术不仅减少了资源浪费,还大幅缩短了页面加载时间。 从技术角度来看,AbortError的应用不仅仅局限于前端开发。在后端服务中,通过结合WebSocket和AbortSignal,开发者可以实现更高效的实时通信协议。例如,某知名在线教育平台利用这一特性,成功将课堂互动延迟从原来的500毫秒降低到100毫秒以下,极大改善了师生间的协作效率。 此外,随着《通用数据保护条例》(GDPR)在全球范围内的实施,AbortError也被赋予了新的法律意义。在涉及用户隐私的数据传输过程中,合理运用AbortError可以帮助企业更好地遵守法规要求,避免因违规操作而导致的巨额罚款。例如,某跨国科技公司在其云存储服务中引入了基于AbortError的权限管理系统,确保敏感信息在未经授权的情况下无法被访问或下载。 总之,AbortError作为现代Web开发的重要组成部分,正逐步渗透到各个领域。无论是提升用户体验、优化系统性能,还是保障数据安全,它都展现出了巨大的潜力。未来,随着更多创新应用场景的涌现,相信AbortError将在数字世界中发挥更大的作用。
2025-03-27 16:22:54
106
月影清风
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 标 题: 我的windows下的mpich的经验 发信站: 南京大学小百合站 (Tue Nov 2 22:02:25 2004) 弄了好久的mpich,现在终于弄懂了 感谢pink, johnsmith给予的帮助 下面是跟都志辉老师的邮件,与还不会的同学共享 希望能给在windows下用的同学有帮助 到这封邮件,我已经懂了,相信大家会比我更快 如果还有不懂的,站内联系 /// 发件人: "Zhihui Du" <duzh@tsinghua.edu.cn> 添加到地址簿 收件人: "zhyi" <zhyi100@yahoo.com.cn> 主题: Re: 请教mpi 日期: Tue, 2 Nov 2004 08:31:20 +0800 我想主要的问题是权限的问题,你先在本机将config文件设置为只有自己的机器,运行一 下该程序看看,如果不能运行,多机当然就更不行了,这说明本机的设置有问题。如何解 决这一问题,我的经验是,你可以在两台机器上分别建立普通帐号,然后用mpiregister对 该帐号进行注册,如果两台机器上分别运行都可以,则可以试试多机,如果多机连接不同 ,则可能是防火墙等安全设置的问题,可以将防火墙去掉,这样就应该可以了,我们在XP 以及NT上实验都是可行的。 ------------------------------ Dr. Zhihui Du Department of Computer Science and Technology Tsinghua University. Beijing, 100084, P.R. China Phone:86-10-62782530 Fax:86-10-62771138 http://hpclab.cs.tsinghua.edu.cn/~duzh ----- Original Message ----- From: zhyi To: Zhihui Du Sent: Monday, November 01, 2004 4:39 PM Subject: Re: 请教mpi 单机模拟的命令为: mpirun -np 2 -localonly d:/cpi.exe 成功 两机器名分别为 liu1 liu2,命令为 mpirun -hosts 2 liu1 liu2 d:/cpi.exe 失败 config文件为 config.cfg exe d:/cpi.exe hosts liu1 2 liu2 2 命令为 mpirun d:/config.cfg 失败 加选项-tcp也没用 可执行文件的存放路径都在d盘根目录下 都老师,我想你们都是用linux 的,能不能请您的研究生给在两台 机器上试一下,估计两个小时够了,有你的指点,就会知道问题出在哪。 我们这边也有很多同学在你的书的指引下在linux下进行的,我是进行数值计算,不敢弄那 么复杂,只好在windows下进行,可也不知问题究竟在哪。 Zhihui Du <duzh@tsinghua.edu.cn> wrote: 你运行的具体命令是什么?可以用mpirun -np 2 xxx 和 mpirun configfile 两种方式都 试试,可执行程序两台机器上都要有。 ------------------------------ Dr. Zhihui Du Department of Computer Science and Technology Tsinghua University. Beijing, 100084, P.R. China Phone:86-10-62782530 Fax:86-10-62771138 http://hpclab.cs.tsinghua.edu.cn/~duzh ----- Original Message ----- From: zhyi To: Zhihui Du Sent: Sunday, October 31, 2004 11:50 AM Subject: Re: 请教mpi 任务管理器里发现有mpd进程,mpiconfig也能找到对方, 我们是在同一个宿舍,用hub相连,这在局域网内应该没问题了, 共享也是可读写的,盘符的格式是一样的,单机可以运行 mpirun -np 2 -localonly c:/ .exe 有结果 Zhihui Du <duzh@tsinghua.edu.cn> wrote: 安装mpich后应该有一个新的mpi进程在运行,用mpiconfig应该能够列出其他的机器才行, 还有这些计算结点的网络配置应该在一个子网内,另外共享的权限是否是任何用户可以读 写?你用mpirun -localonly -np x abc方式是否可以运行? ------------------------------ Dr. Zhihui Du Department of Computer Science and Technology Tsinghua University. Beijing, 100084, P.R. China Phone:86-10-62782530 Fax:86-10-62771138 http://hpclab.cs.tsinghua.edu.cn/~duzh ----- Original Message ----- From: zhyi To: Zhihui Du Sent: Saturday, October 30, 2004 5:55 PM Subject: Re: 请教mpi 我是严格按照mpich的要求进行的, 1。使用管理员权限在两机器上新建同一个名称的用户及相同的口令 2。分别在上面的两用户里安装mpich,然后mpiregister ,用户名和口令同 3。同一名称的盘符共享 4。mpiconfig,显示了对方的mpich 的版本号,说明已找到。 5。运行mpi程序 这样还是没有用,我们这边在windows系统下进行的很少有人成功过 我们都在网上问这个问题 Zhihui Du <duzh@tsinghua.edu.cn> wrote: 如果仅仅是自己做实验用,就可以不要考虑太多的安全问题,把MPI程序所在的盘共享出来 让其他的机器都可以访问,按照MPICH自己的设置,你可以运行MPIREGISTER程序先注册一 下用户名和口令。 ------------------------------ Dr. Zhihui Du Department of Computer Science and Technology Tsinghua University. Beijing, 100084, P.R. China Phone:86-10-62782530 Fax:86-10-62771138 http://hpclab.cs.tsinghua.edu.cn/~duzh ----- Original Message ----- From: zhyi To: duzh@tirc.cs.tsinghua.edu.cn Sent: Friday, October 29, 2004 9:26 PM Subject: 请教mpi 都老师: 你好! 我是南京大学系学生,现在正在用mpi进行数值并行编程, 是在windows系统下,同实验室的两台机器,总是显示登陆失败 不知怎么设置的。两台机器用的是同一用户名和相同密码,同样的注册。 希望能得到您的指点。 此致 -- ※ 来源:.南京大学小百合站 http://bbs.nju.edu.cn [FROM: 172.16.78.68] -- ※ 转寄:.南京大学小百合站 bbs.nju.edu.cn.[FROM: 202.120.20.14] -- ※ 转寄:.南京大学小百合站 bbs.nju.edu.cn.[FROM: 202.120.20.14] 一、预备工作 0. 二、下载 1. 下载mpich 三、安装 2. 用具有管理权限的帐户登陆计算机 3. 执行mpich.nt.1.2.5.exe,选择所有缺省安装 4. 在每台计算机上均执行上述过程2、3 四、配置 5. 运行配置工具 start->programs->MPICH->mpd->MPICH Configuration tool 6. 加入已经安装mpich的主机 7.点击 [Apply] 保存 8 点击 [OK] 退出 五、测试 9. 打开MSDEV工作空间文件 MPICH/SDK/examples/nt/examples.dsw 10. 编译调试该cpi 项目 11. 拷贝MPICH/SDK/examples/nt/basic/Debug/cpi.exe 到每一台机器某一共享目录。 如: c:/temp/cpi.exe 注意:确保每台机器均有同样的共享目录,并且可以互相访问!! 12. 打开命令窗口,改变当前路径到 c:/temp 下(与前相同) 13. 执行命令 MPICH/mpd/bin/mpirun.exe -np 4 cpi 本篇文章为转载内容。原文链接:https://blog.csdn.net/yangdelong/article/details/3946113。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-09 11:52:38
113
转载
Nacos
Nacos服务器配置文件读取失败:我的排查之旅 一、问题初现 为什么Nacos读不到配置? 事情得从头说起。我最近在做一个微服务项目,用了阿里巴巴的Nacos作为配置中心。哎呀,本来事情都挺顺的,结果有一天突然发现一个服务启动的时候,Nacos居然找不到配置文件了!我当时那个慌啊,心一下子提到了嗓子眼儿。 “不可能啊,之前都好好的,怎么今天就出问题了呢?”我心里嘀咕着。于是我赶紧翻看日志,发现报了一个错:“Config file not found in Nacos”。这下脑子更乱了,心里直嘀咕:“完啦,Nacos服务器该不会是罢工了吧?” 一想到这儿,赶紧三步并作两步跑去查看Nacos的状态,结果一看,嘿,人家还挺精神地在那里工作呢! “不对劲啊,难道是我自己的代码出了问题?”我开始怀疑自己是不是哪里写错了。为了验证这个假设,我先尝试重启服务,但还是不行。然后我又跑到Nacos的配置管理页面瞅了一眼,嘿,发现配置文件确实已经上传成功了,路径啥的一点问题都没有,挺顺利的!这让我更加困惑了。 “真是奇怪,到底是哪里出问题了呢?”我决定一步步排查这个问题。 --- 二、初步排查 配置路径和权限 首先,我想到的第一个可能性就是配置路径的问题。其实 Nacos 是靠路径来找配置文件的,要是路径搞错了,那它就压根找不到文件,更别提读出来了。 我打开代码,仔细检查了Nacos客户端的初始化部分: java NacosConfigService configService = NacosFactory.createConfigService("http://localhost:8848"); 这段代码看起来没问题啊,路径明明指向的是本地的Nacos服务器。而且我之前测试的时候也是这么写的,一直都没问题。 “会不会是配置路径格式变了?”我又重新检查了一遍Nacos的配置管理页面,确认路径确实正确无误。然后我又检查了权限设置,确保服务有权限访问这些配置。 “权限应该没问题吧,毕竟之前都好好的。”我自言自语道。不过嘛,我总觉得不放心,就随手叫上咱们的运维小伙伴帮我看了一下Nacos服务端的配置权限。没想到一看还真发现了点小问题,仔细一排查才发现权限其实没啥大事儿,一切正常! “看来不是路径和权限的问题,那问题到底出在哪呢?”我有点沮丧,但还是不死心,继续往下查。 --- 三、深入排查 网络连接与超时设置 接下来,我开始怀疑是不是网络连接出了问题。毕竟Nacos是基于网络通信的,如果网络不通畅,那自然会导致读取失败。 我先检查了Nacos服务端的日志,发现并没有什么异常。再瞧瞧服务端的那个监听端口,嘿,8848端口不仅开着呢,而且服务还稳稳地在跑着,一点问题没有! “难道是客户端的网络问题?”我心中一动,赶紧查看了服务端的防火墙规则,确认没有阻断任何请求。接着我又尝试ping了一下Nacos服务端的IP地址,结果发现网络连通性很好。 “网络应该没问题啊,那会不会是超时时间设置得太短了?”我灵机一动,想到之前在其他项目中遇到过类似的问题,可能是客户端等待响应的时间太短,导致请求超时。 于是我修改了Nacos客户端的配置,增加了超时时间: java Properties properties = new Properties(); properties.put(PropertyKeyConst.SERVER_ADDR, "localhost:8848"); properties.put(PropertyKeyConst.CONNECT_TIMEOUT_MS, "5000"); // 增加到5秒 NacosConfigService configService = NacosFactory.createConfigService(properties); 重新启动服务后,问题依然存在。看来超时时间也不是主要原因。 “真是搞不懂啊,难道是Nacos本身的问题?”我有些泄气,但还是决定继续深挖下去。 --- 四、终极排查 代码逻辑与异常处理 最后,我决定从代码逻辑入手,看看是不是程序内部的某些逻辑出了问题。于是我打开了Nacos客户端的源码,开始逐行分析。 在Nacos客户端的实现中,有一个方法是用来获取配置的: java String content = configService.getConfig(dataId, group, timeoutMs); 我仔细检查了这个方法的调用点,发现它是在服务启动时被调用的。你瞧,服务一启动呢,就会加载一堆东西,像数据库连接池啦,缓存配置啦,各种各样的“装备”都得准备好,这样它才能顺利开工干活呀! “会不会是某个配置项的加载顺序影响了Nacos的读取?”我突然想到这一点。我琢磨着这事儿,干脆把所有的配置加载顺序仔仔细细捋了一遍,就为了确保Nacos的配置能在服务刚启动的时候就给安排上,别拖到后面出了幺蛾子。 同时,我还加强了异常处理逻辑,给Nacos的读取操作加上了try-catch块,以便捕获具体的异常信息: java try { String content = configService.getConfig(dataId, group, timeoutMs); System.out.println("Config loaded successfully: " + content); } catch (NacosException e) { System.err.println("Failed to load config: " + e.getMessage()); } 经过一番调整后,我再次启动服务,终于看到了一条令人振奋的消息:“Config loaded successfully”。 “太好了!”我长舒一口气,“原来问题就出在这里啊。” --- 五、总结与感悟 经过这次折腾,我对Nacos有了更深的理解。Nacos这东西确实挺牛的,是个超棒的配置管理工具,但用着用着你会发现,它也不是完美无缺的,各种小问题啊、坑啊,时不时就冒出来折腾你一下。其实吧,这些问题真不一定是Nacos自己惹的祸,八成是咱们的代码写得有点问题,或者是环境配错了,带偏了Nacos。 “其实啊,调试的过程就像侦探破案一样,需要耐心和细心。我坐在电脑前忍不住感慨:“哎,有时候觉得这问题看起来平平无奇的,可谁知道背后可能藏着啥惊天大秘密呢!”” 总之,这次经历让我明白了一个道理:遇到问题不要慌,要冷静分析,逐步排查。只有这样,才能找到问题的根本原因,解决问题。希望我的经验能对大家有所帮助,如果有类似的问题,不妨按照这个思路试试看!
2025-04-06 15:56:57
67
清风徐来
Go-Spring
...人工智能等技术的快速发展,开源软件的应用范围不断扩大,不仅在企业内部得到广泛应用,也成为全球范围内科技创新与合作的新模式。本文旨在探讨开源软件的价值所在,分析其未来的发展趋势,并提出在拥抱开源软件过程中应考虑的关键因素。 开源软件的价值 开源软件以其透明、可定制和社区驱动的特点,为企业和个人用户带来了诸多价值。首先,开源软件降低了创新门槛,使得开发者能够基于已有代码进行快速迭代和创新,加速产品和服务的推出。其次,开源软件的社区化运作模式促进了知识共享与协作,形成了强大的技术支持和用户群体,有助于解决技术难题,提升产品质量。此外,开源软件的低成本和高可移植性,使其成为中小企业乃至个人开发者降低成本、快速进入市场的重要途径。 未来发展趋势 展望未来,开源软件的发展将呈现出以下几个趋势: 1. 云原生与容器化:随着云计算技术的成熟,基于云原生架构的开源软件将得到更多应用,而容器化技术的普及将进一步提升软件部署的效率与灵活性。 2. AI与机器学习:开源社区正在积极开发AI相关的开源项目,如TensorFlow、PyTorch等,这将促进AI技术的普及与创新,推动行业应用的深度发展。 3. 安全与隐私保护:随着数据安全与隐私保护成为关注焦点,开源社区将加强对安全框架和工具的开发,以满足不同行业对数据安全的需求。 4. 全球化与多语种支持:开源软件的全球化趋势日益明显,多语种支持将成为重要考量因素,有助于提升软件的国际竞争力。 拥抱开源软件的关键因素 1. 知识产权管理:明确开源软件的使用和贡献规则,保护自身权益的同时,尊重和遵守开源社区的规范。 2. 人才培养与激励:培养具备开源文化意识和技术能力的人才,通过项目贡献、社区活动等方式激励开发者积极参与开源项目。 3. 风险评估与管理:在采用开源软件前进行全面的风险评估,包括代码质量、安全漏洞、许可证合规性等方面,确保其符合组织的安全策略和法律法规要求。 4. 持续参与与贡献:积极参与开源社区,不仅使用开源软件,更要贡献自己的代码和知识,促进开源生态的健康发展。 拥抱开源软件不仅是技术层面的选择,更是推动创新、促进知识共享与合作的行动。面对未来的挑战与机遇,企业和个人开发者应积极适应这一趋势,充分利用开源资源,共同构建更加开放、协作的科技生态系统。
2024-07-31 16:06:44
277
月下独酌
转载文章
...。 同时,随着JIT即时编译器的发展,如GraalVM项目,其先进的动态编译技术能更高效地将字节码转换为机器码,使得Java应用程序执行效率大幅提升。对于Class文件内部结构的理解,有助于我们更好地利用这些新特性和工具进行优化配置。 此外,随着微服务、容器化和云原生架构的普及,Class文件在服务启动速度和资源占用上的优化也显得尤为重要。例如,通过提前解析和验证Class文件以减少运行时开销,或者采用Ahead-of-Time(AOT)编译技术将部分Class文件直接编译成本地代码,从而提升系统启动速度和降低内存使用。 另外,对于安全领域,深入理解Class文件结构有助于分析恶意字节码攻击手段,以及如何通过虚拟机层面的安全防护措施来避免有害类文件的加载执行。例如,最新的Java版本不断强化类加载验证机制,防止非法或恶意篡改的Class文件危害系统安全。 综上所述,随着Java技术栈的持续演进,Class文件这一基础而又关键的概念,在实际开发和运维过程中仍具有极高的研究价值和实战意义,值得开发者们密切关注和深入探索。
2024-01-09 17:46:36
645
转载
Netty
...。话说回来,再厉害的工具也不是全能的啊,在那种超高并发、必须稳如老狗的场景里,总免不了会出点幺蛾子。今天咱们就来聊聊Netty是如何帮我们实现故障恢复的。 说到故障恢复,其实很多人可能会觉得这是个很玄乎的事情。但其实,Netty在这方面做得相当出色。它的设计思路非常人性化,既考虑了性能,也兼顾了稳定性。咱们可以从以下几个方面入手,看看它是怎么做到的。 --- 二、为什么需要故障恢复? 首先,咱们得明白一个问题:为什么我们需要故障恢复?在现实世界中,网络环境复杂多变,服务器宕机、网络抖动、数据丢失等情况随时随地可能发生。如果我们的程序没有应对这些问题的能力,那后果简直不堪设想! 想象一下,你正在做一个在线支付系统,用户刚输入完支付信息,结果服务器突然挂了,这笔交易失败了。哎呀,这要是让用户碰上了,那可真是抓狂了!所以啊,咱们得想点办法,给系统加点“容错”的本事,不然出了问题用户可就懵圈了。说白了,故障恢复不就是干这个的嘛,就是为了不让小问题变成大麻烦! Netty在这方面做得非常到位。它有一套挺管用的招数,就算网络突然“捣乱”或者出问题了,也能尽量把损失降到最低,然后赶紧恢复到正常状态,一点儿都不耽误事儿。接下来,咱们就一步步拆解这些机制。 --- 三、Netty的故障恢复机制 3.1 异常处理与重试机制 首先,咱们来看看Netty最基础的故障恢复手段:异常处理与重试机制。 Netty提供了一种优雅的方式来处理异常。好比说呗,当客户端和服务器之间的连接突然“闹别扭”了,Netty就会立刻反应过来,自动给我们发个提醒,就像是“叮咚!出问题啦!”这样,咱们就能赶紧去处理这个小麻烦了。具体代码如下: java // 定义一个ChannelFutureListener,用于监听连接状态 ChannelFuture future = channel.connect(remoteAddress); future.addListener((ChannelFutureListener) futureListen -> { if (!futureListen.isSuccess()) { System.out.println("连接失败,尝试重新连接..."); // 这里可以加入重试逻辑 scheduleRetry(); } }); 在这段代码中,我们通过addListener为连接操作添加了一个监听器。如果连接失败,我们会打印一条日志并调用scheduleRetry()方法。这个办法啊,特别适合用来搞那种简单的重试操作,比如说隔一会儿就再试试重新连上啥的,挺实用的! 当然啦,实际项目中可能需要更复杂的重试策略,比如指数退避算法。不过Netty已经为我们提供了足够的灵活性,剩下的就是根据需求去实现啦! --- 3.2 零拷贝技术与内存管理 接下来,咱们聊聊另一个关键点:零拷贝技术与内存管理。 在高并发场景下,频繁的数据传输会导致内存占用飙升,进而引发GC(垃圾回收)风暴。Netty通过零拷贝技术很好地解决了这个问题。简单说呢,零拷贝技术就像是给数据开了一条“直达通道”,不用再把数据倒来倒去地复制一遍,就能让它直接从这儿跑到那儿。 举个例子,假设我们要将文件内容发送给远程客户端,传统的做法是先将文件读取到内存中,然后再逐字节写入Socket输出流。这样不仅效率低下,还会浪费大量内存资源。Netty 这家伙可聪明了,它能用 FileRegion 类直接把文件塞进 Socket 通道里,这样就省得在内存里来回倒腾数据啦,效率蹭蹭往上涨! java // 使用FileRegion发送文件 FileInputStream fileInputStream = new FileInputStream(new File("data.txt")); FileRegion region = new DefaultFileRegion(fileInputStream.getChannel(), 0, fileSize); channel.writeAndFlush(region); 在这段代码中,我们利用DefaultFileRegion将文件内容直接传递给了Netty的通道,大大提升了传输效率。 --- 3.3 长连接复用与心跳检测 第三个重要的机制是长连接复用与心跳检测。 在高并发环境下,频繁创建和销毁TCP连接的成本是非常高的。所以啊,Netty这个家伙超级聪明,它能让一个TCP连接反复用,不用每次都重新建立新的连接。这就像是你跟朋友煲电话粥,不用每次说完一句话就挂断重拨,直接接着聊就行啦,省心又省资源! 与此同时,为了防止连接因为长时间闲置而失效,Netty还引入了心跳检测机制。简单说吧,就像你隔一会儿给对方发个“我还在线”的消息,就为了确认你们的联系没断就行啦! java // 设置心跳检测参数 Bootstrap bootstrap = new Bootstrap(); bootstrap.option(ChannelOption.SO_KEEPALIVE, true); // 开启TCP保活功能 bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000); // 设置连接超时时间 在这里,我们通过设置SO_KEEPALIVE选项开启了TCP保活功能,并设置了最长的连接等待时间为5秒。这样一来,即使网络出现短暂中断,Netty也会自动尝试恢复连接。 --- 3.4 数据缓冲与批量处理 最后一个要点是数据缓冲与批量处理。 在网络通信过程中,数据的大小和频率往往不可控。要是每次传来的数据都一点点的,那老是去处理这些小碎数据,就会多花不少功夫啦。Netty通过内置的缓冲区(Buffer)解决了这个问题。 例如,我们可以使用ByteBuf来存储和处理接收到的数据。ByteBuf就像是内存管理界的“万金油”,不仅能够灵活地伸缩大小,还能轻松应对各种编码需求,简直是程序员手里的瑞士军刀! java // 创建一个ByteBuf实例 ByteBuf buffer = Unpooled.buffer(1024); buffer.writeBytes(data); // 处理数据 while (buffer.readableBytes() > 0) { byte b = buffer.readByte(); process(b); } 在这段代码中,我们首先创建了一个容量为1024字节的缓冲区,然后将接收到的数据写入其中。接着,我们通过循环逐个读取并处理缓冲区中的数据。这种方式不仅可以提高处理效率,还能更好地应对突发流量。 --- 四、总结与展望 好了,朋友们,今天的分享就到这里啦!通过上面的内容,相信大家对Netty的故障恢复机制有了更深的理解。不管是应对各种意外情况的异常处理,还是能让数据传输更高效的零拷贝技术,又或者是能重复利用长连接和设置数据缓冲这些招数,Netty可真是个实力派选手啊! 不过,技术的世界永远没有尽头。Netty虽然已经足够优秀,但在某些特殊场景下仍可能存在局限性。未来的日子啊,我超级期待能看到更多的小伙伴,在Netty的基础上大展身手,把自己的系统捯饬得既聪明又靠谱,简直就像给它装了个“智慧大脑”一样! 最后,我想说的是,技术的学习是一个不断探索的过程。希望大家能在实践中积累经验,在挑战中成长进步。如果你有任何疑问或者想法,欢迎随时留言交流哦! 祝大家都能写出又快又稳的代码,一起迈向技术巅峰吧!😎
2025-03-19 16:22:40
79
红尘漫步
Sqoop
...随着大数据技术的快速发展,数据迁移工具的选择成为越来越多企业关注的重点。除了Sqoop之外,市场上涌现出了一系列新的工具和技术方案,比如Apache NiFi和Talend Data Integration,它们在数据流管理和实时处理方面展现出了更强的能力。NiFi以其直观的图形界面和灵活的数据路由功能受到开发者的青睐,而Talend则提供了更为全面的企业级支持和服务。这些工具不仅提升了数据迁移的效率,还增强了数据的安全性和可靠性,为企业在数字化转型过程中提供了更多选择。 此外,随着云计算的普及,云原生数据迁移工具也逐渐成为主流趋势。例如,AWS Database Migration Service(DMS)和Google Cloud Data Transfer Service等服务,允许用户在不同的云平台之间无缝迁移数据,同时提供自动化的监控和故障恢复机制。这种云原生解决方案大幅降低了传统本地部署工具的复杂度,使得中小企业也能轻松实现大规模数据迁移。 值得注意的是,数据隐私法规的变化对数据迁移工具提出了更高的合规要求。欧盟的《通用数据保护条例》(GDPR)和美国加州的《消费者隐私法》(CCPA)等法律框架,都对企业如何收集、存储和传输个人数据作出了严格规定。因此,企业在选用数据迁移工具时,不仅要考虑技术层面的兼容性和稳定性,还需要确保工具符合最新的法律法规,以避免潜在的法律风险。 在未来,随着人工智能和机器学习技术的进步,数据迁移工具将进一步智能化。例如,利用AI算法预测数据迁移过程中可能出现的问题,并提前采取措施优化流程,将成为行业发展的新方向。同时,开源社区的持续贡献也将推动工具的创新,为企业提供更多低成本、高效率的解决方案。总之,数据迁移领域的技术创新正在加速演进,为企业的数据管理带来了前所未有的机遇和挑战。
2025-03-22 15:39:31
93
风中飘零
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者。 简介 学习编程,数据结构是你必须要掌握的基础知识,那么数据结构到底是什么呢? 根据百度百科的介绍,数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。 听听这是人话么,我帮你们翻译一下,其实数据结构就是用来描述计算机里存储数据的一种数学模型,因为计算机里要存储很多乱七八糟的数据,所以也需要不同的数据结构来描述。 本文思维导图 为什么要学数据结构 了解了基本概念之后,接下来我们再来看看,为什么我们要学习数据结构呢? 在许多类型的程序的设计中,数据结构的选择是一个基本的设计考虑因素。许多大型系统的构造经验表明,系统实现的困难程度和系统构造的质量都严重的依赖于是否选择了最优的数据结构。 许多时候,确定了数据结构后,算法就容易得到了。有些时候事情也会反过来,我们根据特定算法来选择数据结构与之适应。不论哪种情况,选择合适的数据结构都是非常重要的。 选择了数据结构,算法也随之确定,是数据而不是算法是系统构造的关键因素。这种洞见导致了许多种软件设计方法和程序设计语言的出现,面向对象的程序设计语言就是其中之一。 也就是说,选定数据结构往往是解决问题的核心,比如我们做一道算法题,往往就要先确定数据结构,再根据这个数据结构去思考怎么解题。 如果没有数据结构的基础知识,也就没有谈算法的意义了,很多时候即使你会使用一些封装好的编程api,但你却不知道其背后的实现原理,比如hashmap,linkedlist这些Java里的集合类,实际上都是JDK封装好的基础数据结构。 如何学习数据结构 第一次接触 我第一次接触数据结构这门课还是4年前,那这时候我在准备考研,专业课考的就是数据结构与算法,作为一个非科班的小白,对这个东西可以说是一窍不通。 这个时候的我只有一点点c语言的基础,基本上可以忽略不计,所以小白同学也可以按照这个思路进行学习。 数据结构基本上是考研的必考科目,所以我一开始使用的是考研的复习书籍,《天勤数据结构》和《王道数据结构》这两个家的书都是专门为计算机考研服务的,可以直接百度,这两本书对于我这种小白来说居然都是可以看懂的,所以,用来入门也是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
转载
Hadoop
...道,简直就像在海量的信息海洋里淘宝一样!如果用传统的数据库,可能早就崩溃了。但Hadoop不一样,它可以将这些数据分散到多个服务器上进行并行处理,效率杠杠的! 不过,Hadoop的魅力远不止于此。嘿,大家好!今天我想跟你们分享一个关于Hadoop的超棒功能——它居然能让你在不同的访问控制协议之间轻松切换文件!是不是听着就很带感?哎呀,是不是觉得这事听着有点绕?别慌,我这就用大白话给你说道说道,保证你一听就明白! --- 二、什么是跨访问控制协议迁移? 首先,我们得明白什么是访问控制协议。简单说,就是规定谁可以访问你的数据以及他们能做些什么的规则。好比说啊,你有个公共文件柜,你想让一些人只能打开看看里面的东西,啥都不能动;但另外一些人呢,不仅能看,还能随便改,甚至直接把东西清空或者拿走。这就是访问控制协议的作用。 那么,“跨访问控制协议迁移”又是什么意思呢?想象一下,你有两个不同的系统,它们各自有自己的访问控制规则。比如说,一个是Linux那边的ACL(访问控制列表)系统,另一个则是Windows里的NTFS权限系统,两者各有各的玩法。现在,你要把文件从一个系统迁移到另一个系统,而且你还想保留原来的访问控制设置。这就需要用到跨访问控制协议迁移的技术了。 为什么要关心这个功能呢?因为现实世界中,企业往往会有多种操作系统和存储环境。要是你对文件的权限管理不当,那可就麻烦了,要么重要数据被泄露出去,要么一不小心就把东西给搞砸了。而Hadoop通过其强大的灵活性,完美地解决了这个问题。 --- 三、Hadoop如何实现跨访问控制协议迁移? 接下来,让我们来看看Hadoop是如何做到这一点的。其实,这主要依赖于Hadoop的分布式文件系统(HDFS)和它的API库。为了更好地理解,我们可以一步步来分析。 3.1 HDFS的基本概念 HDFS是Hadoop的核心组件之一,它是用来存储大量数据的分布式文件系统。这就像是一个超大号的硬盘,不过它有点特别,不是集中在一个地方存东西,而是把数据切成小块,分散到不同的“小房间”里去。这样做的好处是即使某个节点坏了,也不会影响整个系统的运行。 HDFS还提供了一套丰富的接口,允许开发者自定义文件的操作行为。这就为实现跨访问控制协议迁移提供了可能性。 3.2 实现步骤 实现跨访问控制协议迁移大致分为以下几个步骤: (1)读取源系统的访问控制信息 第一步是获取源系统的访问控制信息。比如,如果你正在从Linux系统迁移到Windows系统,你需要先读取Linux上的ACL配置。 java // 示例代码:读取Linux ACL import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import java.io.IOException; public class AccessControlReader { public static void main(String[] args) throws IOException { Path path = new Path("/path/to/source/file"); FileSystem fs = FileSystem.get(new Configuration()); // 获取ACL信息 String acl = fs.getAclStatus(path).toString(); System.out.println("Source ACL: " + acl); } } 这段代码展示了如何使用Hadoop API读取Linux系统的ACL信息。可以看到,Hadoop已经为我们封装好了相关的API,调用起来非常方便。 (2)转换为目标系统的格式 接下来,我们需要将读取到的访问控制信息转换为目标系统的格式。比如,将Linux的ACL转换为Windows的NTFS权限。 java // 示例代码:模拟ACL到NTFS的转换 public class AclToNtfsConverter { public static void convert(String linuxAcl) { // 这里可以编写具体的转换逻辑 System.out.println("Converting ACL to NTFS: " + linuxAcl); } } 虽然这里只是一个简单的打印函数,但实际上你可以根据实际需求编写复杂的转换算法。 (3)应用到目标系统 最后一步是将转换后的权限应用到目标系统上。这一步同样可以通过Hadoop提供的API来完成。 java // 示例代码:应用NTFS权限 public class NtfsPermissionApplier { public static void applyPermissions(Path targetPath, String ntfsPermissions) { try { // 模拟应用权限的过程 System.out.println("Applying NTFS permissions to " + targetPath.toString() + ": " + ntfsPermissions); } catch (Exception e) { e.printStackTrace(); } } } 通过这三个步骤,我们就完成了从源系统到目标系统的访问控制协议迁移。 --- 四、实战演练 一个完整的案例 为了让大家更直观地理解,我准备了一个完整的案例。好啦,想象一下,我们现在要干的事儿就是把一个文件从一台Linux服务器搬去Windows服务器,而且还得保证这个文件在新家里的“门禁权限”跟原来一模一样,不能搞错! 4.1 准备工作 首先,确保你的开发环境中已经安装了Hadoop,并且配置好相关的依赖库。此外,还需要准备两台机器,一台装有Linux系统,另一台装有Windows系统。 4.2 编写代码 接下来,我们编写代码来实现迁移过程。首先是读取Linux系统的ACL信息。 java // 读取Linux ACL Path sourcePath = new Path("/source/file.txt"); FileSystem linuxFs = FileSystem.get(new Configuration()); String linuxAcl = linuxFs.getAclStatus(sourcePath).toString(); System.out.println("Linux ACL: " + linuxAcl); 然后,我们将这些ACL信息转换为NTFS格式。 java // 模拟ACL到NTFS的转换 AclToNtfsConverter.convert(linuxAcl); 最后,将转换后的权限应用到Windows系统上。 java // 应用NTFS权限 Path targetPath = new Path("\\\\windows-server\\file.txt"); NtfsPermissionApplier.applyPermissions(targetPath, "Full Control"); 4.3 执行结果 执行完上述代码后,你会发现文件已经被成功迁移到了Windows系统,并且保留了原有的访问控制设置。是不是很神奇? --- 五、总结与展望 通过这篇文章,我相信你对Hadoop支持文件的跨访问控制协议迁移有了更深的理解。Hadoop不仅是一个强大的工具,更是一种思维方式的转变。它就像个聪明的老师,不仅教我们怎么用分布式的思路去搞定问题,还时不时敲打我们:嘿,别忘了数据的安全和规矩可不能丢啊! 未来,随着技术的发展,Hadoop的功能会越来越强大。我希望你能继续探索更多有趣的话题,一起在这个充满挑战的世界里不断前行! 加油吧,程序员们!
2025-04-29 15:54:59
79
风轻云淡
转载文章
...云技术和虚拟化技术的发展,Windows To Go和Azure Sphere等新型安装方式为系统部署提供了更多可能。 在网络配置方面,IPv6在全球范围内的普及速度加快,许多网络设备厂商正致力于提升产品对IPv6协议栈的支持。与此同时,Windows操作系统也在不断更新其网络功能,包括DHCPv6客户端功能增强、DNS-over-HTTPS(DoH)支持以及更完善的组播服务管理工具。此外,Windows防火墙已新增多项高级策略设置,以满足日益复杂的网络安全需求。 最后,关于Office软件中的实用技巧,Microsoft Office 365定期发布更新,提供更丰富的协作工具和智能功能,例如Excel的数据预处理和分析能力得到显著提升,Outlook则集成了更多智能邮件管理和日程安排助手。这些实时更新和新增功能有助于用户提高工作效率,应对各种办公场景挑战。 总之,随着科技不断发展,无论是操作系统的基础架构、网络配置的复杂度还是办公应用的智能化程度都在持续演进,关注行业动态和技术前沿将帮助我们更好地理解和运用文中提及的相关知识。
2023-09-10 16:27:10
270
转载
Netty
...发者快速构建可扩展的服务器端应用程序。想象一下,你正在开发一个需要处理海量数据的大数据流处理平台,这时候Netty就显得尤为重要了。它不仅能够帮助我们高效地管理网络连接,还能让我们轻松应对高并发场景。 我第一次接触Netty的时候,真的被它的灵活性震撼到了。哎,说到程序员的烦心事,那肯定得提一提怎么让程序在被成千上万的人同时戳的时候还能稳如老狗啊!这事儿真心让人头大,尤其是看着服务器指标噌噌往上涨,心里直打鼓,生怕哪一秒就崩了。而Netty通过非阻塞I/O模型,完美解决了这个问题。这就像是一个超级能干的服务员,能够在同一时间同时服务上万个客人,而且就算有个客人纠结半天点菜(也就是某个请求拖拉),也不会耽误其他客人的服务,更不会让整个餐厅都停下来等他。 举个栗子: java EventLoopGroup bossGroup = new NioEventLoopGroup(); // 主线程组 EventLoopGroup workerGroup = new NioEventLoopGroup(); // 工作线程组 try { ServerBootstrap b = new ServerBootstrap(); // 启动辅助类 b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // 使用NIO通道 .childHandler(new ChannelInitializer() { // 子处理器 @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new StringDecoder()); // 解码器 ch.pipeline().addLast(new StringEncoder()); // 编码器 ch.pipeline().addLast(new SimpleChannelInboundHandler() { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println("Received message: " + msg); ctx.writeAndFlush("Echo: " + msg); // 回显消息 } }); } }); ChannelFuture f = b.bind(8080).sync(); // 绑定端口并同步等待完成 f.channel().closeFuture().sync(); // 等待服务关闭 } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } 这段代码展示了如何用Netty创建一个简单的TCP服务器。话说回来,Netty这家伙简直太贴心了,它的API设计得特别直观,想设置啥处理器或者监听事件都超简单,用起来完全没压力,感觉开发效率直接拉满! 2. 大数据流处理平台中的挑战 接下来,我们聊聊大数据流处理平台面临的挑战。在这个领域,我们通常会遇到以下几个问题: - 高吞吐量:我们需要处理每秒数百万条甚至更多的数据记录。 - 低延迟:对于某些实时应用场景(如股票交易),毫秒级的延迟都是不可接受的。 - 可靠性:数据不能丢失,必须保证至少一次投递。 - 扩展性:随着业务增长,系统需要能够无缝扩容。 这些问题听起来是不是很让人头大?但别担心,Netty正是为此而生的! 让我分享一个小故事吧。嘿,有次我正忙着弄个日志收集系统,结果一测试才发现,这传统的阻塞式I/O模型简直是“人形瓶颈”啊!流量一大就直接崩溃,完全hold不住那个高峰时刻,简直让人头大!于是,我开始研究Netty,并将其引入到项目中。哈哈,结果怎么样?系统的性能直接翻了三倍!这下我可真服了,选对工具真的太重要了,感觉像是找到了开挂的装备一样爽。 为了更好地理解这些挑战,我们可以看看下面这段代码,这是Netty中用来实现高性能读写的示例: java public class HighThroughputHandler extends ChannelInboundHandlerAdapter { private final ByteBuf buffer; public HighThroughputHandler() { buffer = Unpooled.buffer(1024); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { for (int i = 0; i < 1024; i++) { buffer.writeByte((byte) i); } ctx.writeAndFlush(buffer.retain()); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.write(msg); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } 在这段代码中,我们创建了一个自定义的处理器HighThroughputHandler,它能够在每次接收到数据后立即转发出去,从而实现高吞吐量的传输。 3. Netty如何优化大数据流处理平台? 现在,让我们进入正题——Netty是如何具体优化大数据流处理平台的呢? 3.1 异步非阻塞I/O Netty的核心优势在于其异步非阻塞I/O模型。这就相当于,当有请求进来的时候,Netty可不会给每个连接都专门安排一个“服务员”,而是让这些连接共用一个“服务团队”。这样既能节省人手,又能高效处理各种任务,多划算啊!这样做的好处是显著减少了内存占用和上下文切换开销。 假设你的大数据流处理平台每天要处理数十亿条数据记录,采用传统的阻塞式I/O模型,很可能早就崩溃了。而Netty则可以通过单线程处理数千个连接,极大地提高了资源利用率。 3.2 零拷贝技术 另一个让Netty脱颖而出的特点是零拷贝技术。嘿,咱们就拿快递打个比方吧!想象一下,你在家里等着收快递,但这个快递特别麻烦——它得先从仓库(相当于内核空间)送到快递员手里(用户空间),然后快递员再把东西送回到你家(又回到内核空间)。这就像是数据在网络通信里来回折腾了好几趟,一会儿在系统深处待着,一会儿又被搬出来给应用用,真是费劲啊!这种操作不仅耗时,还会消耗大量CPU资源。 Netty通过ZeroCopy机制,直接将数据从文件系统传递到网络套接字,避免了不必要的内存拷贝。这种做法不仅加快了数据传输速度,还降低了系统的整体负载。 这里有一个实际的例子: java FileRegion region = new DefaultFileRegion(fileChannel, 0, fileSize); ctx.write(region); 上述代码展示了如何利用Netty的零拷贝功能发送大文件,无需手动加载整个文件到内存中。 3.3 灵活的消息编解码 在大数据流处理平台中,数据格式多种多样,可能包括JSON、Protobuf、Avro等。Netty提供了一套强大的消息编解码框架,允许开发者根据需求自由定制解码逻辑。 例如,如果你的数据是以Protobuf格式传输的,可以这样做: java public class ProtobufDecoder extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { byte[] data = new byte[in.readableBytes()]; in.readBytes(data); MyProtoMessage message = MyProtoMessage.parseFrom(data); out.add(message); } } 通过这种方式,我们可以轻松解析复杂的数据结构,同时保持代码的整洁性和可维护性。 3.4 容错与重试机制 最后但同样重要的是,Netty内置了强大的容错与重试机制。在网上聊天或者传输文件的时候,有时候会出现消息没发出去、对方迟迟收不到的情况,就像快递丢了或者送慢了。Netty这个小助手可机灵了,它会赶紧发现这些问题,然后试着帮咱们把没送到的消息重新发一遍,就像是给快递员多派一个人手,保证咱们的信息能安全顺利地到达目的地。 java RetryHandler retryHandler = new RetryHandler(maxRetries); ctx.pipeline().addFirst(retryHandler); 上面这段代码展示了如何添加一个重试处理器到Netty的管道中,让它在遇到错误时自动重试。 4. 总结与展望 经过这一番探讨,相信大家已经对Netty及其在大数据流处理平台中的应用有了更深入的理解。Netty可不只是个工具库啊,它更像是个靠谱的小伙伴,陪着咱们一起在高性能网络编程的大海里劈波斩浪、寻宝探险! 当然,Netty也有它的局限性。比如说啊,遇到那种超级复杂的业务场景,你可能就得绞尽脑汁写一堆专门定制的代码,不然根本搞不定。还有呢,这门技术的学习难度有点大,刚上手的小白很容易觉得晕头转向,不知道该怎么下手。但我相信,只要坚持实践,总有一天你会爱上它。 未来,随着5G、物联网等新技术的发展,大数据流处理的需求将会更加旺盛。而Netty凭借其卓越的性能和灵活性,必将在这一领域继续发光发热。所以,不妨大胆拥抱Netty吧,它会让你的开发之旅变得更加精彩! 好了,今天的分享就到这里啦!如果你有任何疑问或者想法,欢迎随时交流。记住,编程之路没有终点,只有不断前进的脚步。加油,朋友们!
2025-04-26 15:51:26
46
青山绿水
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 一、写在前面 终于过了9.28,几个月前在和同学吃饭的时候就在说,如果现在是国庆节多好啊,保研就结束了,不用再那么焦虑。保研前就看过网上好多经验帖,就想着等保研结束后把自己的经历与感想写下来,希望能给学弟学妹们一些帮助。在这里十分感谢一路上帮助并鼓励我的家人、老师、学长学姐和同学,是你们对我的帮助让我成功地走下来,走过那段焦虑的时光。 以下是我几个月来的收获与体会,希望能对大家有帮助,如果有问题欢迎私信我交流~~~ 如果对你有帮助记得点个赞哦🙈🙈🙈 PS:以下的个人简历/个人陈述/老师推荐信等材料如果有需要的,欢迎关注我的 微 信 公 号【驭风者小窝】发 送【 保研 】领取大礼包~~ 二、个人情况 学校:末流985 专业排名:5% 四六级:515/449 科研竞赛:学过一些机器学习的知识,有几个简单的科研项目;一些比赛获奖,国奖 最终去向:北航计算机学硕 三、关于保研(前期准备/时间安排/个人材料) 专业知识复习:建议在大三下学期开学初期就开始复习专业课,包括:线代、概率论、数据结构、计网、计组、操作系统等(不用复习的特别深入),有的学校有笔试,大多数在面试时会问到一些基础知识(如果老师问到的基础知识都答上来,老师对你的印象肯定会特别好!)。 信息搜集:各学校/学院官网(研招网);学长学姐;保研论坛,微信公众号(后保研、保研人、保研论坛等);QQ群等。同时也要多与同学交流,互相交换信息。 搜集你想去并且基本能去的学校的要求和特点(南京大学夏令营对机考特别看重,难度也比较大,可以在大三就多刷题好好准备),进行一定的准备,可以在网上搜索相关的经验贴。 个人定位:了解你们学校学长学姐的保研去处,最好多跟本校已经保研的学长学姐交流,根据他们的经历以及自己的实力和研究生规划来对自己进行定位。 方向和选择: 人工智能?CV? NLP? 数据库?分布式系统?其他? 硕士?直博? 小老师?大牛老师? 以上这些选择因人而异,最好自己多了解、多与老师学长学姐交流,根据自己的兴趣、目前的发展以及自己未来的规划进行抉择。 夏令营(4-7月):从四月份开始就有的学校开始了夏令营申请,5-6月是夏令营申请的集中时间;参加夏令营基本都在6-7月份。夏令营的好处:老师名额多;时间比较充裕,可以较好的了解学校以及方向等;大多学校夏令营安排住宿。参加夏令营最重要的是专业排名(这是大多数学校初筛的最重要的依据,科研经历/比赛等都是次要的。当然顶会和ACM大牛除外)。 预推免(7-9月):有的学校夏令营开始后马上就开始预推免的报名与进行(例如哈工大从7月份开始到9月份有四批预推免的面试);大多数学校集中在9月中旬。如果夏令营已经有offer了可以在预推免时冲击更好的offer;如果夏令营没有拿到offer,建议此时以稳重为好。 九推:9月28号在推免系统正式填报推免志愿,录取。 个人简历:建议在寒假期间就把自己大学的经历都整理一遍,写好简历的初始版本;然后再找老师、学长学姐帮忙完善。 个人陈述:包括自己的情况介绍、科研经历、研究生期间的规划等,1000-1500字。网上有模板可以借鉴。 老师推荐信:基本都是自己写好找老师签字,如果老师能帮你手写的话,那太好不过了。 联系老师邮件:建议提前写好一个大概的模板,注意格式、内容以及邮件的标题等(例如XX大学-XXX-保研申请)。建议夏令营前或者初审过了及时联系自己喜欢的老师。 以上只是对各方面的简单介绍,每个方面详细的注意点网上好多资料,多多搜集就好。 PS:以上个人简历/个人陈述/老师推荐信模板如果有需要的私信我分享给你! 建议把以上材料都提前收集整理好,保研结束后发现我的材料文件夹3个多G...... 一年多来整理的保研资料 四、上科大信息学院夏令营(7.3-7.6) 本来没有打算报名上科大,一个同学把上科大宣传单给了我一份,看后感觉上科大实力比较强(虽然不是982/211)就报名了。 校园环境 上科大3号报到,4号-6号有开营活动、参观、自己联系老师面试(后来才知道即使拿到优营九月份也要再来面试,也就是说上科大夏令营拿到优营只是免去了九月预推免面试的初审,但是如果你足够优秀,老师比较中意,九月份就是来走一下过场。) 我参加了三个老师的面试。YY老师只是简单问了几个问题,有点水;HXM老师有一轮笔试(考的概率论比较多,编译原理、操作系统、计网也有涉及)+面试;YJY老师的一轮面试是课题组的学长学姐面的(自我介绍+项目),二轮面试和老师聊。 上科大给我的感觉就是学校小而精;老师比较好(比如YJY/GSH/TKW)、科研氛围浓厚、硬件设施完善(双人宿舍,独立卫浴,中央空调;学校地下全是停车场,下雨不用打伞可以直接走地下),但是由于建立才几年的时间,知名度不高。 学生宿舍 五、北理计算机夏令营(7.8-7.10) 北理今年入营的基本都是985和顶尖211,夏令营去了基本都能拿到优营!入营290+,夏令营参营240+,优营220+。 在北理主楼俯瞰 8号报到,领取宿舍钥匙、校园卡(北理夏令营包括食宿,每人发了一张100元的校园卡,可以在食堂、超市消费)。北理校园比较小、路比较窄;研究生宿舍三栋高层,有电梯,四人间,宿舍空间小、比较挤,大多数宿舍有空调(据说是宿舍的同学自己买或者租的),每一层有一个公共洗澡间。 9号上午宣讲,下午机试。机试两道题目难度不大,老师手动输入三个样例给分(4+3+3,每道题目满分10分)。下午机试结束我找到提前联系的LX老师聊了一个小时,老师人很nice,专心学术(据说她的研究生大都有一篇顶会论文)。 10号上午自己找老师面试。我又参加了院长实验室的面试,比较简单。下午正式面试,分了十多个组一起面试,总共四个小时。面试包括英文自我介绍、项目、研究生规划、是否打算读博、基础知识等,每人大概5-7分钟。面试结束就可以离校了。 六、北航计算机夏令营(7.11-7.14) 北航是不包含食宿的,所以入营人数较多,有600+。北航7.11上午报到+宣讲,下午机试分两组。北航机试类似CSP,可以多次提交,以最后一次为准,但是提交后不能实时出成绩。机试两个小时,包括两道题目,第一道题目比较简单,第二道题目稍微难一些,我第二道题目没有写完但是也过了机试,第二道题目即使没有写完也要能写多少写多少,把代码的思路写出来(有可能会人工判)。北航机试可以用CSP成绩代替,基本250分及以上就没问题,每年具体的情况不一样。11号晚上出机试通过名单(大概500+进340+)。 12号分组面试,每人20分钟,从上午八点一直面试到下午三点。面试包括抽取一道政治题谈看法、抽取一段英文读并翻译、基础知识(数学知识+计算机知识)、项目。政治题和英文翻译感觉大家都差不多(除非你英语特别差),主要的是基础知识面试,北航比较爱问数学问题线代、概率论、离散、高数;如果你的项目比较好的话,老师会着重问你的项目。问到我的问题有梯度、可微和可导、大数定理+中心极限定理等。12号晚上出优营名单,大概340+进180。北航是根据夏令营面试排名来定学硕和专硕的,大概有40个学硕的名额,其他都是专硕,不过北航学硕和专硕培养方式没有区别。 这是在我前面面试同学被问到的部分问题 13号领导师意向表,找导师签字,如果没有找到暑假期间或者九月份也可以再联系老师。 14号校医院体检,夏令营结束。 七、计算所(7.13-7.16) 计算所入营还是比较有难度的,但是即使没入营也可以自己联系老师,如果老师同意可以来参加面试,只是夏令营包括食宿,没入营的不包括食宿。计算所是分实验室面试的,可以参加多个实验室的面试,我参加了网数和智信的笔试+机试+面试。 智信12号笔试,14号机试+面试。笔试包括英文论文理解翻译、概率论题、计算机基础知识题目(操作系统,计网等)、CV题目(智信主要是做CV)。机试五道题目,一个小时,题目代码已经写好了,只需你补全,类似LeetCode,在学长的电脑上完成,有C++和Python可选,两种编程语言题目不同。C++用的是VS2017,会由人给你记每道题目完成的时间,会让你演示调试,结束后打包发送到一个邮箱里。 网数只有机试和面试,13号上午机试,15号面试。机试一个小时七道题目,在自己电脑上写然后拷到老师的优盘上。考察了包括链表、二叉树、图等,偏向于工程,据说今年的题目是计算所一个工程博士出的。机试70人,进入面试60人。面试每人15分钟,包括自我介绍,专业知识,是否读博,项目等。 计算所环境 八、一些建议和感想 一些建议: 提前准备,给自己定位,有针对性的准备,多在网上找经验贴;多和本校保研的学长学姐交流,多和同学交流,多搜集信息; 4月份前把简历、推荐信、个人陈述等写好,再不断修改完善; 最好能提前联系一个老师,以免拿到优营而没有找到好老师; 准备好专业知识,线代、概率论、数据结构、计网、计组、操作系统等; 如果编程能力不是特别强,最好大三开始就刷题,LeetCode的中档题难度基本就够用了; 一些体会与感想: 机会是留给有准备的人的,越努力越幸运! 做最坏的打算,做最好的准备。 保研是一场马拉松,坚持到底就是胜利。 遵道而行,但到半途需努力;会心不远,欲登绝顶莫辞劳。 也送给自己一句话:流年笑掷,未来可期! 以上仅代表个人观点与感想,如果对你有帮助记得点赞哦~如有问题,可以关注我的公主号【驭风者小窝】,我会尽我最大的努力帮助你! 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_28983299/article/details/118319985。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-05-02 23:03:36
120
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 我踩过的坑,希望大家不用再踩。 到现在我工作 17 年了, 担任架构师的职位也超过了 10 年,担任过像 HP、Amazon 这样的世界级团队的架构师,也担任过像汇量科技这样快速成长的中小企业的技术领导。应 InfoQ 邀请分享一下我的工作感悟,分享内容部分来自成功总结,更多是来自失败的反思,希望我踩过的坑大家可以不用再踩。 “提出问题”难于“解决问题” 作为技术人员,我们已经习惯于作为问题的解决者给出设计方案,而很少以问题提出者的身份去思考设计方案。团队中常见的典型矛盾,就是产品团队和研发团队之间的矛盾。作为研发团队,我们常吐槽产品团队的需求不合理、不懂技术等。其实我们可以试着把自己的工作再往前移一下,不仅仅是去设计架构、实现产品的需求,同时也试着去实现客户的需求,甚至发现潜在的需求。 这时我们就变成了在设计上提出问题的人,你会发现提出问题的同时,在很多时候也需要同样深入的思考。设计一个好的问题,甚至比解决问题更难。 其实即便是软件开发领域的大神 Frederick P. Brooks Jr.(《人月神话》的作者)也会有同样的感叹。 “The hardest part of design is deciding what to design.” – 《The design of design》, by Frederick P. Brooks Jr. 决定“不要什么”比“要什么”更难 也许是由于人性的贪婪,对于软件系统我们同样想要更多:更多功能、更好的性能、更好的伸缩性、扩展性等等。作为软件架构师要明白软件架构设计就是一种取舍或平衡。当大家都在往里面加东西的时候,架构师更应该来做这个说“不”的人。 软件设计和定义过程中存在很多取舍,例如: 完善功能和尽早发布的取舍。 伸缩性和性能的取舍。 著名的 CAP 原则,就是一个很好的取舍指导策略。为了更好的取舍,保持架构风格的一致性,在一开始架构师就应该根据系统的实际需求来定义一些取舍的原则,如: 数据一致性拥有最高优先级。 提前发布核心功能优于完整发布等。 非功能性需求决定架构 因为软件是为了满足客户的功能性需求的,所以很多设计人员可能会认为架构是由要实现的功能性需求决定的。但实际上真正决定软件架构的其实是非功能性需求。 架构师要更加关注非功能性需求,常见的非功能性包括:性能,伸缩性,扩展性和可维护性等,甚至还包括团队技术水平和发布时间要求。能实现功能的设计总是有很多,考虑了非功能性需求后才能筛选出最合适的设计。 以上架构模式来自《面向模式的软件架构》的第一卷,这套书多年来一直是架构师的必读经典。面向架构的模式就是为不同的非功能性需求提供了很好的参考和指导。图中的 Micro-Kernel 模式,更加关注可扩展性和可用性(错误隔离)。 “简单”并不“容易” 很多架构师都会常常提到保持简单,但是有时候我们会混淆简单和容易。简单和容易在英语里也是两个词“simple”和“easy”。 “Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it’s worth it in the end because once you get there, you can move mountains. To be truly simple, you have to go really deep.” –SteveJobs 真正的一些简单的方法其实来自于对问题和技术更深入的理解。这些方案往往不是容易获得的、表面上的方法。简单可以说蕴含着一种深入的技巧在其中。 下面我来举一个例子。 首先我们来回顾一下软件生命周期中各个阶段的成本消耗占比。以下是来一个知名统计机构的分析报告。我们可以看到占比最大的是维护部分,对于这一部分的简化将最具有全局意义。 我曾经开发过一个设备管理系统,移动运营商通过这个系统来管理移动设备,实现包括设备的自动注册、固件和软件的同步等管理功能。这些功能是通过一些管理系统与移动设备间的预定义的交互协议来完成的。 电信专家们会根据业务场景及需求来调整和新增这些交互协议。起初我们采用了一种容易实现的方式,即团队中的软件工程会根据电信专家的说明,将协议实现为对应代码。 之后我们很快发现这样的方式,让我们的工作变得没那么简单。 “I believe that the hardest part of software projects, the most common source of project failure, is communication with the customers and users of that software.” –Martin Fowler 正如软件开发大师 MartinFowler 提到的,“沟通”往往是导致软件项目失败的主要原因。前面这个项目最大的问题是在系统上线后的运行维护阶段,电信专家和开发工程师之间会不断就新的协议修改和增加进行持续的沟通,而他们的领域知识和词汇都有很大的差别,这会大大影响沟通的效率。因此这期间系统的运行维护(协议的修改)变得十分艰难,不仅协议更新上线时间慢,而且由于软件工程对于电信协议理解程度有限,很多问题都要在实际上线使用后才能被电信专家发现,导致了很多的交换和反复。 针对上面提到的问题,后来我们和电信专家一起设计了一种协议设计语言(并提供可视化的工具),这种设计语言使用的电信专家所熟悉的词汇。然后通过一个类似于编译器的程序将电信专家定义好的协议模型转换为内存中的 Java 结构。这样整个项目的运行和维护就变得简单高效了,省去了低效的交流和不准确人工转换。 我们可以看到一开始按电信专家的说明直接实现协议是更为容易的办法,但就整个软件生命周期来看却并不是一个简单高效的方法。 永远不要停止编码 架构师也是程序员,代码是软件的最终实现形态,停止编程会逐渐让你忘记作为程序员的感受,更重要的是忘记其中的“痛”,从而容易产生一些不切实际的设计。 大家可能听说过在 Amazon,高级副总裁级别的 Distinguish Engineer(如:James Gosling,Java 之父),他们每年的编码量也非常大,常在 10 万行以上。 风险优先 架构设计很重要的一点是识别可能存在的风险,尤其是非功能性需求实现的风险。因为这些风险往往没有功能性需求这么容易在初期被发现,但修正的代价通常要比修正功能性需求大非常多,甚至可能导致项目的失败,前面我们也提到了非功能性需求决定了架构,如数据一致性要求、响应延迟要求等。 我们应该通过原型或在早期的迭代中确认风险能够通过合理的架构得以解决。 绝对不要把风险放到最后,就算是一个项目要失败也要让它快速失败,这也是一种敏捷。 从“问题”开始,而不是“技术” 技术人员对于新技术的都有着一种与身俱来的激情,总是乐于去学习新技术,同时也更有激情去使用新技术。但是这也同样容易导致一个通病,就是“当我们有一个锤子的时候看什么都是钉子”,使用一些不适合的技术去解决手边的问题,常常会导致简单问题复杂化。 我曾经的一个团队维护过这样一个简单的服务,起初就是一个用 MySQL 作数据存储的简单服务,由团队的一个成员来开发和维护。后来,这位成员对当时新出的 DynamoDB 产生了兴趣,并学习了相关知识。 然后就发生下面这样的事: 用DynamoDB替换了MySQL。 很快发现DynamoDB并不能很好的支持事务特性,在当时只有一个性能极差的客户端类库来支持事物,由于采用客户端方式,引入了大量的额外交互,导致性能差别达7倍之多。这时候,这个同学就采用了当时在NoSQL领域广泛流行的最终一致技术,通过一个Pub-Sub消息队列来实现最终一致(即当某对象的值发生改变后会产生一个事件,然后关注这一改变的逻辑,就会订阅这个通知,并改变于其相关数据,从而实现不同数据的最终一致)。 接着由于DynamoDB无法提供SQL那样方便的查询机制,为了实现数据分析就又引入了EMR/MapReduceJob。 到此,大家可以看到实现一样的功能,但是复杂性大大增加,维护工作也由一个人变成了一个团队。 过度忙碌使你落后 对于 IT 人而言忙碌已成为了习惯,加班常挂在嘴边。“996”工作制似乎也变成了公司高效的标志。而事实上过度的忙碌使你落后。经常遇见一些朋友,在一个公司没日没夜的干了几年,没有留一点学习时间给自己。几年之后倒是对公司越来越“忠诚”了,但忙碌的工作同时也导致了没有时间更新知识,使得自己已经落后了,连跳槽的能力和勇气都失去了。 过度忙碌会导致没有时间学习和更新自己的知识,尤其在这个高速发展的时代。我在工作经历中发现过度繁忙通常会带来以下问题: 缺乏学习导致工作能力没有提升,而面对的问题却变得日益复杂。 技术和业务上没有更大的领先优势,只能被动紧紧追赶。试想一下,要是你都领先同行业五年了,还会在乎通过加班来早一个月发布吗? 反过来上面这些问题会导致你更加繁忙,进而更没有时间提高自己的技术技能,很快就形成了一个恶性循环。 练过健身的朋友都知道,光靠锻炼是不行的,营养补充和锻炼同样重要。个人技术成长其实也一样,实践和学习是一样重要的,当你在一个领域工作了一段时间以后,工作对你而言就主要是实践了,随着你对该领域的熟悉,能学习的到技术会越来越少。所以每个技术人员都要保证充足的学习时间,否则很容易成为井底之蛙,从而陷入前面提到的恶性循环。 最后,以伟大诗人屈原的诗句和大家共勉:“路漫漫其修远兮,吾将上下而求索“。希望我们大家都可以不忘初心,保持匠心! 作者简介: 蔡超,Mobvista 技术 VP 兼首席架构师,SpotMax 云服务创始人。拥有超过 15 年的软件开发经验,其中 9 年任世界级 IT 公司软件架构师/首席软件架构师。2017 年加入 Mobvista,任公司技术副总裁及首席架构师,领导公司的数字移动营销平台的开发,该平台完全建立于云计算技术之上,每天处理来自全球不同 region 的超过 600 亿次的请求。 在加入 Mobvista 之前,曾任亚马逊全球直运平台首席架构师,亚马逊(中国)首席架构师,曾领导了亚马逊的全球直运平台的开发,并领导中国团队通过 AI 及云计算技术为中国客户打造更好的本地体验;曾任 HP(中国)移动设备管理系统首席软件架构师,该系统曾是全球最大的无线设备管理系统(OMA DM)(客户包括中国移动,中国联通,中国电信等);曾任北京天融信网络安全技术公司,首席软件架构师,领导开发的网络安全管理系统(TopAnalyzer)至今仍被政府重要部门及军队广为采用,该系统也曾成功应用于 2008 北京奥运,2010 上海世博等重要事件的网络安全防护。 本篇文章为转载内容。原文链接:https://blog.csdn.net/Honnyee/article/details/111896981。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-09-19 14:55:26
78
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 目录 1. 作者介绍 2. 算法介绍 2.1 阿里云介绍 2.2 证件照生成背景 2.3 图像分割算法 3.调用阿里云API进行证件照生成实例 3.1 准备工作 3.2 实验代码 3.3 实验结果与分析 参考(可供参考的链接和引用文献) 1. 作者介绍 王逸腾,男,西安工程大学电子信息学院,2022级硕士研究生 研究方向:三维手部姿态和网格估计 电子邮件:2978558373@qq.com 路治东,男,西安工程大学电子信息学院,2022级研究生,张宏伟人工智能课题组 研究方向:机器视觉与人工智能 电子邮件:2063079527@qq.com 2. 算法介绍 2.1 阿里云介绍 阿里云创立于2009年,是全球领先的云计算及人工智能科技公司,致力于以在线公共服务的方式,提供安全、可靠的计算和数据处理能力,让计算和人工智能成为普惠科技。阿里云服务着制造、金融、政务、交通、医疗、电信、能源等众多领域的领军企业,包括中国联通、12306、中石化、中石油、飞利浦、华大基因等大型企业客户,以及微博、知乎、锤子科技等明星互联网公司。在天猫双11全球狂欢节、12306春运购票等极富挑战的应用场景中,阿里云保持着良好的运行纪录 阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本 猿辅导、中泰证券、小米、媛福达、Soul和当贝,这些我们耳熟能详的APP或企业中,阿里云给他们提供了性能强大、安全、稳定的云产品与服务。 计算,容器,存储,网络与CDN,安全、中间件、数据库、大数据计算、人工智能与机器学习、媒体服务、企业服务与云通信、物联网、开发工具、迁移与运维管理和专有云等方面,阿里云都做的很不错。 2.2 证件照生成背景 传统做法:通常是人工进行P图,不仅费时费力,而且效果也很难保障,容易有瑕疵。 机器学习做法:通常利用边缘检测算法进行人物轮廓提取。 深度学习做法:通常使用分割算法进行人物分割。例如U-Net网络。 2.3 图像分割算法 《BiHand: Recovering Hand Mesh with Multi-stage Bisected Hourglass Networks》里的SeedNet网络是很经典的网络,它把分割任务转变成多个任务。作者的思想是:尽可能的通过多任务学习收拢语义,这样或许会分割的更好或姿态估计的更好。其实这个模型就是多阶段学习网络的一部分,作者想通过中间监督来提高网络的性能。 我提取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
131
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 前言 今年因为这个疫情,感觉这是从工作以来过的最久的一个年了,在家呆的时间不是一般的久,算一算有好几个月呢!我大概是3月底快4月了才出门,投了超多的简历,天天面试面试面试面试面试面试面试…庆幸的是还是上岸了(嘻嘻开心开心)。但其实所谓的庆幸也是靠努力堆起来的,我记忆力还比较好,背一背,没啥难的,背了1000道题。。。(注:关于我背的这1000题,文末有分享) 眼看着6月就过去了,再过两天就7月份了,想着面试大军可能也过不了几天就要来了,所以这两天整理了一些面经,今天给大家看的是“美团+字节跳动+腾讯”这三家的,每家一二三面,我想大家可以自己测试一下能坚持到哪里。 01 阿里中间件(四面,Java岗) 1.1 Java中间件一面 技术一面考察范围 重点问了Java线程锁:synchronized 和ReentrantLock相关的底层实现 线程池的底层实现以及常见的参数 数据结构基本都问了一遍:链表、队列等 Java内存模型:常问的JVM分代模型,以及JDK1.8后的区别,最后还问了JVM相关的调优参数 分布式锁的实现比较技术 一面题目 自我介绍 擅长哪方面的技术? java有哪些锁中类?(乐观锁&悲观锁、可重入锁&Synchronize等)。 比较重要的数据结构,如链表,队列,栈的基本原理及大致实现 J.U.C下的常见类的使用。Threadpool的深入考察;blockingQueue的使用 Java内存分代模型,GC算法,JVM常见的启动参数;CMS算法的过程。 Volatile关键字有什么用(包括底层原理) 线程池的调优策略 Spring cloud的服务注册与发现是怎么设计的? 分布式系统的全局id如何实现 分布式锁的方案,redis和zookeeper那个好,如果是集群部署,高并发情况下那个性能更好。 1.2 Java中间件二面 技术二面考察范围: 问了项目相关的技术实现细节 数据库相关:索引、索引底层实现、mysql相关的行锁、表锁等 redis相关:架构设计、数据一致性问题 容器:容器的设计原理等技术 二面题目: 参与的项目,选一个,技术难度在哪里? Collections.sort底层排序方式 负载均衡的原理设计模式与重构,谈谈你对重构的理解 谈谈redis相关的集群有哪些成熟方案? 再谈谈一致hash算法(redis)? 数据库索引,B+树的特性和建树过程 Mysql相关的行锁,表锁;乐观锁,悲观锁 谈谈多线程和并发工具的使用 谈谈redis的架构和组件 Redis的数据一致性问题(分布式多节点环境&单机环境) Docker容器 1.3 Java中间件三面 技术三面考察范围: 主要谈到了高并发的实现方案 以及中间件:redis、rocketmq、kafka等的架构设计思路 最后问了平时怎么提升技术的技术 三面题目 高并发情况下,系统是如何支撑大量的请求的? 接着上面的问题,延伸到了中间件,kafka、redis、rocketmq、mycat等设计思路和适用场景等 最近上过哪些技术网站;最近再看那些书。 工作和生活中遇见最大的挑战,怎么去克服? 未来有怎样的打算 1.4 Java中间件四面 最后,你懂的,主要就是HR走流程了,主要问了未来的职业规划。 02 头条Java后台3面 2.1 头条一面 讲讲jvm运行时数据库区 讲讲你知道的垃圾回收算法 jvm内存模型jmm 内存泄漏与内存溢出的区别 select、epool 的区别?底层的数据结构是什么? mysql数据库默认存储引擎,有什么优点 优化数据库的方法,从sql到缓存到cpu到操作系统,知道多少说多少 什么情景下做分表,什么情景下做分库 linkedList与arrayList区别 适用场景 array list是如何扩容的 volatile 关键字的作用?Java 内存模型? java lock的实现,公平锁、非公平锁 悲观锁和乐观锁,应用中的案例,mysql当中怎么实现,java中的实现 2.2 头条二面 Java 内存分配策略? 多个线程同时请求内存,如何分配? Redis 底层用到了哪些数据结构? 使用 Redis 的 set 来做过什么? Redis 使用过程中遇到什么问题? 搭建过 Redis 集群吗? 如何分析“慢查询”日志进行 SQL/索引 优化? MySQL 索引结构解释一下?(B+ 树) MySQL Hash 索引适用情况?举下例子? 2.3 头条三面 如何保证数据库与redis缓存一致的Redis 的并发竞争问题是什么? 如何解决这个问题? 了解 Redis 事务的 CAS 方案吗? 如何保证 Redis 高并发、高可用? Redis 的主从复制原理,以及Redis 的哨兵原理? 如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。 MySQL数据库主从同步怎么实现? 秒杀模块怎么设计的,如何压测,抗压手段 03 今日头条Java后台研发三面 3.1 一面 concurrent包下面用过哪些? countdownlatch功能实现 synchronized和lock区别,重入锁thread和runnable的区别 AtomicInteger实现原理(CAS自旋) java并发sleep与wait、notify与notifyAll的区别 如何实现高效的同步链表 java都有哪些加锁方式(synchronized、ReentrantLock、共享锁、读写锁等) 设计模式(工厂模式、单例模式(几种情况)、适配器模式、装饰者模式) maven依赖树,maven的依赖传递,循环依赖 3.2 二面 synchronized和reentrantLock的区别,synchronized用在代码快、方法、静态方法时锁的都是什么? 介绍spring的IOC和AOP,分别如何实现(classloader、动态代理)JVM的内存布局以及垃圾回收原理及过程 讲一下,讲一下CMS垃圾收集器垃圾回收的流程,以及CMS的缺点 redis如何处理分布式服务器并发造成的不一致OSGi的机制spring中bean加载机制,bean生成的具体步骤,ioc注入的方式spring何时创建- applicationContextlistener是监听哪个事件? 介绍ConcurrentHashMap原理,用的是哪种锁,segment有没可能增大? 解释mysql索引、b树,为啥不用平衡二叉树、红黑树 Zookeeper如何同步配置 3.3 三面 Java线程池ThreadPoolEcecutor参数,基本参数,使用场景 MySQL的ACID讲一下,延伸到隔离级别 dubbo的实现原理,说说RPC的要点 GC停顿原因,如何降低停顿? JVM如何调优、参数怎么调? 如何用工具分析jvm状态(visualVM看堆中对象的分配,对象间的引用、是否有内存泄漏,jstack看线程状态、是否死锁等等) 描述一致性hash算法 分布式雪崩场景如何避免? 再谈谈消息队列 04 抖音Java 三面 4.1 一面: hashmap,怎么扩容,怎么处理数据冲突? 怎么高效率的实现数据迁移? Linux的共享内存如何实现,大概说了一下。 socket网络编程,说一下TCP的三次握手和四次挥手同步IO和异步IO的区别? Java GC机制?GC Roots有哪些? 红黑树讲一下,五个特性,插入删除操作,时间复杂度? 快排的时间复杂度,最坏情况呢,最好情况呢,堆排序的时间复杂度呢,建堆的复杂度是多少 4.2 二面: 自我介绍,主要讲讲做了什么和擅长什么 设计模式了解哪些? AtomicInteger怎么实现原子修改的? ConcurrentHashMap 在Java7和Java8中的区别? 为什么Java8并发效率更好?什么情况下用HashMap,什么情况用ConcurrentHashMap? redis数据结构? redis数据淘汰机制? 4.3 三面(约五十分钟): mysql实现事务的原理(MVCC) MySQL数据主从同步是如何实现的? MySQL索引的实现,innodb的索引,b+树索引是怎么实现的,为什么用b+树做索引节点,一个节点存了多少数据,怎么规定大小,与磁盘页对应。 如果Redis有1亿个key,使用keys命令是否会影响线上服务? Redis的持久化方式,aod和rdb,具体怎么实现,追加日志和备份文件,底层实现原理的话知道么? 遇到最大困难是什么?怎么克服? 未来的规划是什么? 你想问我什么? 05 百度三面 5.1 百度一面 自我介绍 Java中的多态 为什么要同时重写hashcode和equals Hashmap的原理 Hashmap如何变线程安全,每种方式的优缺点 垃圾回收机制 Jvm的参数你知道的说一下 设计模式了解的说一下啊 手撕一个单例模式 手撕算法:反转单链表 手撕算法:实现类似微博子结构的数据结构,输入一系列父子关系,输出一个类似微博评论的父子结构图 手写java多线程 手写java的soeket编程,服务端和客户端 手撕算法: 爬楼梯,写出状态转移方程 智力题:时针分针什么时候重合 5.2 百度二面(现场) 自我介绍 项目介绍 服务器如何负载均衡,有哪些算法,哪个比较好,一致性哈希原理,怎么避免DDOS攻击请求打到少数机器。 TCP连接中的三次握手和四次挥手,四次挥手的最后一个ack的作用是什么,为什么要time wait,为什么是2msl。 数据库的备份和恢复怎么实现的,主从复制怎么做的,什么时候会出现数据不一致,如何解决。 Linux查看cpu占用率高的进程 手撕算法:给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。 然后继续在这个问题上扩展 求出最短那条的路径 递归求出所有的路径 设计模式讲一下熟悉的 会不会滥用设计模式 多线程条件变量为什么要在while体里 你遇到什么挫折,怎么应对和处理 5.3 百度三面(现场) 自我介绍 项目介绍 Redis的特点 Redis的持久化怎么做,aof和rdb,有什么区别,有什么优缺点。 Redis使用哨兵部署会有什么问题,我说需要扩容的话还是得集群部署。 说一下JVM内存模型把,有哪些区,分别干什么的 说一下gc算法,分代回收说下 MySQL的引擎讲一下,有什么区别,使用场景呢 分布式事务了解么 反爬虫的机制,有哪些方式 06 蚂蚁中间件团队面试题 6.1 蚂蚁中间件一面: 自我介绍 JVM垃圾回收算法和垃圾回收器有哪些,最新的JDK采用什么算法。 新生代和老年代的回收机制。 讲一下ArrayList和linkedlist的区别,ArrayList与HashMap的扩容方式。 Concurrenthashmap1.8后的改动。 Java中的多线程,以及线程池的增长策略和拒绝策略了解么。 Tomcat的类加载器了解么 Spring的ioc和aop,Springmvc的基本架构,请求流程。 HTTP协议与Tcp有什么区别,http1.0和2.0的区别。 Java的网络编程,讲讲NIO的实现方式,与BIO的区别,以及介绍常用的NIO框架。 索引什么时候会失效变成全表扫描 介绍下分布式的paxos和raft算法 6.2 蚂蚁中间件二面 你在项目中怎么用到并发的。 消息队列的使用场景,谈谈Kafka。 你说了解分布式服务,那么你怎么理解分布式服务。 Dubbo和Spring Clound的区别,以及使用场景。 讲一下docker的实现原理,以及与JVM的区别。 MongoDB、Redis和Memcached的应用场景,各自优势 MongoDB有事务吗 Redis说一下sorted set底层原理 讲讲Netty为什么并发高,相关的核心组件有哪些 6.3 蚂蚁中间件三面 完整的画一个分布式集群部署图,从负载均衡到后端数据库集群。 分布式锁的方案,Redis和Zookeeper哪个好,如果是集群部署,高并发情况下哪个性能更好。 分布式系统的全局id如何实现。 数据库万级变成亿级,你如何来解决。 常见的服务器雪崩是由什么引起的,如何来防范。 异地容灾怎么实现 常用的高并发技术解决方案有哪些,以及对应的解决步骤。 07 京东4面(Java研发) 7.1 一面(基础面:约1小时) 自我介绍,主要讲讲做了什么和擅长什么 springmvc和spring-boot区别 @Autowired的实现原理 Bean的默认作用范围是什么?其他的作用范围? 索引是什么概念有什么作用?MySQL里主要有哪些索引结构?哈希索引和B+树索引比较? Java线程池的原理?线程池有哪些?线程池工厂有哪些线程池类型,及其线程池参数是什么? hashmap原理,处理哈希冲突用的哪种方法? 还知道什么处理哈希冲突的方法? Java GC机制?GC Roots有哪些? Java怎么进行垃圾回收的?什么对象会进老年代?垃圾回收算法有哪些?为什么新生代使用复制算法? HashMap的时间复杂度?HashMap中Hash冲突是怎么解决的?链表的上一级结构是什么?Java8中的HashMap有什么变化?红黑树需要比较大小才能进行插入,是依据什么进行比较的?其他Hash冲突解决方式? hash和B+树的区别?分别应用于什么场景?哪个比较好? 项目里有个数据安全的,aes和md5的区别?详细点 7.2 二面(问数据库较多) 自我介绍 为什么MyISAM查询性能好? 事务特性(acid) 隔离级别 SQL慢查询的常见优化步骤? 说下乐观锁,悲观锁(select for update),并写出sql实现 TCP协议的三次握手和四次挥手过程? 用到过哪些rpc框架 数据库连接池怎么实现 Java web过滤器的生命周期 7.3 三面(综合面;约一个小时) 自我介绍。 ConcurrentHashMap 在Java7和Java8中的区别?为什么Java8并发效率更好?什么情况下用HashMap,什么情况用ConcurrentHashMap? 加锁有什么机制? ThreadLocal?应用场景? 数据库水平切分,垂直切分的设计思路和切分顺序 Redis如何解决key冲突 soa和微服务的区别? 单机系统演变为分布式系统,会涉及到哪些技术的调整?请从前面负载到后端详细描述。 设计一个秒杀系统? 7.4 四面(HR面) 你自己最大优势和劣势是什么 平时遇见过什么样的挑战,怎么去克服的 工作中遇见了技术解决不了的问题,你的应对思路? 你的兴趣爱好? 未来的职业规划是什么? 08 美团java高级开发3面 8.1 美团一面 自我介绍 项目介绍 Redis介绍 了解redis源码么 了解redis集群么 Hashmap的原理,增删的情况后端数据结构如何位移 hashmap容量为什么是2的幂次 hashset的源码 object类你知道的方法 hashcode和equals 你重写过hashcode和equals么,要注意什么 假设现在一个学生类,有学号和姓名,我现在hashcode方法重写的时候,只将学号参与计算,会出现什么情况? 往set里面put一个学生对象,然后将这个学生对象的学号改了,再put进去,可以放进set么?并讲出为什么 Redis的持久化?有哪些方式,原理是什么? 讲一下稳定的排序算法和不稳定的排序算法 讲一下快速排序的思想 8.2 美团二面 自我介绍 讲一下数据的acid 什么是一致性 什么是隔离性 Mysql的隔离级别 每个隔离级别是如何解决 Mysql要加上nextkey锁,语句该怎么写 Java的内存模型,垃圾回收 线程池的参数 每个参数解释一遍 然后面试官设置了每个参数,给了是个线程,让描述出完整的线程池执行的流程 Nio和IO有什么区别 Nio和aio的区别 Spring的aop怎么实现 Spring的aop有哪些实现方式 动态代理的实现方式和区别 Linux了解么 怎么查看系统负载 Cpu load的参数如果为4,描述一下现在系统处于什么情况 Linux,查找磁盘上最大的文件的命令 Linux,如何查看系统日志文件 手撕算法:leeetcode原题 22,Generate Parentheses,给定 n 对括号,请- 写一个函数以将其生成新的括号组合,并返回所有组合结果。 8.3 美团三面(现场) 三面没怎么问技术,问了很多技术管理方面的问题 自我介绍 项目介绍 怎么管理项目成员 当意见不一致时,如何沟通并说服开发成员,并举个例子 怎么保证项目的进度 数据库的索引原理 非聚簇索引和聚簇索引 索引的使用注意事项 联合索引 从底层解释最左匹配原则 Mysql对联合索引有优化么?会自动调整顺序么?哪个版本开始优化? Redis的应用 Redis的持久化的方式和原理 技术选型,一个新技术和一个稳定的旧技术,你会怎么选择,选择的考虑有哪些 说你印象最深的美团点评技术团队的三篇博客 最近在学什么新技术 你是怎么去接触一门新技术的 会看哪些书 怎么选择要看的书 最后 由于篇幅限制,小编在此截出几张知识讲解的图解,有需要的程序猿(媛)可以点赞后戳这里免费领取全部资料获取哦 子 怎么保证项目的进度 数据库的索引原理 非聚簇索引和聚簇索引 索引的使用注意事项 联合索引 从底层解释最左匹配原则 Mysql对联合索引有优化么?会自动调整顺序么?哪个版本开始优化? Redis的应用 Redis的持久化的方式和原理 技术选型,一个新技术和一个稳定的旧技术,你会怎么选择,选择的考虑有哪些 说你印象最深的美团点评技术团队的三篇博客 最近在学什么新技术 你是怎么去接触一门新技术的 会看哪些书 怎么选择要看的书 最后 由于篇幅限制,小编在此截出几张知识讲解的图解,有需要的程序猿(媛)可以点赞后戳这里免费领取全部资料获取哦 [外链图片转存中…(img-SFREePIJ-1624074891834)] [外链图片转存中…(img-5kF3pkiC-1624074891834)] [外链图片转存中…(img-HDVXfOMR-1624074891835)] [外链图片转存中…(img-RyaAC5jy-1624074891836)] [外链图片转存中…(img-iV32C5Ok-1624074891837)] 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_57285325/article/details/118051767。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-11-13 23:43:59
85
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 1、分布式事务出现场景 场景描述:支付宝转账余额宝 分布式事务必须满足的条件: 1、远程RPC调用,支付宝和余额宝存在接口调用 2、支付宝和余额宝使用不同的数据库 如图: 2、分布式事务解决方案 1、基于数据库XA协议的两段提交 XA协议是数据库支持的一种协议,其核心是一个事务管理器用来统一管理两个分布式数据库,如图 事务管理器负责跟支付宝数据库和余额宝数据库打交道,一旦有一个数据库连接失败,另一个数据库的操作就不会进行,一个数据库操作失败就会导致另一个数据库回滚,只有他们全部成功两个数据库的事务才会提交。 基于XA协议的两段和三段提交是一种严格的安全确认机制,其安全性是非常高的,但是保证安全性的前提是牺牲了性能,这个就是分布式系统里面的CAP理论,做任何架构的前提需要有取舍。所以基于XA协议的分布式事务并发性不高,不适合高并发场景。 2、基于activemq的解决方案 如图: 1、支付宝扣款成功时往message表插入消息 2、message表有message_id(流水id,标识夸系统的一次转账操作),status(confirm,unconfirm) 3、timer扫描message表的unconfirm状态记录往activemq插入消息 4、余额宝收到消息消费消息时先查询message表如果有记录就不处理如果没记录就进行数据库增款操作 5、如果余额宝数据库操作成功往余额宝message表插入消息,表字段跟支付宝message一致 6、如果5操作成功,回调支付宝接口修改message表状态,把unconfirm状态转换成confirm状态 问题描述: 1、支付宝设计message表的目的 如果支付宝往activemq插入消息而余额宝消费消息异常,有可能是消费消息成功而事务操作异常,有可能是网络异常等等不确定因素。如果出现异常而activemq收到了确认消息的信号,这时候activemq中的消息是删除了的,消息丢失了。设置message表就是有一个消息存根,activemq中消息丢失了message表中的消息还在。解决了activemq消息丢失问题 2、余额宝设计message表的目的 当余额宝消费成功并且数据库操作成功时,回调支付宝的消息确认接口,如果回调接口时出现异常导致支付宝状态修改失败还是unconfirm状态,这时候还会被timer扫描到,又会往activemq插入消息,又会被余额宝消费一边,但是这条消息已经消费成功了的只是回调失败而已,所以就需要有一个这样的message表,当余额宝消费时先插入message表,如果message根据message_id能查询到记录就说明之前这条消息被消费过就不再消费只需要回调成功即可,如果查询不到消息就消费这条消息继续数据库操作,数据库操作成功就往message表插入消息。 这样就解决了消息重复消费问题,这也是消费端的幂等操作。 基于消息中间件的分布式事务是最理想的分布式事务解决方案,兼顾了安全性和并发性! 接下来贴代码: 支付宝代码: @Controller@RequestMapping("/order")public class OrderController {/ @Description TODO @param @return 参数 @return String 返回类型 @throws userID:转账的用户ID amount:转多少钱/@Autowired@Qualifier("activemq")OrderService orderService;@RequestMapping("/transfer")public @ResponseBody String transferAmount(String userId,String messageId, int amount) {try {orderService.updateAmount(amount,messageId, userId);}catch (Exception e) {e.printStackTrace();return "===============================transferAmount failed===================";}return "===============================transferAmount successfull===================";}@RequestMapping("/callback")public String callback(String param) {JSONObject parse = JSONObject.parseObject(param);String respCode = parse.getString("respCode");if(!"OK".equalsIgnoreCase(respCode)) {return null;}try {orderService.updateMessage(param);}catch (Exception e) {e.printStackTrace();return "fail";}return "ok";} } public interface OrderService {public void updateAmount(int amount, String userId,String messageId);public void updateMessage(String param);} @Service("activemq")@Transactional(rollbackFor = Exception.class)public class OrderServiceActivemqImpl implements OrderService {Logger logger = LoggerFactory.getLogger(getClass());@AutowiredJdbcTemplate jdbcTemplate;@AutowiredJmsTemplate jmsTemplate;@Overridepublic void updateAmount(final int amount, final String messageId, final String userId) {String sql = "update account set amount = amount - ?,update_time=now() where user_id = ?";int count = jdbcTemplate.update(sql, new Object[]{amount, userId});if (count == 1) {//插入到消息记录表sql = "insert into message(user_id,message_id,amount,status) values (?,?,?,?)";int row = jdbcTemplate.update(sql,new Object[]{userId,messageId,amount,"unconfirm"});if(row == 1) {//往activemq中插入消息jmsTemplate.send("zg.jack.queue", new MessageCreator() {@Overridepublic Message createMessage(Session session) throws JMSException {com.zhuguang.jack.bean.Message message = new com.zhuguang.jack.bean.Message();message.setAmount(Integer.valueOf(amount));message.setStatus("unconfirm");message.setUserId(userId);message.setMessageId(messageId);return session.createObjectMessage(message);} });} }}@Overridepublic void updateMessage(String param) {JSONObject parse = JSONObject.parseObject(param);String messageId = parse.getString("messageId");String sql = "update message set status = ? where message_id = ?";int count = jdbcTemplate.update(sql,new Object[]{"confirm",messageId});if(count == 1) {logger.info(messageId + " callback successfull");} }} activemq.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:amq="http://activemq.apache.org/schema/core"xmlns:jms="http://www.springframework.org/schema/jms"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-4.1.xsdhttp://www.springframework.org/schema/jmshttp://www.springframework.org/schema/jms/spring-jms-4.1.xsdhttp://activemq.apache.org/schema/corehttp://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"><context:component-scan base-package="com.zhuguang.jack" /><mvc:annotation-driven /><amq:connectionFactory id="amqConnectionFactory"brokerURL="tcp://192.168.88.131:61616"userName="system"password="manager" /><!-- 配置JMS连接工长 --><bean id="connectionFactory"class="org.springframework.jms.connection.CachingConnectionFactory"><constructor-arg ref="amqConnectionFactory" /><property name="sessionCacheSize" value="100" /></bean><!-- 定义消息队列(Queue) --><bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue"><!-- 设置消息队列的名字 --><constructor-arg><value>zg.jack.queue</value></constructor-arg></bean><!-- 配置JMS模板(Queue),Spring提供的JMS工具类,它发送、接收消息。 --><bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"><property name="connectionFactory" ref="connectionFactory" /><property name="defaultDestination" ref="demoQueueDestination" /><property name="receiveTimeout" value="10000" /><!-- true是topic,false是queue,默认是false,此处显示写出false --><property name="pubSubDomain" value="false" /></bean></beans> spring-dispatcher.xml <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-3.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.2.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><!-- 引入同文件夹下的redis属性配置文件 --><!-- 解决springMVC响应数据乱码 text/plain就是响应的时候原样返回数据--><import resource="../activemq/activemq.xml"/><!--<context:property-placeholder ignore-unresolvable="true" location="classpath:config/core/core.properties,classpath:config/redis/redis-config.properties" />--><bean id="propertyConfigurerForProject1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="order" value="1" /><property name="ignoreUnresolvablePlaceholders" value="true" /><property name="location"><value>classpath:config/core/core.properties</value></property></bean><mvc:annotation-driven><mvc:message-converters register-defaults="true"><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" /></bean></mvc:message-converters></mvc:annotation-driven><!-- 避免IE执行AJAX时,返回JSON出现下载文件 --><bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value></list></property></bean><!-- 开启controller注解支持 --><!-- 注:如果base-package=com.avicit 则注解事务不起作用 TODO 读源码 --><context:component-scan base-package="com.zhuguang"></context:component-scan><mvc:view-controller path="/" view-name="redirect:/index" /><beanclass="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /><bean id="handlerAdapter"class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean><beanclass="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><property name="mediaTypes"><map><entry key="json" value="application/json" /><entry key="xml" value="application/xml" /><entry key="html" value="text/html" /></map></property><property name="viewResolvers"><list><bean class="org.springframework.web.servlet.view.BeanNameViewResolver" /><bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /><property name="prefix" value="/" /><property name="suffix" value=".jsp" /></bean></list></property></bean><!-- 支持上传文件 --> <!-- 控制器异常处理 --><bean id="exceptionResolver"class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="exceptionMappings"><props><prop key="java.lang.Exception">error</prop></props></property></bean><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><property name="driverClass"><value>${jdbc.driverClassName}</value></property><property name="jdbcUrl"><value>${jdbc.url}</value></property><property name="user"><value>${jdbc.username}</value></property><property name="password"><value>${jdbc.password}</value></property><property name="minPoolSize" value="10" /><property name="maxPoolSize" value="100" /><property name="maxIdleTime" value="1800" /><property name="acquireIncrement" value="3" /><property name="maxStatements" value="1000" /><property name="initialPoolSize" value="10" /><property name="idleConnectionTestPeriod" value="60" /><property name="acquireRetryAttempts" value="30" /><property name="breakAfterAcquireFailure" value="false" /><property name="testConnectionOnCheckout" value="false" /><property name="acquireRetryDelay"><value>100</value></property></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /><aop:aspectj-autoproxy expose-proxy="true"/></beans> logback.xml <?xml version="1.0" encoding="UTF-8"?><!--scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。--><configuration scan="false" scanPeriod="60 seconds" debug="false"><!-- 定义日志的根目录 --><!-- <property name="LOG_HOME" value="/app/log" /> --><!-- 定义日志文件名称 --><property name="appName" value="netty"></property><!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><Encoding>UTF-8</Encoding><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度%logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符--><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><Encoding>UTF-8</Encoding><!-- 指定日志文件的名称 --> <file>${appName}.log</file><!--当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动--><fileNamePattern>${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern><!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。--><MaxHistory>365</MaxHistory><!-- 当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy--><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符--> <encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern></encoder></appender><!-- logger主要用于存放日志对象,也可以定义日志类型、级别name:表示匹配的logger类型前缀,也就是包的前半部分level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERRORadditivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,false:表示只用当前logger的appender-ref,true:表示当前logger的appender-ref和rootLogger的appender-ref都有效--><!-- <logger name="edu.hyh" level="info" additivity="true"><appender-ref ref="appLogAppender" /></logger> --><!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 --><root level="debug"><appender-ref ref="stdout" /><appender-ref ref="appLogAppender" /></root></configuration> 2、余额宝代码 package com.zhuguang.jack.controller;import com.alibaba.fastjson.JSONObject;import com.zhuguang.jack.service.OrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controller@RequestMapping("/order")public class OrderController {/ @Description TODO @param @return 参数 @return String 返回类型 @throws 模拟银行转账 userID:转账的用户ID amount:转多少钱/@AutowiredOrderService orderService;@RequestMapping("/transfer")public @ResponseBody String transferAmount(String userId, String amount) {try {orderService.updateAmount(Integer.valueOf(amount), userId);}catch (Exception e) {e.printStackTrace();return "===============================transferAmount failed===================";}return "===============================transferAmount successfull===================";} } 消息监听器 package com.zhuguang.jack.listener;import com.alibaba.fastjson.JSONObject;import com.zhuguang.jack.service.OrderService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.client.SimpleClientHttpRequestFactory;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import org.springframework.web.client.RestTemplate;import javax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageListener;import javax.jms.ObjectMessage;@Service("queueMessageListener")public class QueueMessageListener implements MessageListener {private Logger logger = LoggerFactory.getLogger(getClass());@AutowiredOrderService orderService;@Transactional(rollbackFor = Exception.class)@Overridepublic void onMessage(Message message) {if (message instanceof ObjectMessage) {ObjectMessage objectMessage = (ObjectMessage) message;try {com.zhuguang.jack.bean.Message message1 = (com.zhuguang.jack.bean.Message) objectMessage.getObject();String userId = message1.getUserId();int count = orderService.queryMessageCountByUserId(userId);if (count == 0) {orderService.updateAmount(message1.getAmount(), message1.getUserId());orderService.insertMessage(message1.getUserId(), message1.getMessageId(), message1.getAmount(), "ok");} else {logger.info("异常转账");}RestTemplate restTemplate = createRestTemplate();JSONObject jo = new JSONObject();jo.put("messageId", message1.getMessageId());jo.put("respCode", "OK");String url = "http://jack.bank_a.com:8080/alipay/order/callback?param="+ jo.toJSONString();restTemplate.getForObject(url,null);} catch (JMSException e) {e.printStackTrace();throw new RuntimeException("异常");} }}public RestTemplate createRestTemplate() {SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();simpleClientHttpRequestFactory.setConnectTimeout(3000);simpleClientHttpRequestFactory.setReadTimeout(2000);return new RestTemplate(simpleClientHttpRequestFactory);} } package com.zhuguang.jack.service;public interface OrderService {public void updateAmount(int amount, String userId);public int queryMessageCountByUserId(String userId);public int insertMessage(String userId,String messageId,int amount,String status);} package com.zhuguang.jack.service;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.client.SimpleClientHttpRequestFactory;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import org.springframework.web.client.RestTemplate;@Service@Transactional(rollbackFor = Exception.class)public class OrderServiceImpl implements OrderService {private Logger logger = LoggerFactory.getLogger(getClass());@AutowiredJdbcTemplate jdbcTemplate;/ 更新数据库表,把账户余额减去amountd/@Overridepublic void updateAmount(int amount, String userId) {//1、农业银行转账3000,也就说农业银行jack账户要减3000String sql = "update account set amount = amount + ?,update_time=now() where user_id = ?";int count = jdbcTemplate.update(sql, new Object[] {amount, userId});if (count != 1) {throw new RuntimeException("订单创建失败,农业银行转账失败!");} }public RestTemplate createRestTemplate() {SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();simpleClientHttpRequestFactory.setConnectTimeout(3000);simpleClientHttpRequestFactory.setReadTimeout(2000);return new RestTemplate(simpleClientHttpRequestFactory);}@Overridepublic int queryMessageCountByUserId(String messageId) {String sql = "select count() from message where message_id = ?";int count = jdbcTemplate.queryForInt(sql, new Object[]{messageId});return count;}@Overridepublic int insertMessage(String userId, String message_id,int amount, String status) {String sql = "insert into message(user_id,message_id,amount,status) values(?,?,?)";int count = jdbcTemplate.update(sql, new Object[]{userId, message_id,amount, status});if(count == 1) {logger.info("Ok");}return count;} } activemq.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:amq="http://activemq.apache.org/schema/core"xmlns:jms="http://www.springframework.org/schema/jms"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-4.1.xsdhttp://www.springframework.org/schema/jmshttp://www.springframework.org/schema/jms/spring-jms-4.1.xsdhttp://activemq.apache.org/schema/corehttp://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"><context:component-scan base-package="com.zhuguang.jack" /><mvc:annotation-driven /><amq:connectionFactory id="amqConnectionFactory"brokerURL="tcp://192.168.88.131:61616"userName="system"password="manager" /><!-- 配置JMS连接工长 --><bean id="connectionFactory"class="org.springframework.jms.connection.CachingConnectionFactory"><constructor-arg ref="amqConnectionFactory" /><property name="sessionCacheSize" value="100" /></bean><!-- 定义消息队列(Queue) --><bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue"><!-- 设置消息队列的名字 --><constructor-arg><value>zg.jack.queue</value></constructor-arg></bean><!-- 显示注入消息监听容器(Queue),配置连接工厂,监听的目标是demoQueueDestination,监听器是上面定义的监听器 --><bean id="queueListenerContainer"class="org.springframework.jms.listener.DefaultMessageListenerContainer"><property name="connectionFactory" ref="connectionFactory" /><property name="destination" ref="demoQueueDestination" /><property name="messageListener" ref="queueMessageListener" /></bean><!-- 配置JMS模板(Queue),Spring提供的JMS工具类,它发送、接收消息。 --><bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"><property name="connectionFactory" ref="connectionFactory" /><property name="defaultDestination" ref="demoQueueDestination" /><property name="receiveTimeout" value="10000" /><!-- true是topic,false是queue,默认是false,此处显示写出false --><property name="pubSubDomain" value="false" /></bean></beans> OK~~~~~~~~~~~~大功告成!!!, 如果大家觉得满意并且对技术感兴趣请加群:171239762, 纯技术交流群,非诚勿扰。 本篇文章为转载内容。原文链接:https://blog.csdn.net/luoyang_java/article/details/84953241。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-16 22:34:52
499
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 From: 再三考虑,决定把今天的面试总结一下,算是对自己的总结,如果能顺便给正在找工作的朋友有所帮助,那就不能再好了。 ps: 今天面试真的好累, 昨晚没睡好,今天早上起床 也没有吃早饭,饿着肚子跑去面试的。话痨了、、 今天面试了两家公司,早上出门前,感觉两家稳稳地可以拿下,but结果并不如人意。。 面试公司:健德门 附近某公司 面试结果:最后聊得工资是 14薪/16K 每天有饭补 。(但是没有当场给offer,详情在下面介绍) 面试过程: 11:00 公司开会(我等,我在等) 12: 00-14:00 跟两位 android程序员+技术总监 pk。 14:00-15:00 :跟两位人事谈人生理想. 面试记录: 11:00 : 到公司,前台后面 摆着桌球, 各种水果,感觉公司气氛还不错。 到公司的时候,已经11.00多了,刚好周一他们团队开会,我就被一个的小哥带到一个会议室等带,给倒了杯水,就把哥丢在那了。在会议室,听到隔壁的会议室,有来参加面试的和人事在那侃大山,略搞笑,依稀记得 还问了,假如 有其他公司 高薪挖你走2828之类的问题。(PPS:面试 技术是一方面,人事也不可以忽略。) 12:00: (一轮PK)终于开会结束了,哥可是饿着肚子呢, 这家公司没有笔试题,直接一个搞Android的哥们进来,简单介绍了一下 ,就聊起来了。首先 J哥 简单介绍了一下 在上一家公司 担任什么角色,平时开发流程 之类的,然后J哥 就说大概在公司开发了有5款APP,自己私下接过一款私活,然后自己没事也做了两款应用,然后J哥 把应用展示给他看,他看了连连称赞不错啊。。。(lalala,其实都是J哥网上巴拉的项目啦。) (然后大体给他介绍了 项目基本框架,是 v4包里的 SlidingPaneLayout 嵌套了实现了轮询效果 自定义的viewpager 。然后 具体界面是用的瀑布流,项目的关键就是 对 图片的处理,因为有N张 图片,但是并没有卡顿,所以就说了 自己用 了开源的imagedownloader 和 volley 以及自己定义的 lrucache 缓存 bitmap 对象,这里大家一定要把图片的三级缓存 自己了解清楚,基本面试会问到。) 其实 当面试问你如何避免oom,内存泄露导致的原因,以及如何处理大图片等等,其实都是 如何优化内存。 可以按照我自己总结的回答,你可以说,这个问题 ,跟 oom以及 内存泄露,其实是一样的,关键 就是 如何 优化内存,避免不必要的 内存泄露, 而 内存泄露 的原因 ,我总结了 4点, 1. 匿名内部类,和非静态内部类, 举个栗子:我们用handler 进行线程间 假如 我们在activity中这样定义 handler : [java] view plain copy print ? Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { mImageView.setImageBitmap(mBitmap); } } 然后,我们用 右键 选中工程 运行 lint工具 , android tools---run lint ,就会提示我们这样一个warning: In Android, Handler classes should be static or leaks might occur.。 就是 ,推荐我们 把handler 定义成static,具体 看这里解释的很详细:http://www.linuxidc.com/Linux/2013-12/94065.htm 类似的还有 匿名子线程。 2.还是 拿网上的 栗子来说, [java] view plain copy print ? Vector v = new Vector( 10 ); for ( int i = 1 ;i < 100 ; i ++ ){ Object o = new Object(); v.add(o); o = null ; } 即便是 我们把 o 对象 置为 null,但是 vector 集合中还有有o的引用,所以 集合 没有被清空,这一部分内存 还是不能被释放,这就导致了内存泄露。 3, 当我们操作数据库的时候,我们在执行完 相应的crud 方法后,我们没有关闭 cursor .close()或者 db.close(),也同样会占用内存、因为只有关闭连接后,才会被GC 回收。 4.继续举个栗子 [java] view plain copy print ? Set<Person> set = new HashSet<Person>(); Person p1 = new Person("唐僧","pwd1",25); Person p2 = new Person("孙悟空","pwd2",26); Person p3 = new Person("猪八戒","pwd3",27); set.add(p1); set.add(p2); set.add(p3); System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:3 个元素! p3.setAge(2); //修改p3的年龄,此时p3元素对应的hashcode值发生改变 set.remove(p3); //此时remove不掉,造成内存泄漏 set.add(p3); //重新添加,居然添加成功 System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:4 个元素! J哥 亲自 实践了下,发现问题了,这个网上的栗子 是错的。实际上是可以remove掉得、真是个悲伤地故事。这个栗子是不正确的。。网上好有一片这样的文章,都是这个栗子。。 这里 看下其他网站上的总结吧 :强烈推荐http://developer.51cto.com/art/201111/302465.htm。很详细。 OK。还有最后一点,就是关于图片的,bitmap对象的及时释放,这里 就不细说了,等在图片三级缓存一起去总结。 此时 感觉 对面的android 小哥 已经被我吸引了。好像很认真的在听我讲课一样。 然后, 他问我问题。我大体总结了一下。 面试官01问:有没有自定义过view。 J哥回答:这个很常见,我自己定义过很多,比如 下拉刷新,上拉加载更多数据的listview,类似github 上面的pulltorefreshlistview。 还有图片轮询播放的viewpager,也是 继承viewpager,然后自己开启一个线程,去控制 切换的。还比如,跑马灯效果的textview ,scrollview与 listview 相互嵌套 导致 listview 高度计算不正确,我也是 自定义listview,复写了 onmeaure方法,然后解决冲突的。在比如 一些开源的 可以放大缩小的图片,我也是做过,主要是对onmeasure 方法,onlayout方法,ondraw 方法的复写。以及复写一下 view 自己的 touch事件等等,奥 对了,我们公司当时有需求 做一个 锁屏软件,侧滑解锁的,我也是自己定义的,然后展示给他看了一下,当时 那篇文章在这里。传送门http://blog.csdn.net/u011733020/article/details/41863861。 面试官01问:listview的优化、 J哥回答:(PS:这种问题,基本上 都快被问烂了,但是没办法 还是要回答。)listview作为最常见的 用来显示数据的view ,一般 从四个方面 去优化。 1 ,复用convertview, 不然假如有1000条数据,那么我们滑动,就会 产生1000个convertview ,这对内存是很大的浪费,所以 我们一定要复用。 2. 减少 findviewbyid 的次数, 因为 每次 去 执行 findviewbyid 也是要消耗资源的,我们要尽可能的减少,通常 我们定义一个viewholder,去管理 这些id ,然后通过tag 去直接拿到 id。 3, 分页加载,延迟加载 预加载。 这个在我们以前项目,有一个榜单,数据量很大,一次请求过来的数据量很大,这样有两个问题,一个是请求网络 时间可能会很长,另一个展示数据 上面 体验对不是很好,所以 我们做了 第一次加载 20条,然后每次请求 再去 加载10条新数据。 4.就是 对 listview 中一些 类似头像, 图片的 优化。这里 类似 三级缓存,推荐大家看一下 开源 的universal-image-loader 的源码。或者 这篇文章http://www.jb51.net/article/38162.htm,J哥有时间 专门写一篇过于 图片缓存的。 面试官01问: 看你简历上面 做过 社交,通信这块是怎么做的。 J哥回答:我看 咱们公司 也用到了 聊天,咱们公司是 自己做的 还是 用的第三方的类似 环信的。结果被J哥猜中,他说 是集成的环信(但是 有丢包现象,所以打算自己做通信)。 OK,J哥说 ,我们 项目中聊天 是基于xmpp协议的做的,在没有android以前 ,java有个开源的 smack ,android 上 现在有一个asmack ,其实 就是移植到android 中来了, 服务端是基于 openfire的 ,我们就是做的 openfire+asmack 的 聊天,这个原理主要 就是 绑定 ip 拿到 connection 然后 connect ,然后进行通信,我说,这个 跟http请求 其实原理上一样,都是 绑定ip,然后 设置一些property,然后通过类似流进行通信的, asmack,其实底层 就是xml通信的。 面试官01问: touch 事件的传递机制,还特意画了,一个 就是 button LinearLayout 嵌套 。 J哥回答:就是这个, 这也难不倒我。因为J哥觉得 这个问题肯定会问到 所以 早有准备,这里 我就大体说下结论,详细原理 给你传送门。 我回答,这个很简单,只要你继承一下 button 和 linearlayout 复写一下 三个方法 dispatchtouchEvent onInterceptTouchEvent 和onTouchEvent .就能很清楚的明白 传递的过程,我给你总的说下结论的,点击这个button,一般是 外面的父控件 先响应这个down 事件,然后 往子类里面传递,让子类 在往子类的下一级子类去传递,让最终的孩子去决定是不要要消费掉这个点击事件,如果消费掉,那么父类将不会响应,如果子类不消费,那么会退回到次级子类,然后看是否要消费,这样,一句话 就是父传子, 子决定要不要,不要 然后传回去。 这里有很详细 很详细的介绍, 包裹事件的分发。所以我就不罗嗦,http://blog.csdn.net/yanbober/article/details/45887547?ref=myread 面试官01问: 项目中图片的优化。 J哥回答:我给他展示的项目 其中有一款app 是有很多图片 ,但是 很流畅,也没有oom。关于图片 优化,一般我们采用三级缓存,1 。内存加载 2.本地加载 3 网络加载。 首先 我们看 内存中有没有,有直接拿来用,这里 我项目里是这样做的,我先获取一下 分配给我们应用的可用内存是多少,然后 拿1/4 或者 1/8做一个 lrucache. 把我们的bitmap对象添加进去。有些比较常用的图片,我会保存到本地,避免每次重复联网下载。结合 开源的 afinal universalimageloader 以及 13年谷歌官方推荐的volley(号称是 asynchttpclient 和universalimageloader)的结合、 所以 在我的项目中基本没有遇到过图片导致的oom 问题,对于单张的 大图片,我也会利用bitmapFactory,进行计算大小,然后 计算手机分辨率,进行定量的 压缩 处理。 面试官问: GC的回收 J哥回答:我说。GC 回收 应该不只是按照一种方式,应该有多种不同的算法,我看过谷歌 官网介绍的一点,有这样一块区域,他分为 latest(最近) middle(中等)permanent(永久的),这样三块子区域。里面分别存放,刚刚被创建的,以及 时间 靠后的,很久的,对象,不断地新对象 往latest里面添加,当达到相应对象区域的阀值的时候,就会触发GC,GC 进行回收的时候,对于latest 中回收的速度是最快的,而permanent 相对是最久的,而时间 也跟 每块区域中对象的个数有关系, 还有一种算法,是根据最近被引用的时间,或者 被引用的次数 去进行 GC的、、这里随便扯就是了。GC 回收并不是立即执行的。是不定时的。GC回收的时候 会阻塞线程,所以代码中要避免创建不必要的对象,例如for循环中 创建大量对象 就会容易引起GC。 当我们也可以主动 在方法中执行system.gc() 去手动释放一些资源。 面试官01问: 怎么避免 viewpager 预加载 fragment的、 J哥回答:这个问题 我也碰到过,我们都知道,viewpager 它本身会预加载 左右两个 和当前一个对象、而 我们viewpager setOffscreenPageLimit(0) 不生效因为看源码知道,这个方法默认最少也要加载一个。所以 这个fragment 还没有被当前页面显示出来,已经夹在好了,有可能数据不是最新的,我是在 setuservisibilityhint() 这个方法中跟参数 动态去判断 要不要刷新的。 问了一圈,这个哥们大概没什么问的了,然后 就让我等一下,说让他们技术总监过来 。 我就等。。。 然后等了几分钟,进来一小姑娘,坐下,看了我简历,我以为是人事,来跟我谈人生理想。结果,没说几句话,让我讲一下我的项目。我qu,惊呆我了。我问,你也是做android的,我去,是这样的、、把J哥吓到, 然后问了J哥几个问题。 Android 小姑娘问: 看你项目中的listview 中item类型 是统一的,而加入 item 差别挺大的 你怎么复用。 J哥回答:J哥装作很牛的样子说,我暂时想到两种方法,1.给这个对象 加一个type 然后 根据 type 去复用,或者 把这几种类型 一起加载,然后控制显示隐藏。然后 我反问小姑娘,假如 我这里 有一百条数据,这一百条是无序的,包含了 10种 item类型,你有没有什么好方法 去处理这个问题, 小姑娘说,你不是定义了类型吗,我们就是 通过type 去判断的。 Android 小姑娘问: onAttch onDetach还是onAttachedToWindow,onDetachedFromWindow J哥回答:其实 那个小姑娘忘记这两个方法了。我说什么方法,她说onAttachIntent() 和 onDetachIntent(). 反正 J哥是没听说过, 我只见过 onAttach ,但是 这个方法 我也没用过。我就问她,这两个方法是做什么的,小姑娘跟我说 是 把子view绑定到界面上的,那么的话 应该是onAttachedToWindow,onDetachedFromWindow方法了,小姑娘说: 在这个方法 可以计算子 view的高度宽度,在 oncreate 里面不能计算,其实虽然刚开始 在oncreate里面是不能计算,但是还是有方法计算的,(本人觉得面试 问你 API 是 最2的了,忍不住吐槽下,我遇到过,Camera 拍照,问我获取 一个图片,还是 视频的 方法,我去百度 一下,随便就知道,真是不懂 为什么会问方法。随便一个程序员 都会百度。。) 跟小姑娘聊得其他问题 不太记得了,感觉这个女程序员啊。。就问方法 给我的印象不太好,不管方法用没用到,我觉得面试 直接问你方法 好2 好2... 然后技术总监 有进来跟我聊了,后技术总监 有进来跟我聊了、技术总监 年龄30出头吧,到是没有问我什么技术问题, 总监: 问我 做没做过通信这块,能不能做这一块。 J哥回答:,我说做过,通信有几种协议的,我们用的 是xmpp协议的 ,服务器 是 基于apache的 openfire 搭建的,客户端 是用的asmack。还有一些 其他协议的 ,比如我知道有些项目中用的 soap协议的,还有ip 协议的。PS:反正就是扯 我说 通信 客户端这一块 我没问题,但是 服务端 我 从工作以来 一直偏向 android 移动端开发,后台这一块,如果数据量大了,还要考虑并发之类的,我是做不了,让我做个tomcat搭建的demo 我可能可以。 其他也是随便聊了下,然后 就说,让人事来跟我谈理想了。 总监: 问我 什么时候能上班 J哥回答:我说 这个看公司需求啦。 其他也是随便聊了下,然后 就说,让人事来跟我谈理想了。 这里 感觉应该没问题了。差不多能拿下了。 人事1:一进来,就问东问西。问加班看法啊,他们公司技术 一般都八九点走啊。说七点基本没有走的啊、、、 J哥回答:我说,一般遇到项目加功能 ,版本升级,等等 这些加班都没什么,只要不是一直在加班。。。。这里每个人自己看法就好了、、 反正人事 是一直跟我强调这个,她不停强调 我就暗暗下决心,薪资 我是不会要低了。 人事1:看你还年轻啊,还能拼一拼啊、、、、 J哥回答:我说现在 这几年对我人生规划也算比较重要的时期,也是过一年少一年了,其实她的意思 还是侧面强调加班。。。。日了UZI了。 中间一堆废话,然后我问了她 公司一般上下班时间啊。。之类的有没有技术交流啊,之类的。。。 最后到关键问题上啦,最关心的,薪资问题。 人事1:期望薪资 J哥回答:我说16K左右吧。她问 你以前公司多少 握手 15K。她说她们公司 是 14薪。反正 我还是说16K。她说 那好,你等下,然后就出去了。 不知道 跟什么人 讨论了许久,然后又来一个 可能是人事吧。又进来,问了一遍,也问了薪资。。哥还是说16K 。 。。估计是她们公司想要我,但是又觉得有点超出她们薪资期望吧,当场被没有给什么offer。然后就有点婉拒的说,两天给我答复,心里很气愤,饿着肚子 面试到三点,竟然婉拒、、、 反正我是很生气,我说,好,然后我就走。结果,没过一个小时,人事又打电话来,非要约我 见一下她们CEO。这是什么鬼,难道她们CEO要给我煲汤 了?我说可以,然后时间定在后天了,,反正心灵鸡汤对我是没用了、 OK ,这家面试 先写到这里,下面下午还有一家,等下在写。准备睡觉。今天面试回来,累的就睡着了,晚上十点多才醒过来,想了想还是 把今天面试的过程总结一下。 ------------------------------待续------------------------- 第二弹http://blog.csdn.net/u011733020/article/details/46058273 本篇文章为转载内容。原文链接:https://blog.csdn.net/haluoluo211/article/details/51010955。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-06-19 17:42:52
336
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 随着容器技术越来越火热,各种大会上标杆企业分享容器化收益,带动其他还未实施容器的企业也在考虑实施容器化。不过真要在自己企业实践容器的时候,会认识到容器化不是一个简单工程,甚至会有一种茫然不知从何入手的感觉。 本文总结了通用的企业容器化实施线路图,主要针对企业有存量系统改造为容器,或者部分新开发的系统使用容器技术的场景。不包含企业系统从0开始全新构建的场景,这种场景相对简单。 容器实践路线图 企业着手实践容器的路线,建议从3个维度评估,然后根据评估结果落地实施。3个评估维度为:商业目标,技术选型,团队配合。 商业目标是重中之重,需要回答为何要容器化,这个也是牵引团队在容器实践路上不断前行的动力,是遇到问题是解决问题的方向指引,最重要的是让决策者认同商业目标,并能了解到支持商业目标的技术原理,上下目标对齐才好办事。 商业目标确定之后,需要确定容器相关的技术选型,容器是一种轻量化的虚拟化技术,与传统虚拟机比较有优点也有缺点,要找出这些差异点识别出对基础设施与应用的影响,提前识别风险并采取应对措施。 技术选型明确之后,在公司或部门内部推广与评审,让开发人员、架构师、测试人员、运维人员相关人员与团队理解与认同方案,听取他们意见,他们是直接使用容器的客户,不要让他们有抱怨。 最后是落地策略,一般是选取一些辅助业务先试点,在实践过程中不断总结经验。 商业目标 容器技术是以应用为中心的轻量级虚拟化技术,而传统的Xen与KVM是以资源为中心的虚拟化技术,这是两者的本质差异。以应用为中心是容器技术演进的指导原则,正是在这个原则指导下,容器技术相对于传统虚拟化有几个特点:打包既部署、镜像分层、应用资源调度。 打包即部署:打包即部署是指在容器镜像制作过程包含了传统软件包部署的过程(安装依赖的操作系统库或工具、创建用户、创建运行目录、解压、设置文件权限等等),这么做的好处是把应用及其依赖封装到了一个相对封闭的环境,减少了应用对外部环境的依赖,增强了应用在各种不同环境下的行为一致性,同时也减少了应用部署时间。 镜像分层:容器镜像包是分层结构,同一个主机上的镜像层是可以在多个容器之间共享的,这个机制可以极大减少镜像更新时候拉取镜像包的时间,通常应用程序更新升级都只是更新业务层(如Java程序的jar包),而镜像中的操作系统Lib层、运行时(如Jre)层等文件不会频繁更新。因此新版本镜像实质有变化的只有很小的一部分,在更新升级时候也只会从镜像仓库拉取很小的文件,所以速度很快。 应用资源调度:资源(计算/存储/网络)都是以应用为中心的,中心体现在资源分配是按照应用粒度分配资源、资源随应用迁移。 基于上述容器技术特点,可以推导出容器技术的3大使用场景:CI/CD、提升资源利用率、弹性伸缩。这3个使用场景自然推导出通用的商业层面收益:CI/CD提升研发效率、提升资源利用率降低成本、按需弹性伸缩在体验与成本之间达成平衡。 当然,除了商业目标之外,可能还有其他一些考虑因素,如基于容器技术实现计算任务调度平台、保持团队技术先进性等。 CI/CD提升研发效率 为什么容器技术适合CI/CD CI/CD是DevOps的关键组成部分,DevOps是一套软件工程的流程,用于持续提升软件开发效率与软件交付质量。DevOps流程来源于制造业的精益生产理念,在这个领域的领头羊是丰田公司,《丰田套路》这本书总结丰田公司如何通过PDCA(Plan-Do-Check-Act)方法实施持续改进。PDCA通常也称为PDCA循环,PDCA实施过程简要描述为:确定目标状态、分析当前状态、找出与目标状态的差距、制定实施计划、实施并总结、开始下一个PDCA过程。 DevOps基本也是这么一个PDCA流程循环,很容易认知到PDCA过程中效率是关键,同一时间段内,实施更多数量的PDCA过程,收益越高。在软件开发领域的DevOps流程中,各种等待(等待编译、等待打包、等待部署等)、各种中断(部署失败、机器故障)是影响DevOps流程效率的重要因素。 容器技术出来之后,将容器技术应用到DevOps场景下,可以从技术手段消除DevOps流程中的部分等待与中断,从而大幅度提升DevOps流程中CI/CD的效率。 容器的OCI标准定义了容器镜像规范,容器镜像包与传统的压缩包(zip/tgz等)相比有两个关键区别点:1)分层存储;2)打包即部署。 分层存储可以极大减少镜像更新时候拉取镜像包的时间,通常应用程序更新升级都只是更新业务层(如Java程序的jar包),而镜像中的操作系统Lib层、运行时(如Jre)层等文件不会频繁更新。因此新版本镜像实质有变化的只有很小的一部分,在更新升级时候也只会从镜像仓库拉取很小的文件,所以速度很快。 打包即部署是指在容器镜像制作过程包含了传统软件包部署的过程(安装依赖的操作系统库或工具、创建用户、创建运行目录、解压、设置文件权限等等),这么做的好处是把应用及其依赖封装到了一个相对封闭的环境,减少了应用对外部环境的依赖,增强了应用在各种不同环境下的行为一致性,同时也减少了应用部署时间。 基于容器镜像的这些优势,容器镜像用到CI/CD场景下,可以减少CI/CD过程中的等待时间,减少因环境差异而导致的部署中断,从而提升CI/CD的效率,提升整体研发效率。 CI/CD的关键诉求与挑战 快 开发人员本地开发调试完成后,提交代码,执行构建与部署,等待部署完成后验证功能。这个等待的过程尽可能短,否则开发人员工作容易被打断,造成后果就是效率降低。如果提交代码后几秒钟就能够完成部署,那么开发人员几乎不用等待,工作也不会被打断;如果需要好几分钟或十几分钟,那么可以想象,这十几分钟就是浪费了,这时候很容易做点别的事情,那么思路又被打断了。 所以构建CI/CD环境时候,快是第一个需要考虑的因素。要达到快,除了有足够的机器资源免除排队等待,引入并行编译技术也是常用做法,如Maven3支持多核并行构建。 自定义流程 不同行业存在不同的行业规范、监管要求,各个企业有一套内部质量规范,这些要求都对软件交付流程有定制需求,如要求使用商用的代码扫描工具做安全扫描,如构建结果与企业内部通信系统对接发送消息。 在团队协同方面,不同的公司,对DevOps流程在不同团队之间分工有差异,典型的有开发者负责代码编写构建出构建物(如jar包),而部署模板、配置由运维人员负责;有的企业开发人员负责构建并部署到测试环境;有的企业开发人员直接可以部署到生产环境。这些不同的场景,对CI/CD的流程、权限管控都有定制需求。 提升资源利用率 OCI标准包含容器镜像标准与容器运行时标准两部分,容器运行时标准聚焦在定义如何将镜像包从镜像仓库拉取到本地并更新、如何隔离运行时资源这些方面。得益于分层存储与打包即部署的特性,容器镜像从到镜像仓库拉取到本地运行速度非常快(通常小于30秒,依赖镜像本身大小等因素),基于此可以实现按需分配容器运行时资源(cpu与内存),并限定单个容器资源用量;然后根据容器进程资源使用率设定弹性伸缩规则,实现自动的弹性伸缩。 这种方式相对于传统的按峰值配置资源方式,可以提升资源利用率。 按需弹性伸缩在体验与成本之间达成平衡 联动弹性伸缩 应用运行到容器,按需分配资源之后,理想情况下,Kubernetes的池子里没有空闲的资源。这时候扩容应用实例数,新扩容的实例会因资源不足调度失败。这时候需要资源池能自动扩容,加入新的虚拟机,调度新扩容的应用。 由于应用对资源的配比与Flavor有要求,因此新加入的虚拟机,应当是与应用所需要的资源配比与Flavor一致的。缩容也是类似。 弹性伸缩还有一个诉求点是“平滑”,对业务做到不感知,也称为“优雅”扩容/缩容。 请求风暴 上面提到的弹性伸缩一般是有计划或缓慢增压的场景,存在另外一种无法预期的请求风暴场景,这种场景的特征是无法预测、突然请求量增大数倍或数十倍、持续时间短。典型的例子如行情交易系统,当行情突变的时候,用户访问量徒增,持续几十分钟或一个小时。 这种场景的弹性诉求,要求短时间内能将资源池扩大数倍,关键是速度要快(秒级),否则会来不及扩容,系统已经被冲垮(如果无限流的话)。 目前基于 Virtual Kubelet 与云厂家的 Serverless 容器,理论上可以提供应对请求风暴的方案。不过在具体实施时候,需要考虑传统托管式Kubernetes容器管理平台与Serverless容器之间互通的问题,需要基于具体厂家提供的能力来评估。 基于容器技术实现计算调度平台 计算(大数据/AI训练等)场景的特征是短时间内需要大量算力,算完即释放。容器的环境一致性以及调度便利性适合这种场景。 技术选型 容器技术是属于基础设施范围,但是与传统虚拟化技术(Xen/KVM)比较,容器技术是应用虚拟化,不是纯粹的资源虚拟化,与传统虚拟化存在差异。在容器技术选型时候,需要结合当前团队在应用管理与资源管理的现状,对照容器技术与虚拟化技术的差异,选择最合适的容器技术栈。 什么是容器技术 (1)容器是一种轻量化的应用虚拟化技术。 在讨论具体的容器技术栈的时候,先介绍目前几种常用的应用虚拟化技术,当前有3种主流的应用虚拟化技术: LXC,MicroVM,UniKernel(LibOS)。 LXC: Linux Container,通过 Linux的 namespace/cgroups/chroot 等技术隔离进程资源,目前应用最广的docker就是基于LXC实现应用虚拟化的。 MicroVM: MicroVM 介于 传统的VM 与 LXC之间,隔离性比LXC好,但是比传统的VM要轻量,轻量体现在体积小(几M到几十M)、启动快(小于1s)。 AWS Firecracker 就是一种MicroVM的实现,用于AWS的Serverless计算领域,Serverless要求启动快,租户之间隔离性好。 UniKernel: 是一种专用的(特定编程语言技术栈专用)、单地址空间、使用 library OS 构建出来的镜像。UniKernel要解决的问题是减少应用软件的技术栈层次,现代软件层次太多导致越来越臃肿:硬件+HostOS+虚拟化模拟+GuestOS+APP。UniKernel目标是:硬件+HostOS+虚拟化模拟+APP-with-libos。 三种技术对比表: 开销 体积 启动速度 隔离/安全 生态 LXC 低(几乎为0) 小 快(等同进程启动) 差(内核共享) 好 MicroVM 高 大 慢(小于1s) 好 中(Kata项目) UniKernel 中 中 中 好 差 根据上述对比来看,LXC是应用虚拟化首选的技术,如果LXC无法满足隔离性要,则可以考虑MicroVM这种技术。当前社区已经在着手融合LXC与MicroVM这两种技术,从应用打包/发布调度/运行层面统一规范,Kubernetes集成Kata支持混合应用调度特性可以了解一下。 UniKernel 在应用生态方面相对比较落后,目前在追赶中,目前通过 linuxkit 工具可以在UniKernel应用镜像中使用docker镜像。这种方式笔者还未验证过,另外docker镜像运行起来之后,如何监控目前还未知。 从上述三种应用虚拟化技术对比,可以得出结论: (2)容器技术与传统虚拟化技术不断融合中。 再从规范视角来看容器技术,可以将容器技术定义为: (3)容器=OCI+CRI+辅助工具。 OCI规范包含两部分,镜像规范与运行时规范。简要的说,要实现一个OCI的规范,需要能够下载镜像并解压镜像到文件系统上组成成一个文件目录结构,运行时工具能够理解这个目录结构并基于此目录结构管理(创建/启动/停止/删除)进程。 容器(container)的技术构成就是实现OCI规范的技术集合。 对于不同的操作系统(Linux/Windows),OCI规范的实现技术不同,当前docker的实现,支持Windows与Linux与MacOS操作系统。当前使用最广的是Linux系统,OCI的实现,在Linux上组成容器的主要技术: chroot: 通过分层文件系统堆叠出容器进程的rootfs,然后通过chroot设置容器进程的根文件系统为堆叠出的rootfs。 cgroups: 通过cgroups技术隔离容器进程的cpu/内存资源。 namesapce: 通过pid, uts, mount, network, user namesapce 分别隔离容器进程的进程ID,时间,文件系统挂载,网络,用户资源。 网络虚拟化: 容器进程被放置到独立的网络命名空间,通过Linux网络虚拟化veth, macvlan, bridge等技术连接主机网络与容器虚拟网络。 存储驱动: 本地文件系统,使用容器镜像分层文件堆叠的各种实现驱动,当前推荐的是overlay2。 广义的容器还包含容器编排,即当下很火热的Kubernetes。Kubernetes为了把控容器调度的生态,发布了CRI规范,通过CRI规范解耦Kubelet与容器,只要实现了CRI接口,都可以与Kubelet交互,从而被Kubernetes调度。OCI规范的容器实现与CRI标准接口对接的实现是CRI-O。 辅助工具用户构建镜像,验证镜像签名,管理存储卷等。 容器定义 容器是一种轻量化的应用虚拟化技术。 容器=OCI+CRI+辅助工具。 容器技术与传统虚拟化技术不断融合中。 什么是容器编排与调度 选择了应用虚拟化技术之后,还需要应用调度编排,当前Kubernetes是容器领域内编排的事实标准,不管使用何种应用虚拟化技术,都已经纳入到了Kubernetes治理框架中。 Kubernetes 通过 CRI 接口规范,将应用编排与应用虚拟化实现解耦:不管使用何种应用虚拟化技术(LXC, MicroVM, LibOS),都能够通过Kubernetes统一编排。 当前使用最多的是docker,其次是cri-o。docker与crio结合kata-runtime都能够支持多种应用虚拟化技术混合编排的场景,如LXC与MicroVM混合编排。 docker(now): Moby 公司贡献的 docker 相关部件,当前主流使用的模式。 docker(daemon) 提供对外访问的API与CLI(docker client) containerd 提供与 kubelet 对接的 CRI 接口实现 shim负责将Pod桥接到Host namespace。 cri-o: 由 RedHat/Intel/SUSE/IBM/Hyper 公司贡献的实现了CRI接口的符合OCI规范的运行时,当前包括 runc 与 kata-runtime ,也就是说使用 cir-o 可以同时运行LXC容器与MicroVM容器,具体在Kata介绍中有详细说明。 CRI-O: 实现了CRI接口的进程,与 kubelet 交互 crictl: 类似 docker 的命令行工具 conmon: Pod监控进程 other cri runtimes: 其他的一些cri实现,目前没有大规模应用到生产环境。 容器与传统虚拟化差异 容器(container)的技术构成 前面主要讲到的是容器与编排,包括CRI接口的各种实现,我们把容器领域的规范归纳为南向与北向两部分,CRI属于北向接口规范,对接编排系统,OCI就属于南向接口规范,实现应用虚拟化。 简单来讲,可以这么定义容器: 容器(container) ~= 应用打包(build) + 应用分发(ship) + 应用运行/资源隔离(run)。 build-ship-run 的内容都被定义到了OCI规范中,因此也可以这么定义容器: 容器(container) == OCI规范 OCI规范包含两部分,镜像规范与运行时规范。简要的说,要实现一个OCI的规范,需要能够下载镜像并解压镜像到文件系统上组成成一个文件目录结构,运行时工具能够理解这个目录结构并基于此目录结构管理(创建/启动/停止/删除)进程。 容器(container)的技术构成就是实现OCI规范的技术集合。 对于不同的操作系统(Linux/Windows),OCI规范的实现技术不同,当前docker的实现,支持Windows与Linux与MacOS操作系统。当前使用最广的是Linux系统,OCI的实现,在Linux上组成容器的主要技术: chroot: 通过分层文件系统堆叠出容器进程的rootfs,然后通过chroot设置容器进程的根文件系统为堆叠出的rootfs。 cgroups: 通过cgroups技术隔离容器进程的cpu/内存资源。 namesapce: 通过pid, uts, mount, network, user namesapce 分别隔离容器进程的进程ID,时间,文件系统挂载,网络,用户资源。 网络虚拟化: 容器进程被放置到独立的网络命名空间,通过Linux网络虚拟化veth, macvlan, bridge等技术连接主机网络与容器虚拟网络。 存储驱动: 本地文件系统,使用容器镜像分层文件堆叠的各种实现驱动,当前推荐的是overlay2。 广义的容器还包含容器编排,即当下很火热的Kubernetes。Kubernetes为了把控容器调度的生态,发布了CRI规范,通过CRI规范解耦Kubelet与容器,只要实现了CRI接口,都可以与Kubelet交互,从而被Kubernetes调度。OCI规范的容器实现与CRI标准接口对接的实现是CRI-O。 容器与虚拟机差异对比 容器与虚拟机的差异可以总结为2点:应用打包与分发的差异,应用资源隔离的差异。当然,导致这两点差异的根基是容器是以应用为中心来设计的,而虚拟化是以资源为中心来设计的,本文对比容器与虚拟机的差异,更多的是站在应用视角来对比。 从3个方面对比差异:资源隔离,应用打包与分发,延伸的日志/监控/DFX差异。 1.资源隔离 隔离机制差异 容器 虚拟化 mem/cpu cgroup, 使用时候设定 require 与 limit 值 QEMU, KVM network Linux网络虚拟化技术(veth,tap,bridge,macvlan,ipvlan), 跨虚拟机或出公网访问:SNAT/DNAT, service转发:iptables/ipvs, SR-IOV Linux网络虚拟化技术(veth,tap,bridge,macvlan,ipvlan), QEMU, SR-IOV storage 本地存储: 容器存储驱动 本地存储:virtio-blk 差异引入问题与实践建议 应用程序未适配 cgroup 的内存隔离导致问题: 典型的是 JVM 虚拟机,在 JVM 启动时候会根据系统内存自动设置 MaxHeapSize 值,通常是系统内存的1/4,但是 JVM 并未考虑 cgroup 场景,读系统内存时候任然读取主机的内存来设置 MaxHeapSize,这样会导致内存超过 cgroup 限制从而导致进程被 kill 。问题详细阐述与解决建议参考Java inside docker: What you must know to not FAIL。 多次网络虚拟化问题: 如果在虚拟机内使用容器,会多一层网络虚拟化,并加入了SNAT/DNAT技术, iptables/ipvs技术,对网络吞吐量与时延都有影响(具体依赖容器网络方案),对问题定位复杂度变高,同时还需要注意网络内核参数调优。 典型的网络调优参数有:转发表大小 /proc/sys/net/netfilter/nf_conntrack_max 使用iptables 作为service转发实现的时候,在转发规则较多的时候,iptables更新由于需要全量更新导致非常耗时,建议使用ipvs。详细参考[华为云在 K8S 大规模场景下的 Service 性能优化实践](https://zhuanlan.zhihu.com/p/37230013)。 容器IP地址频繁变化不固定,周边系统需要协调适配,包括基于IP地址的白名单或防火墙控制策略需要调整,CMDB记录的应用IP地址需要适配动态IP或者使用服务名替代IP地址。 存储驱动带来的性能损耗: 容器本地文件系统是通过联合文件系统方式堆叠出来的,当前主推与默认提供的是overlay2驱动,这种模式应用写本地文件系统文件或修改已有文件,使用Copy-On-Write方式,也就是会先拷贝源文件到可写层然后修改,如果这种操作非常频繁,建议使用 volume 方式。 2.应用打包与分发 应用打包/分发/调度差异 容器 虚拟化 打包 打包既部署 一般不会把应用程序与虚拟机打包在一起,通过部署系统部署应用 分发 使用镜像仓库存储与分发 使用文件存储 调度运行 使用K8S亲和/反亲和调度策略 使用部署系统的调度能力 差异引入问题与实践建议 部署提前到构建阶段,应用需要支持动态配置与静态程序分离;如果在传统部署脚本中依赖外部动态配置,这部分需要做一些调整。 打包格式发生变化,制作容器镜像需要注意安全/效率因素,可参考Dockerfile最佳实践 容器镜像存储与分发是按layer来组织的,镜像在传输过程中放篡改的方式是传统软件包有差异。 3.监控/日志/DFX 差异 容器 虚拟化 监控 cpu/mem的资源上限是cgroup定义的;containerd/shim/docker-daemon等进程的监控 传统进程监控 日志采集 stdout/stderr日志采集方式变化;日志持久化需要挂载到volume;进程会被随机调度到其他节点导致日志需要实时采集否则分散很难定位 传统日志采集 问题定位 进程down之后自动拉起会导致问题定位现场丢失;无法停止进程来定位问题因为停止即删除实例 传统问题定位手段 差异引入问题实践与建议 使用成熟的监控工具,运行在docker中的应用使用cadvisor+prometheus实现采集与警报,cadvisor中预置了常用的监控指标项 对于docker管理进程(containerd/shim/docker-daemon)也需要一并监控 使用成熟的日志采集工具,如果已有日志采集Agent,则可以考虑将日志文件挂载到volume后由Agent采集;需要注意的是stderr/stdout输出也要一并采集 如果希望容器内应用进程退出后保留现场定位问题,则可以将Pod的restartPolicy设置为never,进程退出后进程文件都还保留着(/var/lib/docker/containers)。但是这么做的话需要进程没有及时恢复,会影响业务,需要自己实现进程重拉起。 团队配合 与周边的开发团队、架构团队、测试团队、运维团队评审并交流方案,与周边团队达成一致。 落地策略与注意事项 逐步演进过程中网络互通 根据当前已经存在的基础实施情况,选择容器化落地策略。通常使用逐步演进的方式,由于容器化引入了独立的网络namespace导致容器与传统虚拟机进程网络隔离,逐步演进过程中如何打通隔离的网络是最大的挑战。 分两种场景讨论: 不同服务集群之间使用VIP模式互通: 这种模式相对简单,基于VIP做灰度发布。 不同服务集群之间使用微服务点对点模式互通(SpringCloud/ServiceComb/Dubbo都是这一类): 这种模式相对复杂,在逐步容器化过程中,要求容器网络与传统虚拟机网络能够互通(难点是在虚拟机进程内能够直接访问到容器网络的IP地址),当前解决这个问题有几种方法。 自建Kubernetes场景,可使用开源的kube-router,kube-router 使用BGP协议实现容器网络与传统虚拟机网络之间互通,要求网络交换机支持BGP协议。 使用云厂商托管Kubernetes场景,选择云厂商提供的VPC-Router互通的网络插件,如阿里云的Terway网络插件, 华为云的Underlay网络模式。 选择物理机还是虚拟机 选择物理机运行容器还是虚拟机运行容器,需要结合基础设施与业务隔离性要求综合考虑。分两种场景:自建IDC、租用公有云。 自建IDC: 理想情况是使用物理机组成一个大集群,根据业务诉求,对资源保障与安全性要求高的应用,使用MicorVM方式隔离;普通应用使用LXC方式隔离。所有物理机在一个大集群内,方便削峰填谷提升资源利用率。 租用公有云:当前公有云厂家提供的裸金属服务价格较贵且只能包周期,使用裸金属性价比并不高,使用虚拟机更合适。 集群规模与划分 选择集群时候,是多个应用共用一个大集群,还是按应用分组分成多个小集群呢?我们把节点规模数量>=1000的定义为大集群,节点数<1000的定义为小集群。 大集群的优点是资源池共享容器,方便资源调度(削峰填谷);缺点是随着节点数量与负载数量的增多,会引入管理性能问题(需要量化): DNS 解析表变大,增加/删除 Service 或 增加/删除 Endpoint 导致DNS表刷新慢 K8S Service 转发表变大,导致工作负载增加/删除刷新iptables/ipvs记录变慢 etcd 存储空间变大,如果加上ConfigMap,可能导致 etcd 访问时延增加 小集群的优点是不会有管理性能问题,缺点是会导致资源碎片化,不容易共享。共享分两种情况: 应用之间削峰填谷:目前无法实现 计算任务与应用之间削峰填谷:由于计算任务是短时任务,可以通过上层的任务调度软件,在多个集群之间分发计算任务,从而达到集群之间资源共享的目的。 选择集群规模的时候,可以参考上述分析,结合实际情况选择适合的集群划分。 Helm? Helm是为了解决K8S管理对象散碎的问题,在K8S中并没有"应用"的概念,只有一个个散的对象(Deployment, ConfigMap, Service, etc),而一个"应用"是多个对象组合起来的,且这些对象之间还可能存在一定的版本配套关系。 Helm 通过将K8S多个对象打包为一个包并标注版本号形成一个"应用",通过 Helm 管理进程部署/升级这个"应用"。这种方式解决了一些问题(应用分发更方便)同时也引入了一些问题(引入Helm增加应用发布/管理复杂度、在K8S修改了对象后如何同步到Helm)。对于是否需要使用Helm,建议如下: 在自运维模式下不使用Helm: 自运维模式下,很多场景是开发团队交付一个运行包,运维团队负责部署与配置下发,内部通过兼容性或软件包与配置版本配套清单、管理软件包与配置的配套关系。 在交付软件包模式下使用Helm: 交付软件包模式下,Helm 这种把散碎组件组装为一个应用的模式比较适合,使用Helm实现软件包分发/部署/升级场比较简单。 Reference DOCKER vs LXC vs VIRTUAL MACHINES Cgroup与LXC简介 Introducing Container Runtime Interface (CRI) in Kubernetes frakti rkt appc-spec OCI 和 runc:容器标准化和 docker Linux 容器技术史话:从 chroot 到未来 Linux Namespace和Cgroup Java inside docker: What you must know to not FAIL QEMU,KVM及QEMU-KVM介绍 kvm libvirt qemu实践系列(一)-kvm介绍 KVM 介绍(4):I/O 设备直接分配和 SR-IOV [KVM PCI/PCIe Pass-Through SR-IOV] prometheus-book 到底什么是Unikernel? The Rise and Fall of the Operating System The Design and Implementation of the Anykernel and Rump Kernels UniKernel Unikernel:从不入门到入门 OSv 京东如何打造K8s全球最大集群支撑万亿电商交易 Cloud Native App Hub 更多云最佳实践 https://best.practices.cloud 本篇文章为转载内容。原文链接:https://blog.csdn.net/sinat_33155975/article/details/118013855。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-09-17 15:03:28
225
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 浅谈 前段时间有个客户问我,为啥你们项目都搞了好几年了,为啥线上还会经常反馈卡顿,呃呃呃。。 于是根据自己的理解以及网上大佬们的思路总结了一篇关于卡顿优化这块的文章。 卡顿问题是一个老生常谈的话题了,一个App的好坏,卡顿也许会占一半,它直接决定了用户的留存问题,各大app排行版上,那些知名度较高,但是排行较低的,可能就要思考思考是不是和你app本身有关系了。 卡顿一直是性能优化中相对重要的一个点,因为其涉及了UI绘制、垃圾回收(GC)、线程调度以及Binder,CPU,GPU方面等JVM以及FrameWork相关知识 如果能做好卡顿优化,那么也就间接证明你对Android FrameWork的理解之深。 接下来我们就来讲解下卡顿方面的知识。 什么是卡顿: 对用户来讲就是界面不流畅,滞顿。 场景如下: 1.视频加载慢,画面卡顿,卡死,黑屏 2.声音卡顿,音画不同步。 3.动画帧卡顿,交互响应慢 4.滑动不跟手,列表自动更新,滚动不流畅 5.网络响应慢,数据和画面展示慢、 6.过渡动画生硬。 7.界面不可交互,卡死,等等现象。 卡顿是如何发生的 卡顿产生的原因一般都比较复杂,如CPU内存大小,IO操作,锁操作,低效的算法等都会引起卡顿。 站在开发的角度看: 通常我们讲,屏幕刷新率是60fps,需要在16ms内完成所有的工作才不会造成卡顿。 为什么是16ms,不是17,18呢? 下面我们先来理清在UI绘制中的几个概念: SurfaceFlinger: SurfaceFlinger作用是接受多个来源的图形显示数据Surface,合成后发送到显示设备,比如我们的主界面中:可能会有statusBar,侧滑菜单,主界面,这些View都是独立Surface渲染和更新,最后提交给SF后,SF根据Zorder,透明度,大小,位置等参数,合成为一个数据buffer,传递HWComposer或者OpenGL处理,最终给显示器。 在显示过程中使用到了bufferqueue,surfaceflinger作为consumer方,比如windowmanager管理的surface作为生产方产生页面,交由surfaceflinger进行合成。 VSYNC Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,VSYNC是一种在PC上很早就有应用,可以理解为一种定时中断技术。 tearing 问题: 早期的 Android 是没有 vsync 机制的,CPU 和 GPU 的配合也比较混乱,这也造成著名的 tearing 问题,即 CPU/GPU 直接更新正在显示的屏幕 buffer 造成画面撕裂。 后续 Android 引入了双缓冲机制,但是 buffer 的切换也需要一个比较合适的时机,也就是屏幕扫描完上一帧后的时机,这也就是引入 vsync 的原因。 早先一般的屏幕刷新率是 60fps,所以每个 vsync 信号的间隔也是 16ms,不过随着技术的更迭以及厂商对于流畅性的追求,越来越多 90fps 和 120fps 的手机面世,相对应的间隔也就变成了 11ms 和 8ms。 VSYNC信号种类: 1.屏幕产生的硬件VSYNC:硬件VSYNC是一种脉冲信号,起到开关和触发某种操作的作用。 2.由SurfaceFlinger将其转成的软件VSYNC信号,经由Binder传递给Choreographer Choreographer: 编舞者,用于注册VSYNC信号并接收VSYNC信号回调,当内部接收到这个信号时最终会调用到doFrame进行帧的绘制操作。 Choreographer在系统中流程: 如何通过Choreographer计算掉帧情况:原理就是: 通过给Choreographer设置FrameCallback,在每次绘制前后看时间差是16.6ms的多少倍,即为前后掉帧率。 使用方式如下: //Application.javapublic void onCreate() {super.onCreate();//在Application中使用postFrameCallbackChoreographer.getInstance().postFrameCallback(new FPSFrameCallback(System.nanoTime()));}public class FPSFrameCallback implements Choreographer.FrameCallback {private static final String TAG = "FPS_TEST";private long mLastFrameTimeNanos = 0;private long mFrameIntervalNanos;public FPSFrameCallback(long lastFrameTimeNanos) {mLastFrameTimeNanos = lastFrameTimeNanos;mFrameIntervalNanos = (long)(1000000000 / 60.0);}@Overridepublic void doFrame(long frameTimeNanos) {//初始化时间if (mLastFrameTimeNanos == 0) {mLastFrameTimeNanos = frameTimeNanos;}final long jitterNanos = frameTimeNanos - mLastFrameTimeNanos;if (jitterNanos >= mFrameIntervalNanos) {final long skippedFrames = jitterNanos / mFrameIntervalNanos;if(skippedFrames>30){//丢帧30以上打印日志Log.i(TAG, "Skipped " + skippedFrames + " frames! "+ "The application may be doing too much work on its main thread.");} }mLastFrameTimeNanos=frameTimeNanos;//注册下一帧回调Choreographer.getInstance().postFrameCallback(this);} } UI绘制全路径分析: 有了前面几个概念,这里我们让SurfaceFlinger结合View的绘制流程用一张图来表达整个绘制流程: 生产者:APP方构建Surface的过程。 消费者:SurfaceFlinger UI绘制全路径分析卡顿原因: 接下来,我们逐个分析,看看都会有哪些原因可能造成卡顿: 1.渲染流程 1.Vsync 调度:这个是起始点,但是调度的过程会经过线程切换以及一些委派的逻辑,有可能造成卡顿,但是一般可能性比较小,我们也基本无法介入; 2.消息调度:主要是 doframe Message 的调度,这就是一个普通的 Handler 调度,如果这个调度被其他的 Message 阻塞产生了时延,会直接导致后续的所有流程不会被触发 3.input 处理:input 是一次 Vsync 调度最先执行的逻辑,主要处理 input 事件。如果有大量的事件堆积或者在事件分发逻辑中加入大量耗时业务逻辑,会造成当前帧的时长被拉大,造成卡顿,可以尝试通过事件采样的方案,减少 event 的处理 4.动画处理:主要是 animator 动画的更新,同理,动画数量过多,或者动画的更新中有比较耗时的逻辑,也会造成当前帧的渲染卡顿。对动画的降帧和降复杂度其实解决的就是这个问题; 5.view 处理:主要是接下来的三大流程,过度绘制、频繁刷新、复杂的视图效果都是此处造成卡顿的主要原因。比如我们平时所说的降低页面层级,主要解决的就是这个问题; 6.measure/layout/draw:view 渲染的三大流程,因为涉及到遍历和高频执行,所以这里涉及到的耗时问题均会被放大,比如我们会降不能在 draw 里面调用耗时函数,不能 new 对象等等; 7.DisplayList 的更新:这里主要是 canvas 和 displaylist 的映射,一般不会存在卡顿问题,反而可能存在映射失败导致的显示问题; 8.OpenGL 指令转换:这里主要是将 canvas 的命令转换为 OpenGL 的指令,一般不存在问题 9.buffer 交换:这里主要指 OpenGL 指令集交换给 GPU,这个一般和指令的复杂度有关 10.GPU 处理:顾名思义,这里是 GPU 对数据的处理,耗时主要和任务量和纹理复杂度有关。这也就是我们降低 GPU 负载有助于降低卡顿的原因; 11.layer 合成:Android P 修改了 Layer 的计算方法 , 把这部分放到了 SurfaceFlinger 主线程去执行, 如果后台 Layer 过多, 就会导致 SurfaceFlinger 在执行 rebuildLayerStacks 的时候耗时 , 导致 SurfaceFlinger 主线程执行时间过长。 可以选择降低Surface层级来优化卡顿。 12.光栅化/Display:这里暂时忽略,底层系统行为; Buffer 切换:主要是屏幕的显示,这里 buffer 的数量也会影响帧的整体延迟,不过是系统行为,不能干预。 2.系统负载 内存:内存的吃紧会直接导致 GC 的增加甚至 ANR,是造成卡顿的一个不可忽视的因素; CPU:CPU 对卡顿的影响主要在于线程调度慢、任务执行的慢和资源竞争,比如 1.降频会直接导致应用卡顿; 2.后台活动进程太多导致系统繁忙,cpu \ io \ memory 等资源都会被占用, 这时候很容易出现卡顿问题 ,这种情况比较常见,可以使用dumpsys cpuinfo查看当前设备的cpu使用情况: 3.主线程调度不到 , 处于 Runnable 状态,这种情况比较少见 4.System 锁:system_server 的 AMS 锁和 WMS 锁 , 在系统异常的情况下 , 会变得非常严重 , 如下图所示 , 许多系统的关键任务都被阻塞 , 等待锁的释放 , 这时候如果有 App 发来的 Binder 请求带锁 , 那么也会进入等待状态 , 这时候 App 就会产生性能问题 ; 如果此时做 Window 动画 , 那么 system_server 的这些锁也会导致窗口动画卡顿 GPU:GPU 的影响见渲染流程,但是其实还会间接影响到功耗和发热; 功耗/发热:功耗和发热一般是不分家的,高功耗会引起高发热,进而会引起系统保护,比如降频、热缓解等,间接的导致卡顿。 如何监控卡顿 线下监控: 我们知道卡顿问题的原因错综复杂,但最终都可以反馈到CPU使用率上来 1.使用dumpsys cpuinfo命令 这个命令可以获取当时设备cpu使用情况,我们可以在线下通过重度使用应用来检测可能存在的卡顿点 A8S:/ $ dumpsys cpuinfoLoad: 1.12 / 1.12 / 1.09CPU usage from 484321ms to 184247ms ago (2022-11-02 14:48:30.793 to 2022-11-02 14:53:30.866):2% 1053/scanserver: 0.2% user + 1.7% kernel0.6% 934/system_server: 0.4% user + 0.1% kernel / faults: 563 minor0.4% 564/signserver: 0% user + 0.4% kernel0.2% 256/ueventd: 0.1% user + 0% kernel / faults: 320 minor0.2% 474/surfaceflinger: 0.1% user + 0.1% kernel0.1% 576/vendor.sprd.hardware.gnss@2.0-service: 0.1% user + 0% kernel / faults: 54 minor0.1% 286/logd: 0% user + 0% kernel / faults: 10 minor0.1% 2821/com.allinpay.appstore: 0.1% user + 0% kernel / faults: 1312 minor0.1% 447/android.hardware.health@2.0-service: 0% user + 0% kernel / faults: 1175 minor0% 1855/com.smartpos.dataacqservice: 0% user + 0% kernel / faults: 755 minor0% 2875/com.allinpay.appstore:pushcore: 0% user + 0% kernel / faults: 744 minor0% 1191/com.android.systemui: 0% user + 0% kernel / faults: 70 minor0% 1774/com.android.nfc: 0% user + 0% kernel0% 172/kworker/1:2: 0% user + 0% kernel0% 145/irq/24-70900000: 0% user + 0% kernel0% 575/thermald: 0% user + 0% kernel / faults: 300 minor... 2.CPU Profiler 这个工具是AS自带的CPU性能检测工具,可以在PC上实时查看我们CPU使用情况。 AS提供了四种Profiling Model配置: 1.Sample Java Methods:在应用程序基于Java的代码执行过程中,频繁捕获应用程序的调用堆栈 获取有关应用程序基于Java的代码执行的时间和资源使用情况信息。 2.Trace java methods:在运行时对应用程序进行检测,以在每个方法调用的开始和结束时记录时间戳。收集时间戳并进行比较以生成方法跟踪数据,包括时序信息和CPU使用率。 请注意与检测每种方法相关的开销会影响运行时性能,并可能影响性能分析数据。对于生命周期相对较短的方法,这一点甚至更为明显。此外,如果您的应用在短时间内执行大量方法,则探查器可能会很快超过其文件大小限制,并且可能无法记录任何进一步的跟踪数据。 3.Sample C/C++ Functions:捕获应用程序本机线程的示例跟踪。要使用此配置,您必须将应用程序部署到运行Android 8.0(API级别26)或更高版本的设备。 4.Trace System Calls:捕获细粒度的详细信息,使您可以检查应用程序与系统资源的交互方式 您可以检查线程状态的确切时间和持续时间,可视化CPU瓶颈在所有内核中的位置,并添加自定义跟踪事件进行分析。在对性能问题进行故障排除时,此类信息可能至关重要。要使用此配置,您必须将应用程序部署到运行Android 7.0(API级别24)或更高版本的设备。 使用方式: Debug.startMethodTracing("");// 需要检测的代码片段...Debug.stopMethodTracing(); 优点:有比较全面的调用栈以及图像化方法时间显示,包含所有线程的情况 缺点:本身也会带来一点的性能开销,可能会带偏优化方向 火焰图:可以显示当前应用的方法堆栈: 3.Systrace Systrace在前面一篇分析启动优化的文章讲解过 这里我们简单来复习下: Systrace用来记录当前应用的系统以及应用(使用Trace类打点)的各阶段耗时信息包括绘制信息以及CPU信息等。 使用方式: Trace.beginSection("MyApp.onCreate_1");alt(200);Trace.endSection(); 在命令行中: python systrace.py -t 5 sched gfx view wm am app webview -a "com.chinaebipay.thirdcall" -o D:\trac1.html 记录的方法以及CPU中的耗时情况: 优点: 1.轻量级,开销小,CPU使用率可以直观反映 2.右侧的Alerts能够根据我们应用的问题给出具体的建议,比如说,它会告诉我们App界面的绘制比较慢或者GC比较频繁。 4.StrictModel StrictModel是Android提供的一种运行时检测机制,用来帮助开发者自动检测代码中不规范的地方。 主要和两部分相关: 1.线程相关 2.虚拟机相关 基础代码: private void initStrictMode() {// 1、设置Debug标志位,仅仅在线下环境才使用StrictModeif (DEV_MODE) {// 2、设置线程策略StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectCustomSlowCalls() //API等级11,使用StrictMode.noteSlowCode.detectDiskReads().detectDiskWrites().detectNetwork() // or .detectAll() for all detectable problems.penaltyLog() //在Logcat 中打印违规异常信息// .penaltyDialog() //也可以直接跳出警报dialog// .penaltyDeath() //或者直接崩溃.build());// 3、设置虚拟机策略StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects()// 给NewsItem对象的实例数量限制为1.setClassInstanceLimit(NewsItem.class, 1).detectLeakedClosableObjects() //API等级11.penaltyLog().build());} } 线上监控: 线上需要自动化的卡顿检测方案来定位卡顿,它能记录卡顿发生时的场景。 自动化监控原理: 采用拦截消息调度流程,在消息执行前埋点计时,当耗时超过阈值时,则认为是一次卡顿,会进行堆栈抓取和上报工作 首先,我们看下Looper用于执行消息循环的loop()方法,关键代码如下所示: / Run the message queue in this thread. Be sure to call {@link quit()} to end the loop./public static void loop() {...for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;// This must be in a local variable, in case a UI event sets the loggerfinal Printer logging = me.mLogging;if (logging != null) {// 1logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}...try {// 2 msg.target.dispatchMessage(msg);dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);} }...if (logging != null) {// 3logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);} 在Looper的loop()方法中,在其执行每一个消息(注释2处)的前后都由logging进行了一次打印输出。可以看到,在执行消息前是输出的">>>>> Dispatching to “,在执行消息后是输出的”<<<<< Finished to ",它们打印的日志是不一样的,我们就可以由此来判断消息执行的前后时间点。 具体的实现可以归纳为如下步骤: 1、首先,我们需要使用Looper.getMainLooper().setMessageLogging()去设置我们自己的Printer实现类去打印输出logging。这样,在每个message执行的之前和之后都会调用我们设置的这个Printer实现类。 2、如果我们匹配到">>>>> Dispatching to "之后,我们就可以执行一行代码:也就是在指定的时间阈值之后,我们在子线程去执行一个任务,这个任务就是去获取当前主线程的堆栈信息以及当前的一些场景信息,比如:内存大小、电脑、网络状态等。 3、如果在指定的阈值之内匹配到了"<<<<< Finished to ",那么说明message就被执行完成了,则表明此时没有产生我们认为的卡顿效果,那我们就可以将这个子线程任务取消掉。 这里我们使用blockcanary来做测试: BlockCanary APM是一个非侵入式的性能监控组件,可以通过通知的形式弹出卡顿信息。它的原理就是我们刚刚讲述到的卡顿监控的实现原理。 使用方式: 1.导入依赖 implementation 'com.github.markzhai:blockcanary-android:1.5.0' Application的onCreate方法中开启卡顿监控 // 注意在主进程初始化调用BlockCanary.install(this, new AppBlockCanaryContext()).start(); 3.继承BlockCanaryContext类去实现自己的监控配置上下文类 public class AppBlockCanaryContext extends BlockCanaryContext {....../ 指定判定为卡顿的阈值threshold (in millis), 你可以根据不同设备的性能去指定不同的阈值 @return threshold in mills/public int provideBlockThreshold() {return 1000;}....} 4.在Activity的onCreate方法中执行一个耗时操作 try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();} 5.结果: 可以看到一个和LeakCanary一样效果的阻塞可视化堆栈图 那有了BlockCanary的方法耗时监控方式是不是就可以解百愁了呢,呵呵。有那么容易就好了 根据原理:我们拿到的是msg执行前后的时间和堆栈信息,如果msg中有几百上千个方法,就无法确认到底是哪个方法导致的耗时,也有可能是多个方法堆积导致。 这就导致我们无法准确定位哪个方法是最耗时的。如图中:堆栈信息是T2的,而发生耗时的方法可能是T1到T2中任何一个方法甚至是堆积导致。 那如何优化这块? 这里我们采用字节跳动给我们提供的一个方案:基于 Sliver trace 的卡顿监控体系 Sliver trace 整体流程图: 主要包含两个方面: 检测方案: 在监控卡顿时,首先需要打开 Sliver 的 trace 记录能力,Sliver 采样记录 trace 执行信息,对抓取到的堆栈进行 diff 聚合和缓存。 同时基于我们的需要设置相应的卡顿阈值,以 Message 的执行耗时为衡量。对主线程消息调度流程进行拦截,在消息开始分发执行时埋点,在消息执行结束时计算消息执行耗时,当消息执行耗时超过阈值,则认为产生了一次卡顿。 堆栈聚合策略: 当卡顿发生时,我们需要为此次卡顿准备数据,这部分工作是在端上子线程中完成的,主要是 dump trace 到文件以及过滤聚合要上报的堆栈。分为以下几步: 1.拿到缓存的主线程 trace 信息并 dump 到文件中。 2.然后从文件中读取 trace 信息,按照数据格式,从最近的方法栈向上追溯,找到当前 Message 包含的全部 trace 信息,并将当前 Message 的完整 trace 写入到待上传的 trace 文件中,删除其余 trace 信息。 3.遍历当前 Message trace,按照(Method 执行耗时 > Method 耗时阈值 & Method 耗时为该层堆栈中最耗时)为条件过滤出每一层函数调用堆栈的最长耗时函数,构成最后要上报的堆栈链路,这样特征堆栈中的每一步都是最耗时的,且最底层 Method 为最后的耗时大于阈值的 Method。 之后,将 trace 文件和堆栈一同上报,这样的特征堆栈提取策略保证了堆栈聚合的可靠性和准确性,保证了上报到平台后堆栈的正确合理聚合,同时提供了进一步分析问题的 trace 文件。 可以看到字节给的是一整套监控方案,和前面BlockCanary不同之处就在于,其是定时存储堆栈,缓存,然后使用diff去重的方式,并上传到服务器,可以最大限度的监控到可能发生比较耗时的方法。 开发中哪些习惯会影响卡顿的发生 1.布局太乱,层级太深。 1.1:通过减少冗余或者嵌套布局来降低视图层次结构。比如使用约束布局代替线性布局和相对布局。 1.2:用 ViewStub 替代在启动过程中不需要显示的 UI 控件。 1.3:使用自定义 View 替代复杂的 View 叠加。 2.主线程耗时操作 2.1:主线程中不要直接操作数据库,数据库的操作应该放在数据库线程中完成。 2.2:sharepreference尽量使用apply,少使用commit,可以使用MMKV框架来代替sharepreference。 2.3:网络请求回来的数据解析尽量放在子线程中,不要在主线程中进行复制的数据解析操作。 2.4:不要在activity的onResume和onCreate中进行耗时操作,比如大量的计算等。 2.5:不要在 draw 里面调用耗时函数,不能 new 对象 3.过度绘制 过度绘制是同一个像素点上被多次绘制,减少过度绘制一般减少布局背景叠加等方式,如下图所示右边是过度绘制的图片。 4.列表 RecyclerView使用优化,使用DiffUtil和notifyItemDataSetChanged进行局部更新等。 5.对象分配和回收优化 自从Android引入 ART 并且在Android 5.0上成为默认的运行时之后,对象分配和垃圾回收(GC)造成的卡顿已经显著降低了,但是由于对象分配和GC有额外的开销,它依然又可能使线程负载过重。 在一个调用不频繁的地方(比如按钮点击)分配对象是没有问题的,但如果在在一个被频繁调用的紧密的循环里,就需要避免对象分配来降低GC的压力。 减少小对象的频繁分配和回收操作。 好了,关于卡顿优化的问题就讲到这里,下篇文章会对卡顿中的ANR情况的处理,这里做个铺垫。 如果喜欢我的文章,欢迎关注我的公众号。 点击这看原文链接: 参考 Android卡顿检测及优化 一文读懂直播卡顿优化那些事儿 “终于懂了” 系列:Android屏幕刷新机制—VSync、Choreographer 全面理解! 深入探索Android卡顿优化(上) 西瓜卡顿 & ANR 优化治理及监控体系建设 5376)] 参考 Android卡顿检测及优化 一文读懂直播卡顿优化那些事儿 “终于懂了” 系列:Android屏幕刷新机制—VSync、Choreographer 全面理解! 深入探索Android卡顿优化(上) 西瓜卡顿 & ANR 优化治理及监控体系建设 本篇文章为转载内容。原文链接:https://blog.csdn.net/yuhaibing111/article/details/127682399。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-26 08:05:57
214
转载
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
lastlog
- 显示每个用户最后一次成功登录的时间和相关信息。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
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
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"