<p><strong><span style="text-wrap: nowrap;">SSH概述</span></strong><br/></p><p><span style="text-wrap: nowrap;">Secure Shell的缩写即为SSH,此网络安全协议是由IETF的网络小组(Network Working Group)制作修订的,SSH 为建立在应用层基础上的安全协议。SSH 相比较是可靠的,并且为远程登录</span><span style="text-wrap: nowrap;">会话以及其他的网络服务提供安全性的协议。利用 SSH 协议可以很有效地防止远程管理过程中的账号密码安全问题,SSH 最开始是在 UNIX 操作系统上的一个软件程序,后来快速发展至其他操</span></p><p><span style="text-wrap: nowrap;">作系统, SSH在正确使用时可弥补网络中的漏洞 SSH 客户端适用于多种平台,几乎所有 UNIX 平台包括 HP-UX、Linux、AIX、Solaris、Digital UNIX、Irix,且都可运行 SSH。</span></p><p><strong><span style="text-wrap: nowrap;">选择终端</span></strong><br/></p><p><span style="text-wrap: nowrap;">登录Linux服务器需要终端软件支持。</span><span style="text-wrap: nowrap;">大家可以选择自己比较习惯的终端,只要能正常输入ssh命令的软件都可以。</span><span style="text-wrap: nowrap;">比如:</span></p><ul class=" list-paddingleft-2" style="list-style-type: disc;"><li><p><span style="text-wrap: nowrap;">Windows自带的PowerShell</span></p></li><li><p><span style="text-wrap: nowrap;">Windows的Terminal</span></p></li><li><p><span style="text-wrap: nowrap;">自己下载的xshell软件</span></p></li><li><p><span style="text-wrap: nowrap;">Tabby软件</span></p></li><li><p><span style="text-wrap: nowrap;">git客户端</span></p></li><li><p><span style="text-wrap: nowrap;">编辑器自带的终端,如vscode等</span></p></li></ul><p><span style="text-wrap: nowrap;">简单地区分,只要你的终端,即命令行工作,能够支持ssh命令,即可以使用该终端登录远程服务器。</span></p><p><strong><span style="text-wrap: nowrap;">如何本地电脑 SSH 命令远程登录 Linux</span></strong><br/></p><p><span style="text-wrap: nowrap;">首先确保前面配置服务器处于开机状态,其次,需要保证开启了sshd服务,登录命令如下:</span><br/></p><pre class="brush:ps;toolbar:false">ssh -p port user@ip</pre><p><span style="text-wrap: nowrap;">Tips: 其中`-p port` 表示输入远程连接的端口号,一般默认为 22, `user` 表示登录用户名, `ip` 表示远程 Linux 系统的 ip 地址。</span></p><p><span style="text-wrap: nowrap;">测试:</span></p><p><span style="text-wrap: nowrap;">登录远程服务器:</span></p><pre class="brush:ps;toolbar:false">ssh root@182.92.223.149</pre><p><span style="text-wrap: nowrap;">这是一台阿里云服务器,安装的Linux系统版本为:CentOS</span></p>
文章列表
<p><strong><span style="text-wrap: nowrap;">确认虚拟机网络是否正常:</span></strong><br/></p><ul class=" list-paddingleft-2" style="list-style-type: disc;"><li><p><span style="text-wrap: nowrap;">虚拟机是否可以访问外网</span></p></li><li><p><span style="text-wrap: nowrap;">虚拟机是否与windows网络互通。</span></p></li></ul><p><strong><span style="text-wrap: nowrap;">查看ip:</span></strong></p><pre class="brush:ps;toolbar:false">ifconfig</pre><p><span style="text-wrap: nowrap;">提示命令未找到,安装net-tools:</span></p><pre class="brush:ps;toolbar:false">sudo apt install net-tools</pre><p><strong><span style="text-wrap: nowrap;">windows下查看IP:</span></strong></p><pre class="brush:ps;toolbar:false">ipconfig</pre><p><strong><span style="text-wrap: nowrap;">测试虚拟机是否可以访问外网:</span></strong></p><pre class="brush:ps;toolbar:false">ping www.baidu.com</pre><p><strong><span style="text-wrap: nowrap;">测试虚拟机与windows主机是否互通:</span></strong></p><p><span style="text-wrap: nowrap;">互相ping对方ip</span></p><p><span style="text-wrap: nowrap;">Windows power shell: </span><span style="text-wrap: nowrap;">ping 虚拟机ip;</span></p><p><span style="text-wrap: nowrap;">虚拟机:</span><span style="text-wrap: nowrap;">ping windows ip</span></p><p><strong><span style="text-wrap: nowrap;">将虚拟机的ip改为固定ip</span></strong><br/></p><p><span style="text-wrap: nowrap;">如果你的虚拟机每次重启的时候,ip地址可能会发生变化。当我们访问一个项目的时候,由于虚拟机的ip发生了变化,会导致项目访问不到的情况。</span></p><p><span style="text-wrap: nowrap;">这样操作会很麻烦,如果能把虚拟机的ip改成固定的就好了。</span><br/></p><p><span style="text-wrap: nowrap;">下面是修改的步骤:</span><br/></p><p><span style="text-wrap: nowrap;">第一步:在windows中打开cmd,使用ipconfig /all命令查看windows机器ip,如:10.1.53.218</span></p><p><span style="text-wrap: nowrap;">第二步:确认网卡设置为桥接网卡</span></p><p><span style="text-wrap: nowrap;">第三步:进入ubuntu桌面,点击右上角网络图标,点有线设置,如下图:</span></p><p><br/></p><p><img src="/uploads/images/20230212/409e5c3849fcfd30100c2f1754d43079.png" title="1.png" alt="" width="859" height="520"/></p><p><span style="text-wrap: nowrap;">第四步.设置ip,子网掩码,网关:</span></p><p><span style="text-wrap: nowrap;">1.切换到ipv4选项卡,ipv4,由自动改为手动。</span></p><p><span style="text-wrap: nowrap;">2.填写固定ip,如第一步查看到的windows的ip为**10.1.53.218**</span></p><p><span style="text-wrap: nowrap;">我们虚拟机这里的ip要保持和windows在一个网段,如设置为:10.1.53.132</span></p><p><span style="text-wrap: nowrap;">(与windows机器ip保持在同一网段,即前三位相同,最后一位填写1-255中间的一个值),</span></p><p><span style="text-wrap: nowrap;">3.子网掩码、网关与windows保持一致</span></p><p><span style="text-wrap: nowrap;">4.DNS填写114.114.114.114即可</span></p><p><span style="text-wrap: nowrap;">如图:</span></p><p><img src="/uploads/images/20240616/91601151da34a520b2cab5d5a1d9c2a7.png" title="image.png" alt=""/></p><p><span style="text-wrap: nowrap;">最后,重启虚拟机,再次输入ifconfig命令查看虚拟机ip,ip被设置为10.1.53.132,并使用'ping www.baidu.com'测试是否可以连网,如果有返回结果,即设置成功。以后再重启虚拟后,ip将</span></p><p><span style="text-wrap: nowrap;">保持固定不变。</span></p><p><br/></p>
<h5 style="color:red;">系统学习shopify开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/shopify_dev.html" target="_blank">《Shopify应用实战开发》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/shopify_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230612/03b58362c0718203696abbd7c748a136.jpg" alt="Shopify应用实战开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>这本小册将领您进入 Shopify 平台,学习开发出Shopify应用程序。作为全球最受欢迎的电子商务平台之一,Shopify 提供了一个强大的基础架构,让开发者可以创建个性化、功能丰富的在线商店。本课程将专注于 Shopify 应用开发,为您提供全面的指导和实践机会,打造功能齐全的app,帮助商家实现收益增长,作为个人开发者从中赚取收益。</p> </div> <hr><h5 style="color:red;">系统学习shopify开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/shopify_dev.html" target="_blank">《Shopify应用实战开发》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/shopify_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230612/03b58362c0718203696abbd7c748a136.jpg" alt="Shopify应用实战开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>这本小册将领您进入 Shopify 平台,学习开发出Shopify应用程序。作为全球最受欢迎的电子商务平台之一,Shopify 提供了一个强大的基础架构,让开发者可以创建个性化、功能丰富的在线商店。本课程将专注于 Shopify 应用开发,为您提供全面的指导和实践机会,打造功能齐全的app,帮助商家实现收益增长,作为个人开发者从中赚取收益。</p> </div> <hr><h5 style="color:red;">系统学习shopify开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/shopify_dev.html" target="_blank">《Shopify应用实战开发》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/shopify_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230612/03b58362c0718203696abbd7c748a136.jpg" alt="Shopify应用实战开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>这本小册将领您进入 Shopify 平台,学习开发出Shopify应用程序。作为全球最受欢迎的电子商务平台之一,Shopify 提供了一个强大的基础架构,让开发者可以创建个性化、功能丰富的在线商店。本课程将专注于 Shopify 应用开发,为您提供全面的指导和实践机会,打造功能齐全的app,帮助商家实现收益增长,作为个人开发者从中赚取收益。</p> </div> <hr><p><span style="color: rgb(77, 82, 89); font-family: "Microsoft YaHei", sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);">这门课程将带领您进入 Shopify 平台,学习开发出Shopify应用程序。作为全球最受欢迎的电子商务平台之一,Shopify 提供了一个强大的基础架构,让开发者可以创建个性化、功能丰富的在线商店。本课程将专注于 Shopify 应用开发,为您提供全面的指导和实践机会,打造功能齐全的app,帮助商家实现收益增长,作为个人开发者从中赚取收益。</span></p><p><span style="color: rgb(77, 82, 89); font-family: "Microsoft YaHei", sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);">shopify是一个独立站平台,类似于国内的淘宝,京东。商家可以在shopify平台开启自己的小店,打造自己的电子商务外贸平台。<br/></span></p><p><span style="color: rgb(77, 82, 89); font-family: "Microsoft YaHei", sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);">同时,为了方便商家打造自己独特的个性平台,shopify平台提供了二次开发功能。商家可以通过自己编程的方式,为自己的店铺添加功能,帮助平台增加销售。</span></p><p><span style="color: rgb(77, 82, 89); font-family: "Microsoft YaHei", sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);">shopify二次开发包含两个方向:shopify的app二次开发和shopify的店铺模板美化二次开发。</span></p><p><span style="color:#4d5259;font-family:Microsoft YaHei, sans-serif"><span style="background-color: rgb(255, 255, 255);">shopify是一款国外的平台,目前在国内关于技术方面的二次开发教程较少。因此,码小课平台为大家提供了专门的shopify二次开发教程。本教程以一本小册的形式,为大家介绍shopify二次开发一个app并将该app添加到自己的店铺的完整项目开发过程。同时,也可以将自己开发出来的app上传到shopify官方平台上上架销售,当其他商家安装了我们开发的shopify功能的app后,会给我们支付收益。我们可以在shopify平台上赠取收益。</span></span></p><p><span style="color:#4d5259;font-family:Microsoft YaHei, sans-serif"><span style="background-color: rgb(255, 255, 255);">本小册是国内唯一一部真正深入到shopify功能二次开发的教程。包含了shopify二次开发的完整流程,填补了国内shopify二次开发中文教程资料稀少的问题。</span></span></p><p><span style="color:#4d5259;font-family:Microsoft YaHei, sans-serif"><span style="background-color: rgb(255, 255, 255);">大家可以在码小课中学习该教程,本小册一共分为二十几章内容,从shopify创建店铺,到创建shopify项目代码,进行二次开发编写代码,最终将自己开发的app上线等完整功能。</span></span></p><p><span style="color:#4d5259;font-family:Microsoft YaHei, sans-serif"><span style="background-color: rgb(255, 255, 255);">通过这个shopify中文教程学会shopify的二次开发后,无论是想自己在shopify官方开店,给自己的店铺增加功能,还是单纯的以个人开发者名义开发shopify的app上架到shopify应用市场进行销售,赚取收益,都可以从这本shopify应用实战开发小册中掌握到全部技能。</span></span></p><p><span style="color:#4d5259;font-family:Microsoft YaHei, sans-serif"><span style="background-color: rgb(255, 255, 255);">最后,祝愿大家早日掌握shopify二次开发技能。</span></span></p><p><span style="color:#4d5259;font-family:Microsoft YaHei, sans-serif"><span style="background-color: rgb(255, 255, 255);">本小册链接地址如下,可以直接点击跳转学习:</span></span></p><p><a href="http://www.maxiaoke.com/manual/shopify_dev.html" target="_blank"><strong>shopify应用实战开发</strong></a><br/></p><p><br/></p>
<h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238);">一、数据压缩介绍</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">数据从服务器传输到客户端,需要传输时间,文件越大传输时间就越长,为了减少传输时间,我们一般把数据压缩后在传给客户端。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">apache支持两种压缩:deflate、gzip</p><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background: transparent; transition: all 0.3s linear 0s; outline: none !important;"></a>mod_gzip 和mod_deflate比较</h4><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">首先一个区别是安装它们的Apache Web服务器版本的差异。Apache 1.x系列没有内建网页压缩技术,所以才去用额外的第三方mod_gzip 模块来执行压缩。而Apache 2.x官方在开发的时候,就把网页压缩考虑进去,内建了mod_deflate 这个模块,用以取代mod_gzip。虽然两者都是使用的Gzip压缩算法,它们的运作原理是类似的。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">第二个区别是压缩质量。mod_deflate 压缩速度略快而mod_gzip 的压缩比略高。一般默认情况下,mod_gzip 会比mod_deflate 多出4%~6%的压缩量。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">那么,为什么使用mod_deflate?第三个区别是对服务器资源的占用。 一般来说mod_gzip 对服务器CPU的占用要高一些。mod_deflate 是专门为确保服务器的性能而使用的一个压缩模块,mod_deflate 需要较少的资源来压缩文件。这意味着在高流量的服务器,使用mod_deflate 可能会比mod_gzip 加载速度更快。</p><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background: transparent; transition: all 0.3s linear 0s; outline: none !important;"></a><strong style="box-sizing: border-box;">应用场景:数据压缩传输</strong></h4><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background: transparent; transition: all 0.3s linear 0s; outline: none !important;"></a><strong style="box-sizing: border-box;">优化目的:提升用户访问页面加载速度,节约带宽</strong></h4><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238);"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background: transparent; transition: all 0.3s linear 0s; outline: none !important;"></a>二、数据压缩实现</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">1)开启模块</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">LoadModule deflate_module modules/mod_deflate.so</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">2)调用模块</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">DeflateCompressionLevel 4</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-javascript application/x-httpd-php</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">AddOutputFilter DEFLATE js css</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">BrowserMatch \bMSIE\s[1-6] dont-vary</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">SetEnvIfNoCase Request_URI .(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">SetEnvIfNoCase Request_URI .(?:pdf|doc)$ no-gzip dont-vary</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;"><IfModule deflate_module> # 压缩等级 4 1-9,数字越大压缩的越好,也越占用CPU时间 DeflateCompressionLevel 4 # 压缩类型 html、xml、php、css、js AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-javascript application/x-httpd-php AddOutputFilter DEFLATE js css #浏览器匹配 IE1-6的不压缩 BrowserMatch \bMSIE\s[1-6] dont-vary #设置不压缩的文件,注意图片本身就是压缩过的,所以不需要再压缩 SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary SetEnvIfNoCase Request_URI .(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary SetEnvIfNoCase Request_URI .(?:pdf|doc)$ no-gzip dont-vary </IfModule></pre><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238);"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background: transparent; transition: all 0.3s linear 0s; outline: none !important;"></a>三、测试</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">1)生成HTML数据页面</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">for i in `seq 1 20`;do cat /etc/passwd >> /usr/local/apache/htdocs/test_deflate.htmldone</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">2)未启用压缩前通过浏览器访问该页面,通过开发者工具查看页面大小</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;"><img src="https://www.maxiaoke.com/uploads/images/20231230/96989d3e0f9fc03d9cb8f7566788784b.png" alt="" width="1145" height="656"/></p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;">3)启用压缩再次通过浏览器访问该页面,通过开发者工具查看页面大小,如果明显变小了则说明压缩成功。也可以从响应头中看出多了压缩字段。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;"><img src="https://www.maxiaoke.com/uploads/images/20231230/a43bc0eb502efe4f293d709c893b8c3d.png" alt="" width="1151" height="502"/></p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;"><img src="https://www.maxiaoke.com/uploads/images/20231230/a8697fe774807c14a91ef3d4c9fc3611.png" alt="" width="1136" height="764"/></p><p>上</p><p><br/></p>
<h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;">一、静态缓存介绍</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">用户每次访问网站都会将页面中的所有元素都请求一遍,全部下载后通过浏览器渲染,展示到浏览器中。但是,网站中的某些元素我们一般都是固定不变的,比如logo,框架文件等元。,用户每次访问都需要加载这些元素。这样做好处是保证了数据的新鲜,可是这些数据不是常变化的,很久才变化一次。每次都请求、下载浪费了用户时间和公司带宽。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">所以我们通过静态缓存的方式,将这些不常变化的数据缓存到用户本地磁盘,用户以后再访问这些请求,直接从本地磁盘打开加载,这样的好处是加载速度快,且节约公司带宽及成本。</p><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a><strong style="box-sizing: border-box;">应用场景:数据缓存</strong></h4><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a><strong style="box-sizing: border-box;">优化目的:提升用户访问页面加载速度,节约带宽</strong></h4><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>二、静态缓存实现</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">1)修改apache主配置文件,加载缓存模块</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">LoadModule expires_module modules/mod_expires.so</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">2)针对虚拟主机或者目录设置缓存策略</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;"><IfModule expires_module> #开启缓存 ExpiresActive on #针对不同类型元素设置缓存时间 ExpiresByType image/gif "access plus 1 days" ExpiresByType image/jpeg "access plus 24 hours" ExpiresByType image/png "access plus 24 hours" ExpiresByType text/css "now plus 2 hour" ExpiresByType application/x-javascript "now plus 2 hours" ExpiresByType application/x-shockwave-flash "now plus 2 hours” #其他数据不缓存 ExpiresDefault "now plus 0 min" </IfModule> 缓存起始点 access 从当前访问时间开始 now (equivalent to 'access') 相当于access modification 从修改时间算起 缓存时间单位 years months weeks days hours minutes seconds</pre><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>三、验证测试</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">缓存没有生效前</strong><br/><img src="https://www.maxiaoke.com/uploads/images/20231230/56b04d57f667a061ebea1ef833bc38b6.png" alt="" width="919" height="559"/></p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">缓存生效后测试</strong><br/><img src="https://www.maxiaoke.com/uploads/images/20231230/3892f40e922975685fc76138fb5cdb1c.png" alt="" width="920" height="775"/><br/>响应头中加载了缓存字段</p><p style="box-sizing: border-box; margin-top: 0px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap; margin-bottom: 0px !important;">Cache-control 和 Expires,并且缓存的时间和我们预设的一致,成功啦。</p><p><br/></p>
<p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;"><strong style="box-sizing: border-box;">案例需求</strong><br/>写一个程序,模拟KFC点餐系统,要求有以下功能:</p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em;" class=" list-paddingleft-2"><li><p>1、点餐功能</p></li><li><p>2、结算功能</p></li><li><p>3、打印流水单</p></li></ul><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;"><strong style="box-sizing: border-box;">案例步骤</strong></p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em;" class=" list-paddingleft-2"><li><p>1、交互点餐</p></li><li><p>2、结账收银</p></li><li><p>3、打印流水单给客户</p></li></ul><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;"><strong style="box-sizing: border-box;">案例代码</strong></p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">#!/bin/bash # #Author:www.zutuanxue.com # #Release: #Description: #1)录入单价 HBB=19.8 JC=12.3 KL=9.9 #2)定义输出 cat <<EOF welcome to KFC 今天KFC提供菜品如下: 1)汉堡 2)鸡翅 3)可乐 EOF echo -e "\n请您输入希望购买菜品的数量,不需要输入0\n" ###1.用户交互 #定义变量类型为整形 declare -i NUM_HBB declare -i NUM_JC declare -i NUM_KL read -p "汉堡: " NUM_HBB read -p "鸡翅: " NUM_JC read -p "可乐: " NUM_KL ###2.计算输出 HBB_price=`echo "scale=2;$HBB*$NUM_HBB"|bc` JC_price=`echo "scale=2;$JC*$NUM_JC"|bc` KL_price=`echo "scale=2;$KL*$NUM_KL"|bc` total_price=`echo "scale=2;$HBB_price+$JC_price+$KL_price"|bc` ###3.付款 echo -n "合计: $total_price " read -p "请付款: " USER_price ###4.打印小票 clear echo -e "\t\tKFC结算单" echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" echo -e "商品\t单价\t数量\t合计" echo -e "汉堡包\t$HBB\t$NUM_HBB\t$HBB_price" echo -e "鸡翅\t$JC\t$NUM_JC\t$JC_price" echo -e "可乐\t$KL\t$NUM_KL\t$KL_price" echo -e "\n\n" echo "总计: $total_price" echo -e "支付:$USER_price" echo -e "找零: `echo "scale=2;$USER_price-$total_price"|bc`" echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" echo -e "地址:北京东大桥路33号KFC店\n联系电话:400-123-456\nwww.kfc.com"</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px;"><strong style="box-sizing: border-box;">案例效果</strong></p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0px !important;"><img src="https://www.maxiaoke.com/uploads/images/20231230/6d68b3f528b66d82c1e094d122cad552.gif" alt=""/></p><p><br/></p><p><br/></p>
<p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">计算机编程就是三大步:输入、运算、输出</strong></p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">那么计算机运算有哪些呢,计算机能做哪些运算呢?</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">我们来看看常见的计算机运算</strong></p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>一、赋值运算</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">赋值运算符 =</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;"> a=10 name='baism' 重点:字符串必须用引号引起来</pre><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>二、算术运算[四则运算]</h2><h3 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.43; font-size: 1.5em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>2.1 运算符与命令</h3><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">四则运算符:</strong> + - <em style="box-sizing: border-box;">\ 【加减乘除】<br/><strong style="box-sizing: border-box;">扩展:</strong> % *</em> 【取余 开方】</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">运算命令:</strong></p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>整形运算<br/>– expr<br/>– let<br/>– $(())<br/>– bc</p></li><li><p>浮点运算<br/>– bc</p></li></ul><h3 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.43; font-size: 1.5em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>2.2 整形运算</h3><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">expr 命令:只能做整数运算,格式比较古板,注意空格</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[root@zutuanxue ~]# expr 1 + 1 2 [root@zutuanxue ~]# expr 5 - 2 3 [root@zutuanxue ~]# expr 5 \* 2 #注意*出现应该转义,否则认为是通配符 10 [root@zutuanxue ~]# expr 5 / 2 2 [root@zutuanxue ~]# expr 5 % 2 1</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">let命令:只能做整数运算,且运算元素必须是变量,无法直接对整数做运算</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[root@zutuanxue ~]# let a=100+3;echo $a 103 root@zutuanxue ~]# let a=100-3;echo $a 97 [root@zutuanxue ~]# let a=100/3;echo $a 33 [root@zutuanxue ~]# let a=100*3;echo $a 300 [root@zutuanxue ~]# let a=100%3;echo $a 1 [root@zutuanxue ~]# let a=100**3;echo $a 1000000 [root@zutuanxue ~]# a=100 [root@zutuanxue ~]# let a++;echo $a 101 [root@zutuanxue ~]# let a--;echo $a 100 [root@zutuanxue ~]# let a-=3;echo $a 97 [root@zutuanxue ~]# let a+=5;echo $a 102</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">双小圆括号运算,在shell中(( ))也可以用来做数学运算</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[root@zutuanxue ~]# echo $(( 100+3)) 103 [root@zutuanxue ~]# echo $(( 100-3)) 97 [root@zutuanxue ~]# echo $(( 100%3)) 1 [root@zutuanxue ~]# echo $(( 100*3)) 300 [root@zutuanxue ~]# echo $(( 100/3)) 33 [root@zutuanxue ~]# echo $(( 100**3)) #开方运算 1000000</pre><h3 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.43; font-size: 1.5em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>2.3 浮点运算</h3><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">浮点运算是采用的命令组合的方式来实现的 echo “scale=N;表达式”|bc</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[root@zutuanxue ~]# echo "scale=2;3+100"|bc 103 [root@zutuanxue ~]# echo "scale=2;100-3"|bc 97 [root@zutuanxue ~]# echo "scale=2;100/3"|bc 33.33 [root@zutuanxue ~]# echo "scale=2;100*3"|bc 300</pre><h3 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.43; font-size: 1.5em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>2.4、练习案例</h3><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>2.4.1 实现一个四则运算计算器</h4><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">案例思考:</strong> 计算器的功能: + - * \</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">实现步骤:</strong><br/>1、要求用户传输三个参数,num1 算术运算符 num2<br/>2、运算输出结果</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">实现代码</strong></p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">##03_calculator.sh #!/bin/bash # #Author: www.zutuanxue.com #Release: #Description: 简单计算器 echo "$1 $2 $3"|bc</pre><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>2.4.2 内存使用率统计,要求打印内存使用率</h4><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">案例思考:</strong></p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>物料1、内存总量 获得方式是什么 free top /proc/meminfo</p></li><li><p>物料2、内存使用量</p></li><li><p>物料3、内存使用率公式 使用量/总量*100%</p></li></ul><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">实现步骤:</strong></p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>1、获取内存总量</p></li><li><p>2、获取内存使用量</p></li><li><p>3、运算输出结果</p></li></ul><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">实现代码</strong></p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">#job实现代码 04_memory_use.sh #!/bin/bash # #Author: www.zutuanxue.com #Release: #Description:内存使用率计算脚本 #free #1、获得内存总量 memory_total=`free -m|grep -i "mem"|tr -s " "|cut -d " " -f2` #2、获得内存使用的量 memory_use=`free -m|grep -i "mem"|tr -s " "|cut -d " " -f3` #3、计算输出 #运算的时候是否需要小数点 浮点运算,要考虑使用的命令 (难点 重点) #echo "内存使用率: $((memory_use*100/memory_total))%" #难点:浮点运算中,同优先级的情况下,大数除以小数 尽可能保证精确 echo "内存使用率: `echo "scale=2;$memory_use*100/$memory_total"|bc`%"</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">实现效果</strong></p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">#运算结果[root@zutuanxue day2]# sh memory_use.sh Memory使用率: 2.61%</pre><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>三、比较运算</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">计算机除了算术和赋值运算外,还有比较运算,比如说比较两个数的关系,比较两个字符串的关系【用户登录系统】等。接下来我们学习如何在shell中进行比较运算</p><h3 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.43; font-size: 1.5em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>3.1、整形比较运算</h3><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;"> 运算符解释: 精确比较 -eq 等于 equal -gt 大于 -lt 小于 模糊比较 -ge 大于或等于 -le 小于或等于 -ne 不等于</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><strong style="box-sizing: border-box;">通过test命令比较两个整数关系</strong></p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[root@zutuanxue ~]# test 100 -gt 300;echo $? 1 [root@zutuanxue ~]# test 100 -ge 300;echo $? 1 [root@zutuanxue ~]# test 100 -eq 300;echo $? 1 [root@zutuanxue ~]# test 100 -le 300;echo $? 0 [root@zutuanxue ~]# test 100 -lt 300;echo $? 0 [root@zutuanxue ~]# test 100 -ne 300;echo $? 0 备注:linux命令test只能比较两个整数的关系,不会返回结果,需要通过$?才能看到结果</pre><h3 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.43; font-size: 1.5em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><br/><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a></h3>
<p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">只要不使用C的标准库函数,Go中是可以直接调用C和汇编语言的。其实道理很简单,Go的运行时库就是用C和汇编实现的,Go必须是能够调用到它们的。当然,会有一些额外的约束,这就是函数调用协议。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>Go中调用汇编</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">假设我们做一个汇编版本的加法函数。首先GOPATH的src下新建一个add目录,然后在该目录加入add.go的文件,内容如下:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">package add func Add(a, b uint64) uint64 { return a+b }</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这个函数将两个uint64的数字相加,并返回结果。我们写一个简单的函数调用它,内容如下:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">package main import ( "fmt" "add" ) func main() { fmt.Println(add.Add(2, 15)) }</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">可以看到输出了结果为17。好的,接下来让我们删除Add函数的实现,只留下定义部分:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">package add func Add(a, b uint64) uint64</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">然后在add.go同一目录中建立一个add_amd64.s的文件(假设你使用的是64位系统),内容如下:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">TEXT ·Add+0(SB),$0-24 MOVQ a+0(FP),BX MOVQ b+8(FP),BP ADDQ BP,BX MOVQ BX,res+16(FP) RET ,</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">虽然汇编是相当难理解的,但我相信读懂上面这段不会有困难。前两条MOVQ指令分别将第一个参数放到寄存器BX,第二个参数放到寄存器BP,然后ADDQ指令将两者相加后,最后的MOVQ和RET指令返回结果。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">现在,再次运行前面的main函数,它将使用自定义的汇编版本函数,可以看到成功的输出了结果17。从这个例子中可以看出Go是可以直接调用汇编实现的函数的。大多时候不必要你去写汇编,即使是研究Go的内部实现,能读懂汇编已经很足够了。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">也许你真的觉得在Go中写汇编很酷,但是不要忽视了这些忠告:</p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>汇编很难编写,特别是很难写好。通常编译器会比你写出更快的代码。</p></li><li><p>汇编仅能运行在一个平台上。在这个例子中,代码仅能运行在 amd64 上。这个问题有一个解决方案是给 Go 对于 x86 和 不同版本的代码分别写一套代码,文件名相应的以_386.s和_arm.s结尾。</p></li><li><p>汇编让你和底层绑定在一起,而标准的 Go 不会。例如,slice 的长度当前是 32 位整数。但是也不是不可能为长整型。当发生这些变化时,这些代码就被破坏了。</p></li></ul><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">当前Go编译器不能将汇编编译为函数的内联,但是对于小的Go函数是可以的。因此使用汇编可能意味着让你的程序更慢。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">有时需要汇编给你带来一些力量(不论是性能方面的原因,还是一些相当特殊的关于CPU的操作)。对于什么时候应该使用它,Go源码包括了若干相当好的例子(可以看看 crypto 和 math)。由于它非常容易实践,所以这绝对是个学习汇编的好途径。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>Go中调用C</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">接下来,我们继续尝试在Go中调用C,跟调用汇编的过程很类似。首先删掉前面的add_amd64.s文件,并确保add.go文件中只是给出了Add函数的声明部分:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">package add func Add(a, b uint64) uint64</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">然后在add.go同目录中,新建一个add.c文件,内容如下:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">#include "runtime.h" void ·Add(uint64 a, uint64 b, uint64 ret) { ret = a + b; FLUSH(&ret); }</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">编译该包,运行前面的测试函数:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">go install add</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">会发现输出结果为17,说明Go中成功地调用到了C写的函数。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">要注意的是不管是C或是汇编实现的函数,其函数名都是以·开头的。还有,C文件中需要包含runtime.h头文件。这个原因在该文件中有说明:<br/>Go用了特殊寄存器来存放像全局的struct G和struct M。包含这个头文件可以让所有链接到Go的C文件都知道这一点,这样编译器可以避免使用这些特定的寄存器作其它用途。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">让我们仔细看一下这个C实现的函数。可以看到函数的返回值为空,而参数多了一个,第三个参数实际上被作为了返回值使用。其中FLUSH是在pkg/runtime/runtime.h中定义为USED(x),这个定义是Go的C编译器自带的primitive,作用是抑制编译器优化掉对*x的赋值的。如果你很好奇USED是怎样定义的,可以去$GOROOT/include/libc.h文件里去找找。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">被调函数中对参数ret的修改居然返回到了调用函数,这个看起来似乎不可理解,不过早期的C编译器确实是可以这么做的。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>函数调用时的内存布局</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">Go中使用的C编译器其实是plan9的C编译器,和我们平时理解的gcc等会有一些区别。我们将上面的add.c汇编一下:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">go tool 6c -I $GOROOT/src/pkg/runtime -S add.c</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">生成的汇编代码大概是这个样子的:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">"".Add t=1 size=16 value=0 args=0x18 locals=0 000000 00000 (add.c:3) TEXT "".Add+0(SB),4,$0-24 000000 00000 (add.c:3) NOP , 000000 00000 (add.c:3) NOP , 000000 00000 (add.c:3) FUNCDATA $2,gcargs.0<>+0(SB) 000000 00000 (add.c:3) FUNCDATA $3,gclocals.1<>+0(SB) 000000 00000 (add.c:4) MOVQ a+8(FP),AX 0x0005 00005 (add.c:4) ADDQ b+16(FP),AX 0x000a 00010 (add.c:4) MOVQ AX,c+24(FP) 0x000f 00015 (add.c:5) RET , 000000 48 8b 44 24 08 48 03 44 24 10 48 89 44 24 18 c3 H.D$.H.D$.H.D$..</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">这是Go使用的汇编代码,是一种类似plan9的汇编代码。类似a+8(FP)这种表示的含义是“变量名+偏移(寄存器)”。其中FP是帧寄存器,它是一个伪寄存器,实际上是内存位置的一个引用,其实就是BP(栈基址寄存器)上移一个机器字长位置的内存地址。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">函数调用之前,a+8(FP),b+16(FP)分别表示参数a和b,而参数3的位置被空着,在被调函数中,这个位置将用于存放返回值。此时的其内存布局如下所示:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">参数3参数2参数1 <-SP</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">进入被调函数之后,内存布局如下所示:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">参数3参数2参数1 <-FP保存PC <-SP......</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">CALL指令会使得SP下移,SP位置的内存用于保存返回地址。帧寄存器FP此时位置在SP上面。在plan9汇编中,进入函数之后的前几条指令并没有出现<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">push ebp; mov esp ebp</code>这种模式。plan9函数调用协议中采用的是caller-save的模式,也就是由调用者负责保存寄存器。注意这和传统的C是不同的。传统C中是callee-save的模式,被调函数要负责保存它想使用的寄存器,在函数退出时恢复这些寄存器。</p><p style="box-sizing: border-box; margin-top: 0px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap; margin-bottom: 0px !important;">需要注意的是参数和返回值都是有对齐的。这里是按Structrnd对齐的,Structrnd在源代码中义为sizeof(uintptr)。</p><p><br/></p>
<p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">什么?nil是一种数据结构么?为什么会讲到它,没搞错吧?没搞错。不仅仅是Go语言中,每门语言中nil都是非常重要的,它代表的是空值的语义。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">在不同语言中,表示空这个概念都有细微不同。比如在scheme语言(一种lisp方言)中,nil是true的!而在ruby语言中,一切都是对象,连nil也是一个对象!在C中NULL跟0是等价的。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">按照Go语言规范,任何类型在未初始化时都对应一个零值:布尔类型是false,整型是0,字符串是””,而指针,函数,interface,slice,channel和map的零值都是nil。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>interface</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">一个interface在没有进行初始化时,对应的值是nil。也就是说<code style="box-sizing: border-box; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; font-size: 14px; color: rgb(232, 62, 140); overflow-wrap: break-word; padding: 3px; margin: 0px 4px 0px 5px; background: rgb(246, 246, 246); border-radius: 3px; border: 1px solid rgb(238, 238, 238);">var v interface{}</code>,</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">此时v就是一个nil。在底层存储上,它是一个空指针。与之不同的情况是,interface值为空。比如:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">var v *T var i interface{} i = v</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">此时i是一个interface,它的值是nil,但它自身不为nil。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">Go中的error其实就是一个实现了Error方法的接口:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">type error interface { Error() string }</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">因此,我们可以自定义一个error:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">type Error struct { errCode uint8 } func (e *Error) Error() string { switch e.errCode { case 1: return "file not found" case 2: return "time out" case 3: return "permission denied" default: return "unknown error" } }</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">如果我们这样使用它:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">func checkError(err error) { if err != nil { panic(err) } } var e *Error checkError(e)</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">e是nil的,但是当我们checkError时就会panic。请读者思考一下为什么?</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">总之,interface跟C语言的指针一样非常灵活,关于空的语义,也跟空指针一样容易困扰新手的,需要注意。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>string和slice</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">string的空值是””,它是不能跟nil比较的。即使是空的string,它的大小也是两个机器字长的。slice也类似,它的空值并不是一个空指针,而是结构体中的指针域为空,空的slice的大小也是三个机器字长的。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>channel和map</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">channel跟string或slice有些不同,它在栈上只是一个指针,实际的数据都是由指针所指向的堆上面。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">跟channel相关的操作有:初始化/读/写/关闭。channel未初始化值就是nil,未初始化的channel是不能使用的。下面是一些操作规则:</p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>读或者写一个nil的channel的操作会永远阻塞。</p></li><li><p>读一个关闭的channel会立刻返回一个channel元素类型的零值。</p></li><li><p>写一个关闭的channel会导致panic。</p></li></ul><p style="box-sizing: border-box; margin-top: 0px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap; margin-bottom: 0px !important;">map也是指针,实际数据在堆中,未初始化的值是nil。</p><p><br/></p>
<p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">上一节已经介绍了哈希表的基本原理并实现了一个基本的哈希表,而在实际项目中,<br/>对哈希表的需求远不止那么简单。对性能,灵活性都有不同的要求。下面我们看看PHP中的哈希表是怎么实现的。</p><h2 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 1em; font-weight: 300; line-height: 1.225; font-size: 1.75em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; padding-bottom: 0.5em; border-bottom: 1px solid rgb(238, 238, 238); color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>PHP的哈希实现</h2><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">PHP内核中的哈希表是十分重要的数据结构,PHP的大部分的语言特性都是基于哈希表实现的,<br/>例如:变量的作用域、函数表、类的属性、方法等,Zend引擎内部的很多数据都是保存在哈希表中的。</p><h3 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.43; font-size: 1.5em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>数据结构及说明</h3><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">上一节提到PHP中的哈希表是使用拉链法来解决冲突的,具体点讲就是使用链表来存储哈希到同一个槽位的数据,<br/>Zend为了保存数据之间的关系使用了双向链表来链接元素。</p><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>哈希表结构</h4><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">PHP中的哈希表实现在Zend/zend_hash.c中,还是按照上一小节的方式,先看看PHP实现中的数据结构,<br/>PHP使用如下两个数据结构来实现哈希表,HashTable结构体用于保存整个哈希表需要的基本信息,<br/>而Bucket结构体用于保存具体的数据内容,如下:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[c] typedef struct _hashtable { uint nTableSize; // hash Bucket的大小,最小为8,以2x增长。 uint nTableMask; // nTableSize-1 , 索引取值的优化 uint nNumOfElements; // hash Bucket中当前存在的元素个数,count()函数会直接返回此值 ulong nNextFreeElement; // 下一个数字索引的位置 Bucket *pInternalPointer; // 当前遍历的指针(foreach比for快的原因之一) Bucket *pListHead; // 存储数组头元素指针 Bucket *pListTail; // 存储数组尾元素指针 Bucket **arBuckets; // 存储hash数组 dtor_func_t pDestructor; // 在删除元素时执行的回调函数,用于资源的释放 zend_bool persistent; //指出了Bucket内存分配的方式。如果persisient为TRUE,则使用操作系统本身的内存分配函数为Bucket分配内存,否则使用PHP的内存分配函数。 unsigned char nApplyCount; // 标记当前hash Bucket被递归访问的次数(防止多次递归) zend_bool bApplyProtection;// 标记当前hash桶允许不允许多次访问,不允许时,最多只能递归3次 #if ZEND_DEBUG int inconsistent; #endif } HashTable;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">nTableSize字段用于标示哈希表的容量,哈希表的初始容量最小为8。首先看看哈希表的初始化函数:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[c] ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) { uint i = 3; //... if (nSize >= 0x80000000) { /* prevent overflow */ ht->nTableSize = 0x80000000; } else { while ((1U << i) < nSize) { i++; } ht->nTableSize = 1 << i; } // ... ht->nTableMask = ht->nTableSize - 1; /* Uses ecalloc() so that Bucket* == NULL */ if (persistent) { tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *)); if (!tmp) { return FAILURE; } ht->arBuckets = tmp; } else { tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *)); if (tmp) { ht->arBuckets = tmp; } } return SUCCESS; }</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">例如如果设置初始大小为10,则上面的算法将会将大小调整为16。也就是始终将大小调整为接近初始大小的<br/>2的整数次方。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">为什么会做这样的调整呢?我们先看看HashTable将哈希值映射到槽位的方法,上一小节我们使用了取模的方式来将哈希值<br/>映射到槽位,例如大小为8的哈希表,哈希值为100, 则映射的槽位索引为: 100 % 8 = 4,由于索引通常从0开始,<br/>所以槽位的索引值为3,在PHP中使用如下的方式计算索引:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[c] h = zend_inline_hash_func(arKey, nKeyLength); nIndex = h & ht->nTableMask;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">从上面的_zend_hash_init()函数中可知,ht->nTableMask的大小为ht->nTableSize -1。<br/>这里使用&操作而不是使用取模,这是因为是相对来说取模操作的消耗和按位与的操作大很多。</p><blockquote style="box-sizing: border-box; margin: 0px 0px 16px; border-left: 4px solid rgb(238, 238, 238); font-size: 14px; padding: 0px 15px 0px 20px; color: rgb(102, 102, 102); font-style: italic; font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0px;"><strong style="box-sizing: border-box;">NOTE</strong><br/>mask的作用就是将哈希值映射到槽位所能存储的索引范围内。 例如:某个key的索引值是21,<br/>哈希表的大小为8,则mask为7,则求与时的二进制表示为: 10101 & 111 = 101 也就是十进制的5。<br/>因为2的整数次方-1的二进制比较特殊:后面N位的值都是1,这样比较容易能将值进行映射,<br/>如果是普通数字进行了二进制与之后会影响哈希值的结果。那么哈希函数计算的值的平均分布就可能出现影响。</p></blockquote><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">设置好哈希表大小之后就需要为哈希表申请存储数据的空间了,如上面初始化的代码,<br/>根据是否需要持久保存而调用了不同的内存申请方法。如前面PHP生命周期里介绍的,是否需要持久保存体现在:持久内容能在多个请求之间访问,而非持久存储是会在请求结束时释放占用的空间。<br/>具体内容将在内存管理章节中进行介绍。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">HashTable中的nNumOfElements字段很好理解,每插入一个元素或者unset删掉元素时会更新这个字段。<br/>这样在进行count()函数统计数组元素个数时就能快速的返回。</p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">nNextFreeElement字段非常有用。先看一段PHP代码:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[php] <?php $a = array(10 => 'Hello'); $a[] = 'TIPI'; var_dump($a); // ouput array(2) { [10]=> string(5) "Hello" [11]=> string(5) "TIPI" }</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">PHP中可以不指定索引值向数组中添加元素,这时将默认使用数字作为索引,<br/>和<a href="http://en.wikipedia.org/wiki/Enumerated_type" style="box-sizing: border-box; color: rgb(51, 202, 187); text-decoration-line: none; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;">C语言中的枚举</a>类似,<br/>而这个元素的索引到底是多少就由nNextFreeElement字段决定了。<br/>如果数组中存在了数字key,则会默认使用最新使用的key + 1,例如上例中已经存在了10作为key的元素,<br/>这样新插入的默认索引就为11了。</p><h4 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.4; font-size: 1.25em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>数据容器:槽位</h4><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">下面看看保存哈希表数据的槽位数据结构体:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[c] typedef struct bucket { ulong h; // 对char *key进行hash后的值,或者是用户指定的数字索引值 uint nKeyLength; // hash关键字的长度,如果数组索引为数字,此值为0 void *pData; // 指向value,一般是用户数据的副本,如果是指针数据,则指向pDataPtr void *pDataPtr; //如果是指针数据,此值会指向真正的value,同时上面pData会指向此值 struct bucket *pListNext; // 整个hash表的下一元素 struct bucket *pListLast; // 整个哈希表该元素的上一个元素 struct bucket *pNext; // 存放在同一个hash Bucket内的下一个元素 struct bucket *pLast; // 同一个哈希bucket的上一个元素 // 保存当前值所对于的key字符串,这个字段只能定义在最后,实现变长结构体 char arKey[1]; } Bucket;</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">如上面各字段的注释。h字段保存哈希表key哈希后的值。这里保存的哈希值而不是在哈希表中的索引值,<br/>这是因为索引值和哈希表的容量有直接关系,如果哈希表扩容了,那么这些索引还得重新进行哈希在进行索引映射,<br/>这也是一种优化手段。<br/>在PHP中可以使用字符串或者数字作为数组的索引。<br/>数字索引直接就可以作为哈希表的索引,数字也无需进行哈希处理。h字段后面的nKeyLength字段是作为key长度的标示,<br/>如果索引是数字的话,则nKeyLength为0。在PHP数组中如果索引字符串可以被转换成数字也会被转换成数字索引。<br/><strong style="box-sizing: border-box;">所以在PHP中例如’10’,’11’这类的字符索引和数字索引10, 11没有区别。</strong></p><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">上面结构体的最后一个字段用来保存key的字符串,而这个字段却申明为只有一个字符的数组,<br/>其实这里是一种长见的<a href="http://stackoverflow.com/a/4690976/319672" style="box-sizing: border-box; color: rgb(51, 202, 187); text-decoration-line: none; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;">变长结构体</a>,主要的目的是增加灵活性。<br/>以下为哈希表插入新元素时申请空间的代码</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[c] p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); if (!p) { return FAILURE; } memcpy(p->arKey, arKey, nKeyLength);</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">如代码,申请的空间大小加上了字符串key的长度,然后把key拷贝到新申请的空间里。<br/>在后面比如需要进行hash查找的时候就需要对比key这样就可以通过对比p->arKey和查找的key是否一样来进行数据的<br/>查找。申请空间的大小-1是因为结构体内本身的那个字节还是可以使用的。</p><blockquote style="box-sizing: border-box; margin: 0px 0px 16px; border-left: 4px solid rgb(238, 238, 238); font-size: 14px; padding: 0px 15px 0px 20px; color: rgb(102, 102, 102); font-style: italic; font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0px;"><strong style="box-sizing: border-box;">NOTE</strong><br/>在PHP5.4中将这个字段定义成const char* arKey类型了。</p></blockquote><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">上图来源于<a href="http://gsm56.com/?p=124" style="box-sizing: border-box; color: rgb(51, 202, 187); text-decoration-line: none; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;">网络</a>。</p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>Bucket结构体维护了两个双向链表,pNext和pLast指针分别指向本槽位所在的链表的关系。</p></li><li><p>而pListNext和pListLast指针指向的则是整个哈希表所有的数据之间的链接关系。<br/>HashTable结构体中的pListHead和pListTail则维护整个哈希表的头元素指针和最后一个元素的指针。</p></li></ul><blockquote style="box-sizing: border-box; margin: 0px 0px 16px; border-left: 4px solid rgb(238, 238, 238); font-size: 14px; padding: 0px 15px 0px 20px; color: rgb(102, 102, 102); font-style: italic; font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;"><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 0px;"><strong style="box-sizing: border-box;">NOTE</strong><br/>PHP中数组的操作函数非常多,例如:array_shift()和array_pop()函数,分别从数组的头部和尾部弹出元素。<br/>哈希表中保存了头部和尾部指针,这样在执行这些操作时就能在常数时间内找到目标。<br/>PHP中还有一些使用的相对不那么多的数组操作函数:next(),prev()等的循环中,<br/>哈希表的另外一个指针就能发挥作用了:pInternalPointer,这个用于保存当前哈希表内部的指针。<br/>这在循环时就非常有用。</p></blockquote><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">如图中左下角的假设,假设依次插入了Bucket1,Bucket2,Bucket3三个元素:</p><ol style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>插入Bucket1时,哈希表为空,经过哈希后定位到索引为1的槽位。此时的1槽位只有一个元素Bucket1。<br/>其中Bucket1的pData或者pDataPtr指向的是Bucket1所存储的数据。此时由于没有链接关系。pNext,<br/>pLast,pListNext,pListLast指针均为空。同时在HashTable结构体中也保存了整个哈希表的第一个元素指针,<br/>和最后一个元素指针,此时HashTable的pListHead和pListTail指针均指向Bucket1。</p></li><li><p>插入Bucket2时,由于Bucket2的key和Bucket1的key出现冲突,此时将Bucket2放在双链表的前面。<br/>由于Bucket2后插入并置于链表的前端,此时Bucket2.pNext指向Bucket1,由于Bucket2后插入。<br/>Bucket1.pListNext指向Bucket2,这时Bucket2就是哈希表的最后一个元素,这是HashTable.pListTail指向Bucket2。</p></li><li><p>插入Bucket3,该key没有哈希到槽位1,这时Bucket2.pListNext指向Bucket3,因为Bucket3后插入。<br/>同时HashTable.pListTail改为指向Bucket3。</p></li></ol><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">简单来说就是哈希表的Bucket结构维护了哈希表中插入元素的先后顺序,哈希表结构维护了整个哈希表的头和尾。<br/>在操作哈希表的过程中始终保持预算之间的关系。</p><h3 style="box-sizing: border-box; margin-top: 0.3em; margin-bottom: 16px; font-weight: 300; line-height: 1.43; font-size: 1.5em; font-family: Raleway, 微軟正黑體, "Helvetica Neue", Helvetica, Arial, sans-serif; letter-spacing: 0.5px; position: relative; color: rgb(77, 82, 89); text-wrap: wrap;"><a class="reference-link" style="box-sizing: border-box; color: rgb(51, 202, 187); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; transition: all 0.3s linear 0s; outline: none !important;"></a>哈希表的操作接口</h3><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">和上一节类似,将简单介绍PHP哈希表的操作接口实现。提供了如下几类操作接口:</p><ul style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>初始化操作,例如zend_hash_init()函数,用于初始化哈希表接口,分配空间等。</p></li><li><p>查找,插入,删除和更新操作接口,这是比较常规的操作。</p></li><li><p>迭代和循环,这类的接口用于循环对哈希表进行操作。</p></li><li><p>复制,排序,倒置和销毁等操作。</p></li></ul><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">本小节选取其中的插入操作进行介绍。<br/>在PHP中不管是对数组的添加操作(zend_hash_add),还是对数组的更新操作(zend_hash_update),<br/>其最终都是调用_zend_hash_add_or_update函数完成,这在面向对象编程中相当于两个公有方法和一个公共的私有方法的结构,<br/>以实现一定程度上的代码复用。</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box; font-variant-numeric: normal; font-variant-east-asian: normal; font-variant-alternates: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-variant-position: normal; font-stretch: normal; font-size: 13.6px; line-height: 1.6; font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin-top: 0px; margin-bottom: 16px; overflow: auto; color: rgb(47, 111, 159); background-color: rgb(246, 246, 246); border: 1px solid rgb(238, 238, 238); padding: 10px; border-radius: 3px; overflow-wrap: break-word; text-wrap: wrap;">[c] ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC) { //...省略变量初始化和nKeyLength <=0 的异常处理 h = zend_inline_hash_func(arKey, nKeyLength); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { if ((p->h == h) && (p->nKeyLength == nKeyLength)) { if (!memcmp(p->arKey, arKey, nKeyLength)) { // 更新操作 if (flag & HASH_ADD) { return FAILURE; } HANDLE_BLOCK_INTERRUPTIONS(); //..省略debug输出 if (ht->pDestructor) { ht->pDestructor(p->pData); } UPDATE_DATA(ht, p, pData, nDataSize); if (pDest) { *pDest = p->pData; } HANDLE_UNBLOCK_INTERRUPTIONS(); return SUCCESS; } } p = p->pNext; } p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); if (!p) { return FAILURE; } memcpy(p->arKey, arKey, nKeyLength); p->nKeyLength = nKeyLength; INIT_DATA(ht, p, pData, nDataSize); p->h = h; CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]); //Bucket双向链表操作 if (pDest) { *pDest = p->pData; } HANDLE_BLOCK_INTERRUPTIONS(); CONNECT_TO_GLOBAL_DLLIST(p, ht); // 将新的Bucket元素添加到数组的链接表的最后面 ht->arBuckets[nIndex] = p; HANDLE_UNBLOCK_INTERRUPTIONS(); ht->nNumOfElements++; ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* 如果此时数组的容量满了,则对其进行扩容。*/ return SUCCESS; }</pre><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;">整个写入或更新的操作流程如下:</p><ol style="box-sizing: border-box; margin-bottom: 16px; padding: 0px 0px 0px 2em; color: rgb(77, 82, 89); font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif; text-wrap: wrap;" class=" list-paddingleft-2"><li><p>生成hash值,通过与nTableMask执行与操作,获取在arBuckets数组中的Bucket。</p></li><li><p>如果Bucket中已经存在元素,则遍历整个Bucket,查找是否存在相同的key值元素,如果有并且是update调用,则执行update数据操作。</p></li><li><p>创建新的Bucket元素,初始化数据,并将新元素添加到当前hash值对应的Bucket链表的最前面(CONNECT_TO_BUCKET_DLLIST)。</p></li><li><p>将新的Bucket元素添加到数组的链接表的最后面(CONNECT_TO_GLOBAL_DLLIST)。</p></li><li><p>将元素个数加1,如果此时数组的容量满了,则对其进行扩容。这里的判断是依据nNumOfElements和nTableSize的大小。<br/>如果nNumOfElements > nTableSize则会调用zend_hash_do_resize以2X的方式扩容(nTableSize << 1)。</p></li></ol><p><br/></p>