<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>smallyu feed</title>
  <subtitle>blog, blog-b, blog-crazy, old-blog, and microblog updates</subtitle>
  <link href="https://feed.smallyu.net/atom.xml" rel="self"/>
  <link href="https://feed.smallyu.net/"/>
  <updated>2026-08-12T02:52:50.338Z</updated>
  <id>https://feed.smallyu.net/</id>
  <author><name>smallyu</name></author>
  <entry>
    <title>预测市场生态的项目为什么难做</title>
    <link href="https://smallyu.net/2026/08/09/%E9%A2%84%E6%B5%8B%E5%B8%82%E5%9C%BA%E7%94%9F%E6%80%81%E7%9A%84%E9%A1%B9%E7%9B%AE%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9A%BE%E5%81%9A/"/>
    <id>blog:https://smallyu.net/2026/08/09/%E9%A2%84%E6%B5%8B%E5%B8%82%E5%9C%BA%E7%94%9F%E6%80%81%E7%9A%84%E9%A1%B9%E7%9B%AE%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9A%BE%E5%81%9A/</id>
    <published>2026-08-09T15:14:31.000Z</published>
    <updated>2026-08-09T15:14:12.911Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>前情提要：</p>
<ul>
<li>《<a]]></summary>
    <content type="html"><![CDATA[<p>前情提要：</p><ul><li>《<a href="https://b.smallyu.net/2026/05/27/%E6%9C%80%E8%BF%91%E5%A4%A7%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C/">最近大半年的工作</a>》2026-05-27</li><li>《<a href="/2026/06/29/%E4%B8%BA%E4%BB%80%E4%B9%88DM-KOL%E7%9A%84GTM%E7%AD%96%E7%95%A5%E4%B8%80%E5%AE%9A%E6%98%AF%E2%80%9C%E5%AF%B9%E2%80%9D%E7%9A%84/">为什么 DM KOL 的 GTM 策略一定是 “对” 的</a>》2026-06-29</li><li>《<a href="/2026/07/10/%E5%81%9APolymarket%E9%A1%B9%E7%9B%AE%E8%B8%A9%E7%9A%84%E5%9D%91/">做 Polymarket 项目踩的坑</a>》2026-07-10</li></ul><p>我会总结分析一下最近半年来，我们团队做项目遇到的种种困难。总的来说，现在项目仍然没有找到 PMF、没有达到用户自增长的状态。与以前的项目经历不同，我可以毫不掩饰地说这个项目的官网是：<a href="http://virae.ai/">http://virae.ai/</a></p><p>在这个项目上，团队一直在以最少的人员配置 + 最低的硬件成本去做。这种低成本主要也是为了试错。至少我是这么理解的。</p><h3 id="数据服务-VS-交易工具"><a href="#数据服务-VS-交易工具" class="headerlink" title="数据服务 VS 交易工具"></a>数据服务 VS 交易工具</h3><p>一开始想要切入预测市场、做一个预测市场生态上的项目时，我们就看到了一个<a href="https://x.com/pmx_trade/status/2008997887678820862?s=46">新闻</a>，一个叫 <a href="https://www.polycule.trade/">Polycule</a> 的 TG Bot 项目，算是 Polymarket 生态比较头部和知名的一个项目，因为服务器被黑客攻击、一度损失资金甚至传闻跑路，目前也已经改名换姓、整个产品换了方向。</p><p>当时忌惮这种托管私钥方面的安全问题，团队对于项目的约束是，不要做这种托管私钥类型的交易工具。</p><p>那么不做交易工具做什么呢？主要在这几个方向上徘徊：</p><ol><li>Alerting 类型，比如市场动态方面的告警、仓位提醒等，典型项目是 <a href="http://cryptocurrencyalerting.com/">Cryptocurrying Alerting</a>、<a href="https://polyalerthub.com/">PolyAlertHub</a></li><li>DexScreener 类型，聚合不同预测市场（Polymarket、Predict.fun、Kalshi 等）的事件、并且提供相似事件的对比分析，典型项目是 <a href="https://dexscreener.com/">DexScreener</a></li><li>Lookonchain 类型，分析挖掘链上数据、讲故事，典型项目是 <a href="https://x.com/lookonchain">Lookonchain</a></li></ol><p>另外还有一个团队自己发掘出来的方向：预测市场事件的语义搜索。因为无论是从 news 文本-&gt; 提醒，还是从链上数据-&gt; 提醒，都绕不开一个关键环节：怎么精确找到自己想找的事件？我看到一个特朗普的新闻，但是并不知道与这条新闻相关的预测市场事件是哪个、去哪里下注。</p><p>然后我告诉你为什么这几个方向没做起来：</p><ol><li>语义搜索方面，做了官网、试着做推广但是没下文、没有人用。服务器方面的成本，大概需要索引40 GB 左右的市场数据到数据库，包括 embedding 数据等用于检索。</li><li>DexScreener 方面，不同的预测市场平台会刻意避开事件相同、结算规则相同，以避免跨平台套利的行为发生。这一点和 Crypto Dex 的逻辑是不一样的，同一个 Crypto Token 会尽可能去多个平台上流通，而预测市场的事件都在各自的平台上维护。</li><li>Lookonchain 数据挖掘方面，需要很强的讲故事能力。看到数据不是重点，重点是需要把信息关联起来讲故事，这一点既需要数据分析能力，也需要小编来写内容，而不是纯程序分析出来的信号可以做到的。</li><li>Alerting 服务方面，看似轻量级，但是需要高速且不限速的 API 接口，或者自己索引链上数据。而如果自己索引链上数据，就免不了需要自建节点或者自建 SubGraph。</li></ol><p>我一开始提到我们在硬件投入上也是维持在低成本模式。有多低呢，现在整个 Virae 的后端服务器，一共用了 3 vCPU、6 GB 内存，100 GB 数据，在 AWS 上。</p><p>我并不是说这样的配置不够用，而是在这样的成本约束下，自建节点、自建 SubGraph 一类的服务自然是做不了的。举个直观的对比，运行一个以太坊节点的配置，是 8 vCPU、32 GB 内存、1 TB 磁盘、且要 IOPS 大于 10k 的固态硬盘。</p><h3 id="信息聚合终端"><a href="#信息聚合终端" class="headerlink" title="信息聚合终端"></a>信息聚合终端</h3><p>这是在可以做交易工具之后、首先比较看好的方向，比如用户需要在 NBA 相关赛事下注，需要同时打开 NBA 比赛以及 Polymarket 的事件下注页面。我们能不能做一个交易终端，同时展示体育赛事的信息、以及聚合 Polymarket 的下注交易能力？</p><p>这个方向上有明确的竞品，包括 Crypto 领域的 <a href="https://gmgn.ai/">GMGN</a>、<a href="https://axiom.trade/">Axiom</a>，预测市场领域的 <a href="https://betmoar.fun/">Betmoar</a>、<a href="https://ares.pro/">Areas</a>、<a href="https://www.stand.trade/">stand.trade</a>。</p><p>结果就是没有人用。</p><p>至于为什么没有人用，是我们一直都在反思但是不知道答案的问题。</p><p>顺便提一下，所有在 Polymarket 生态的项目，都在 Polymarket 的 Builder 榜单上。Polymarket 官方提供的榜单只有交易量总额，没有更多信息。因此我做了一个辅助网站 <a href="https://poly.dark20.xyz/">https://poly.dark20.xyz/</a> ，这些数据都是从 Polymarket 官方的公开接口拿到的，列出了每一个项目方的交易额、交易人数、甚至具体的每一笔交易的详情。由于交易接口方面的约束，同赛道的项目方一定都在这个榜单上，反之，不在这个榜单上的项目方一定不是 Polymarket 生态的项目。</p><h3 id="Copy-Trading-Bot"><a href="#Copy-Trading-Bot" class="headerlink" title="Copy Trading Bot"></a>Copy Trading Bot</h3><p>在 Crypto 领域有很多 TG Bot，提供 snipe 代币的功能，或者很简便的贴一个代币的 CA 地址就可以开始交易。那么在预测市场是否需要一种 copy trading bot 来一键复制别人的交易行为呢？</p><p>比较头部的竞品很多，做的也都不错，除了之前提到的 <a href="https://www.polycule.trade/">Polycule</a>、还有 <a href="https://polycop.ai/">PolyCop</a>、<a href="https://kreo.app/">Kreo</a>、<a href="https://polybot.trading/">PolyBot</a> 等。</p><p>结果也是没有人用。</p><p>至于为什么没有人用，能找到一些原因：</p><ol><li>如果要做到0区块延迟的跟单速度，需要自建节点、监听 mempool 里的交易、然后跟单。上文提到，自建节点需要一笔硬件成本的投入。</li><li>马太效应，越是头部的 bot 越有人用，越是小的 bot 越没有人用。</li><li>运营能力，我们没有人具备运营 X 账号、其他平台发广告推广的能力。</li></ol><h3 id="电脑端-VS-手机端"><a href="#电脑端-VS-手机端" class="headerlink" title="电脑端 VS 手机端"></a>电脑端 VS 手机端</h3><p>世界杯期间，项目准备了一些预算做活动，交易就给钱那种，来了不少来自印度的撸毛用户。当时有一个发现，大多数用户都是在手机上操作，要么在手机浏览器里打开网页，要么在 TG bot 里操作。很少有用电脑直接操作。</p><p>这一点和我们的预期有很大偏差，因为一直以来，都是在做专业的交易终端，而交易终端一定是电脑网页，也因此几乎没有刻意做什么移动端的适配。</p><p>再后来，又关注到一个用户数量很多的项目 <a href="https://polym.trade/">polymtrade</a>，是一个手机 App，在苹果商店能搜到那种。这个项目页面非常简陋、而且不支持高频交易，但是月活跃交易用户在1000以上、交易额在百万美元以上。我调查过，这个项目没有融资背景、只有 3 个开发者。</p><p>所以我们后来一方面优化移动端网页、另一方面适配了 TG Mini App，希望用户可以直接在 TG 上面打开 Mini App、就能拥有完整的体验。</p><p>结果也是依然没有人用。</p><h3 id="高频交易-VS-低频交易"><a href="#高频交易-VS-低频交易" class="headerlink" title="高频交易 VS 低频交易"></a>高频交易 VS 低频交易</h3><p>高频交易就是给专业交易员操作用的，比如现在下单后、看 K 线、发现几秒钟的动量、马上操作卖出，或者同时挂很多订单、止盈止损、频繁操作。这种就要求界面操作要流畅、下单速度要快、交易反馈要准确。与之相应的，技术难度高。</p><p>低频交易是指那些佛系散户，比如今天看到什么新闻、想去某个事件上下一单、明天想起来就又下一单、下单之后也不看 K 线也不看流动性、甚至不操作不卖出，就纯粹等半年后的结算。</p><p>这两种交易频率的不同，也是产品方向上的分歧。高频交易注定使用者专业、数量少、交易量大。低频交易也许用户量多、但是交易量会很少。</p><p>有研究报告指出，整个 Polymarket 有80%的散户交易总额在100美元以下。而且这是整个 Polymarket 生态的，其中 Polymarket 官网的交易人数和交易量占了90%左右，留给第三方项目方的交易量只有10%。（研究报告原文找不到了，大概是这个数字，你不相信的话可以让 AI 重新调研一次。）</p><p>这个数据如果靠谱的话，那么 Polymarket 生态的项目会过得比较惨。看起来预测市场的交易量和收入年年新高，但是跟第三方项目方有什么关系呢？</p><h3 id="再做一个官网"><a href="#再做一个官网" class="headerlink" title="再做一个官网"></a>再做一个官网</h3><p>随着项目功能越做越多，后来逐渐发现一个误区：再做一个官网。</p><p>当时正是世界杯，Polymarket 和 Kalshi 都出了 combo 交易的功能，我们就在看能不能从接口接入这种 combo 交易的能力。后来发现官方提供的 API 不支持。</p><p>这就导致一个尴尬的现象：专业的交易终端本应该是功能增强版本的 Polymarket，结果 Polymarket 出了新功能、第三方交易终端跟不上！</p><p>这也突然带来一个警醒：Polymarket 是中心化平台、不是去中心化协议！</p><p>CLOB v1 版本的时候也许还能看到一点去中心化的影子，自从 CLOB v2 之后，就实锤 Polymarket 是中心化平台了，毫无疑问。</p><p>也因此后来 Polymarket 出了 perps 交易的功能，我们根本不去看能不能接入了。接入了也没人用。</p><p>再后来，Kalshi 还出了官网版本的交易终端 Kalshi Pro，杀死比赛。</p><p>总之再做一个官网绝对是行不通的方向。</p><h3 id="Agentic-Trading"><a href="#Agentic-Trading" class="headerlink" title="Agentic Trading"></a>Agentic Trading</h3><p>后来看 Agentic Trading 的方向比较火，很多交易所相继出了这方面的功能，我们也开始往自动交易、代理交易方向转型。转型的结果就是，目前平台上支持 BTC&#x2F;ETH 的 15m&#x2F;1h 市场的尾盘策略，可以配置参数一键启动。这个方向上目前看到最直接的竞品是 <a href="https://pm.evplus.ai/">EVPLUS</a>。</p><p>这里有一个考量在于，是做执行工具还是做策略？执行工具就是用户自己设定策略参数、我们只管执行；做策略就是我们找到稳健的策略或者策略参数、推荐给用户运行。对于用户来说，肯定是希望直接给策略，而对于项目方来说，因为考虑到策略风险，只能是做工具比较稳妥。</p><p>并且我诚实的告诉你，我们的项目也没有 edge；不但我们的项目没有，而且我可以负责任的告诉你，我们的竞品 EVPLUS 也没有，因为它的策略源码是公开的。</p><p>然后为了推广现在的这个 Auto Trade 功能，还开发了针对 Auto Trade 的 Paper Trading 账户和排行榜，希望做一场活动、让用户免费参与、最终 PNL 高的用户可以获得 100 USD 的奖励、培养用户习惯。</p><p>原本计划明天周一开始这个模拟盘交易大赛活动的，后来一个团队外部的成员，以命令式的语气、在没有经过团队讨论的情况下、就直接告诉运营人员推迟这个模拟盘交易大赛的活动。也因此我现在甚至不知道这个活动还搞不搞、什么时候开始。（你会不会没看懂，什么叫团队外的 “成员”？）</p><h3 id="单一领域-VS-多领域聚合"><a href="#单一领域-VS-多领域聚合" class="headerlink" title="单一领域 VS 多领域聚合"></a>单一领域 VS 多领域聚合</h3><p>事实证明经过了预测市场的大热点世界杯，我们在预测市场辅助工具这个方向上没有做起来。后来又开始考虑做更多领域的集成，比如前段时间看 Robinhood Chain 比较火，就集成了 Robinhood 的 Memecoins 交易。</p><p>再后来又看到 Robinhood Chain 上有一个叫 <a href="https://slvr.fun/">SLVR</a> 的链上游戏很火、交易量很高，我就直接把他们公开的合约源码拿下来、自己开发前后端、直接出了一个类似的仿盘出来 <a href="https://c.dark20.xyz/">VORE</a>（只是演示，千万不要玩）。这个 VORE 是为了证明我们能做出和 SLVR 一样的链上游戏。同时也在考虑 SLVR 这种游戏的玩法有没有什么 Virae 能够借鉴的。</p><p>总之就是这个阶段已经不局限于预测市场，而是开始打 Memecoins 或者其他链上热点项目的主意了。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>为什么我现在可以做这样一个总结呢，因为你能看到，我们尝试了各种各样的产品方向，结果都不太尽人意。我作为开发者的角度，已经没有灵感下一步还能做什么了。因为很明显，不管做什么新功能，都不会有更多人来用，这已经不是开发层面的问题。</p><p>我其实之前反复跟团队说一个道理，如果 100 个用户进来了、用着不好用、功能有 bug、走了，那是产品或者开发的问题，我们就可以去优化产品、修复 bug、提高用户留存率。但事实上是，根本没有 100 个用户进来，连来都没有来。所以问题在哪里？</p>]]></content>
  </entry>
  <entry>
    <title>想坐船吹海风 想看流星雨 想看极光 想去长江 想去韩国日本荷兰 想留学做海龟 想住别墅 想财富自由</title>
    <link href="https://t.smallyu.net/#2026-14"/>
    <id>micro:5225714751</id>
    <published>2026-08-08T10:31:25Z</published>
    <updated>2026-08-08T15:55:04Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想坐船吹海风 想看流星雨 想看极光 想去长江 想去韩国日本荷兰 想留学做海龟 想住别墅 想财富自由</p>]]></summary>
    <content type="html"><![CDATA[<p>想坐船吹海风
想看流星雨
想看极光
想去长江
想去韩国日本荷兰
想留学做海龟
想住别墅
想财富自由</p>
]]></content>
  </entry>
  <entry>
    <title>突然有个疑问，连自己今天晚饭吃什么都预测不了的普罗大众，凭什么觉得自己能在预测市场上，预测中世界级别的随机事件？</title>
    <link href="https://t.smallyu.net/#2026-13"/>
    <id>micro:5225162722</id>
    <published>2026-08-08T07:39:16Z</published>
    <updated>2026-08-08T07:39:16Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>突然有个疑问，连自己今天晚饭吃什么都预测不了的普罗大众，凭什么觉得自己能在预测市场上，预测中世界级别的随机事件？</p>]]></summary>
    <content type="html"><![CDATA[<p>突然有个疑问，连自己今天晚饭吃什么都预测不了的普罗大众，凭什么觉得自己能在预测市场上，预测中世界级别的随机事件？</p>
]]></content>
  </entry>
  <entry>
    <title>炒币、炒股，有一个重要的前提是：目标价位是多少。 比如在 65000 买了 BTC，心理预期价位是 20万，那么就一直拿...</title>
    <link href="https://t.smallyu.net/#2026-12"/>
    <id>micro:5224424583</id>
    <published>2026-08-08T04:07:11Z</published>
    <updated>2026-08-08T04:07:11Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>炒币、炒股，有一个重要的前提是：目标价位是多少。 比如在 65000 买了 BTC，心理预期价位是 20万，那么就一直拿着、甚至加仓。 但是如果在 110 买了 SpacX，现在涨到了 130，卖不卖？因为没有一个目标价格，所以会迷茫。</p>]]></summary>
    <content type="html"><![CDATA[<p>炒币、炒股，有一个重要的前提是：目标价位是多少。
比如在 65000 买了 BTC，心理预期价位是 20万，那么就一直拿着、甚至加仓。
但是如果在 110 买了 SpacX，现在涨到了 130，卖不卖？因为没有一个目标价格，所以会迷茫。</p>
]]></content>
  </entry>
  <entry>
    <title>PySonar2 如何帮助 AI 节省 Token</title>
    <link href="https://smallyu.net/2026/08/03/PySonar2%E5%A6%82%E4%BD%95%E5%B8%AE%E5%8A%A9AI%E8%8A%82%E7%9C%81Token/"/>
    <id>blog:https://smallyu.net/2026/08/03/PySonar2%E5%A6%82%E4%BD%95%E5%B8%AE%E5%8A%A9AI%E8%8A%82%E7%9C%81Token/</id>
    <published>2026-08-02T16:32:47.000Z</published>
    <updated>2026-08-09T04:36:03.375Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>今天有一个 “重大” 发现想要分享：<a]]></summary>
    <content type="html"><![CDATA[<h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>今天有一个 “重大” 发现想要分享：<a href="https://github.com/yinwang0/pysonar2">PySonar2</a> 可以大幅度降低 AI 在执行 Python 项目修改的时候的 Token 消耗。</p><p>这是 ChatGPT 运行出来的 benchmark 结果：</p><img src="1.png" width="80%"><p>补充一下这个 benchmark 任务的定义：</p><img src="2.png" width="55%"><p>具体任务有 2 个：</p><img src="3.png" width="100%"><p>概括来说，就是基于一个测试专用的大型 Python 项目，设定两个方向的任务，一个任务横跨多个目录和文件，另一个任务目标明确、不需要跨文件定义，然后分别用 skill 和不用 skill 执行。</p><p>结果如你所见，使用了 skill 之后，速度略微有提高，token 消耗量则直接减少 30%！</p><h3 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h3><p>说明一下，刚才提到的 skill，是指基于 PySonar2 源码封装的、符合 AI Skills 规范的 skill，你可以直接告诉 ChatGPT：</p><blockquote><p>帮我安装这个 skill 到用户级目录：<a href="https://github.com/smallyunet/pysonar2">https://github.com/smallyunet/pysonar2</a></p></blockquote><p>就可以了。</p><p>这个 PySonar2 的仓库是 fork 出来的，因为原版的 PySonar2 仓库是王垠 13 年前的项目，已经有一些工程和特性方面的 “过时”，所以做了一点点新的工程方面的包装。当然 PySonar2 最核心的词法分析、类型推断是没有过时的。</p><p>除了这个 AI skill，我还把 PySonar2 以 VS Code 插件的形式发布了，安装后可以在 VS Code 上打开 Python 代码之后，鼠标 hover 上去看到 PySonar2 的类型推断：</p><ul><li>插件链接：<a href="https://marketplace.visualstudio.com/items?itemName=smallyu.pysonar2-code-intelligence">PySonar2 Code Intelligence</a></li></ul><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>解释一下为什么 PySonar2 可以帮助 AI 节省。</p><p>如果你是程序员并且经常让 AI 写代码，一定会看到 AI 会使用大量的 <code>rg</code>，每一次任务都会把各种代码文件看一遍，然后继续执行代码修改。而 PySonar2 可以提供一种基于代码语义的、基于 AST 结构分析出来的这种内容：</p><pre><code class="json">&#123;  &quot;symbol&quot;: &quot;User&quot;,  &quot;definitions&quot;: [    &#123;&quot;file&quot;: &quot;models.py&quot;, &quot;startLine&quot;: 12&#125;  ],  &quot;references&quot;: [    &#123;&quot;file&quot;: &quot;service.py&quot;, &quot;startLine&quot;: 48&#125;,    &#123;&quot;file&quot;: &quot;tests/test_service.py&quot;, &quot;startLine&quot;: 31&#125;  ],  &quot;affectedFiles&quot;: [    &quot;models.py&quot;,    &quot;service.py&quot;,    &quot;tests/test_service.py&quot;  ]&#125;</code></pre><p>直接在一个文件里把每个变量定义的来龙去脉、相关源码文件总结出来。相当于本地建立了一个索引，AI 直接看索引，而不需要每次看一遍全部代码。</p><p>因为任何 AI 工具目前都有两方面限制：</p><ol><li>使用 AI 要花费 Token，Token 就是钱。省 Token 就是省钱</li><li>所有基于 Transformer 架构的 AI 模型，都有上下文限制。这种建立索引的做法可以节省上下文空间</li></ol><h3 id="对比"><a href="#对比" class="headerlink" title="对比"></a>对比</h3><p>那么 PySonar2 现在是否还具有某些独特的价值呢？答案是有：</p><img src="4.png" width="90%"><p>很多同类型的、号称节省 Token 的项目，都是基于关键词匹配、甚至 embedding 的匹配，与 PySonar2 的语义分析不在一个层面。</p><p>不过毕竟已经过去了 13 年，PySonar2 已经 13 年没有在学术理论上继续更新，要说 PySonar2 仍然处于世界前沿是不可能的。但是 PySonar2 因为开源、代码轻量、逻辑清晰，在 Agent 适配方面也许会有独特的优势和潜力：</p><img src="5.png" width="90%"><h3 id="启发"><a href="#启发" class="headerlink" title="启发"></a>启发</h3><h4 id="1-Python-语言只是开始"><a href="#1-Python-语言只是开始" class="headerlink" title="1. Python 语言只是开始"></a>1. Python 语言只是开始</h4><p>既然针对 Python 项目，PySonar2 可以帮助 AI 节省大量的 Token 消耗，那么其他语言的项目呢？JavaScript 是否可以借鉴同样的思路？以及更多脚本语言？同样的思路，已经不局限于 PySonar2 这个工具了。</p><h4 id="2-帮助-AI-节省-Token"><a href="#2-帮助-AI-节省-Token" class="headerlink" title="2. 帮助 AI 节省 Token"></a>2. 帮助 AI 节省 Token</h4><p>比起让 PySonar2 这个古老的项目重新发挥价值，我更在意的事情是：在 AI 时代，还有哪些代码工具是有价值的？</p><p>因为人已经不需要写代码了，甚至不需要看代码了。但是 PySonar2 在这个场景下发挥了巨大的作用，让我看到了不一样的希望：</p><ol><li>帮助 AI 节省 Token 是一个好的工具方向。</li></ol><p>（与此同时，我还在优化另外一个项目：<a href="https://smallyu.net/2025/05/11/%E6%83%B3%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E6%9C%80%E5%B0%8FEVM%E8%99%9A%E6%8B%9F%E6%9C%BA/">EchoEVM</a>。基于 EchoEVM 的 EVM 解释器底座，让 AI 能够在编写 Solidity 脚本的时候、有能力看到脚本文件字节码级别的执行过程。这种 debug 工具对人类没什么用，但是对于 AI 极其有用，因为人类看不懂字节码、AI 可以）</p><ol start="2"><li>底层原理在 AI 时代不会过时。</li></ol><p>PySonar2 作为拥有学术级别原理的工具，在人类已经不需要写代码的今天，仍然能够发挥价值、让 AI 节省 Token、给使用者省钱，这是真正意义上的效率工具。</p><h3 id="相关阅读"><a href="#相关阅读" class="headerlink" title="相关阅读"></a>相关阅读</h3><p>如果你不了解 PySonar2 的背景，分享几篇相关文章可以看一下：</p><ul><li>《<a href="https://smallyunet.github.io/yinwang-blog/blog-cn_2013_10_06_sourcegraph_20140513.html">PySonar 的第二个用户</a>》</li><li>《<a href="https://smallyunet.github.io/yinwang-blog/blog-cn_2013_10_29_pysonar2_20161011.html">PySonar2 开源了</a>》</li><li>《<a href="https://www.yinwang.org/posts/pysonar2-sg">PySonar2 与 Sourcegraph 集成完毕</a>》</li><li>《<a href="https://smallyunet.github.io/yinwang-blog/blog-cn_2013_06_21_pysonar-slides_20130725.html">PySonar 的工作原理</a>》</li></ul><h3 id="更新（2026-08-09）"><a href="#更新（2026-08-09）" class="headerlink" title="更新（2026.08.09）"></a>更新（2026.08.09）</h3><p>要补充说明的是，原文中对于节省 40% 的 Token 消耗，仅限于某些特定的、大量跨文件、变量名重叠、语义不清晰的任务。经过后来更丰富的测试，最新的 <a href="https://github.com/smallyunet/pysonar2/blob/main/docs/agent-skill-benchmark.md">benchmark 结果</a> 显示，很多通用任务中，如果强制使用 Pysonar2，消耗的 Token 和时长反而是增加的。不过由于 PySonar2 提供的精准语义分析能力，在 benchmark 中使用了 PySonar2 的准确率能达到 100%，给 AI 提供语义级别的事实证据是 Pysonar2 目前对于 AI 最明确的增强。</p><p>至于 “先给代码建立语义索引、修改代码直接使用索引” 的方式是否能够提交效率、节省 Token，我后来创建了单独的项目 <a href="https://github.com/smallyunet/code-engram">code-engram</a> 来进一步测试。目前 code-engram 主要支持 TypeScript 以及适配了 Pysonar2，唯一正向的 benchmark 数据是，在大型项目的 rename 任务中，Token 消耗节省 60%。但是对于小型项目或者其他通用任务，Token 消耗反而是增加的。这一点和 Pysonar2 单个仓库的结果类似。所以 code-engram 这个项目也仍然在继续探索中……</p>]]></content>
  </entry>
  <entry>
    <title>数据： 建一个比特币矿场需要 3000万美元 建一个 AI 算力中心需要 5亿美元</title>
    <link href="https://t.smallyu.net/#2026-11"/>
    <id>micro:5105460608</id>
    <published>2026-07-28T14:29:03Z</published>
    <updated>2026-07-28T14:29:03Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>数据： 建一个比特币矿场需要 3000万美元 建一个 AI 算力中心需要 5亿美元</p>]]></summary>
    <content type="html"><![CDATA[<p>数据：</p>
<ol>
<li>建一个比特币矿场需要 3000万美元</li>
<li>建一个 AI 算力中心需要 5亿美元</li>
</ol>
]]></content>
  </entry>
  <entry>
    <title>一个比特币 Taproot 脚本漏洞开始的调查</title>
    <link href="https://smallyu.net/2026/07/28/%E4%B8%80%E4%B8%AA%E6%AF%94%E7%89%B9%E5%B8%81Taproot%E8%84%9A%E6%9C%AC%E6%BC%8F%E6%B4%9E%E5%BC%80%E5%A7%8B%E7%9A%84%E8%B0%83%E6%9F%A5/"/>
    <id>blog:https://smallyu.net/2026/07/28/%E4%B8%80%E4%B8%AA%E6%AF%94%E7%89%B9%E5%B8%81Taproot%E8%84%9A%E6%9C%AC%E6%BC%8F%E6%B4%9E%E5%BC%80%E5%A7%8B%E7%9A%84%E8%B0%83%E6%9F%A5/</id>
    <published>2026-07-27T16:50:05.000Z</published>
    <updated>2026-07-28T05:41:19.708Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h3><p>在 bitcointalk 上看到一个帖子：<a]]></summary>
    <content type="html"><![CDATA[<h3 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h3><p>在 bitcointalk 上看到一个帖子：<a href="https://bitcointalk.org/index.php?topic=5588964.0">How to handle weak scripts?</a></p><p>这个帖子说明了一种 Taproot 脚本的漏洞，无需经过签名验证，任何人都可以花费在这个 UTXO 上的余额。在 mempool 浏览器的界面上可以清晰看到，这笔 <a href="https://mempool.space/tx/f460443ee5b2bff69b9f299e31e1258f01a023555de5a63cd2d10c4ead0a5bc2"><code>f460...5bc2</code></a> 交易转出的一方有一个 unsigned 的标识，这个标识在比特币网络上并不多见：</p><img src="1.png" width="100%"><p>帖子中描述的 Taproot 脚本的逻辑是这样，这也是 <code>f460...5bc2</code> 交易真实执行的脚本过程：</p><pre><code class="bash">OP_PUSHBYTES_32 fa9b5ec193f735c41b804fc6ace1d28e81a299fc815c0f5009dd2dd7d0293c3bOP_CHECKSIGOP_IFOP_PUSHBYTES_32 ff1275b635cd160914cfe1bc516f521abde0fc8ae3fd92ae01ca16449e4758e9OP_ENDIF</code></pre><p>可以简化为：</p><pre><code class="bash">&lt;pubkey A&gt;OP_CHECKSIGOP_IF    &lt;pubkey B&gt;OP_ENDIF</code></pre><p>比特币的 Taproot 是基于栈结构的脚本，理解起来需要绕弯，把这个脚本翻译为 JavaScript 代码的话，大概是这个意思：</p><pre><code class="js">function isTrue(...params)&#123;  var pubkeyA = params[-1];  params--;  if (checkSign(pubkeyA))  &#123;    return true;  &#125;  else  &#123;    //  &#125;  return params[-1];&#125;</code></pre><p>从代码来看，在正常使用流程下，假如输入的参数是 <code>[pubkeyA]</code>，那么 <code>checkSign(pubkeyA)</code> 为 true，最终 <code>return true</code>，这个是合理的。</p><p>假如输入的参数是 <code>[pubkeyC]</code>，那么 <code>checkSign(pubkeyA)</code> 为 <code>false</code>，下面的 else 分支什么都不做，最终 <code>return null</code>，依然不是 <code>true</code>，这个也合理。</p><p>这个脚本的漏洞在哪里呢，在于 params 是一个数组，用户未必只输入一个参数。</p><p>在漏洞逻辑下，可以输入非预期的参数组合 <code>[true, pubkeyC]</code>，那么按照后面的执行流程，当进入 else 分支什么都不做之后，<code>return params[0]</code> 会把 <code>true</code> 给返回出来。</p><p>这里面存在几个基础的问题：</p><ol><li>代码没有处理 else 分支</li><li>比特币的 Taproot 脚本没有类型检查（只有操作码）</li><li>脚本作者没有正确理解 Taproot 脚本的写法，忽略了 witness 可以提交任意数量的参数</li></ol><h3 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h3><p>所以很简单，这个所谓的脚本漏洞，实际上是作者自己写了不严谨的代码导致的。要注意这里指的不是比特币的作者，仅仅只是比特币的用户。比特币的 Taproot 相当于以太坊的智能合约，任何人都可以写一些脚本规则，来决定钱怎么控制、怎么花。只不过比特币的脚本写起来复杂，而且不是图灵完备，所以很多人忽略了比特币可以自己写脚本这件事情。</p><p>很明显这不是一个比特币协议级别的漏洞，比特币的共识只负责按照脚本规则正确执行，而脚本逻辑是否有漏洞，跟协议无关。</p><p>而且事实上无论是比特币钱包还是比特币生态的项目，如果依赖于 Taproot 的脚本逻辑，一定会经过审计公司来审核代码，这种低级错误出现在主网上的情况恐怕会非常少。</p><p>另外 Taproot 这种脚本设计的隐私性其实很强，我们只能知道比特币地址 <code>bc1p</code> 开头是 Taproot 脚本，<code>0xc0</code> 开头的是当前版本号，但是一个 UTXO 在没有被花费之前，网络上是无法看到脚本具体内容的。而在被花费的那一刻，大概率全部的钱都已经被转走了。一个 P2TR UTXO 被创建的时候，链上只保存这棵树结构的根节点哈希，任何可以解锁 root 的路径都是有效输入，这些有效输入只有在花费的时候，链上才需要根据具体的 leaf 和 key path 去验证。而且即使某一个 leaf 被公开，链上也只能看到其中一个，看不到同一个 root 下的其他 leaf。</p><p>比特币从设计之初，就提倡每一笔转账都使用一个新的地址，实际上大多数靠谱的钱包也是这么设计的，这本身就很大程度规避了漏洞脚本被再次利用的风险。</p><p>所以无论是从技术上和商业逻辑上，这种漏洞脚本的出现都是极其小概率的个例，完全就是脚本作者自己写错了。主网上存在漏洞脚本的可能性很小。</p><h3 id="调查"><a href="#调查" class="headerlink" title="调查"></a>调查</h3><h4 id="示例地址"><a href="#示例地址" class="headerlink" title="示例地址"></a>示例地址</h4><p>有没有可能网路上真的存在这种漏洞脚本，不需要验证签名就可以把钱转走的？</p><p>先从 <a href="https://mempool.space/address/bc1p78u5v2rgsu7gf79yw5c85fs3da0hfsw25ht5tr6p3mvh5wvmck6qpxcn8z"><code>bc1p...cn8z</code></a> 这个例子入手，有几个问题：</p><ol><li>假如这个地址上还有钱，要怎么转出？</li></ol><p>这显然不是钱包 App 提供的功能，而且比特币的交易比较麻烦，得把 UTXO 来源的交易和编号都作为参数才能构造出交易。这是一个示例脚本 <a href="./taproot-script-path-demo.mjs">taproot-script-path-demo.mjs</a>，可以这样来运行：</p><pre><code class="bash">TXID=&#39;0618d93bc4eef77f4b47c4b4b188011f95c7ccb929e6226df2774b88b5d4693d&#39;VOUT=&#39;0&#39;INPUT_SATS=&#39;15000&#39;DESTINATION=&#39;bc1px6jn77jd4tplp94q46svkuutc53wtn24dk34wxp4dfur6tvez89swvlcmj&#39;FEE_SATS=&#39;1000&#39;node outputs/taproot-script-path-demo.mjs \  &quot;$TXID&quot; \  &quot;$VOUT&quot; \  &quot;$INPUT_SATS&quot; \  &quot;$DESTINATION&quot; \  &quot;$FEE_SATS&quot;</code></pre><p>如果你不小心把钱打到了地址 <code>bc1p...cn8z</code> 上，就可以用这个脚本，在没有私钥的情况下，把钱转出来。但是要小心脚本里的 <code>xOnlyKey</code> 和 <code>payload</code> 都是硬编码，如果换一个目标地址，这两个值就不一样了，得用另外的值。那么这个值应该是什么呢？这个值只有在 P2TR 被花费过之后才能知道。</p><p>这也就意味着，即使我们知道链上某一个地址有余额、脚本有漏洞，因为不知道整个树结构、拿不到 xOnlyKey 和 payload 的值，我们也无法动这个地址上的钱。从这个角度看，比特币上的资产安全程度还是很高的。</p><ol start="2"><li>有没有可能这个作者把钱转给了某一个有同样漏洞的 P2TR，但是忘了转出？</li></ol><p>同样有一个示例脚本来干这个事情：<a href="./audit-taproot-neighborhood.mjs">audit-taproot-neighborhood.mjs</a>，结果就是，没有。这个作者把全部关联地址的钱都转走了，不存在这种低级漏洞。</p><h4 id="扫描全网"><a href="#扫描全网" class="headerlink" title="扫描全网"></a>扫描全网</h4><p>这个程序可以扫描整个比特币网络上类似的脚本漏洞：<a href="https://github.com/smallyunet/tapscript_weak_finder">tapscript_weak_finder</a></p><p>扫描逻辑是这样：</p><ol><li>逐个区块扫描每一笔交易，判断是不是 Taproot Script 且 version 为 <code>0xc0</code></li><li>这个程序里实现了一个非常轻量的解释器，用来处理 witness 参数</li><li>会分别用 3 种参数策略来测试脚本是否可以不需要签名也能通过</li><li>直接用 <code>[01, &lt;empty signatrue&gt;]</code> 的排列组合，处理 0 个参数、1 个参数、2 个参数的情况，一共 12 种</li><li>把 atom 从 <code>01</code>, <code>&lt;empty signatrue&gt;</code>，扩展到小整数和一些常量，比如 <code>02</code>, <code>03</code>, <code>true</code>, <code>false</code> 等</li><li>对于已经公开执行过的 witness 参数比如 <code>[[data, sigA, sigB]]</code>，尝试变换组合，比如 <code>[data, &quot;&quot;, sigB]</code>、<code>[data, sigA, &quot;&quot;]</code> 等</li><li>如果程序发现了不需要签名的脚本、一定返回 <code>OP_SUCCESS80</code>的脚本，或者目前规范还没有定义的公钥类型，会记录到数据库</li></ol><h4 id="扫描结果"><a href="#扫描结果" class="headerlink" title="扫描结果"></a>扫描结果</h4><p>当然我会告诉你运行结果。如果你运行了这个开源程序，会得到和我一样的结果和结论。我的启动参数是从区块高度 <code>709632</code> 开始，这是比特币主网启用 Taproot 的高度，到 <code>959701</code> 高度结束，也就是最新的区块高度。</p><p>一共扫描了 71037 个区块，扫描了 127119410 笔交易，扫描到 1000061 个 Taproot 地址，其中 427378 个属于当前程序没识别出问题的脚本，12 是有可能有漏洞的弱脚本。</p><p>在 12 个有可能有漏洞的脚本中，8 个属于不需要签名的弱脚本，1 个属于始终返回 <code>OP_SUCCESS80</code> 的非漏洞脚本，3 个属于包含扫描程序解释器不支持操作码的非漏洞脚本。</p><h4 id="结果分析"><a href="#结果分析" class="headerlink" title="结果分析"></a>结果分析</h4><p>来逐个分析一下扫描到的有可能是 weak script 的交易。最终输出的、未经加工的结果数据在这个文件：<a href="./result_report.json">result_report.json</a>，可以还原出我下面提到的地址和交易、脚本。</p><h5 id="1"><a href="#1" class="headerlink" title="1"></a>1</h5><p>首先扫描到的这个 taproot 地址出现在 758737 区块：<a href="https://mempool.space/address/bc1pnwu7l0wln4c2l5av9nhsz968yd4alyyr9futpr6h6yfe7pa2jxzshv2354"><code>bc1p...2354</code></a></p><p>这个地址出现了 2 笔异常交易：</p><ul><li><a href="https://mempool.space/tx/00c1af8f7d9e2bfe854d1718db078eb6740920f702bc00d4a9f205d3a084c40e"><code>00c1...c40e</code></a></li><li><a href="https://mempool.space/tx/73be398c4bdc43709db7398106609eea2a7841aaf3a4fa2000dc18184faa2a7e"><code>73be...2a7e</code></a></li></ul><p>先说结论，这 2 笔交易是非常专业的开发者在演示比特币主网的 BIP342 规范而发起的。</p><p>第一笔交易 <code>00c1...c40e</code> 包含 2 个 witness 参数，是用来测试交易的。</p><p>第二笔交易 <code>73be...2a7e</code> 就离谱了，包含 500001 个 witness 参数，<code>OP_RETURN</code> 的内容解码后得到 “you’ll run cln. and you’ll be happy.” 的文本。</p><p>TapScript 的规定是，初始栈最多只能有 1000 个元素，但是第二笔交易出现了 500001 个元素而且交易成功了，是因为 BIP342 规范定义，如果脚本中出现 <code>OP_SUCCESSx</code>，则无论脚本包含多少元素，一律视作成功。因为 <code>OP_SUCCESSx</code> 属于目前还未明确支持、但是预留给未来有可能使用的操作码，所以 BIP342 这样来规定了。</p><p>很明显第二笔交易就是用来演示这种状况的。也因为这笔交易包含大量参数，花费了超过 700 美元的手续费。</p><h5 id="2"><a href="#2" class="headerlink" title="2"></a>2</h5><p>其次扫描到的地址出现在 771740 区块；</p><ul><li><a href="https://mempool.space/address/bc1pzmc9a8uczft74n2s0lakz7jgmfn3jmgpd8wnqg2eyn8mev25cccsne648w"><code>bc1p...648w</code></a></li><li><a href="https://mempool.space/address/bc1p2y390fnxvgevhwx5v47amhzm4e347vkckksusc30z0z6zq8f62hqc2u69a"><code>bc1p...u69a</code></a></li><li><a href="https://mempool.space/address/bc1pkntn5g8mg9fwf32xwj52e0vx9gaxv5zzn4yt54saaaj8x825a43qu3n6cl"><code>bc1p...n6cl</code></a></li></ul><p>这 3 个脚本对应的交易包含了 <code>OP_CHECKSEQUENCEVERIFY</code> 操作码，扫描程序没有处理这个操作码，所以认为是异常给挑出来了。<code>OP_CHECKSEQUENCEVERIFY</code> 操作码的含义是，必须等待多少个区块，才可以使用地址里的资金。属于是典型的 TimeLock 脚本。</p><h5 id="3"><a href="#3" class="headerlink" title="3"></a>3</h5><p>在区块高度 775722，扫描到了这个地址：<a href="https://mempool.space/address/bc1p9zpp682rerqscftc98kn7g3yne08mkte27eletq3w9kdw8q3prcqqaamq6"><code>bc1p...amq6</code></a></p><p>这是一个真正有逻辑漏洞的脚本，不需要任何签名就可以转移资金。这个脚本明显是一个 Ordinals 数据结构的封装，可能是某个开发者在尝试自己开发类似 Ordinals 的协议。当然这个地址上的钱当时就被全部转走了，现在没有余额。</p><p>另外还有几个地址，数量不多，大多数是 Ordinals 的测试交易，就不一一详细解释了：</p><ul><li><a href="https://mempool.space/address/bc1p07d0z7drxkewne2z665xngf8rtnga9p32wl957zwtd96n89qja2sch3hu0"><code>bc1p...3hu0</code></a>，区块高度 777335，一个 Ordinals PNG 图片</li><li><a href="https://mempool.space/address/bc1pna0qxzm3z8vwre6h6vv5fh6m7pc5e9pk3nqtfxd77zad4jm8c25q88xgdr"><code>bc1p...xgdr</code></a>，区块高度 777617，一个加法运算，没有校验签名</li><li><a href="https://mempool.space/address/bc1p395qvu3zaehjrvek9nqjkdd785f379y7zsjesy0p8vugd7gkr94qd7gq7d"><code>bc1p...gq7d</code></a>，区块高度 777681，一个测试脚本，固定返回 true</li><li><a href="https://mempool.space/address/bc1pmqpwg3gh5dcaepz2ttuet7vtdtug23zpjz93p7e902jv582nudcqk09x3t"><code>bc1p...9x3t</code></a>，一个 Ordinals 的 Hello World 脚本</li><li>…</li></ul><h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>已经扫描了从 Taproot 脚本功能上线到至今为止全部的区块和交易，真的出现了少量 <a href="https://bitcointalk.org/index.php?topic=5588964.0">How to handle weak scripts?</a> 中描述的类似的脚本漏洞，不过那些地址上都已经没有余额了。</p><p>这件事情另外的启发：</p><ol><li>比特币网络是否存在更复杂类型的脚本漏洞？</li><li>以太坊的脚本漏洞是否可以用类似的手段扫描？</li></ol>]]></content>
  </entry>
  <entry>
    <title>ETH Killer 都被 ETH Layer2 杀死了。说明对于 PoS 链，大家根本不在乎它是不是去中心化。</title>
    <link href="https://t.smallyu.net/#2026-10"/>
    <id>micro:5078389470</id>
    <published>2026-07-25T11:55:06Z</published>
    <updated>2026-07-25T11:55:06Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>ETH Killer 都被 ETH Layer2 杀死了。说明对于 PoS 链，大家根本不在乎它是不是去中心化。</p>]]></summary>
    <content type="html"><![CDATA[<p>ETH Killer 都被 ETH Layer2 杀死了。说明对于 PoS 链，大家根本不在乎它是不是去中心化。</p>
]]></content>
  </entry>
  <entry>
    <title>不要用 hackmd.io</title>
    <link href="https://crazy.smallyu.net/2026/07/21/%E4%B8%8D%E8%A6%81%E7%94%A8hackmd-io/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/07/21/%E4%B8%8D%E8%A6%81%E7%94%A8hackmd-io/</id>
    <published>2026-07-21T10:59:34.000Z</published>
    <updated>2026-07-21T11:04:00.428Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>工具官网：<a href="https://hackmd.io/">https://hackmd.io/</a></p>
<p>一开始为什么会用呢，因为看到以太坊的团队在用，以太坊发布 weekly news 以及那个 ops panda]]></summary>
    <content type="html"><![CDATA[<p>工具官网：<a href="https://hackmd.io/">https://hackmd.io/</a></p><p>一开始为什么会用呢，因为看到以太坊的团队在用，以太坊发布 weekly news 以及那个 ops panda 团队内部沟通都在用。</p><p>但是今天我发现 hackmd.io 会擅自取消我 publish 公开的文章、以及擅自删除我的文件内容：</p><img src="1.png" width="90%"><img src="2.png" width="90%"><p>这已经不单纯是平台内容审核的问题了。内容审核你可以不 public 我的文章，但是擅自给我内容删了、在 version history 里看到的是我自己清空了内容，这算怎么回事？</p><p>所以比起 hackmd.io 比起来，还不如直接用 github 的 wiki 或者 gist。</p>]]></content>
  </entry>
  <entry>
    <title>突然想起来一个小事。曾经有一个运营人员，给我们的项目反馈是 “太卡了”，没有任何更多的信息和细节。 这样的描述真的太主观...</title>
    <link href="https://t.smallyu.net/#2026-9"/>
    <id>micro:5014731946</id>
    <published>2026-07-19T06:39:30Z</published>
    <updated>2026-07-19T06:39:30Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>突然想起来一个小事。曾经有一个运营人员，给我们的项目反馈是 “太卡了”，没有任何更多的信息和细节。 这样的描述真的太主观、太模糊了，作为技术人员根本无从下手。至少得说一下在什么设备上、访问哪个页面、网络状态如何、具体哪个组件、卡顿的现象是样式错位还是加载延迟或者别的什么。 这不是在对非技术人员提过分的要求。你可以这么想...</p>]]></summary>
    <content type="html"><![CDATA[<p>突然想起来一个小事。曾经有一个运营人员，给我们的项目反馈是 “太卡了”，没有任何更多的信息和细节。</p>
<p>这样的描述真的太主观、太模糊了，作为技术人员根本无从下手。至少得说一下在什么设备上、访问哪个页面、网络状态如何、具体哪个组件、卡顿的现象是样式错位还是加载延迟或者别的什么。</p>
<p>这不是在对非技术人员提过分的要求。你可以这么想，去大街上随便拉一个人过来，没有读过书、没有文化、没有学历、没有工作、没有职场经验、没有收入，随便一个人，是不是都能说得出 “太卡了” 这三个字？而作为一个混迹于职场、身处 web3 行业的资深牛马，竟然说出了是个人都能说出的话？你和 anybody 的区别在哪里？</p>
]]></content>
  </entry>
  <entry>
    <title>不要用自动雨伞</title>
    <link href="https://crazy.smallyu.net/2026/07/17/%E4%B8%8D%E8%A6%81%E7%94%A8%E8%87%AA%E5%8A%A8%E9%9B%A8%E4%BC%9E/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/07/17/%E4%B8%8D%E8%A6%81%E7%94%A8%E8%87%AA%E5%8A%A8%E9%9B%A8%E4%BC%9E/</id>
    <published>2026-07-17T09:55:14.000Z</published>
    <updated>2026-07-17T09:55:41.927Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>自动雨伞是指那种，按一下会自动弹开、再按一下会自动收起（但不会自动把弹簧压回来那种）。</p>
<p>最大的风险是很危险。</p>
<p>这种伞很容易坏，第一次用是公司发的一个定制款，第二次用是买的小米挂牌的雨伞。</p>
<p>结果小米的反而更不耐用，两三天就坏了。</p]]></summary>
    <content type="html"><![CDATA[<p>自动雨伞是指那种，按一下会自动弹开、再按一下会自动收起（但不会自动把弹簧压回来那种）。</p><p>最大的风险是很危险。</p><p>这种伞很容易坏，第一次用是公司发的一个定制款，第二次用是买的小米挂牌的雨伞。</p><p>结果小米的反而更不耐用，两三天就坏了。</p><p>我怀疑坏掉最大的原因是我拎着那个挂绳一直甩着转圈。</p><p>但是这不重要，你肯定说轻拿轻放就不行了吗。</p><p>但是说明这种伞从设计之初就没有考虑好各种情况。</p><p>而且在伞坏掉的那一刻，大概率是你解开绳子、伞会自动弹出来的一刻。这一刻毫无疑问会打伤你自己的手指。更加严重的话，会弹开伤到你对面的人，或者路人。</p><p>所以以后，应该只用非自动的雨伞，也就是以前那种手动打开手动关闭的雨伞。</p><p>不要过于相信自动化。</p>]]></content>
  </entry>
  <entry>
    <title>人的成功有两种。一种是一下子做对了一件很大的事情。另一种是连续做对了很多小事。</title>
    <link href="https://t.smallyu.net/#2026-8"/>
    <id>micro:4992205265</id>
    <published>2026-07-16T13:06:10Z</published>
    <updated>2026-07-16T13:06:10Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>人的成功有两种。一种是一下子做对了一件很大的事情。另一种是连续做对了很多小事。</p>]]></summary>
    <content type="html"><![CDATA[<p>人的成功有两种。一种是一下子做对了一件很大的事情。另一种是连续做对了很多小事。</p>
]]></content>
  </entry>
  <entry>
    <title>我从王垠的计算机科学课学到了什么（一年版）</title>
    <link href="https://b.smallyu.net/2026/07/16/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%884/"/>
    <id>blog-b:https://b.smallyu.net/2026/07/16/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%884/</id>
    <published>2026-07-16T11:59:44.000Z</published>
    <updated>2026-07-17T06:30:51.763Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>一年时间过去了，刚才和 ChatGPT 简单聊了一下我以前对王垠老师课程的评价，以及现在经过了一整年的时间后，我对于课程的体会和感受。以下内容是 ChatGPT]]></summary>
    <content type="html"><![CDATA[<p>一年时间过去了，刚才和 ChatGPT 简单聊了一下我以前对王垠老师课程的评价，以及现在经过了一整年的时间后，我对于课程的体会和感受。以下内容是 ChatGPT 帮我写的总结：</p><ul><li>以前的评价</li></ul><blockquote><p>王垠的计算机科学课程，对我来说不只是一门普通的编程课，更像是一套关于编程和计算机科学的核心训练。</p><p>我过去虽然有多年工程经验，也做过不少区块链相关的技术工作，但这些知识和经验一直是零散的。我可以把事情做出来，可以写出能运行的代码，却缺少一套完整的体系，不知道自己掌握的知识处在什么位置，也不知道真正扎实的计算机基础是什么样子。</p><p>这门课程像是一张完整的地图，把我过去散落在工作和学习中的经验重新组织起来。很多以前模糊理解、但说不清楚的东西，在课程中变得清晰。它让我看到，真正的编程不只是掌握语法、框架和工程技巧，而是理解递归、抽象、数据结构、程序求值和计算模型背后的思想。</p><p>课程最重要的价值，也不只是教会了某些具体知识，而是让我见识到了高水平的计算机课程应该是什么样子。课程内容高度精炼、层层递进，用很少的编程要素表达了非常丰富的思想。通过练习，我也第一次真正感受到，“代码能够运行”和“代码真正写对、写得简洁优雅”之间存在很大的差距。</p><p>学完课程以后，我对自己的技术能力有了新的认识。我不再因为没有接受过系统的计算机教育而感到不安，也不再担心自己因为做了某种具体工作，就偏离了程序员的道路。只要掌握了这些核心的计算思维，无论以后使用什么语言、进入什么技术方向，都仍然拥有继续学习和前进的基础。</p><p>它像一颗定心丸，也像一次迟到的系统教育。它没有替代我过去多年的工作经验，而是在恰当的时候，把这些经验真正整理和“生产”了出来。</p></blockquote><ul><li>现在的评价</li></ul><blockquote><p>接近一年后再回头看，王垠的计算机科学课程仍然是一门质量很高的课程，但我对它的价值有了更清楚、更克制的认识。</p><p>这门课最大的优势，在于内容高度精炼、体系完整，能够抓住编程和计算思维中的关键问题。很多单独的知识点，在其他教材、课程和工程实践中也能接触到，但王垠把这些内容组织成了一条连贯的学习路径，让学习者能够看到主干，知道不同概念之间的联系，而不是在大量语言、框架和技术细节中零散摸索。</p><p>对于初学者来说，它可以提前提供一张地图，减少很多不必要的弯路。对于已经有工程经验的程序员来说，它更像一次经验整理：很多能力本来就会在长期工作中逐渐形成，只是通常比较零散、缺少名称，也没有清晰的整体结构。课程的作用，是把这些经验组织起来，让人看清自己已经走过哪些路，还缺少哪些部分。</p><p>对我个人而言，它最重要的价值，是帮助我补足了对计算机基础的长期不安，建立了信心，也让我真正见识过一套高水平、成体系的课程是什么样子。它没有直接改变我的工作方式，没有直接解决职业、产品和收入问题，也没有像我刚学完时想象的那样，成为一种能够解释所有技术问题的核心心法。</p><p>在 AI 已经可以完成大量编码工作的时代，课程中的很多具体训练，未必会直接转化为日常生产力。程序员越来越不需要亲手完成大量局部代码，但仍然需要理解程序背后的状态、抽象、语义和执行过程。课程在这方面仍然有价值，只是它的价值更接近基础教育和思维训练，而不是直接服务于工作的职业技能培训。</p><p>所以现在再评价这门课，我会说：它是一门很好的课，一张很好的地图，也是一次对我很重要的学习经历。它没有改变一切，但它帮助我结束了对自己“没有系统基础、算不上真正程序员”的长期怀疑。</p></blockquote><ul><li>ChatGPT 的总结</li></ul><blockquote><p>两版最明显的差别是：以前强调它给了你一种“核心力量”，现在强调它帮你建立了“地图与尺度”。</p></blockquote>]]></content>
  </entry>
  <entry>
    <title>我发现自己天然看不起中文撸毛KOL，因为有两个雷点：中文、撸毛。 但是我也不清楚为什么。他们大概率比我有钱、有人气、有影...</title>
    <link href="https://t.smallyu.net/#2026-7"/>
    <id>micro:4979295078</id>
    <published>2026-07-15T09:58:17Z</published>
    <updated>2026-07-15T09:58:17Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>我发现自己天然看不起中文撸毛KOL，因为有两个雷点：中文、撸毛。 但是我也不清楚为什么。他们大概率比我有钱、有人气、有影响力、有人“求”、过得好，但我依然觉得自己内心对他们充满鄙夷。</p>]]></summary>
    <content type="html"><![CDATA[<p>我发现自己天然看不起中文撸毛KOL，因为有两个雷点：中文、撸毛。</p>
<p>但是我也不清楚为什么。他们大概率比我有钱、有人气、有影响力、有人“求”、过得好，但我依然觉得自己内心对他们充满鄙夷。</p>
]]></content>
  </entry>
  <entry>
    <title>所有古装影视剧都是架空虚构世界。</title>
    <link href="https://t.smallyu.net/#2026-6"/>
    <id>micro:4954632814</id>
    <published>2026-07-13T05:10:12Z</published>
    <updated>2026-07-13T05:10:12Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>所有古装影视剧都是架空虚构世界。</p>]]></summary>
    <content type="html"><![CDATA[<p>所有古装影视剧都是架空虚构世界。</p>
]]></content>
  </entry>
  <entry>
    <title>我有没有浪费很多年</title>
    <link href="https://b.smallyu.net/2026/07/11/%E6%88%91%E6%9C%89%E6%B2%A1%E6%9C%89%E6%B5%AA%E8%B4%B9%E5%BE%88%E5%A4%9A%E5%B9%B4/"/>
    <id>blog-b:https://b.smallyu.net/2026/07/11/%E6%88%91%E6%9C%89%E6%B2%A1%E6%9C%89%E6%B5%AA%E8%B4%B9%E5%BE%88%E5%A4%9A%E5%B9%B4/</id>
    <published>2026-07-11T14:24:21.000Z</published>
    <updated>2026-07-11T14:45:43.629Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>客观上说，是。这种浪费不是贪图享乐的浪费，而是站在一个很平庸的起点，费劲力气才站上另一个竞技台的浪费。不是因为努力没有结果，而是努力完了之后才站到起跑线上。</p>
<p>从实习到工作之后，在一家非常平庸的公司。也许很多人五年、十年都不会走出来，他们会一直工作下去、拿个一万]]></summary>
    <content type="html"><![CDATA[<p>客观上说，是。这种浪费不是贪图享乐的浪费，而是站在一个很平庸的起点，费劲力气才站上另一个竞技台的浪费。不是因为努力没有结果，而是努力完了之后才站到起跑线上。</p><p>从实习到工作之后，在一家非常平庸的公司。也许很多人五年、十年都不会走出来，他们会一直工作下去、拿个一万多的工资、养家糊口。回头看去，整个公司都在做着低效、低产的工作。</p><p>就像中学时候心心念念想着的白月光，经过很多年后再回头看去，你会发现她只不过是极其普通的，生活在县城里甚至农村里的普通姑娘，她会早早嫁人、相夫教子。你曾经以为的爱情，其实只是你自己的期待，即使爱情真的存在，也不会以你想象的方式存在。</p><p>身处其中的时候，没有人救你，你很难发现自己在水中。</p><p>后来，我真正间接见识到了 “有钱人”，但同时又浪费了点时间。当你自身能力不够的时候，不要指望着项目带你起飞。你就是项目本身。也不要想着赚轻松的钱，轻松的钱首先有尽头，其次轻松就意味着有人在替你扛着，这种“替”大多是无意的。</p><p>再然后，我加入并退出了一个有背景的项目。我总觉得和那里的人格格不入。我感谢那个项目带给我的成长，但是也不想再做一次那样的工作。当然真正的原因还是，我身处其中，非常明白项目的前景。</p><p>梅开二度的是，接下来几个月，我再一次加入并退出了一个糟糕的项目。那次已经不只是项目前景的问题，而是项目成员的人品恶劣、连混个工资都呆不下去。</p><p>连续两次主动离开、每一次都需要接近3个月没有收入、找工作的日子。</p><p>职业连续性上、收入的积累上，都不算成功。只是经历的多了之后，增加了不少带有戾气的垃圾项目的辨别能力。这种判断力会让收入增加、项目成功吗？不会的，只是避坑而已。</p><p>也因此我也很羡慕那种运气好的人，也许他们一开始就有足够的辨别能力，或者运气好到不需要辨别。</p><p>然后再看这个 <a href="https://feed.smallyu.net/">feed 列表</a>，这么多年过去，忽然发现，真正能复利的东西，包括认知和技术，都很少。尤其是现在 AI 更强大之后。</p><p>从博客来看，最大的问题没能建立统一的人设。我没能坚持学习多种编程语言、没能持续走在区块链底层开发的职业道路上。</p><p>但是这种话题分散的背后是有原因的，我在不断否定以前的东西。学习很多编程语言没前途、做合约开发没前途、做底层开发离钱远、找不到工作，这些都是是真实的客观因素。顺便问一句，2 年前叫嚣着自己是链上科学家、智能合约开发的人，现在还好吗？</p><p>所以严格来说，我现在遇到的失败，不是过程上的失败，是结果上的失败。</p><p>不过现实的残酷之处在于，你失败了，你浪费了，你能怎么着呢。</p>]]></content>
  </entry>
  <entry>
    <title>做 Polymarket 项目踩的坑</title>
    <link href="https://smallyu.net/2026/07/10/%E5%81%9APolymarket%E9%A1%B9%E7%9B%AE%E8%B8%A9%E7%9A%84%E5%9D%91/"/>
    <id>blog:https://smallyu.net/2026/07/10/%E5%81%9APolymarket%E9%A1%B9%E7%9B%AE%E8%B8%A9%E7%9A%84%E5%9D%91/</id>
    <published>2026-07-10T11:53:28.000Z</published>
    <updated>2026-07-10T11:53:28.685Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="钱包设施的选择"><a href="#钱包设施的选择" class="headerlink" title="钱包设施的选择"></a>钱包设施的选择</h3><p>现在做 Crypto 方向的项目，一般会选择 <a]]></summary>
    <content type="html"><![CDATA[<h3 id="钱包设施的选择"><a href="#钱包设施的选择" class="headerlink" title="钱包设施的选择"></a>钱包设施的选择</h3><p>现在做 Crypto 方向的项目，一般会选择 <a href="https://www.privy.io/">Privy.io</a> 或 <a href="https://www.turnkey.com/">Turnkey</a> 来作为钱包的基础设施提供商。这些钱包设施提供了注册登录方面的集成，可以用传统方式邮箱、Google 登录，也可以用 web3 一点的方式，比如 MetaMask 钱包或者 OKX 钱包登录。更重要的是这些钱包设施解决了钱包安全的问题，允许给用户创建 embedded wallet，如果不使用这些钱包服务，项目方需要自己在服务器上保存用户的私钥，这是很危险的，尤其是对于中小团队来说，安全问题是很沉重的负担。Privy 或者 Turnkey 的解决方案是，私钥由他们来保管，储存在 TEE 一类的加密硬件中，项目方只需要通过 API 来访问和使用钱包。</p><p>至于 Privy 还是 Turnkey 的取舍问题，比如我们经常在看的 <a href="https://kreopoly.app/">Kreo</a>、<a href="https://polycop.ai/">PolyCop</a>、<a href="https://polym.trade/">polymtrade</a> 等项目都在用 Privy。这些项目列表都在 <a href="https://builders.polymarket.com/">Polymarket Builder 榜单</a> 上。Polymarket 的这个 Builder 榜单上，列出了每一个 Polymarket 生态的项目方交易量排名。<a href="https://gmgn.ai/">GMGN</a> 也用的 Privy。</p><p>用 Turnkey 的项目也有，比如 <a href="https://axiom.trade/">Axiom</a>、<a href="https://www.alchemy.com/">alchemy</a> 等。我们当时用了 Turnkey。一开始是因为 Turnkey 从定位上对自动化运行的 Trading Bot 更加友善，Privy 定位上有很重的对前端界面 SDK 的依赖。后来又发现了一个 Privy 和 Turnkey 比较大的区别：是否支持 Telegram 注册登录。</p><p>Privy 支持 TG 登录，Turnkey 不支持，为什么呢？</p><p>因为 TG 没有像 Google 那样成熟的 OAuth 体系，TG 账号本身无法像 email 或者 wallet 一样给 Privy&#x2F;Turnkey 一个 identity provider。Privy 针对这种场景做了简化，你用 TG 登录，登录后 Privy 代替你去通过 API 请求钱包的操作，实际上此时 Privy 后端 “就是你”，假如 Privy 后端的服务器被黑了，你的钱包权限会完全暴露在黑客手里。而 Turnkey 比较生硬，无法提供 identity provider，就不能让你操作钱包，Turnkey 的后端不愿意代替用户承担这种权限风险。</p><p>所以这是我们发现的 Privy 和 Turnkey 之间比较大的场景支持程度上的差异。如果想要用 Turnkey 并且支持 TG 登录，就得专门做一个 TG Miniapp，登录的时候唤起 Miniapp 来完成。</p><h3 id="CLOB-V2-集成"><a href="#CLOB-V2-集成" class="headerlink" title="CLOB V2 集成"></a>CLOB V2 集成</h3><p>Polymarket 上的订单系统叫 CLOB，下单等行为都是在和 CLOB API 交互。4月28日，Polymarket 正式启用 <a href="https://docs.polymarket.com/v2-migration">CLOB V2</a>。对于我们这种下游项目来说，最大的变动是需要换掉一些合约地址信息，比如 Copy Trading 功能需要扫描链上交易，以前监听的是 V1 版本的合约，迁移后监听的是 V2 版本的合约。此外如果下游不适配也是可以的，因为大体上兼容旧版本的订单参数。</p><p>而 CLOB V2 也引入了 FAK、FOK 等 Market Order 在使用的参数，这些参数直到一个多月以后我才发现它们的差异。因为在 V1 版本订单如果没有立即成交，会把没成交的部分自动挂单为 Limit Order，但同时又要求 Limit Order 的 shares 数量必须大于 5。所以用户有时会遇到一个奇怪的错误，为什么订单 shares 数量必须最小是 5？又为什么有时候会提醒最小订单金额是 1 美元？为什么有时候能成功有时候失败了，最小金额不是固定的？用上 FAK 参数的话倒是没有这种旧的问题了。</p><h3 id="Safe-Wallet-gt-Deposit-Wallet"><a href="#Safe-Wallet-gt-Deposit-Wallet" class="headerlink" title="Safe Wallet -&gt; Deposit Wallet"></a>Safe Wallet -&gt; Deposit Wallet</h3><p>5月4日，Polymarket 发公告说启用新的 <a href="https://x.com/PolymarketDevs/status/2050992767372013922">Deposit Wallet</a>，不再使用旧版本的 Safe wallet。这是一个 breaking change，所有旧的用户依然兼容，但是新的尤其是通过 api 操作的钱包，都将使用新的 Deposit Wallet，也就是说下游项目必须兼容。</p><p>这个时间点非常微妙，因为我们原本计划项目 Beta 版本上线的日期是 5月5日。也因此当时连续两三天我紧赶慢赶去适配这个 Deposit Wallet 的迁移。这本身不是一件特别难的事情，但是由于突然升级带来的措手不及，以及上线的 delay，还是有一点点压力。</p><p>至于集成过程中遇到的唯一挫折，是 Polymarket 的 Migration 文档里没有写新的 Deposit Wallet Implementation 地址。在用 Factory 合约创建钱包的时候，需要一个 implement 合约作为参数，不同的 implement 合约出来的钱包地址是完全不一样的。而重点不只是我们用哪个地址，而是 Polymarket 的 Relayer api 用哪个，因为在新的这种 Deposit Wallet 模式下，所有的钱包操作都会通过官方的 Relayer api 了。以前用的 Safe wallet，其实我们可以自己直接去链上调合约的。Polymarket 的这个改动，反而让钱包体系更加不那么去中心化。至于正确的 implement 的值，则是需要直接从 Polymarket 发布的 SDK 里去读。而且当时还遇到个小坑就是 Polymarket 发布的不同 SDK 之间用的 implement 地址还不一样。不是同一个 SDK 不同版本，而是那种不同 SDK，比如 client-sdk, server-sdk 这种。当时 Discord 群里遇到这个集成问题的开发者非常多。</p><h3 id="Relayer-API"><a href="#Relayer-API" class="headerlink" title="Relayer API"></a>Relayer API</h3><p>刚才提到新的 Deposit Wallet 必须要通过 Polymarket 官方的 Relayer API。我们在迁移后并且项目上线一段时间、做活动，紧接着就遇到了另一个坑：Unverified 状态的 Builder API 只有每天 100次的请求额度。</p><img src="1.png" width="80%"><p>看出 Polymarket 的阴险之处了吧，先是要求所有新用户都用 Deposit Wallet，而新的 Deposit Wallet 自然必须通过 Relayer API 来操作钱包，再然后你会发现，Relayer API 的请求是有额度限制的！如果是原本的 Safe wallet 可以直接链上操作绕过 Polymarket 的 API 额度限制。现在不行了。</p><p>这个 Relayer API，每次创建新的钱包都要用、每一次从钱包里 withdraw 钱要用，所以这是一个高频率会用到的接口。</p><p>针对这个限制的缓兵之计是，Polymarket 默认用 Builder API 来对 Relayer API 授权，但是 Relayer API 却没有要求 Builder API 具体是哪一个。所以我注册了 10个账号、每一个账号都创建了 builder api，配置到服务器里，用来暂时缓解 relayer api 的额度限制问题。每个账号每天100次请求额度，也就意味着 10 个账号一天有 1000 次额度。因为 verified 从提交到审核需要两到四周的时间，是一个很长的周期。</p><p>当然最终还是通过了 Verified，现在我们的项目已经出现在 Polymarket Builder 榜单上，并且状态是 Verified。</p><h3 id="Deposit-Wallet-升级"><a href="#Deposit-Wallet-升级" class="headerlink" title="Deposit Wallet 升级"></a>Deposit Wallet 升级</h3><p>7月6日，又是 Deposit Wallet 的问题。我们发现了一个很严重的 bug，自从 7月1日以来注册的全部用户，创建钱包都失败了！而因为用户反馈少，出问题很多天我们才发现这个问题。也就是说，新注册的用户，注册完之后如果充值，会把钱充值到错误的地址上。</p><p>为什么会出现这个 bug 呢，因为 7月1日，Polymarket 直接修改了创建钱包的逻辑，用上了 beacon 的方式去创建代理钱包，而且连公告都没发，直接改变 API 接口的行为。这种改动，是需要下游项目方主动适配的。</p><img src="2.jpg" width="100%"><p>我们也有错误，我们的错误之处就在于没能及时发现这种异常，并且在程序前后端加上足够的保护性、防御措施。针对这次事故所有用户充值钱到错误地址的，全部金额都赔了，好在金额不大。</p><h3 id="Combos"><a href="#Combos" class="headerlink" title="Combos"></a>Combos</h3><img src="3.png" width="100%"><p>Polymarket 针对世界杯的市场，新出了一个叫 combos 的功能。我们就开始评估是否可以接入这个 combos 的功能。结果就是，从 <a href="https://docs.polymarket.com/market-makers/combos">combos 文档</a> 上看，API 只提供了针对做市商提交 quote 的接口，没有提供作为普通用户作为 taker 角色去下单的接口。</p><p>Polymarket 从 6月4日开始运作 combos 的接口，看起来也是在辛苦 build 中。</p><img src="4.png" width="60%"><h3 id="tick-size"><a href="#tick-size" class="headerlink" title="tick size"></a>tick size</h3><p>7月10日，用户反馈遇到了订单交易失败的问题。经过排查后发现是订单的 <a href="https://docs.polymarket.com/changelog">tick size 有了变化</a>，所有的世界杯市场都支持 0.0025 (0.25¢) 级别精度的 tick size。在此之前 tick size 只有固定 4 种，这个 0.25¢ 属于第 5 种（枚举类型）。</p><p>同样的，这个变动其实 Polymarket 早在 7月2日就上线了，但是我们直到 7月10日才发现 bug。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>所以你看到了，一直以来，我们都在不断的追随 Polymarket 的脚步，一直不断的响应 Polymarket 的功能更新和变化。</p><p>也因此，在构建项目的过程中，我们也开始逐渐意识到这样的项目误区：再做一个官网。</p><p>如果定位是 “再做一个官网”，项目方就会陷入非常被动的处境。而且 Polymarket 家大业大，官网 UI 做的也好，有功能都是第一时间上官网，再者官网自家的服务器，下单速度也快。我们的订单速度再快也不可能快过 Polymarket 官网。</p><p>这是一件尴尬的事情，如果想要做的比官网使用体验好，客观上难度是很高的。Polymarket 不是 memecoins，一般 memecoins 没有官网至少不会有官方钱包、官方 DEX，但是 Polymarket 有官网、有官方解决方案。Polymarket Builder 的定位，从来都不是说，Polymarket 是一个开放的去中心化协议，大家都来建设项目去玩。</p><p>与之相反，Polymarket 最近的功能更新上也越来越往中心化的方向走，定位更像是中心化交易所，比如 Binance 这种，Polymarket API，就是 Binance API。做 Polymarket 生态的项目，就有点像是做 Binance 的 Trading Bot 一类事情。</p>]]></content>
  </entry>
  <entry>
    <title>分享一个 Polymarket 的 BTC 5分钟策略</title>
    <link href="https://smallyu.net/2026/07/05/%E5%88%86%E4%BA%AB%E4%B8%80%E4%B8%AAPolymarket%E7%9A%84BTC-5%E5%88%86%E9%92%9F%E7%AD%96%E7%95%A5/"/>
    <id>blog:https://smallyu.net/2026/07/05/%E5%88%86%E4%BA%AB%E4%B8%80%E4%B8%AAPolymarket%E7%9A%84BTC-5%E5%88%86%E9%92%9F%E7%AD%96%E7%95%A5/</id>
    <published>2026-07-04T17:32:20.000Z</published>
    <updated>2026-08-09T04:50:13.356Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="免责声明"><a href="#免责声明" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<h3 id="免责声明"><a href="#免责声明" class="headerlink" title="免责声明"></a>免责声明</h3><ol><li>这不是无风险套利，只是普通的策略，数学上不是正期望的，存在明显的策略风险</li><li>有可能赚钱也有可能亏钱，跟随市场情况波动，过去的收益率不代表未来的收益率</li><li>策略数据方面，因为这几天一直在频繁调整策略和参数，我也不确定未来连续运行几天后真实的收益是多少，能确定的是我最近半个月一直在运行、下单超过 300 个场次，总收益微弱，但是没有亏本。至少说明这个策略不是亏钱机器。</li></ol><h3 id="代码仓库"><a href="#代码仓库" class="headerlink" title="代码仓库"></a>代码仓库</h3><ul><li><a href="https://github.com/smallyunet/poly-btc5m">https://github.com/smallyunet/poly-btc5m</a></li></ul><p>更新比较频繁，谨慎使用。是我自己实际在运行的代码，虽然策略简单但是开发量并不小，如果想尝试可以直接使用。另外如果你不相信我接下来对于策略的判断，则务必亲自尝试 🐶</p><p>顺便说一个开发体会是，X 上很多玩预测市场的人，在通过 Vibe Coding 的方式来写策略 Bot、自己执行。从我的感受来看，非程序员群体想要实现出能运行的策略，基本不可能可靠（高素质具备逻辑能力除外）。</p><p>有些策略包括我接下来说的策略，看起来和理解起来是异常简单的，但是落实到代码上，有很多具体的问题。比如重复下单的问题、退出策略是否正常执行、线上突然多了一堆订单属于策略内还是程序异常，这些都需要反复调试。不是说非程序员想不清楚，而是这个调试的过程非常磨人，得不断调参数、看效果、效果不好改策略、再看效果。这实际上就是程序开发每天在干的事情，现在虽然不需要自己动手写代码了，但是结果还得自己看。</p><h3 id="策略说明"><a href="#策略说明" class="headerlink" title="策略说明"></a>策略说明</h3><h4 id="基本策略"><a href="#基本策略" class="headerlink" title="基本策略"></a>基本策略</h4><p>对于下一场还未开始的 BTC 5分钟市场，提前直接挂单 limit order，以 45c 的价格买入 Up，同时以 45c 的价格买入 Down。如果两个挂单都成交，则结算的时候因为 0.45+0.45 &lt; 1，所以必然得到本金 10% 的收益。一旦两个订单都成交，收益必然锁定，不需要任何后续操作。</p><p>损失风险也很明确，如果开盘后进入单边行情，价格在整个 5 分钟的周期内都没有震荡超过 55%，则策略遭受 50% 本金损失。这也就意味着，每次输 1 场，需要赢 5 场才能够转亏为盈。</p><p>为了减少损失，策略也包含两个止损机制：</p><ol><li>如果开盘后单腿成交、收益达到 5%、同时另一腿没有成交，则直接止盈成交的一侧、另一侧直接取消挂单</li><li>如果最后 1 分钟内还是只有单腿成交，并且另一腿的价格低于 75c，则以当前价格买入 2 倍数量的另一腿，锁定损失</li></ol><h4 id="策略的主观部分"><a href="#策略的主观部分" class="headerlink" title="策略的主观部分"></a>策略的主观部分</h4><p>这个策略从纯粹的逻辑和量化的角度，显然是站不住脚的，风险很大也很明确，而且没有程序化的规避方式，策略本身也没有足够的回测数据做支撑。所以这个策略很大程度上是主观的，我要解释的是，为什么我主观上认为这个策略可行？</p><p>btc5m 这种市场，行情分两种，一种是这个策略双边同时开单能够获利的震荡行情，另一种就是一旦开盘就已经锁定了结算方向、价格一去不复返的单边行情。</p><p>那么反过来想，假如单边行情多于震荡行情，是否意味着，在开盘后几秒内，直接买入价格高于 55c 的一边，就可以拿着等待结算了？单次收益率超过 80%。然后结合单边行情概率上多于震荡行情这一点，只要简单执行跟风买入的操作，就是一种能稳定赚钱的策略了。这是一种 “超级尾盘” 策略，因为尾盘一般在接近结算的价格比如 99c 才入场，而现在概率告诉你，55c 就足以入场。</p><p>但是事实上，大家交易的体感上，btc5m 结算前 5 秒钟结果大反转的场次都很频繁。别说单边买入，尾盘买入都会亏的很惨。而且我也不太相信赚钱可以简单到持续单边买入就可以，过于违反直觉。</p><p>所以再正过来想，既然不可能单边行情多于震荡行情，那么就应该是震荡行情居多。</p><h4 id="已忽略的客观部分"><a href="#已忽略的客观部分" class="headerlink" title="已忽略的客观部分"></a>已忽略的客观部分</h4><p>既然刚才的判断是纯主观，那么是否可以通过判断 BTC 的价格动量，来预测 BTC 是否会在接下来 5 分钟内大幅波动呢？</p><p>这个测试我已经做过了，从 Binance 的 wss api 去获取实时价格信息、判断下一个轮次开始前 120 秒内价格是否在某一个中间线上下波动，并且还加了复杂的评分系统，需要至少上下横穿 2 次、并且价格波动幅度在 12bps 以上、信号连续持续出现 3 次、以及根据 Polymarket 上 orderbook 本场的波动情况等等各种条件，甚至还考虑拿一下 Binance 上的资金费率、Polymarket 上下一场的 Top holder 等数据来辅助判断。</p><p>也尝试过一些动态调整参数方面的优化，比如根据评分结果的高低来动态调整入场价格和入场金额，分数高一点就 42c, 1.2*amount，分数低一点就 46c, 0.8*amount 之类。</p><p>结果就是，不但能经过层层筛选的场次非常少，会导致下单的场次也非常少。而且主要是没有明显的效果。假如闭着眼睛不判断，直接下单，可能 10 场里有 9 场是 paired 状态（盈利的）、还有 1 场是 single 状态（亏损的）。而经过一系列评分系统最后高于波动率才下单的做法，可能一天下单 10 场，这 10 场里还是有 1 场 single。高的评分并没有减少 single 状态的风险，反而还大幅减少了下单的场次。</p><p>当然，你肯定会觉得，是我的量化思维不够专业，写不出足够专业有效的模型去预测下一场价格的波动情况。那我承认……</p><h4 id="收益上限"><a href="#收益上限" class="headerlink" title="收益上限"></a>收益上限</h4><p>即使这个策略真的有效可以赚钱，收益也是有上限的。从最近几场 Polymarket 上的流动性深度来看，每一次下单的金额，单腿金额在 100 美元左右还是安全的，如果到 200 美元以上，就会出现买单不够、无法成交的风险。</p><p>这一点其实违反直觉，也许你觉得 Polymarket 交易量那么大（百亿美元级别）、玩 btc5m 的人应该很多才对吧？从官网上可以直接看到每一场的 Top holder 和 Top PNL，持有者最多在几千个 shares，收益最高的在几百、几千美元的区间。</p><p>那么一天有 288 个 5 分钟，假如真的每一场都是赚的，按照 200 美元的本金算，每一场收益是 10% 也就是 20 美元，一天的收益是 5760 美元。这个是理论上限。当然不可能每一场都赢，大概率赢 9 场输 1 场，收益率减半，一旦多 1 场输，就抹平 5 场的收益，收益打一折，再然后……</p><h4 id="策略扩展"><a href="#策略扩展" class="headerlink" title="策略扩展"></a>策略扩展</h4><p>既然 btc5m 市场可以用这样的做法，那么 btc15m, btc1h, btc4h, btc1d，eth15m, sol1h…… 是不是也都可以用这样的策略？显然是可以的。</p><h3 id="FAQ"><a href="#FAQ" class="headerlink" title="FAQ"></a>FAQ</h3><ul><li>F：如果这个策略真的可以赚钱，为什么要分享出来？    </li><li>Q：因为真正赚钱的策略从来都是公开的秘密。比如一直反复在说的，能长期重仓投入的策略，只有定投 BTC。</li></ul><br><ul><li>F：为什么不等多运行几天、等有一份好看的策略数据出来再分享？    </li><li>Q：没耐心。即使最近几天、几个月、几年通过策略赚钱了，也许接下来几天、几个月、几年会再亏进去。我还是同样的观点，只要在牌桌上，就没有赢家。</li></ul><h3 id="相关阅读"><a href="#相关阅读" class="headerlink" title="相关阅读"></a>相关阅读</h3><ul><li>《<a href="https://crazy.smallyu.net/2026/06/30/%E4%B8%8D%E8%A6%81Copy-Trading/">不要 Copy Trading</a>》2026-06-30</li><li>《<a href="https://crazy.smallyu.net/2026/05/10/%E5%9C%A8%E5%B8%81%E5%9C%88%E4%B8%8D%E8%A6%81%E5%81%9A%E6%92%B8%E6%AF%9B%E5%85%9A/">在币圈不要做撸毛党</a>》2026-05-10</li><li>《<a href="/2022/12/03/%E6%88%91%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E4%BA%A4%E6%98%93%E6%9C%BA%E5%99%A8%E4%BA%BA/">我的加密货币交易机器人</a>》2022-12-03</li></ul><br><h3 id="更新（2026-07-17）"><a href="#更新（2026-07-17）" class="headerlink" title="更新（2026.07.17）"></a>更新（2026.07.17）</h3><p>这是一个 200 美元买来的教训。其实我早就应该明白、或者已经明白这个道理：策略不可以赚钱。但是由于工作原因，以及可能受到一些其他影响，我突发奇想开始去尝试 Polymarket 上的策略。</p><p>真正试验这个策略的过程要远比文章写出来的复杂，花费了大量的时间和精力。但是在经过这样的尝试后，反而更加佐证了这个结论：策略不可以赚钱。也许周期性可以依靠运气赚钱，但是长期来看一定是负期望。</p><p>我没有时间和耐心去写复盘，就让 ChatGPT 完整总结了一下前因后果：</p><p>《<a href="https://github.com/smallyunet/poly-btc5m/wiki/%E6%88%91%E4%BB%AC%E6%98%AF%E6%80%8E%E4%B9%88%E6%8A%8A%E4%B8%80%E4%B8%AA%E7%9C%8B%E8%B5%B7%E6%9D%A5%E8%83%BD%E8%B5%9A%E9%92%B1%E7%9A%84-BTC-5-%E5%88%86%E9%92%9F%E7%AD%96%E7%95%A5%EF%BC%8C%E8%B7%91%E5%88%B0%E6%9C%80%E7%BB%88%E5%81%9C%E6%9C%8D%E7%9A%84">我们是怎么把一个看起来能赚钱的 BTC 5 分钟策略，跑到最终停服的</a>》</p><p>最后我再解释和强调一下这里说的 “教训” 是指：不要抱有侥幸心理。当你知道 “策略不可以赚钱” 之后，也许偶然会想再试试、也许这一次会不一样、也许这样那样就可以，然后就会发现，最终不但没赚到钱，还赔了钱。这就是教训。</p><br><h3 id="更新（2026-08-09）"><a href="#更新（2026-08-09）" class="headerlink" title="更新（2026.08.09）"></a>更新（2026.08.09）</h3><p>策略还在继续维护中，只是现在会更加谨慎；结合之前急于求成的教训，现在仅运行模拟盘、然后分析回归测试出来的数据；有新的发现和结果会再更新。</p>]]></content>
  </entry>
  <entry>
    <title>不要 Copy Trading</title>
    <link href="https://crazy.smallyu.net/2026/06/30/%E4%B8%8D%E8%A6%81Copy-Trading/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/06/30/%E4%B8%8D%E8%A6%81Copy-Trading/</id>
    <published>2026-06-30T07:09:12.000Z</published>
    <updated>2026-07-04T17:36:19.130Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>来理解一下 Copy Trading 的本质是什么。</p>
<p>本质就是我什么都不需要懂，我看到一个人有钱，我想直接跟着对方赚钱，抄近路、走近道、抄作业。</p>
<p>假如 Copy Trading]]></summary>
    <content type="html"><![CDATA[<p>来理解一下 Copy Trading 的本质是什么。</p><p>本质就是我什么都不需要懂，我看到一个人有钱，我想直接跟着对方赚钱，抄近路、走近道、抄作业。</p><p>假如 Copy Trading 真的能赚钱，有几个人靠这个赚到钱的？</p><p>有几个人靠抄作业抄成学霸的？</p><p>我来直接给 Copy Trading 定性：</p><ol><li>Copy Trading 赚不到钱</li><li>Copy Trading 的动机本质上是骨子里的懒惰，世界从来不会给懒惰的人超预期的奖励</li></ol>]]></content>
  </entry>
  <entry>
    <title>为什么 DM KOL 的 GTM 策略一定是 “对” 的</title>
    <link href="https://smallyu.net/2026/06/29/%E4%B8%BA%E4%BB%80%E4%B9%88DM-KOL%E7%9A%84GTM%E7%AD%96%E7%95%A5%E4%B8%80%E5%AE%9A%E6%98%AF%E2%80%9C%E5%AF%B9%E2%80%9D%E7%9A%84/"/>
    <id>blog:https://smallyu.net/2026/06/29/%E4%B8%BA%E4%BB%80%E4%B9%88DM-KOL%E7%9A%84GTM%E7%AD%96%E7%95%A5%E4%B8%80%E5%AE%9A%E6%98%AF%E2%80%9C%E5%AF%B9%E2%80%9D%E7%9A%84/</id>
    <published>2026-06-29T06:24:59.000Z</published>
    <updated>2026-06-29T08:15:54.321Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>团队的项目在 Go to Market 环节遇到了困难，所以找了有经验的 BD（商务拓展）来提供指导意见。对方给出的策略是：每个人都去 DM KOL 谈合作。</p>
<p>具体做法是直接在 X 上找到相关领域的]]></summary>
    <content type="html"><![CDATA[<p>团队的项目在 Go to Market 环节遇到了困难，所以找了有经验的 BD（商务拓展）来提供指导意见。对方给出的策略是：每个人都去 DM KOL 谈合作。</p><p>具体做法是直接在 X 上找到相关领域的 KOL，然后跟对方聊天、套近乎、问需求、谈合作。</p><p>这个策略能够达到的目的是（转述）：</p><ol><li>最差的结果，是把产品介绍发给了对方，对方看到了、知道有这么个产品，不回复</li><li>稍微好一点的结果是，对方有回复，并且体验了产品，并且还给出了对产品的意见，这个属于很大的收获</li><li>最好的结果是，对方不但体验了产品，还对产品表达认可，愿意和项目方合作，把产品推荐给他的粉丝，以及通过返佣的方式长期合作</li></ol><p>这个策略是 BD 给出的、在他的理解中最为可行的、用户转化率、留存率最高的方案。</p><p>说实话我没有 GTM 的经验，所以我也在不断反思，这个策略好不好、对不对、为什么专业的有经验的 BD 唯一认可的是这个策略。当然我早就想明白了结论，只是现在把这个结论写出来。我来跟你解释一下为什么。</p><p>我的结论是：这个策略一定是对的，但未必是有结果的。</p><h3 id="学习的例子"><a href="#学习的例子" class="headerlink" title="学习的例子"></a>学习的例子</h3><p>很简单的道理，如果一个学生问老师，怎么提高学习成绩？老师会说，课前预习、上课好好听讲做笔记、课后认真完成作业、有不会的题要请教同学和老师。这一套学习方面的方法论，亘古不变。</p><p>但是很明显，我们都知道，同一个班级、同样的老师、同样的课本、同样的作业，学生的成绩就是天差地别。</p><p>为什么呢，因为策略方向是对的，但是具体到执行上每个学生都不一样，每个人的行为差异会被放大。</p><p>所以只要策略方向足够大、足够宽泛，策略就一定 “正确”。只是正确未必有用，因为策略需要具体的人来执行，而每一个人都是有差异的，只要不能机械化到代码程序可以重复执行，结果就肯定有差异。</p><p>也因此，你学习成绩不好不能怪老师吧？怎么有的学生人家就是成绩好呢？老师讲的东西都一样，你不能说老师讲的道理不对吧？</p><h3 id="投资的例子"><a href="#投资的例子" class="headerlink" title="投资的例子"></a>投资的例子</h3><p>李笑来在 2022 年之后就不再做投资了，专职做家庭教育、写书、卖课、讲课。我喜欢李笑来的《财富自由之路》和《韭菜的自我修养》两本书，现在也时不时留意李笑来的新书和课程。</p><p>他最近几年的观点，非常明显有一个共同点，就是非常 “基础”、非常 “简单”，简单到像跟 6 岁小孩子讲道理一样，比如我们跟孩子说要诚实、勇敢、善良等，李笑来讲的观点，也都类似这种，比如 “生产是财富的来源”、“要学会复利”、“知识是可以迁移的、只要有时间就学习”、“自我暗示非常有力量” 等等。</p><p>他讲的这些内容，感觉都简单到 “是个人知道”，他讲的每一点，简单到 “每一个普通人都可以做到”。</p><p>然而事实上，世界上只有一个李笑来，真正财富自由的只有李笑来。他的课程并没能把那些 “真理” 一样的道理教给别人、让别人变得富有。</p><p>我也经常反思这个问题，为什么呢，为什么李笑来这样经历丰富的人，最终总结出的各种道理，反而异常朴实、基础、简单？我相信他不是刻意隐瞒，而是真心实意相信自己的那套东西。</p><p>所以现在直接能串联起来了。就跟学生问老师成绩怎么变好一样。很多人问李笑来，怎么变有钱，怎么变富有？然后李笑来告诉你，要坚持，要努力，要学习，要产出，要……</p><p>明白这里面的漏洞了吗？策略方向一定对，具体执行因人而异。还是那句话，只要策略方向足够大、足够宽泛，策略就一定 “正确”。</p><h3 id="DM-KOL-的例子"><a href="#DM-KOL-的例子" class="headerlink" title="DM KOL 的例子"></a>DM KOL 的例子</h3><p>回到 DM KOL 这个策略，我来拆解两个问题：</p><h4 id="1-策略范围是不是很大？"><a href="#1-策略范围是不是很大？" class="headerlink" title="1. 策略范围是不是很大？"></a>1. 策略范围是不是很大？</h4><p>很大。从一开始转述的、期望达到的 3 个效果来看，其实包含了市场调研、功能反馈、寻找合作 3 种目的。对于大公司来说这可能是 3 件事情，只是小团队就直接聚合为一件事情、全都放在 “DM KOL” 这句话里了。</p><p>只看这几个词可能不够直观，具体来说，我们期望问 KOL：</p><ol><li>你觉得 PM 有哪些不好用的地方？</li><li>你觉得我们的产品是否好用、有什么建议？</li><li>是否愿意跟我们合作、推荐并拿返佣？</li></ol><p>当然前提是对方愿意回信息。因为实际上大多数 KOL 不会回消息，或者上来就报价。而这个 DM KOL 策略的重点，实际上在于建立关系、跟人搭讪，先建立联系、然后表述出目的。</p><p>从这个描述能听出问题所在不。这就全部依赖于个人的社交能力了，而且是通过网络打字社交。BD 也跟我们说，要持续骚扰对方到骂你为止。</p><h4 id="2-实际执行效果怎么样？"><a href="#2-实际执行效果怎么样？" class="headerlink" title="2. 实际执行效果怎么样？"></a>2. 实际执行效果怎么样？</h4><p>也很差。不过我要分享的，是我们团队面对的最大问题，以及为什么效果不好：因为执行成本高。</p><p>很多交易所，长期招聘 BD、而且 BD 没有无责底薪、说开除就开除，随便去任何一个招聘群，都能看到类似的吐槽。</p><p>很多项目方，在小红书上招聘实习生，一个月 3000块人民币，实习生就愿意辛辛苦苦任劳任怨干一个月，天天在 X 上刷流量、发广告。</p><p>而 DM KOL 的策略，属于周期长、反馈慢的策略，可能 DM 1000 个 KOL，其中能有 10 个给出反馈、有 1 个能达成合作。这还得是你花心思认真跟对方接触的情况下。</p><p>如果对这个过程没有实际感受，可以回想一下找工作的过程。比如我找工作的频率就很高，深刻理解这种状态。在找工作的时候，可能联系几百个 HR，然后面试几十家公司，最终找到一份合适的工作。</p><p>对于 BD 或者销售人员来说，DM KOL 就是他们的工作呀，他们不但能用整天的时间来干这件事情，而且有足够的时间去思考、总结相关的经验。</p><p>至于我所在的团队，所有成员中，目测时间成本没有比我低的。每个人都戴着 “金手铐”。毕竟不是专业的 BD 人员，也都有自己职业方向的事情需要做，能够用于 DM 的时间很少，更重要的是，DM 是一件反馈周期长、不确定性很高的事情。花一整天的时间去 DM，可能都什么反馈都不会得到。而在自己熟悉的道路上，总是能有一些结果的。</p><p>所以让成员兼职去 DM KOL 这件事情，如果想要得到可观的结果，难度不亚于先让成员做一次职业转型，然后再统一做长时间刻苦的执行后，才能有结果。</p><p>如果不那样，要么有人能认真把这件事情做好，要么什么都做不好。我个人是不相信，有人能顺带做一件事情，不用心也不总结，就能比专业的人做出更好的效果。</p><p>毕竟哪怕是专业的 BD 团队，同样完全正确的策略下，10 个 BD 成员里得到的结果想必也天差地别，有的人被开除了，有的人成为金牌员工了。这种事情谁说得准呢。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>所以你应该看出来了，我写这些的目的并不是在吐槽，而是在分析和分享。</p><p>重要的是我明白了一个道理：为什么看起来正确的策略，却得不到好的结果？</p><p>不知道我讲清楚了吗？</p>]]></content>
  </entry>
  <entry>
    <title>AI Agent 看板</title>
    <link href="https://smallyu.net/2026/06/18/AI-Agent%E7%9C%8B%E6%9D%BF/"/>
    <id>blog:https://smallyu.net/2026/06/18/AI-Agent%E7%9C%8B%E6%9D%BF/</id>
    <published>2026-06-18T13:56:27.000Z</published>
    <updated>2026-06-18T14:21:51.804Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>有一个给 AI Agent 设计的看板工具叫 Multica，理念是本地部署，本地运行的 AI 比如 Codex、Claude Code、Antigravity 等都以 Agent 形式接入看板，然后你就可以给 AI Agent]]></summary>
    <content type="html"><![CDATA[<p>有一个给 AI Agent 设计的看板工具叫 Multica，理念是本地部署，本地运行的 AI 比如 Codex、Claude Code、Antigravity 等都以 Agent 形式接入看板，然后你就可以给 AI Agent 分配任务、管理项目进度等。</p><p>看到这个产品后有感而发。</p><p>对于这个产品本身，怎么理解这个事情呢，我觉得可以这样理解：</p><p>首先看板工具是指类似 Jira、Linear、GitHub Project、Notion 这些知名的项目管理工具。</p><p>然后先不说 AI，就说人，假如就是一些真实的人、真实的员工、真实的技术团队。有能力通过任务面板把技术团队管理明白的 leader，包括任务怎么分配、任务时长、任务难度的定义、结果怎么验收等等。对于能处理好任务、把项目进度安排的井井有条的 leader，这个 AI Agent 看板工具才有意义。</p><p>也就是说，对于已经具备能力管理好 “人” 的 leader 型人，他才需要把员工换成 AI，然后在看板工具上给 AI 分配任务这种产品。</p><p>AI 相对于人类，有优点也有弱点。优点就是效率高，你给它明确的任务，它能执行的很好。但是 AI 的弱点在于，不需要主动汇报工作、没有情绪，也不需要承担责任。如果 AI 把你的数据库删了，或者强硬汇报错误的内容、或者突然降智听不懂人话了，你能拿他怎么办呢？骂它？扣它工资？给它讲道理、画大饼让它内疚？</p><p>所以当你作为一个能管理好员工或者下属的 leader，试图通过 AI 降本增效的时候，这个 AI Agent 看板工具才能发挥作用。而与此同时，这个 leader 也得好好掂量一下能不能用好 AI。</p><p>下一个问题，AI 能提高效率是显而易见的，但是 AI 真的能降低成本吗？用 Codex 日常写代码一天三四个小时，需要开每个月 100 美元的套餐。如果更高强度使用，大概一天六七个小时运行时长的话，每个月 200 美元的套餐是必需的。</p><p>同时考虑到 Codex 有周限额和日限额，200 美元的套餐跑满肯定不够，算作一个 AI Agent 300 美元吧。然后看板工具的意义当然在于，多个 Agent 同时运行。如果只需要一个，在 Codex 里用就行，没有必要看板。</p><p>那么按照小型技术团队 3 个人的规模来算，AI Agent 的费用算作一个月 1000 美元吧。</p><p>也就是说，原本也许 1 leader + 2 senior + 1 junior 配置的技术团队，可以精简为 1 leader + 2 Codex + 1 Antigravity。要只算订阅费的话，是不是真的节省了不少成本？</p><p>不过还要考虑一个小问题，人类队伍中 leader 不需要独自承担责任，只需要验收就行。但是在 Agent 的配置形式下，leader 必然是更忙更累的，因为需要 review 所有 AI 的工作结果、手动打字（甚至不能语音和会议）来同步给 AI 工作任务、需要把任务边界和规则定义的非常清楚。相信做过技术的话就会理解，看似用 AI 代替了大量人力，但同时极大增加了 leader 的负荷。这种推演方式下 leader 一定是忙不过来的。</p><p>所以可以退一步，改为 2 leader + 2 Codex + 2 Antigravity 的模式，也就是 (1 leader + 1 Codex + 1 Antigravity)*2 的模式。这样的话 leader（或者工程师）的工作负荷勉强合理、工作任务能够合理完成。这种模式下，成本变成了多少呢？</p><p>继续下一个问题，刚才的讨论一直有一个前提，就是这个 leader 本身有能力管理好 “人”，在此基础上去使用 AI。那么如果本身这个 leader（工程师）不具备管理人类的能力呢？</p><p>结合之前提到的 AI 的弱点，那么工作一定是一团糟糕的，毫无疑问。难道我们或者你，在过往的工作经历中没有遇到过管理能力糟糕的 leader 吗？设想他们管理一堆不需要承担责任的 AI Agent，真的能让工作或者项目完成的更好吗？</p><p>总的来说，项目的任务看板工具实际上不是技术问题而是管理问题。有能力用好看板的人没那么需要 AI，没有能力用好看板的人也用不好 AI。</p><p><br><br></p><img src="summary.png" width="80%">]]></content>
  </entry>
  <entry>
    <title>加密货币的价值，本质上来自市场的注意力。所以所有加密货币的经济模型，都是注意力经济。</title>
    <link href="https://t.smallyu.net/#2026-5"/>
    <id>micro:4686489606</id>
    <published>2026-06-12T01:21:19Z</published>
    <updated>2026-06-12T01:21:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>加密货币的价值，本质上来自市场的注意力。所以所有加密货币的经济模型，都是注意力经济。</p>]]></summary>
    <content type="html"><![CDATA[<p>加密货币的价值，本质上来自市场的注意力。所以所有加密货币的经济模型，都是注意力经济。</p>
]]></content>
  </entry>
  <entry>
    <title>不要喝无糖可乐</title>
    <link href="https://crazy.smallyu.net/2026/06/10/%E4%B8%8D%E8%A6%81%E5%96%9D%E6%97%A0%E7%B3%96%E5%8F%AF%E4%B9%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/06/10/%E4%B8%8D%E8%A6%81%E5%96%9D%E6%97%A0%E7%B3%96%E5%8F%AF%E4%B9%90/</id>
    <published>2026-06-10T13:26:43.000Z</published>
    <updated>2026-07-04T17:36:19.131Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>无糖可乐的原理是，没有热量、没有能量，但是用了某种调料，让可乐喝起来甜味很足。</p>
<p>那么喝了无糖可乐 -&gt; 你的肚子以为吃了高热量食物 -&gt; 开始分泌很多消化液 -&gt; 肚子饿的更快了 -&gt; 下一顿报复性饮食；</p>
<p>喝了无糖可乐]]></summary>
    <content type="html"><![CDATA[<p>无糖可乐的原理是，没有热量、没有能量，但是用了某种调料，让可乐喝起来甜味很足。</p><p>那么喝了无糖可乐 -&gt; 你的肚子以为吃了高热量食物 -&gt; 开始分泌很多消化液 -&gt; 肚子饿的更快了 -&gt; 下一顿报复性饮食；</p><p>喝了无糖可乐 -&gt; 你的肾脏以为身体含糖量会增加 -&gt; 开始分泌胰岛素 -&gt; 发现事实上没有热量提升 -&gt; 长此以往发现被骗 -&gt; 下次真的吃了高热量食物也不分泌胰岛素了 -&gt; 导致糖尿病。</p><p>所以不要再和无糖可乐。</p>]]></content>
  </entry>
  <entry>
    <title>Trust Wallet 这么知名的钱包，仍然没有解析和处理 Base 链的 internal 交易。这会导致 inte...</title>
    <link href="https://t.smallyu.net/#2026-4"/>
    <id>micro:4649152650</id>
    <published>2026-06-08T12:51:13Z</published>
    <updated>2026-06-08T12:51:13Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Trust Wallet 这么知名的钱包，仍然没有解析和处理 Base 链的 internal 交易。这会导致 internal 交易收到资产不会有消息通知，动态里也没有记录。比如从 Uniswap 到账就没有通知。 去年只做过 1 个月的钱包开发，但恰好就负责这种交易记录的解析。</p>]]></summary>
    <content type="html"><![CDATA[<p>Trust Wallet 这么知名的钱包，仍然没有解析和处理 Base 链的 internal 交易。这会导致 internal 交易收到资产不会有消息通知，动态里也没有记录。比如从 Uniswap 到账就没有通知。</p>
<p>去年只做过 1 个月的钱包开发，但恰好就负责这种交易记录的解析。</p>
]]></content>
  </entry>
  <entry>
    <title>感觉天然对 Polymarket 市场的交易机会免疫，套利、策略、理财、赌，从一开始就不相信作为交易员可以在预测市场赚钱...</title>
    <link href="https://t.smallyu.net/#2026-3"/>
    <id>micro:4648295581</id>
    <published>2026-06-08T11:09:08Z</published>
    <updated>2026-06-08T11:09:08Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>感觉天然对 Polymarket 市场的交易机会免疫，套利、策略、理财、赌，从一开始就不相信作为交易员可以在预测市场赚钱。 为什么呢，经历了币圈的洗礼，已经不信了。炒币的人已经反复在说，不要开合约、不要加杠杆、不要炒山寨、不要频繁换仓……</p>]]></summary>
    <content type="html"><![CDATA[<p>感觉天然对 Polymarket 市场的交易机会免疫，套利、策略、理财、赌，从一开始就不相信作为交易员可以在预测市场赚钱。</p>
<p>为什么呢，经历了币圈的洗礼，已经不信了。炒币的人已经反复在说，不要开合约、不要加杠杆、不要炒山寨、不要频繁换仓……</p>
]]></content>
  </entry>
  <entry>
    <title>从我的整个职业生涯的经历出发，我能够幻想到的最赚钱的路径，是作为项目的核心初创人员，拿到团队的内部币权，然后项目如期TG...</title>
    <link href="https://t.smallyu.net/#2026-2"/>
    <id>micro:4647974532</id>
    <published>2026-06-08T10:32:59Z</published>
    <updated>2026-06-12T01:21:29Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>从我的整个职业生涯的经历出发，我能够幻想到的最赚钱的路径，是作为项目的核心初创人员，拿到团队的内部币权，然后项目如期TGE、上交易所、解锁拿到代币，然后在流动性里卖掉。 除此之外，看不到更加清晰的有逻辑的路径，什么链上科学家、安全审计、交易员、BD。 也因此我之前换工作的频率很高，基本上一年一次。每当离开一个项目，我都...</p>]]></summary>
    <content type="html"><![CDATA[<p>从我的整个职业生涯的经历出发，我能够幻想到的最赚钱的路径，是作为项目的核心初创人员，拿到团队的内部币权，然后项目如期TGE、上交易所、解锁拿到代币，然后在流动性里卖掉。</p>
<p>除此之外，看不到更加清晰的有逻辑的路径，什么链上科学家、安全审计、交易员、BD。</p>
<p>也因此我之前换工作的频率很高，基本上一年一次。每当离开一个项目，我都深刻的知道，那个项目一定不行了、一定做起不来、一定会持续走下坡路。</p>
<p>当然，我看不到任何除了“打工”（参与项目、合作）之外能赚钱的方式。</p>
]]></content>
  </entry>
  <entry>
    <title>Hello, I&amp;#39;m back.</title>
    <link href="https://t.smallyu.net/#2026-1"/>
    <id>micro:4646794532</id>
    <published>2026-06-08T08:32:27Z</published>
    <updated>2026-06-08T08:32:27Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Hello, I&amp;#39;m back.</p>]]></summary>
    <content type="html"><![CDATA[<p>Hello, I&#39;m back.</p>
]]></content>
  </entry>
  <entry>
    <title>被 AI 工具裹挟的程序员</title>
    <link href="https://smallyu.net/2026/06/04/%E8%A2%ABAI%E5%B7%A5%E5%85%B7%E8%A3%B9%E6%8C%9F%E7%9A%84%E7%A8%8B%E5%BA%8F%E5%91%98/"/>
    <id>blog:https://smallyu.net/2026/06/04/%E8%A2%ABAI%E5%B7%A5%E5%85%B7%E8%A3%B9%E6%8C%9F%E7%9A%84%E7%A8%8B%E5%BA%8F%E5%91%98/</id>
    <published>2026-06-04T09:02:57.000Z</published>
    <updated>2026-06-04T09:19:27.919Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>6月1日，GitHub Copilot 换成了根据使用量计费的模式。按照我原本的使用习惯，新的计费模式下，一个月至少得花 800 美元才够用，所以不得不寻找更便宜的套餐。这也就导致最近两三天，除了关心工作内容本身，我还需要花费大量时间和精力去体验]]></summary>
    <content type="html"><![CDATA[<p>6月1日，GitHub Copilot 换成了根据使用量计费的模式。按照我原本的使用习惯，新的计费模式下，一个月至少得花 800 美元才够用，所以不得不寻找更便宜的套餐。这也就导致最近两三天，除了关心工作内容本身，我还需要花费大量时间和精力去体验 Antigravity、CodexX 等工具和模型，以及解决不同工具之间切换带来的上下文摩擦。</p><p>当然我还是坚持一贯的偏见：不用 Claude Code 的工具和模型。因为 Claude Code 的模型太过听话，出现路灯效应的现象比较严重。</p><br><p>由此联想到的问题是，自从有了 AI，我们开始关心的话题变成了：</p><ol><li>哪个 AI 模型好用</li><li>哪个 AI 套餐便宜</li><li>哪个 AI 工具好用、prompt 工程做得好</li></ol><p>而 AI 出现以前，我们关心的问题是：</p><ol><li>哪种编程语言好用</li><li>哪种编程语言编译速度快、写起来简单、心智负担小、运行时错误可控</li><li>哪种 IDE 好用</li></ol><p>在 AI 出现以前，有个人站出来说：</p><ol><li>编程语言是不重要的，编程思想才重要</li><li>编程语言的语法是不重要的，从本质上理解语义才重要</li><li>我教给你们学会所有编程语言的方法</li><li>我的工作不是去评价现有的垃圾语言，而是去设计最先进、优雅的编程语言</li><li>……</li></ol><p>那么 AI 出现以后，会不会有个人站出来说：</p><ol><li>AI 模型是不重要的，重要的是使用 AI 的人</li><li>好的程序员应该懂得如何驾驭各种 AI 模型</li><li>理解 AI 模型的能力只是表面，要深刻理解 AI 模型的训练方法、“智力”的来源才重要</li><li>我教给你们理解所有 AI 模型的方法</li><li>我的工作不是评价现有的垃圾模型，而是设计最高效、最先进的 AI 模型</li><li>……</li></ol><p>会不会有这样的人出现呢？🐶</p><br><p>其实我有一个更深层次的焦虑：</p><p>AI 时代，我们曾经学的那些编程语言、原理，都是手工艺时代的知识和技能，是不是已经过期、过时、不重要了？你可以说它本质上重要，但是事实上确实 AI 抹平了大多数程序员的能力。</p><p>或者我换个问题，AI 时代，理解 Lambda 演算还重要吗？把图灵放到现代，他肯定不会写代码，调 API 的能力和普通程序员用 AI 写出来的差不了多少。你觉得这个观点能带来什么启发？</p>]]></content>
  </entry>
  <entry>
    <title>比特币社区在讨论的抗量子计算是怎么回事</title>
    <link href="https://smallyu.net/2026/05/31/%E6%AF%94%E7%89%B9%E5%B8%81%E7%A4%BE%E5%8C%BA%E5%9C%A8%E8%AE%A8%E8%AE%BA%E7%9A%84%E6%8A%97%E9%87%8F%E5%AD%90%E8%AE%A1%E7%AE%97%E6%98%AF%E6%80%8E%E4%B9%88%E5%9B%9E%E4%BA%8B/"/>
    <id>blog:https://smallyu.net/2026/05/31/%E6%AF%94%E7%89%B9%E5%B8%81%E7%A4%BE%E5%8C%BA%E5%9C%A8%E8%AE%A8%E8%AE%BA%E7%9A%84%E6%8A%97%E9%87%8F%E5%AD%90%E8%AE%A1%E7%AE%97%E6%98%AF%E6%80%8E%E4%B9%88%E5%9B%9E%E4%BA%8B/</id>
    <published>2026-05-31T08:15:55.000Z</published>
    <updated>2026-05-31T08:44:55.697Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>引用框里的内容都是 Gemini 生成的。我也不太喜欢这种大量 AI 生成内容的文章，但是很多专业名词和数据又依赖于 AI 给出的数据。所以还是以分享和整理信息为主吧。</p>
<h3 id="生成式-AI"><a href="#生成式-AI"]]></summary>
    <content type="html"><![CDATA[<p>引用框里的内容都是 Gemini 生成的。我也不太喜欢这种大量 AI 生成内容的文章，但是很多专业名词和数据又依赖于 AI 给出的数据。所以还是以分享和整理信息为主吧。</p><h3 id="生成式-AI"><a href="#生成式-AI" class="headerlink" title="生成式 AI"></a>生成式 AI</h3><p>对于我们外行人来说，ChatGPT 3.5 似乎是一夜之间出现的，2023 年横空出世，一下子到达了能够通过图灵测试的地步。而实际上 GPT 已经连续多年发布有突破性的论文，让 GPT 模型不断演进：</p><blockquote><ul><li><strong>2018年（GPT-1）</strong>： 发表论文 《Improving Language Understanding by Generative Pre-Training》，正式提出了“生成式预训练”的概念。</li><li><strong>2019年（GPT-2）</strong>： 发表论文 《Language Models are Unsupervised Multitask Learners》，证明了网页大模型在不需要微调的情况下，就能做很多不同的任务</li><li><strong>2020年（GPT-3）</strong>： 发表了里程碑式的论文 《Language Models are Few-Shot Learners》。这时候模型参数达到了 1750 亿，大家突然发现，大力出奇迹，模型开始展现出惊人的理解能力。</li><li><strong>2022年 3月</strong>，OpenAI 发表了一篇极为重要的论文：《Training language models to follow instructions with human feedback》。在这篇论文中，他们引入了 RLHF（基于人类反馈的强化学习） 技术，训练出了 InstructGPT。</li><li><strong>2022年 11月</strong>，ChatGPT （基于 GPT-3.5 架构）诞生，实际上就是 InstructGPT 的 “亲兄弟” 或直接衍生版。OpenAI 将这种 “听得懂指令” 的模型，套上了一个最符合人类习惯的聊天框界面（UI），并在 2022 年 11 月底作为研究预览版免费开放。</li></ul></blockquote><h3 id="量子计算的现状"><a href="#量子计算的现状" class="headerlink" title="量子计算的现状"></a>量子计算的现状</h3><p>所以针对量子计算的担忧不是杞人忧天，那些我们未曾关注到的行业也许正在发生惊天动地的变化。</p><blockquote><p>如果把之前的量子计算比作 GPT-3 之前的“野生天才”，它空有庞大的计算潜力，但极度不稳定。目前（2026年），整个行业正在全力攻克量子计算的“InstructGPT 时刻”——<strong>量子纠错（QEC, Quantum Error Correction）</strong>。</p><p>目前行业呈现出以下几个核心进展：</p><ol><li>从 “物理比特” 走向 “逻辑比特”</li></ol><ul><li>以前媒体炒作 “IBM 达到 1000 个量子比特” 或 “谷歌实现量子霸权”，那些都是<strong>物理比特（Physical Qubits）</strong>。它们就像极其脆弱的肥皂泡，周围有一点温度波动、Wi-Fi 信号，甚至空气流动，就会发生 “退相干（Decoherence）”，导致计算崩溃。现在的行业共识是：数量不再是唯一标准，<strong>质量（纠错能力）</strong>才是。谷歌的 Willow 芯片和微软、IBM 的最新路线图都在证明一件事——通过把几十甚至上百个脆弱的 “物理比特” 绑定在一起，变成一个具有容错能力的 “逻辑比特（Logical Qubits）”。</li></ul><ol start="2"><li>多技术路线的“军阀混战”</li></ol><p>不同于大模型几乎全盘采用 Transformer 架构，量子计算目前还没有统一的硬件标准：</p><ul><li><strong>超导路线（IBM、谷歌）</strong>： 跑得最快，但需要接近绝对零度（0.015 Kelvin）的极低温冰箱，工程成本极高。</li><li><strong>拓扑量子（微软 Majorana 1）</strong>： 走纯物理学底层突破，利用新型拓扑材料自带的抗噪特性，如果成功，能在一颗芯片上塞进 100 万个比特。</li><li><strong>离子阱&#x2F;光子路线（Quantinuum、Xanadu）</strong>： 在常温或更高温度下表现更好，相干时间长。</li></ul></blockquote><h3 id="击溃加密体系需要的算力"><a href="#击溃加密体系需要的算力" class="headerlink" title="击溃加密体系需要的算力"></a>击溃加密体系需要的算力</h3><blockquote><p>要让现有的全球加密体系（如银行、政府通信、区块链使用的 RSA、ECC、DH 等非对称加密算法）彻底崩溃，传统的经典计算机和未来的量子计算机需要跨越的算力鸿沟完全不在一个维度。</p><ol><li><strong>经典计算机</strong>：需要“宇宙毁灭级”的算力</li></ol><p>目前互联网安全的基石（比如 RSA-2048 算法），其核心数学原理是“大整数质因数分解”。把两个很大的质数乘起来很容易，但要把乘积倒推拆解成这两个质数，极其困难。</p><p>要用现有的超级计算机去暴力破解一个 RSA-2048 密钥，需要多大算力？</p><ul><li><strong>算力需求</strong>： 大约需要 2^112 次运算。</li><li><strong>时间成本</strong>： 即使动用全人类目前所有的超级计算机（包括最顶级的超级计算机集群）一起不吃不喝地算，也需要<strong>几千万年甚至上亿年</strong>。</li><li><strong>能量成本</strong>： 破译一个密钥消耗的电能，可能需要抽干几个地球的能源。因此，在经典计算机的框架下，现有的主流加密体系在物理上是绝对安全的。</li></ul><ol start="2"><li><strong>量子计算机</strong>：只需要“数千个逻辑比特”的降维打击</li></ol><p>量子计算机之所以恐怖，是因为它拥有一个专属的数学武器——Shor 算法（秀尔算法）。</p><p>Shor 算法在处理“大整数质因数分解”时，把计算复杂度的量级从经典计算机的指数级（Exponential）直接降到了多项式级（Polynomial）。</p><p>在量子计算中，算力不再用“每秒运算多少次（FLOPS）”来衡量，而是看“容错逻辑比特（Logical Qubits）的数量”。</p><p>根据目前的理论和工程推算，要在一夜之间攻破 RSA-2048，量子计算机需要达到以下指标：</p><table><thead><tr><th>指标</th><th>理论需求值</th><th>为什么现在做不到？</th></tr></thead><tbody><tr><td><strong>逻辑比特数量</strong></td><td><strong>大约 4000 个</strong>完美的、高质量容错逻辑比特</td><td>目前人类最顶尖的实验室也只能勉强制造出<strong>几十个</strong>逻辑比特。</td></tr><tr><td><strong>物理比特数量</strong></td><td><strong>大约 2000 万个</strong>物理比特</td><td>因为量子极易受到干扰，平均需要几千个脆弱的“物理比特”去纠错、合成 1 个“逻辑比特”。</td></tr><tr><td><strong>破解时间</strong></td><td><strong>大约几小时到几天</strong></td><td>一旦硬件达标，量子计算机只需要喝一杯咖啡或睡一觉的时间，就能解开经典计算机算上亿年的题目。</td></tr></tbody></table></blockquote><h3 id="击溃比特币（ECC-椭圆曲线加密）需要的算力"><a href="#击溃比特币（ECC-椭圆曲线加密）需要的算力" class="headerlink" title="击溃比特币（ECC 椭圆曲线加密）需要的算力"></a>击溃比特币（ECC 椭圆曲线加密）需要的算力</h3><blockquote><p>比特币使用的是 SECP256k1 椭圆曲线加密。相比于 RSA，椭圆曲线在面对量子攻击时更加脆弱。</p><ul><li>攻破比特币的公钥私钥对，理论上只需要 2000 到 3000 个逻辑比特。</li><li>如果量子计算机拥有足够的比特数，它可以在 10 分钟内（比特币下一个区块打包出来之前）直接通过公钥反算出私钥，从而瞬间转移任何钱包里的资产。</li></ul><p>既然只需要 4000 个逻辑比特就能让世界瘫痪，那这一天离我们有多远？</p><p>目前全球的顶尖量子机构（IBM、谷歌、微软、Quantinuum等）正处于从“几百个物理比特”向“数十万个物理比特”冲刺的阶段。按照目前的工程进度预测：</p><ul><li>2026 - 2030年（<strong>安全期</strong>）： 量子计算机的逻辑比特数预计突破三位数，能够用来模拟新材料、新药物，但依然无法撼动 RSA-2048。</li><li>2030 - 2035年（<strong>高危期</strong>）： 如果量子纠错技术（QEC）发生突破，物理比特到逻辑比特的转化率大幅提升，千万级物理比特的计算机可能面世。这时候，现有的加密体系将进入真正的倒计时。</li></ul></blockquote><h3 id="比特币社区的讨论"><a href="#比特币社区的讨论" class="headerlink" title="比特币社区的讨论"></a>比特币社区的讨论</h3><blockquote><p>近期比特币社区（特别是核心开发者、Blockstream 等研究机构）关于量子计算的讨论确实骤然升温，甚至可以说是<strong>近年来争论最激烈的一次</strong>。</p><p>引发这波热烈讨论的直接导火索是 <strong>2026 年 3 月底谷歌、以太坊基金会和斯坦福大学联合发布的一篇重磅论文</strong>。论文指出：攻破比特币底层加密算法（ECDSA）所需的物理比特数量，比之前预估的要<strong>整整低了 20 倍</strong>（大约只需要不到 50 万个物理比特），并且在极端算力下，最快可能在 <strong>9 分钟</strong>内反算出私钥。由于比特币出块时间是 10 分钟，这意味着量子计算机有可能在交易发出后、被打包进区块前的这短短几分钟里，进行“拦截偷地雷”。</p><p>面对这个被大幅压缩的时间表，目前比特币社区主要在密集进行以下三件事：</p><ul><li>推进首个抗量子提案：BIP-360 (P2MR)。这是比特币历史上<strong>第一个正式写入路线图的抗量子改进提案</strong>（Bitcoin Improvement Proposal）。</li><li>激烈争论：“直接搬用美国标准（NIST）” 还是 “用哈希签名”。NIST（美国国家标准局）推荐了 Dilithium 和 Falcon 等基于格（Lattice-based）的抗量子算法。但比特币核心开发者们发现：直接搬过来会要了比特币的命。</li><li>排查“沉睡钱包”，商讨软分叉与“遗产冻结”政策。比特币网络中，真正面临迫切量子威胁的，其实是那些公开了公钥的旧地址。</li></ul></blockquote><h3 id="哪些加密算法受到威胁"><a href="#哪些加密算法受到威胁" class="headerlink" title="哪些加密算法受到威胁"></a>哪些加密算法受到威胁</h3><p>那么我们来搞清楚，到底哪些加密算法会受到量子计算机的威胁，哪些不会：</p><blockquote><p>核心结论：</p><ul><li><strong>非对称加密（RSA&#x2F;ECC）</strong> 依靠的是“精妙的数学大厦”，量子计算机有“画好的图纸（Shor 算法）”，所以一拆就倒。</li><li><strong>单向哈希（SHA&#x2F;Keccak</strong>） 依靠的是“无序的混沌黑盒”</li></ul></blockquote><h3 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h3><p>我发现这样下去不太好，文章里全是复制粘贴 AI 生成的文本，所以干脆放一些后续的问题列表，能够把这个话题延续下去。只要把这些问题复制给任何 AI，都会得到比较好的解答：</p><ul><li>为什么 SHA-256 天生抗量子？</li><li>那么 Merkle root 为什么可以代替用户的公钥来代表资产？</li><li>为什么比特币现在的资产是在公钥里，而不是在 SHA-256(公钥) 里？</li><li>你提到了 P2PK，比特币还有哪几种资产形式，分别都有没有套上 hash？</li><li>现在的 P2TR 是为了干什么来着，或者说有什么特性和优势，相比 P2WPKH？</li><li>以太坊社区推崇的 ZK 加密是在解决什么问题，ZK 加密抗量子计算吗？</li><li>我还是没能太理解，Merkle tree 在选择路径去验证某几个节点的时候，是怎么去选择的？</li><li>为什么全节点要打包给我 Hash(EFGH)？</li><li>全节点知道 EFGH 的数据吗？</li><li>在比特币的 Taproot 中，在最新的抗量子方案中，Merkle tree 是怎么发挥作用的？</li><li>所以我的疑问在于，你刚才提到一句“提供一条到 Merkle Root 的路径证明”，我想知道这个路径是怎么来的？</li><li>那么在 P2MR 的过程中，意思是我的资产是被锁在某个叶子节点上吗？</li><li>我理解了，那么 A、B、C、D 其实分别都是一把钥匙，每次都使用不同的钥匙，用来抵抗量子计算的攻击？</li><li>我还是不理解，这个 Merkle tree 默认有多少个节点？一个用户的私钥默认有多少个节点？</li><li>Merkle tree 的节点数量一旦生成，是不是就不能改了，因为 root hash 是确定性的？</li><li>我想想，P2MR 中，节点会知道我的 Merkle tree 上有几个节点吗？</li><li>那么这个使用场景，和那种轻节点从全节点拿某一个 hash 值的场景，其实是不一样的？</li></ul><p>这个问题列表反映出另外一个有意思的点，我早期的 <a href="/2025/12/02/%E6%88%91%E5%AF%B9%E4%BA%8EAI%E6%97%B6%E4%BB%A3%E7%9A%84%E7%AD%94%E6%A1%88/">观点和结论</a> 在于，AI 时代，回答问题的能力已经不重要，而提问问题的能力更加重要。这个问题列表正是印证了这一点，答案不重要，任意一个顶级 AI 模型都可以解答。而提问问题的过程和思路是重要的。</p>]]></content>
  </entry>
  <entry>
    <title>最近大半年的工作</title>
    <link href="https://b.smallyu.net/2026/05/27/%E6%9C%80%E8%BF%91%E5%A4%A7%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C/"/>
    <id>blog-b:https://b.smallyu.net/2026/05/27/%E6%9C%80%E8%BF%91%E5%A4%A7%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C/</id>
    <published>2026-05-27T09:00:16.000Z</published>
    <updated>2026-05-27T08:59:37.027Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>前几年关于工作内容方面的回顾：</p>
<ul>
<li>2025 年：《<a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>前几年关于工作内容方面的回顾：</p><ul><li>2025 年：《<a href="/2025/10/18/%E6%9C%80%E8%BF%91%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">最近一年的工作回顾</a>》</li><li>2024 年：《<a href="/2024/02/17/%E6%9C%80%E8%BF%91%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C/">最近半年的工作</a>》</li><li>2023 年：《<a href="/2023/05/06/%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">半年的工作回顾</a>》</li><li>2022 年：《<a href="/2022/08/27/%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">一年的工作回顾</a>》</li></ul></blockquote><h3 id="一个-friend-tech-仿盘项目"><a href="#一个-friend-tech-仿盘项目" class="headerlink" title="一个 friend.tech 仿盘项目"></a>一个 friend.tech 仿盘项目</h3><p>大概开发了两个月，MVP 功能基本完成，公开内测之后运营效果比较差，就直接搁置了。我承担包括合约开发、后端逻辑开发、前端界面开发。</p><p>这个项目在产品形态上做成了 friend.tech + 分答（知乎）+ NGL 模式的混合体。</p><p>项目的核心逻辑是，creator 为主体，可以创建 card（key），card 的价格可以被炒作。其他人可以向 creator 提问问题，creator 回答问题的时候，可以选择公开或者不公开。对于不公开的回答，其他人可以花费 1 USD 来解锁答案。同时，creator 接受匿名提问（NGL 模式）。</p><p>还有一些运营方面的功能，可以根据 X 账号给别人创建 card、一键把 X 账号的信息同步到网站上之类。</p><h3 id="一个内部的加密货币交易和控盘工具"><a href="#一个内部的加密货币交易和控盘工具" class="headerlink" title="一个内部的加密货币交易和控盘工具"></a>一个内部的加密货币交易和控盘工具</h3><p>开发了大概两个月，核心逻辑基本可用，虽然还有 bug。我承担包括后端和前端逻辑的开发。</p><p>这个 Trading Bot 的核心功能包括：批量生成钱包、从 Binance、BitMart、MEXC 批量提现、集成了 Aerodrome 和 Uniswap 交易、支持 V2 和 Slipstream 交易池，功能模块上可以一键导入代币、管理交易对、管理 project，支持一键批量 warm up 钱包的交易、在某一个价格范围内的 range trading 交易。有 K 线图、一键 simulation 交易数据、根据 simulation 数据创建 task、交易结果 analysis 等。还有余额情况的 snapshot、trends 图、gas fee 图等。还有对某一个代币持仓情况分布的监控、对某一个地址行为的监控等。</p><h3 id="一个预测市场的-TG-小程序"><a href="#一个预测市场的-TG-小程序" class="headerlink" title="一个预测市场的 TG 小程序"></a>一个预测市场的 TG 小程序</h3><p>两周时间出 MVP，当时在考虑做预测市场周边的项目，但是不确定做什么，所以这个小程序类似一个 Polymarket 平台的 paper trading 游戏，只是比交易更简单，在 PM 已经结束的 markets 中，单纯选择 yes 和 no，然后和真实的事件结果对比。用户有积分榜、连胜榜等统计。</p><h3 id="一个预测市场的-Dex-Screener"><a href="#一个预测市场的-Dex-Screener" class="headerlink" title="一个预测市场的 Dex Screener"></a>一个预测市场的 Dex Screener</h3><p>可能做了不到一个月，说实话做的很糟糕。项目本意是做预测事件的跨平台对比，我们索引了 DefiLlama 上排名靠前的六七个预测市场的数据，包括 Polymarket、Kalshi、Limitless Exchange 等，然后试图把数据整合为一种事件数据对比的工具界面。</p><p>但是遇到不少问题，这种预测市场本质上是中心化的交易平台，对标 Binance、OKX 这种交易所，而不是去中心化的数据。预测市场基本上都是链下撮合、链上交易的模式，所以索引数据本身就是个问题，很大程序上受到平台方 API 的 rate limit 限制。</p><p>其次是数据分析比较重，哪怕通过 Subgraph 之类索引到全部的数据，也需要稍微高配的数据库和硬件做分析，需要不小的硬件成本。</p><p>最后是盈利模式的问题，除非数据分析的非常好非常准，然后以订阅制也就是 BaaS 的运作模式收费，否则普通用户看到了跨平台的数据、甚至看到套利机会，然后呢，去对应的平台交易了。所以这个方向比较吃力不讨好。</p><h3 id="一个预测市场语义搜索入口"><a href="#一个预测市场语义搜索入口" class="headerlink" title="一个预测市场语义搜索入口"></a>一个预测市场语义搜索入口</h3><p>做了可能不到半个月。基于做 Screener 索引到的大量数据，就发现市场上存在一个缺口，就是把新闻一类的信息，和真实的预测市场的交易盘之间，如何关联起来？</p><p>所以我们做的事情是把预测市场摘要文本生成 embedding 数据存起来，用户可以输入任意文本，无论是长文本还是短文本，然后返回与搜索文本相匹配的 markets 数据，包括 Polymarket、Kalshi 等。</p><p>这个功能的本意是，假如用户看到一个突发新闻，想要去 Polymarket 上下注，但是又不知道有哪些可以下注的 markets。</p><h3 id="一个预测市场的交易终端"><a href="#一个预测市场的交易终端" class="headerlink" title="一个预测市场的交易终端"></a>一个预测市场的交易终端</h3><p>这是现在仍然在进行的项目，已经开发了三四个月，参考了 Polymarket Builder 榜单上的主流项目，现在 Web Terminal 和 TG Copy Trading 两个方向在同时推进。</p><p>这个项目主要就是通过预测市场平台的 API 进行套壳交易，已经支持了 Polymarket 和 Predict.fun 两个平台，也支持了针对 Polymarket 交易的 Copy Trading。当然也在试图集成一些概念，比如 AI 分析、AI Skills、托管自动交易等。</p><br><h3 id="工作之外"><a href="#工作之外" class="headerlink" title="工作之外"></a>工作之外</h3><p>现在，AI Coding 已经成为事实上在发生的事情，会带来深刻的变革。关于程序员的身份认同、价值体现、差异性来源等问题，我发现两句有意思的话，并且附带来源：</p><blockquote><p>Computer science can be probably called applied logic because it originated from logicians.</p></blockquote><p>来源：《<a href="https://www.yinwang.org/resources/gucs-sample-chapter3.pdf">Ground-Up Computer Science</a> 》第 3 章</p><blockquote><p>Programming is just another name for the lost art of thinking.</p></blockquote><p>来源：《<a href="https://www.yinwang.org/resources/gucs-sample-chapter7.pdf">Ground-Up Computer Science</a> 》第 7 章</p>]]></content>
  </entry>
  <entry>
    <title>电影《阿嬷的情书》</title>
    <link href="https://crazy.smallyu.net/2026/05/23/%E7%94%B5%E5%BD%B1%E3%80%8A%E9%98%BF%E5%AC%B7%E7%9A%84%E6%83%85%E4%B9%A6%E3%80%8B/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/05/23/%E7%94%B5%E5%BD%B1%E3%80%8A%E9%98%BF%E5%AC%B7%E7%9A%84%E6%83%85%E4%B9%A6%E3%80%8B/</id>
    <published>2026-05-23T03:53:04.000Z</published>
    <updated>2026-07-04T17:36:19.133Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>感人，还算好看，重点是不油腻，没有大起大和的国家情怀，也不会强调什么车马慢，非得把历史背景和科技条件摆到你眼前。大多数油腻和俗套的要点都没有。</p>
<p>电影里真正的女主是谢南枝，最感人的故事也是谢南枝的行为。</p>
<p>从常理来推断，谢南枝的行为是不符合逻辑的。木]]></summary>
    <content type="html"><![CDATA[<p>感人，还算好看，重点是不油腻，没有大起大和的国家情怀，也不会强调什么车马慢，非得把历史背景和科技条件摆到你眼前。大多数油腻和俗套的要点都没有。</p><p>电影里真正的女主是谢南枝，最感人的故事也是谢南枝的行为。</p><p>从常理来推断，谢南枝的行为是不符合逻辑的。木生确实救了谢南枝父女的命，但是木生死了，南枝终生未嫁，十八年供养着两个家庭。行为有点过于崇高，如果解读为为了报恩，显然是不合理的。</p><p>我对于谢南枝的理解是，谢南枝羡慕淑柔，羡慕淑柔有一个木生这样，有爱有情义的老公。所以谢南枝在救赎淑柔的同时，也就是在救赎自己。谢南枝把自己投射到了淑柔身上，盼望有一个远在他乡的爱自己的丈夫。为了营造这个梦，同时也是怜悯自己，谢南枝才做出了这样“感人”的行动。</p><p>电影的故事很复杂，人的情感也很复杂，电影剧情平平，但是打动人。</p>]]></content>
  </entry>
  <entry>
    <title>为什么买的加密货币一定要去中心化</title>
    <link href="https://smallyu.net/2026/05/16/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B9%B0%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E4%B8%80%E5%AE%9A%E8%A6%81%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96/"/>
    <id>blog:https://smallyu.net/2026/05/16/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B9%B0%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E4%B8%80%E5%AE%9A%E8%A6%81%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96/</id>
    <published>2026-05-16T08:50:14.000Z</published>
    <updated>2026-05-18T08:32:57.121Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>中心化的加密货币价格能不能涨呢？能涨，而且拉盘、控盘、砸盘更狠。大一点的像 ETH，SOL、BNB，随意一点的就是 TRUMP、DOGE]]></summary>
    <content type="html"><![CDATA[<p>中心化的加密货币价格能不能涨呢？能涨，而且拉盘、控盘、砸盘更狠。大一点的像 ETH，SOL、BNB，随意一点的就是 TRUMP、DOGE 一类。但是你要相信，如果你是从二级市场开始参与，那么拉盘周期吃到肉的人，一定不会是你。要么喝汤，要么被割（大概率）。</p><p>美股能不能涨呢？能涨，虽然所有的股票都是中心化的，但是完全适合用于投资，因为有监管，有审核。英伟达、苹果、谷歌、特斯拉。</p><p>从投资者的视角，硅谷已经不从二级市场割韭菜了，从 1.5 级市场就开始割。OpenAI 和 Anthropic 万亿美元级别的估值，一旦上了二级市场，就等着小韭菜们接盘，价格会逐渐跌。但是人家融资，你有钱也投不进去。真正顶级的公司，一级市场都没机会。而不那么顶级的公司，几个 VC 互相割。不管能不能 IPO 割小韭菜，VC 的钱是割到了。</p><p>人们买加密货币是为了什么？是为了高倍的涨幅，想从中挣钱。币圈没有信仰，要有信仰也都是信仰钱。金融市场都是为了钱。没有人是为了去中心化的信仰和理想买比特币的。</p><p>回到比特币的初衷，比特币想干什么来着？比特币想要抗通胀。现代政府和金融体系要依靠负债表的不断扩张，来维持社会运转，也就意味着法币从趋势上是持续增发的。</p><p>比特币有供应量上限，正是为了应对通胀。所以 ETH 等所有没有供应量上限的公链，哪怕代币供应量是动态条件之后通缩的，也达不到抗通胀的目的。</p><p>2008 年，全球的法币总供应量大概 21 万亿美元，因此比特币的总供应量设计为 2100 万。按照当时的愿景，当比特币能代替全球的法币职能的那一天到来，一个 BTC 的价格应该等于（当时的） 100 万美元。</p><p>这不是巧合，比特币的精度是 8 位小数点，最小单位是 sat，那么如果 1 BTC &#x3D; 100 万美元，恰好 1 sat &#x3D; 1 美分，美元的最小单位就是比特币的最小单位。</p><p>2009 年，密码学家 Hal Finney 成为历史上第一个接受比特币转账的人，收到了来自中本聪 10 BTC 的转账。</p><p>2009 年，全球的家庭总财富体量大概在 100 万亿到 300 万亿之间。按照这个财富价值估算，如果比特币在全球的资产储备中占据主导地位，一个 BTC 的价格将约等于（当时的） 1000 万美元。</p><p>2027 年，全球货币总供应量大概 70 万亿美元，全球家庭财富总量大概 530 万亿美元。映射到比特币上，如果按照 M1 供应量计算，每个 BTC 的价值等于 333 万美元。如果按照财富总量计算，每个 BTC 的价值等于 2650 万美元。</p><p>这就是比特币的特殊之处，比特币不是为了创造下一个百万富翁，而是为了保护全世界人的资产不受到损失。BTC 的价格不应该再大幅暴涨，而是应该稳定逐步随着法币的增发而价值上涨。</p><p>从抗通胀的逻辑，比特币和黄金在同一个赛道，山寨币和美股在同一个赛道。</p><p>所以结论是：</p><ol><li>定投 BTC、PAXG</li><li>Alpha 机会你自己随缘，ETH、Nvidia 等，Do Your Own Research</li><li>争取一级市场机会，投资、工作、创业，你自己想办法</li></ol><p>两个负面规则：</p><ol><li>不要指望一个素不相识的人发个币让你买，就能带你起飞</li><li>炒币、炒股造就的富翁很少，大多数是做了什么事情、参与了什么项目、有什么实体企业。只要还在牌桌上，就没有赢家</li></ol>]]></content>
  </entry>
  <entry>
    <title>在币圈不要做撸毛党</title>
    <link href="https://crazy.smallyu.net/2026/05/10/%E5%9C%A8%E5%B8%81%E5%9C%88%E4%B8%8D%E8%A6%81%E5%81%9A%E6%92%B8%E6%AF%9B%E5%85%9A/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/05/10/%E5%9C%A8%E5%B8%81%E5%9C%88%E4%B8%8D%E8%A6%81%E5%81%9A%E6%92%B8%E6%AF%9B%E5%85%9A/</id>
    <published>2026-05-10T13:52:20.000Z</published>
    <updated>2026-07-04T17:36:19.132Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>2022 年、2023 年，OP 和 ARB 大火，让很多撸毛的玩家挣到了大笔的钱。因为 Layer 2 概念火热、配合着币圈的牛市，空投的代币价格超预期的高。</p>
<p>2024 年，我从 __]]></summary>
    <content type="html"><![CDATA[<p>2022 年、2023 年，OP 和 ARB 大火，让很多撸毛的玩家挣到了大笔的钱。因为 Layer 2 概念火热、配合着币圈的牛市，空投的代币价格超预期的高。</p><p>2024 年，我从 __ 离职，当时对接工作的人，似乎对撸毛很感兴趣。我当时的观点是，“撸毛都是不可持续的，所以不要做”。</p><p>这个观点的原因有两个，一个是当时我对自己的定位，在于开发者，所以你会觉得 OP 的开发者去撸毛吗？当然不会，他们只会内部等待 Token 的解锁。再一个原因是，撸毛党确实收入不稳定，三年不开张，开张吃三年，但是没有人能确定三年能开张一次。</p><p>后来 2025 年熊市，Polymarket 是唯一出圈、大火的方向。</p><p>交易所为什么挣钱呢，因为交易所挣的根本不是手续费，是爆仓的客损。在推特，你花 20 美元，就是尊贵的会员，免广告、能编辑长文信息什么的。在各种服务平台，只要你一个月花 20 美元，你都是权限非常高的会员。</p><p>但是币安不是，在币安你可能从来没有感觉自己花了手续费，但是一爆仓就是几千、几万。你给平台贡献的金钱，远超订阅费、会员费。所以交易所，是真正的灰产，但是还不够黑。</p><p>Polymarket，是真正意义的赌场，手续费根本不重要，重要的是事件必然会结算。一旦结算，就意味着有一半的人会爆仓、被清算。</p><p>相应的，有一些人开始研究、琢磨所谓的交易策略，想要抢占系统的漏洞、在结算时机前买入赚点利差之类。这些策略类型的赚钱方式，总结起来就是大概率有可能能挣钱，但是存在可能亏钱，一旦亏钱，挣得钱就都得赔进去。</p><p>这个和币圈的撸毛，道理是一样的。只要你在牌桌上，只要你不下桌，就不可能一直赢下去。</p><p>所以我从来不相信预测市场的交易策略，哪怕现在能挣钱，哪怕今年能挣钱，除非一次性挣够了财富自由的钱，或者挣一次钱之后永远离开牌桌。否则这些钱都不是你的，早晚还要亏进去。</p><p>这个等同于交易货币中的合约交易，尤其是加杠杆的交易。预测市场，也就是个赌博版本的合约交易。</p>]]></content>
  </entry>
  <entry>
    <title>什么是 “俗”</title>
    <link href="https://crazy.smallyu.net/2026/04/25/%E4%BB%80%E4%B9%88%E6%98%AF%E4%BF%97/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/04/25/%E4%BB%80%E4%B9%88%E6%98%AF%E4%BF%97/</id>
    <published>2026-04-25T07:24:57.000Z</published>
    <updated>2026-07-04T17:36:19.131Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>结婚生子，家长里短，柴米油盐，就是俗。<br>胸无大志，安居乐业，就是俗。<br>趋炎附势，人云亦云，为生计奔波，就是俗。   ]]></summary>
    <content type="html"><![CDATA[<p>结婚生子，家长里短，柴米油盐，就是俗。<br>胸无大志，安居乐业，就是俗。<br>趋炎附势，人云亦云，为生计奔波，就是俗。    </p><p>自从工作以来，工作上的一些小钱比如打车、吃饭、个别网络上的开销之类，从来都懒得填工单、去申请报销。为了那么点小钱刻意报销，太无聊了，不值得操作，很俗。</p><p>想跳槽就跳槽，为了工资忍受垃圾工作、垃圾同事，被每个月挣那点钱拿捏，唯唯诺诺，就是俗。</p><p>代码里出现中文，就是俗。</p><p>为了结婚找对象、百般讨好女性，实际上是一种价值交换的思路，就是俗。</p><p>平凡市井、人间百态，都是俗。</p>]]></content>
  </entry>
  <entry>
    <title>RISC-V 虚拟机无法代替 EVM 虚拟机</title>
    <link href="https://smallyu.net/2026/04/24/RISC-V%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%97%A0%E6%B3%95%E4%BB%A3%E6%9B%BFEVM%E8%99%9A%E6%8B%9F%E6%9C%BA/"/>
    <id>blog:https://smallyu.net/2026/04/24/RISC-V%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%97%A0%E6%B3%95%E4%BB%A3%E6%9B%BFEVM%E8%99%9A%E6%8B%9F%E6%9C%BA/</id>
    <published>2026-04-24T12:34:05.000Z</published>
    <updated>2026-04-24T12:41:19.686Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<ol>
<li>RISC-V 太复杂，非常依赖于虚拟机沙盒环境的标准化，但是现在还没有统一的规范</li>
<li>EVM 经过多年百亿级别金融生态的磨练，从开发到审计已经比较成熟，切换到 RISC-V 的成本很高</li>
<li>RISC-V]]></summary>
    <content type="html"><![CDATA[<ol><li>RISC-V 太复杂，非常依赖于虚拟机沙盒环境的标准化，但是现在还没有统一的规范</li><li>EVM 经过多年百亿级别金融生态的磨练，从开发到审计已经比较成熟，切换到 RISC-V 的成本很高</li><li>RISC-V 虚拟机的冯诺伊曼税更高、确定性更脆弱</li></ol><p>Gavin Wood 当年在设计 EVM 的时候，会面临两个问题：基于栈还是基于寄存器？显然实际上的 EVM 是基于栈的，也许是出于上线迭代等外部因素影响，也许是出于 Gavin 当时的历史局限性。后来 Gavin 离开了以太坊、创建了 Polkadot 之后，一开始把 Polkadot 的虚拟机设计为 基于 WASM 虚拟机，最近又转向了基于 RISC-V 指令集的、用于实现通用计算的虚拟机。也就是说，Gavin 抛弃了基于栈的 EVM 的老路，最终转向寄存器结构的 RISC-V。</p><p>EVM 底层是 256 位的无符号数字，每一条指令、每一个数据，都会拆解为 256 位的数字来表示。至于为什么是 256 位，可能因为以太坊是从比特币演变来的，而哈希算法 Keccak-256 和签名算法 secp256k1 等都沿用了比特币的设计，它们的输出都是 256 位，为了无缝适配这些加密算法，就采用了 256 位的字长。</p><p>我们平时使用的电脑 CPU，大都是 64 位的。CPU 经历过 32 位的时代，但是由于在地址寻址的方式下，32 位最多表示 2^32 Byte &#x3D; 4 GB 的内存大小，已经跟不上使用需求，所以现在的 CPU 已经都是 64 位的。</p><p>这里有两个数字，EVM 是 256 位的，CPU 是 64 位的。这也就意味着，每一个 EVM 的指令操作，到了 CPU 上都至少需要 10 个指令来完成，模拟一个栈内存、计算低位、计算高位、把结果推回栈等，这一套动作下来，256 位的 EVM 指令在执行效率上，比使用 64 位 CPU 指令，慢大概 10 倍到 100 倍。</p><p>RISC-V 是一个精简的指令集架构标准，包含有 64 位的 RISC-V 虚拟机指令标准。这就意味着，通过 JIT 编译，RISC-V 的指令几乎可以 1:1 映射到现代 64 位的 CPU 上，执行效率接近于 CPU 本身的效率。</p><p>Arbitrum 有过一次叫 Stylus 的 <a href="https://chronicle.castlecapital.vc/p/state-arbitrum">版本升级</a>，内容是用运行于 WASM 的虚拟机性能与 EVM 虚拟机的性能进行对比，官方的宣传口径是，一个简单的加法 <code>ADD</code> 运算，在 WASM 上的 Gas 消耗比在 EVM 上少 150 倍，而这 150 倍就是指令集转换带来的额外开销。WASM 的性能比 RISC-V 差，因为 WASM 从设计之初是在浏览器环境运行一个多编程语言的虚拟机，所以合理推测，基于 RISC-V 的指令，性能上也要好过 EVM 至少 100 倍。</p><p>从指令执行的效率方面来看，RISC-V 绝对要好过 EVM 太多。</p><p>另一方面，RISC-V 非常适合做通用计算，比如 <a href="https://cartesi.io/">cartesi</a> 这个项目，相当于直接在每一个链上节点本地，运行一个小型的 Linux 系统，这个系统内能运行的，就不只是智能合约，而可以包括各种各样进程级别的程序，这能释放很大的想象空间。</p><p>很多 zkVM 也都是基于 RISC-V 在做，毕竟要给一个 256 位的虚拟机以及各种复杂的指令集开发 ZK 电路，心智负担太大了，而 RISC-V 是一个精简指令集，只有比较底层的指令，比 zkEVM 实现起来要更加容易并且通用。</p><p>至于 EVM 方面，也有在性能方面做出卓越突破的链比如 <a href="https://www.monad.xyz/">Monad</a>，实现了真正的并行 EVM。只不过 Monad 提高性能的方式并不是从比较底层的指令集层面去做，而是乐观执行、有冲突再回滚的方式，以及实现了专用的数据库而不是通用的 KV 数据库来提高磁盘 IO 效率，整体结合下来，让 EVM 的执行速度有了显著提升。</p><p>那么至此可以看到的是，基于 RISC-V 指令集的虚拟机、智能合约语言，有着种种性能上的优点。</p><p>是不是意味着 RISC-V 是替代 EVM 的最佳趋势呢？显然也不是。</p><p>生态方面的护城河当然很重要，RISC-V 属于彻底抛弃了 EVM 体系、自成一套，支持各种编译型的编程语言。那也就意味着，包括开发者和审计公司，在 EVM 上踩过的坑，需要推倒重来。这是谁都不愿意看到的事情。EVM 的简单带来了性能上的劣势，也让安全风险和执行逻辑上的排查更加可控，因为是栈结构，Solidity 语言里连指针操作都没有，确定性非常高。而 RISC-V 的寄存器模式，合约的 ABI 不再是字节码而是 ecall ABI，里面涉及到内存分配、有堆内存、有垃圾回收，复杂度非常高。</p><p>而为了解决确定性的问题，一般的做法是在 RISC-V 支持的编程语言上，再阉割一层，用一个沙盒环境来执行合约逻辑，并且禁用一些语言特性，从沙盒外部能够看到一个确定性的结果。这当然就会牵扯到，每一个项目都在定义自己的沙盒标准，没有业界统一的方案。</p><p>再就是很多项目方宣传口径上的问题，放大了 RISC-V 的性能优势，刻意在忽略 RISC-V 模式带来的冯诺伊曼税的问题。在 EVM 上，修改余额就是一个 SSTORE 指令，EVM 天然知道什么是账户、什么是余额，要去数据库的什么位置寻找数据。而 RISC-V 过于通用，如果要修改余额，可能需要先分配内存、处理语言运行时的边界检查、写入数据、释放内存等，虽然单个指令的执行效率高了，但是反而在业务逻辑上消耗了更多的 CPU 周期。</p><p>总的来说，RISC-V 虚拟机还无法代替 EVM 虚拟机。</p>]]></content>
  </entry>
  <entry>
    <title>希望少年时候的伙伴都能有所成</title>
    <link href="https://crazy.smallyu.net/2026/04/23/%E5%B8%8C%E6%9C%9B%E5%B0%91%E5%B9%B4%E6%97%B6%E5%80%99%E7%9A%84%E4%BC%99%E4%BC%B4%E9%83%BD%E8%83%BD%E6%9C%89%E6%89%80%E6%88%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/04/23/%E5%B8%8C%E6%9C%9B%E5%B0%91%E5%B9%B4%E6%97%B6%E5%80%99%E7%9A%84%E4%BC%99%E4%BC%B4%E9%83%BD%E8%83%BD%E6%9C%89%E6%89%80%E6%88%90/</id>
    <published>2026-04-23T15:39:35.000Z</published>
    <updated>2026-07-04T17:36:19.132Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>我希望我所有的小时候认识的人都可以事业有成，这样我就不会没有朋友了</p>
<p>我为什么没有朋友呢，我离开了小小的村子，初中去了稍微大一点的村子，高中去了县城，大学去了省会城市，毕业后工作去了首都。</p>
<p>每一个小小的人生阶段，都在全面抛弃以前的人际关系。</p>]]></summary>
    <content type="html"><![CDATA[<p>我希望我所有的小时候认识的人都可以事业有成，这样我就不会没有朋友了</p><p>我为什么没有朋友呢，我离开了小小的村子，初中去了稍微大一点的村子，高中去了县城，大学去了省会城市，毕业后工作去了首都。</p><p>每一个小小的人生阶段，都在全面抛弃以前的人际关系。</p><p>那么为什么进入新的环境就没办法再保持联系了呢？哪怕线上。</p><p>有什么可联系的呢。学历、背景、工作、生活完全不一样。</p><p>假如我幼儿园认识的人，都能够一路成长起来，现在也生活在这里呢。</p><p>……倒也是，曾经也有我小时候认识的人，可是中间几年不见，已经也相去甚远了。</p><p>假如我出生在这里呢。我的幼儿园同学，小学、初中、高中、大学同学都在这里，现在会是什么样的场景。</p><p>我可以随时见到他们，也可以跟他们聚会、见面、娱乐、甚至讨论工作、项目机会。</p><p>我并不遗憾自己现在没有朋友，也不期待我的旧同伴们混的不好。只是确实离得太远了。</p>]]></content>
  </entry>
  <entry>
    <title>Polkadot 的 Existential Deposit 机制错在哪里</title>
    <link href="https://smallyu.net/2026/04/22/Polkdot%E7%9A%84Existential-Deposit%E6%9C%BA%E5%88%B6%E9%94%99%E5%9C%A8%E5%93%AA%E9%87%8C/"/>
    <id>blog:https://smallyu.net/2026/04/22/Polkdot%E7%9A%84Existential-Deposit%E6%9C%BA%E5%88%B6%E9%94%99%E5%9C%A8%E5%93%AA%E9%87%8C/</id>
    <published>2026-04-22T09:50:48.000Z</published>
    <updated>2026-04-22T09:55:32.176Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Polkadot 有一个叫 <a]]></summary>
    <content type="html"><![CDATA[<p>Polkadot 有一个叫 <a href="https://support.polkadot.network/support/solutions/articles/65000168651-what-is-the-existential-deposit-">Existential Deposit (ED)</a> 的机制，含义是如果你的账户余额小于 1 DOT，区块链网络会直接删除你的账户以及余额。删除的意思是指，你的地址信息将不存在于链上，其他地址无法转账小于 1 DOT 给你，你的余额以及 Nonce 值会被直接抹除，整个网络的代币总供应量也会因此减少。</p><h3 id="问题背景"><a href="#问题背景" class="headerlink" title="问题背景"></a>问题背景</h3><p>我们先来理解一下为什么 ED 这样的设计会存在。Vitalik 要说代码和工程水平可能远不及他拥有的名气，Gavin Wood 是以太坊的实际开发者。Gavin 因为实际设计了以太坊的节点，所以很清楚以太坊存在状态数据会无限膨胀的问题。</p><p>以太坊节点会把整条链上所有有过交易记录的地址信息，都维护到世界状态中，用的是一种叫 MPT 的树结构，每个地址信息都是树上的一个叶子节点。那么就存在一个问题，我们平时使用以太坊钱包也会有体会，如果地址里有 0.00001 ETH 的余额，这种非常小额的余额，是永远无法被转出的，因为以太坊对于普通转账交易，固定要求 21000 Gas，无论 Gas Price 多低，以太坊账户的余额都不可能彻底清零。这种非常小的余额被称为粉尘余额，对于强迫症来说会是一种灾难。</p><p>对于以太坊节点来说，这些地址以及余额，就不仅只是视觉上强迫症的问题，而是意味着，节点需要维护的状态数据，永远都会只增加、不减少。每多一个新的地址有余额，服务器上的节点就需要多储存一份地址的键值对信息，哪怕对内存的占用量很小，也会持续累积和增加，给服务器持续带来压力。这种设计在工程上是很暴力、不负责也不合理的。</p><p>针对粉尘余额，存在两个问题，我们分别来对比：</p><ol><li>用户视角的粉尘余额是否可以消除、让余额彻底清零</li><li>节点视角的粉尘余额是否会持续给服务器增加压力</li></ol><h4 id="用户视角"><a href="#用户视角" class="headerlink" title="用户视角"></a>用户视角</h4><p>比特币是如何解决粉尘余额问题的？假如有一个 UTXO 地址里的余额非常小只有 1 sats，那么自己发起转账肯定是不行的，因为 1 sats 不够付矿工费。但是比特币的交易允许有多个 input，只要把小额的 UTXO 作为其中一个 input，再让其他有大额余额的 UTXO 作为另外的 input 来支付矿工费，整笔交易就可以成功，拥有 1 sats 的 UTXO 余额也会清零。所以是 UTXO 账户模型让比特币天然没有粉尘余额的问题。</p><p>以太坊是粉尘余额的起源地，所以目前始终无法解决。</p><p>Polkadot 为了解决粉尘余额的问题，把 Existential Deposit 作为 Day Zero 的核心设计写到了协议里。余额小于 1 DOT 就会被自动清除，自然不存在粉尘余额的问题。这种清除余额并不是指余额会转给矿工或者转给黑洞地址，而是凭空消失一样地清除。</p><h4 id="节点视角"><a href="#节点视角" class="headerlink" title="节点视角"></a>节点视角</h4><p>比特币节点也是需要 chainstate 的，会把所有有余额信息的地址信息都维护在节点的内存中。不过相比以太坊，由于比特币地址的粉尘余额是可以被清零的，而节点方面对于余额是 0 的地址不需要维护一份状态数据，如果一个地址的余额是 0，节点就可以把地址从状态数据中删掉，内存占用就可以减少一点点。所以对于比特币节点来说，状态数据并不会只增不减，而是可以根据实际情况有增有减。</p><p>以太坊节点呢，一方面因为用户余额本身就无法清零，余额再小节点也得维护状态。另一方面在于，以太坊其实有清理状态数据的机制，只是地址可以被清理的要求很苛刻，需要余额为 0，并且 Nonce 值为 0。Nonce 值这个东西，也是比特币没有的概念，以太坊为了账户-余额模型加的。也就是说，哪怕余额为 0 了，只要发出过交易，Nonce 值就不可能是 0。两方面原因叠加下来，以太坊的状态数据会只增不减，持续膨胀。</p><p>Polkadot 呢，同样是利用 Existential Deposit 的设计，会直接清理掉小于阈值的地址以及相关信息，相应的，链上节点维护状态数据的压力就会变小。</p><h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><p>所以 Polkadot 利用 Existential Deposit 这种机制，同时解决了粉尘余额对于用户以及对于节点的影响，在工程上是一种比较纯粹和现代化的设计。</p><h3 id="错在哪里"><a href="#错在哪里" class="headerlink" title="错在哪里"></a>错在哪里</h3><p>回到标题，Polkadot 的这种设计有错吗？</p><ol><li>太过纯粹的工程思维</li></ol><p>程序员群体在解决现实问题的时候，往往会偏好工程化的解决方式，而忽略现实用户的体验。Polkadot 给人的感觉就是，小钱不是钱，我没钱就不配用。</p><p>加密货币作为一种资产，一种货币，一种钱，链上节点像是在回收垃圾一样，把我的余额给回收掉。是不是等同于在说，小的金额就是垃圾？用编程语言的垃圾回收机制，来针对加密资产做回收，这是比较错配的行为。内存中的无效资源、悬空对象可以是垃圾，但是用户的资金不是。在比特币网络，哪怕只有 1 sats，也会安安静静躺在那里。</p><ol start="2"><li>违背了加密货币的原则</li></ol><p>Polkadot 的 Existential Deposit，直接违背了加密货币的根本原则：只有持有私钥的人，才有资产的控制权。</p><p>我们常说 “Not your keys, not your coins”，但是到了 Polkadot 这里，只有你自己持有私钥对吧，但是链上的节点可以直接抹掉你的余额，在没有私钥的情况下让地址内的余额发生了变化。这是一种非常违背原则的做法。</p><p>在区块链中，唯一有效的、对余额产生影响的，应该来自于账本数据，以太坊尚且没有做得这么过分，但是 Polkadot 做了，直接改了状态数据里的余额，在没有交易行为的情况下，引入了节点层面的收割机制。</p><ol start="3"><li>账户模型的原罪</li></ol><p>如果说 <a href="/2025/10/24/%E4%BB%A5%E5%A4%AA%E5%9D%8AAA%E9%92%B1%E5%8C%85%E7%9A%84%E8%87%B4%E5%91%BD%E9%97%AE%E9%A2%98%E6%98%AF%E4%BB%80%E4%B9%88/">AA 钱包</a> 是以太坊为了解决账户模型而打出的一个补丁，那么 Existential Deposit 就是 Polkadot 为了填补账户模型打出的另外一个补丁，试图在以太坊的基础上向前多走一步，而做出的激进设计。</p>]]></content>
  </entry>
  <entry>
    <title>号称有代码洁癖的都是菜x</title>
    <link href="https://crazy.smallyu.net/2026/04/12/%E5%8F%B7%E7%A7%B0%E6%9C%89%E4%BB%A3%E7%A0%81%E6%B4%81%E7%99%96%E7%9A%84%E9%83%BD%E6%98%AF%E8%8F%9Cx/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/04/12/%E5%8F%B7%E7%A7%B0%E6%9C%89%E4%BB%A3%E7%A0%81%E6%B4%81%E7%99%96%E7%9A%84%E9%83%BD%E6%98%AF%E8%8F%9Cx/</id>
    <published>2026-04-12T10:49:34.000Z</published>
    <updated>2026-07-04T17:36:19.132Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>别人用 1 个小时，你用 3]]></summary>
    <content type="html"><![CDATA[<p>别人用 1 个小时，你用 3 个小时，然后说你有代码洁癖，那就是菜x。</p><p>所谓的代码洁癖，是一个标签，是效率低的代名词和挡箭牌。</p><p>有人说自己有代码洁癖，然后另一个人马上附和，我也有代码洁癖，似乎这是一件很光荣的事情。</p><p>差生文具多。我们哪怕是小孩子，都知道整理好自己的物品。再不聪明的人，也知道数落自己关心的东西。</p><p>代码洁癖是人类与生俱来的、生来就有的性格。但是刻意把这种整理的爱好当作优点，就是技术菜、能力差、效率低。</p><p>负责任地说，用代码洁癖来形容自己的人，绝对属于团队里面不是真正干活的那一类人。</p><p>干活需要时间，出结果需要时间。</p><p>你把时间用在代码洁癖上，算什么。</p><p>想起来 Pell 团队同事了。想起来就生气。一群菜鸟。</p>]]></content>
  </entry>
  <entry>
    <title>尽量还是不要负债</title>
    <link href="https://crazy.smallyu.net/2026/04/11/%E5%B0%BD%E9%87%8F%E8%BF%98%E6%98%AF%E4%B8%8D%E8%A6%81%E8%B4%9F%E5%80%BA/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/04/11/%E5%B0%BD%E9%87%8F%E8%BF%98%E6%98%AF%E4%B8%8D%E8%A6%81%E8%B4%9F%E5%80%BA/</id>
    <published>2026-04-11T10:54:41.000Z</published>
    <updated>2026-07-04T17:36:19.132Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>几个月前，因为这些原因，开始尝试贷款、分期、超前消费：</p>
<ol>
<li>所有的国家和政府，都是依靠发债来维持社会运转</li>
<li>罗永浩负债 6 个亿，王自如负债 2]]></summary>
    <content type="html"><![CDATA[<p>几个月前，因为这些原因，开始尝试贷款、分期、超前消费：</p><ol><li>所有的国家和政府，都是依靠发债来维持社会运转</li><li>罗永浩负债 6 个亿，王自如负债 2 个亿，他们依然在过正常的生活</li><li>保持持有美元、消费人民币、做空人民币的原则</li></ol><p>然后的结果是什么呢，结果就是体感压力非常大：</p><ol><li>每个月的工资还没发，就知道需要多少钱用于还分期。实际可支配金额寥寥无几</li><li>看着长达 2 年的分期，感觉是一种背负在身上的煎熬，意味着以后每个月都要这么度过</li><li>负债会加大对于工作不稳定的恐惧感，一旦断流，就会断供</li></ol><p>于是终于忍不住动用了一些存款，把欠的债务一次性还掉了一半，分期压力降低了不少。</p><p>以前经常看到人们说，还完房贷后一身轻松，想要消费一下开心。看到只是看到，终于自己体会到负债和分期的压力时候，才明白这种感觉，真是一种很让人沮丧的压力。</p><p>假如月入 3000，贷款需要还 2700，那么实际上呢，实际上相当于月薪 300！这是一件非常恐怖的事情。无论绝对值上你的工资是多少，可支配金额就大幅减少，意味着在体感上，你辛苦工作了一个月，结果什么都没落下，什么都买不起，而且接下来一个月，十二个月，都将是这样……你的人生将会陷入绝望的境地。</p><p>所以真的无法想象什么样的 xx 才能做到，贷款 30 年买房…… 这些人无论是被传统观念洗脑，还是被社会新闻洗脑，还是自己没脑子，总之在贷款 30 年的那一刻，就已经宣布了精神上的死亡，毫无疑问。</p>]]></content>
  </entry>
  <entry>
    <title>X 第二次封我的账号</title>
    <link href="https://crazy.smallyu.net/2026/04/08/X%E7%AC%AC%E4%BA%8C%E6%AC%A1%E5%B0%81%E6%88%91%E7%9A%84%E8%B4%A6%E5%8F%B7/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/04/08/X%E7%AC%AC%E4%BA%8C%E6%AC%A1%E5%B0%81%E6%88%91%E7%9A%84%E8%B4%A6%E5%8F%B7/</id>
    <published>2026-04-08T08:12:11.000Z</published>
    <updated>2026-07-04T17:36:19.127Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>比起主动选择的自由，更让人安心的是被动选择。当选择很多的时候，反而不知道该用哪个平台。当被迫排除掉一些选项后，反而清晰了</p>
<p>2025年 7月 14日，X 第一次封了我的账号：</p>
<img src="1.png" width="40%" />

<p>今天]]></summary>
    <content type="html"><![CDATA[<p>比起主动选择的自由，更让人安心的是被动选择。当选择很多的时候，反而不知道该用哪个平台。当被迫排除掉一些选项后，反而清晰了</p><p>2025年 7月 14日，X 第一次封了我的账号：</p><img src="1.png" width="40%" /><p>今天 2026年 4 月 8日，X 封了我的另一个账号：</p><img src="2.png" width="40%" /><p>具体原因不清楚，申诉没有用。我确信自己只是正常在使用，没有刷量或者其他明显异常的行为。而且在 X 上，哪怕是极端或者 18+ 内容，也在允许范围之内，而我的账号也没说什么、什么交互，就反复封我的账号。</p><p>小红书也是类似的，之前发过两个交互量比较大的帖子，带一点刻意的错误或者引战一类的内容，流量不错，但是被小红书删帖了。当时就觉得言论管控太严格，不想用了。而到了 X 上，不是言论是否自由的问题，而是不知道因为什么，直接封号，大概率不是因为发言的内容。</p><p>微博之前因为网络问题，连续点击了 10 次左右一条帖子的转发按钮，被封了 15 天，说是异常交互。就几乎不想再用了。</p><p>总之，微博、小红书、X 等平台，目前注册了新的账号，但是不再发言，只是看一些信息。</p><p>那么为什么非要看呢？确实还真不能不看，既然不好用，那不说话就可以了，看还是得看的。小红书上有一些本地化的经验，什么 APP 就架不住大量女性用户的影响力。X 上则是一线新闻，账号还是需要的。所以接下来的策略也很明确，不再这些平台上发言就可以了。</p>]]></content>
  </entry>
  <entry>
    <title>不要用 Claude 的 AI 模型编程</title>
    <link href="https://b.smallyu.net/2026/04/07/%E4%B8%8D%E8%A6%81%E7%94%A8Claude%E7%9A%84AI%E6%A8%A1%E5%9E%8B%E7%BC%96%E7%A8%8B/"/>
    <id>blog-b:https://b.smallyu.net/2026/04/07/%E4%B8%8D%E8%A6%81%E7%94%A8Claude%E7%9A%84AI%E6%A8%A1%E5%9E%8B%E7%BC%96%E7%A8%8B/</id>
    <published>2026-04-07T12:12:21.000Z</published>
    <updated>2026-04-24T04:07:50.797Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<h3 id="2026-04-24"><a href="#2026-04-24" class="headerlink" title="2026.04.24"></a>2026.04.24</h3><blockquote>
<p>此前 Opus 4.6 和 4.7]]></summary>
    <content type="html"><![CDATA[<h3 id="2026-04-24"><a href="#2026-04-24" class="headerlink" title="2026.04.24"></a>2026.04.24</h3><blockquote><p>此前 Opus 4.6 和 4.7 在该测试中均出现欺骗供应商、拒绝退款、串谋定价等行为。</p></blockquote><p>原文链接：<a href="https://t.me/OneMillion_AI/1551">https://t.me/OneMillion_AI/1551</a></p><h3 id="2026-04-07"><a href="#2026-04-07" class="headerlink" title="2026.04.07"></a>2026.04.07</h3><p>其他从业者感受：</p><blockquote><p>Claude 模型「急于完成任务」的摆烂行为依然明显。</p></blockquote><p>原文链接：<a href="https://www.theblockbeats.info/flash/339963">https://www.theblockbeats.info/flash/339963</a></p><h3 id="2026-03-28"><a href="#2026-03-28" class="headerlink" title="2026.03.28"></a>2026.03.28</h3><p>我对 LLM 模型编程的感受，尤其是对比 GPT 和 Claude 模型，我的感受是，Claude Code 的模型，执行力很强，非常听话，告诉它干什么它就干什么，哪怕技术方案是错的，或者口误打错了字，它也会按照输入的命令执行。GPT 模型则是更有头脑，能够做一些调研、判断类型的事情，还会指出你的错误。</p><p>当然，这个仅仅是体验，所以我又寻找了更多场景和证据，来搞清楚这种使用体验是否是偏见。经过 Gemini 和 Grok 的分析，我注意到这个特质比较关键：</p><blockquote><p>Claude 的特质： 它是绝对的“严谨执行者”。如果你给的指令有逻辑漏洞，或者说得不够清楚，Claude 往往会严格按照你字面上的意思去执行，哪怕结果看起来很蠢；或者它会停下来反复向你确认。</p><p>GPT&#x2F;Gemini 的特质： 我们通常被训练得更具“服务意识”。面对模糊的指令，我们会倾向于去“猜”你的真实意图（Read between the lines），并直接给出我们认为你想要的惊艳结果。</p></blockquote><p>这个特质没有表面上那么简单。表面上，他们的区别在于对于模糊指令的处理，Claude 不会猜测你的意图，而是会根据准确的文字描述来分析问题。GPT 则是会根据指令来猜测义务。深层次上，我发现这个特质对于代码分析和处理也是一样。</p><p>Claude 会根据代码本身来进行分析和修正，而不是猜测你的业务流程和业务意图。这个特点，非常要命。凡是有经验的程序员都会有类似的体会，有一些业务问题，或者在 debug 的时候，往往表面上盯着某几个文件你会得出一种结论，而根据业务逻辑来梳理，会得出另外的一套结论。有些问题，从代码层面看要如何如何解决，但是从业务层面看，有一些隐性的约束以及外部 API 的约束，就导致这个问题本身不再是代码问题。</p><p>Claude 的逻辑能力并非不够强，而是由于 AI 宪法的存在，Claude 会执着于代码逻辑，而不会猜测你的指令以及代码的意图，单纯脱离场景分析代码的问题。Claude 给出的往往是代码落实方案，而 GPT 给出的是场景分析、业务层面的 trade-off 方案。我们都知道，在大多数工作场景中，代码实际上是不重要的，理解业务才是重要的。不能理解业务逻辑的代码，就是低级的代码。跟程序员一样。</p><p>再补充一个例子。业务场景是，链下 Order id，链上 Tx hash，数据库里保存映射关系，然后前端展示。遇到的问题是前端展示不出关联关系。Claude 在分析之后，很自信的给出了修复方案，说因为数据库查询分页，导致一些数据没有查到。而实际上问题没有解决，为什么呢，因为关键问题在于，链下 Order id 和链上 Tx hash 的映射关系存在问题，而落库的那一套异步程序，在另外一个模块中，有比较复杂的代码逻辑。Claude 根本没有去全盘分析整个项目的业务逻辑，而是执着于看到代码片段、分析代码片段的问题、给出修复方案，不具备分析和定位全局性质的、复杂业务逻辑 bug 的能力。</p><p>这是典型的 “路灯效应”，Claude 模型则更容易掉入这种陷阱。</p><h3 id="2026-01-23"><a href="#2026-01-23" class="headerlink" title="2026.01.23"></a>2026.01.23</h3><p>前端能力不如 Gemini，后端逻辑能力不如 GPT，包括 Oups 也是，前端也不行，后端也不行，主打一个听话。</p><p>随着最近 Google Antigravity 的 rate limit 越来越严格，可以用这样的组合：</p><ul><li>VS Code + GitHub Copilot + GPT 5.2</li><li>Google Antigravity + Gemini 3 Pro High</li></ul><p>Claude Code 真的干啥啥不行。</p><p>很多人在评价 AI 写的代码需要 review、不好用之类，因为他们根本没有使用最讲道理的模型 GPT，而是认为 Claude Opus 是世界上最好的编程模型，自然就会限制他们对于 AI 的认识。</p><h3 id="2025-11-11"><a href="#2025-11-11" class="headerlink" title="2025.11.11"></a>2025.11.11</h3><p>因为不好用。特指 Claude Sonnet 4.5。</p><p>在日常的使用中已经被坑过几次：</p><ol><li>一味按照我说的做，不会提出任何反驳意见或者提醒</li><li>在代码里留下 TODO，然后说完美，功能完成了</li><li>会执行一些危险操作，比如 <code>git checkout —</code></li><li>对于有执行顺序的数据库 schema 变更记录，竟然直接修改某一个历史节点</li></ol><p>相比之下，GPT-5 几乎不会犯这种错误。</p><p>所以可以放心地禁用掉所有来自 Claude 的 AI 模型。除非你的项目允许生成有逻辑漏洞的代码。</p><!-- --- --><!-- 顺便分享一个 instructions 文件，用于指导 AI Agent 编程：[yincs-coding-style.md](https://gist.github.com/smallyunet/7095f51f7bf8c1b31e7e6dcd83a29703) -->]]></content>
  </entry>
  <entry>
    <title>拼多多，蜜雪冰城，华莱士</title>
    <link href="https://crazy.smallyu.net/2026/04/03/%E6%8B%BC%E5%A4%9A%E5%A4%9A%EF%BC%8C%E8%9C%9C%E9%9B%AA%E5%86%B0%E5%9F%8E%EF%BC%8C%E5%8D%8E%E8%8E%B1%E5%A3%AB/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/04/03/%E6%8B%BC%E5%A4%9A%E5%A4%9A%EF%BC%8C%E8%9C%9C%E9%9B%AA%E5%86%B0%E5%9F%8E%EF%BC%8C%E5%8D%8E%E8%8E%B1%E5%A3%AB/</id>
    <published>2026-04-03T11:33:03.000Z</published>
    <updated>2026-07-04T17:36:19.132Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>拼多多是低配版本的淘宝。</p>
<p>蜜雪冰城是低配版本的奈雪。</p>
<p>华莱士是低配版本的麦当劳。</p>
<p>这些低配的平台和品牌，意味着便宜、廉价切劣质。</p>
<p>拼多多上的日用品，蜜雪的橙汁，华莱士的汉堡套餐。</p>
<p>便宜，且劣质。</p>
]]></summary>
    <content type="html"><![CDATA[<p>拼多多是低配版本的淘宝。</p><p>蜜雪冰城是低配版本的奈雪。</p><p>华莱士是低配版本的麦当劳。</p><p>这些低配的平台和品牌，意味着便宜、廉价切劣质。</p><p>拼多多上的日用品，蜜雪的橙汁，华莱士的汉堡套餐。</p><p>便宜，且劣质。</p><p>为了过上有品质的生活，应该远离这些低配版本的平台和品牌。选择稍微贵但是有品质保障的、稍微好一点的品牌。</p>]]></content>
  </entry>
  <entry>
    <title>真相和真话不重要</title>
    <link href="https://crazy.smallyu.net/2026/03/31/%E7%9C%9F%E7%9B%B8%E5%92%8C%E7%9C%9F%E8%AF%9D%E4%B8%8D%E9%87%8D%E8%A6%81/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/03/31/%E7%9C%9F%E7%9B%B8%E5%92%8C%E7%9C%9F%E8%AF%9D%E4%B8%8D%E9%87%8D%E8%A6%81/</id>
    <published>2026-03-31T07:52:40.000Z</published>
    <updated>2026-07-04T17:36:19.133Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>很简单的一件事情，在网上购物写了个差评，商家说退款不退货删除差评，我同意了。</p>
<img src="1.png" width="40%"]]></summary>
    <content type="html"><![CDATA[<p>很简单的一件事情，在网上购物写了个差评，商家说退款不退货删除差评，我同意了。</p><img src="1.png" width="40%" /><p>在这个事情上，还是有点受震撼的。我并不是所谓的为了钱放弃说真话的权利，而是我忽然觉得，真相不重要，说真话不重要。</p><p>我不在乎买这个商家商品的人，他们是否知道真相、是否觉得吃亏。我丝毫没有兴趣教育别人，或者帮助别人排雷，我为什么要有这种助人情节？</p><p>而且我也没有理由影响人家的生意，愿意买的买，愿意卖的卖，社会资金流转起来了，完全是好事，对我来说无所谓。</p><p>我脑海中浮现出的是崔永元，他爱说真话、揭露真相，然后呢，下场是什么呢，为什么要说真话、让大众知道真相呢？真相不重要，大众也不在乎。大众本来就是愚昧的。他们的亏损与我无关。</p>]]></content>
  </entry>
  <entry>
    <title>资本家，打工人，群众</title>
    <link href="https://b.smallyu.net/2026/03/23/%E8%B5%84%E6%9C%AC%E5%AE%B6%EF%BC%8C%E6%89%93%E5%B7%A5%E4%BA%BA%EF%BC%8C%E7%BE%A4%E4%BC%97/"/>
    <id>blog-b:https://b.smallyu.net/2026/03/23/%E8%B5%84%E6%9C%AC%E5%AE%B6%EF%BC%8C%E6%89%93%E5%B7%A5%E4%BA%BA%EF%BC%8C%E7%BE%A4%E4%BC%97/</id>
    <published>2026-03-22T18:38:29.000Z</published>
    <updated>2026-03-22T18:40:33.734Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>没有学历、不懂技术、只会吹牛、素质低下的富二代算是什么人呢，算是资本家。</p>
<p>名校毕业、大厂光环、资深技术、追求真理的程序员算是什么人呢，算是打工人。</p>
<br>

<p>你代码写得再好、再漂亮、懂技术、懂架构、懂原理、懂协议，你是打工人，终其一生都需要为几]]></summary>
    <content type="html"><![CDATA[<p>没有学历、不懂技术、只会吹牛、素质低下的富二代算是什么人呢，算是资本家。</p><p>名校毕业、大厂光环、资深技术、追求真理的程序员算是什么人呢，算是打工人。</p><br><p>你代码写得再好、再漂亮、懂技术、懂架构、懂原理、懂协议，你是打工人，终其一生都需要为几千块钱的薪水付出生命。</p><p>丝毫不懂技术，只要踩对时代的红利、做出几个无论是否是运气的投资选择、拿到上千倍的投资回报，你是资本家，永远都不需要懂上班和打工是什么，只需要考虑如何赢对下一场赌博。</p><br><p>你是打工人，无论懂多少技术原理，你是观众，只能在台下听讲。</p><p>你是资本家，钱可以换来 Title 和名气，你是演讲者，在台上说一些不痛不痒的话，只要逻辑正常像个人样，就能安全下场。</p><br><p>群众不在乎你懂不懂技术。群众只在乎你有没有钱。</p><p>有钱，你就是成功的，有钱，你就有资格站在台上。有钱，你就有可能讲出赚钱的道理，我就愿意听。</p><p>没钱，要技术有什么用。没钱，你学技术干什么。没钱，我为什么要听你讲。</p><p>群众在追求的，从来不是技术、不是真理，是钱。</p><br><p>大学生、研究生、博士、专家，大家都在为多少钱的工资努力奋斗呢？</p>]]></content>
  </entry>
  <entry>
    <title>OpenClaw（龙虾）没什么用</title>
    <link href="https://crazy.smallyu.net/2026/03/13/OpenClaw%EF%BC%88%E9%BE%99%E8%99%BE%EF%BC%89%E6%B2%A1%E4%BB%80%E4%B9%88%E7%94%A8/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/03/13/OpenClaw%EF%BC%88%E9%BE%99%E8%99%BE%EF%BC%89%E6%B2%A1%E4%BB%80%E4%B9%88%E7%94%A8/</id>
    <published>2026-03-13T06:30:58.000Z</published>
    <updated>2026-07-04T17:36:19.127Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>最近 OpenClaw]]></summary>
    <content type="html"><![CDATA[<p>最近 OpenClaw 很火，甚至中国大陆的互联网大厂、各地政府都发布和制定了关于龙虾的产品和政策指导。</p><p>为什么龙虾这么火呢，原因很简单，因为现在市场和政府都需要一个热点，无论有没有用，近几年持续的经济低迷已经让大家处于极度的压抑之中，急需要一个不破坏现有利益链又低成本的新的产品来炒作和好玩。</p><p>大家快憋疯了。</p><p>要说 OpenClaw 真的有没有用、能不能提高效率，答案是毫无用处，都是噱头。中国大陆的人力成本远低于 AI。</p>]]></content>
  </entry>
  <entry>
    <title>Idlen 和 MystNodes</title>
    <link href="https://crazy.smallyu.net/2026/03/10/Idlen%E5%92%8CMystNodes/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/03/10/Idlen%E5%92%8CMystNodes/</id>
    <published>2026-03-10T09:53:21.000Z</published>
    <updated>2026-07-04T17:36:19.111Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>经过实际测试，这点钱真的不值得挣，千万不要尝试，我已经放弃。所有类似这种广告费的 “被动收入” 都不值得尝试。</p>
<p>因为 Idlen]]></summary>
    <content type="html"><![CDATA[<p>经过实际测试，这点钱真的不值得挣，千万不要尝试，我已经放弃。所有类似这种广告费的 “被动收入” 都不值得尝试。</p><p>因为 Idlen 作为一个插件，会占用非常高的内存，而且有时候会存在性能问题拖慢整个电脑环境。体验很糟糕。</p><hr><p>前几天在寻找被动收入的办法，确实很少。说两个无意间看到、收入非常少、聊胜于无的。</p><ul><li>Idlen<ul><li>官网：<a href="https://idlen.io/">https://idlen.io</a><!-- - 邀请链接：https://dashboard.idlen.io/register?ref=DNC94VE9 --></li></ul></li></ul><p>通过邀请链接进入的话，我会获取 0.5 美元，被邀请的账户会获取的 0.25 美元。</p><p>这个插件和平台只对程序员有效。我们每天都会在编辑器里用 AI 写代码，而这个插件的广告只会在 AI 思考的时候出现。相信在写代码的程序员能理解我在说什么。</p><img src="1.png" width="100%" /><p>我试用了几天下来，大概每天 0.5 美元的广告费，满 50 美元可以提现。算下来一个月大概可以有 20 美元的广告费，我现在用的是 GitHub Copilot Pro+ 的套餐，一个月的订阅费是 39 美元，也就是广告费可以抵扣回一半的订阅费。</p><ul><li>MystNodes<ul><li>官网：<a href="https://mystnodes.com/">https://mystnodes.com</a><!-- - 邀请链接：https://mystnodes.co/?referral_code=OdjmNsh45KxYHTOj2n0Xxlw85Kq0acGs6NeNrieI --></li></ul></li></ul><p>另一个是 MystNodes。如果有闲置的 VPS 或者云服务器，可以在上面一键启动一个节点：</p><pre><code class="bash">docker run --cap-add NET_ADMIN \  -d \  -p 4449:4449 \  --name myst \  -v ~/myst-data:/var/lib/mysterium-node \  --restart unless-stopped \  mysteriumnetwork/myst:latest \  service --agreed-terms-and-conditions</code></pre><p>不过这个平台的收入更加少的可怜，就是赚点共享流量费用而已。这么点收入几乎等于没有。</p><img src="2.png" width="100%" />]]></content>
  </entry>
  <entry>
    <title>第一次体会到人性的贪婪</title>
    <link href="https://crazy.smallyu.net/2026/03/07/%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%BD%93%E4%BC%9A%E5%88%B0%E4%BA%BA%E6%80%A7%E7%9A%84%E8%B4%AA%E5%A9%AA/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/03/07/%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%BD%93%E4%BC%9A%E5%88%B0%E4%BA%BA%E6%80%A7%E7%9A%84%E8%B4%AA%E5%A9%AA/</id>
    <published>2026-03-06T16:21:54.000Z</published>
    <updated>2026-07-04T17:36:19.127Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>我有一个 iMac 电脑，具体配置是 iMac 2024 24寸 10+10核 32g+512g。这个配置很高了，内存属于顶配。官方售价 1.7万，减去国补 1.5万。</p>
<p>今天我把电脑挂在了京东闲置和闲鱼上，两个平台都是瞬间有人出价 9000]]></summary>
    <content type="html"><![CDATA[<p>我有一个 iMac 电脑，具体配置是 iMac 2024 24寸 10+10核 32g+512g。这个配置很高了，内存属于顶配。官方售价 1.7万，减去国补 1.5万。</p><p>今天我把电脑挂在了京东闲置和闲鱼上，两个平台都是瞬间有人出价 9000 块钱，我就知道这个电脑的回收价格是 9000 块，因为出价的人明显是二手贩子。</p><p>然后我挂的价格是 10999，这其实不高了。</p><p>有一个态度很好、说话也不错的买家，聊了几句之后感觉不错，是一个个人买家，问能不能降价。我看到对方是个人，并且 IP 在重庆（重庆没国补），看主页是一个做服装买卖之类的人，对话中体现出来的态度也不错。对方还说出了会对它（我的电脑）好这种话。</p><p>我在犹豫了几分钟后，主动降价，给出了 1万块钱+邮费的提议。然后我们又聊了聊，说邮寄方面的安全之类的问题。</p><p>我本来觉得这个降价已经很诚意了，结果没想到对方仍然在继续砍价，说 9500+邮费行不行？</p><p>我又犹豫了几分钟，然后把对方拉黑了。</p><p>我感觉自己被上了一课。我好心主动给对方大幅度的降价，并且也是看对方态度好，而且主页上有评价说属于买卖利落的买家，她自己也说不扯皮。</p><p>我已经告诉对方 9000 块钱是回收价，只要愿意随时会有人收。</p><p>没想到对方还能出价 9500。</p><p>我不在乎比 1 万块钱少的那 500 块钱，我不差那点钱，但是我很不喜欢这种得寸进尺、贪婪的态度。</p><p>9000 块钱是回收价，我能随便就卖掉，我也不在乎比 9000 块钱多出来那 500 块钱的利润。我多挣那 500 干啥。</p><p>500 块钱一顿饭的钱，一张沉浸剧场门票的钱。</p><p>我本来看对方态度好是个个人买家愿意多聊，并且主动降价。</p><p>我觉得我的好心被辜负。</p>]]></content>
  </entry>
  <entry>
    <title>近期思考与结论</title>
    <link href="https://b.smallyu.net/2026/03/06/%E8%BF%91%E6%9C%9F%E6%80%9D%E8%80%83%E4%B8%8E%E7%BB%93%E8%AE%BA/"/>
    <id>blog-b:https://b.smallyu.net/2026/03/06/%E8%BF%91%E6%9C%9F%E6%80%9D%E8%80%83%E4%B8%8E%E7%BB%93%E8%AE%BA/</id>
    <published>2026-03-06T08:26:47.000Z</published>
    <updated>2026-03-06T08:29:14.540Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<ol>
<li>所有 web3 项目，唯一赚钱的方式是发币</li>
<li>技术本身不产生价值，商业模式、商业行为才产生价值</li>
<li>一个人整个人生的上限和下限，在出生的时候就已经决定</li>
<li>只要创始人还在，链、项目、DAO等]]></summary>
    <content type="html"><![CDATA[<ol><li>所有 web3 项目，唯一赚钱的方式是发币</li><li>技术本身不产生价值，商业模式、商业行为才产生价值</li><li>一个人整个人生的上限和下限，在出生的时候就已经决定</li><li>只要创始人还在，链、项目、DAO等 就都不可能去中心化</li><li>比时间成本更宝贵的是注意力成本</li><li>大多数商业项目不需要博士学历或者博士水平，是过载的。商业和研究是平行（互不相交）的领域。</li><li>代码不是资产，代码是负债</li><li>币圈没有长期主义。你可以希望它有，但事实上就是没有</li><li>除了你自己，每有人会真正关心你（理解你的思考逻辑）</li><li>合作是成功唯一的路径。与谁合作决定了是否能成功</li></ol>]]></content>
  </entry>
  <entry>
    <title>利息，套利，交易策略，金融市场</title>
    <link href="https://smallyu.net/2026/03/02/%E5%88%A9%E6%81%AF%EF%BC%8C%E5%A5%97%E5%88%A9%EF%BC%8C%E4%BA%A4%E6%98%93%E7%AD%96%E7%95%A5%EF%BC%8C%E9%87%91%E8%9E%8D%E5%B8%82%E5%9C%BA/"/>
    <id>blog:https://smallyu.net/2026/03/02/%E5%88%A9%E6%81%AF%EF%BC%8C%E5%A5%97%E5%88%A9%EF%BC%8C%E4%BA%A4%E6%98%93%E7%AD%96%E7%95%A5%EF%BC%8C%E9%87%91%E8%9E%8D%E5%B8%82%E5%9C%BA/</id>
    <published>2026-03-02T05:52:16.000Z</published>
    <updated>2026-03-21T10:25:18.055Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="资金费率套利"><a href="#资金费率套利" class="headerlink" title="资金费率套利"></a>资金费率套利</h3><p>资金费率套利是一种没有风险、保本的套利方式。我一开始尝试自己写脚本来运行策略，后来发现 Binance]]></summary>
    <content type="html"><![CDATA[<h3 id="资金费率套利"><a href="#资金费率套利" class="headerlink" title="资金费率套利"></a>资金费率套利</h3><p>资金费率套利是一种没有风险、保本的套利方式。我一开始尝试自己写脚本来运行策略，后来发现 Binance 直接提供了 bot 来进行这种操作：</p><div style="display:flex; justify-content:center; gap:12px; flex-wrap:wrap;">    <img src="1.png" style="width:35%; height:auto;">    <img src="2.png" style="width:35%; height:auto;"></div><p>这里的 Arbitrage Bot 就是资金费率套利的 Bot，点开可以看到有很多币种可以选，包括按照资金费率来排序等。而且 Binance 的 Bot 做的很智能，如果资金费率是正的，就开正向的套利策略（使用 USDT），如果资金费率是负的，就开反向的策略（使用代币）。</p><p>资金费率套利的获利空间很小，尤其是 BTC 等主流币种，APR 在 1% 以下，当前低迷的市场环境下，大概持有 300 天以上才能磨平手续费损耗。实际上是很不划算的方式。而如果按照资金费率排序，选最高的一个代币，APR 能相对高一点，也许能达到 40% 甚至更多，当然高收益也就意味着高的波动和风险：</p><div style="display:flex; justify-content:center; gap:12px; flex-wrap:wrap;">  <img src="3.png" style="width:35%; height:auto;">  <!-- <img src="4.png" style="width:35%; height:auto;"> -->  <img src="5.png" style="width:35%; height:auto;">  </div><p>资金费率套利是 Detla 中性的，假如代币突然暴涨，把 2 倍的做多合约给爆仓了，会不会导致损失一半本金呢？不会，因为现货涨了 2 倍后卖掉正好抵消了爆仓的损失，所以本金没有变化，整个过程就是赚了这段时间的资金费率。</p><p>所以根据资金费率高的代币排序，然后开套利 Bot，是我唯一尝试过想赚点利息的方式。</p><h3 id="保本赚币"><a href="#保本赚币" class="headerlink" title="保本赚币"></a>保本赚币</h3><div style="display:flex; justify-content:center; gap:12px; flex-wrap:wrap;">  <img src="5.png" style="width:35%; height:auto;">  <img src="6.png" style="width:35%; height:auto;"></div><p>Simple Earn 很简单，存到 Binance 里赚利息。问题在于 APR 并不高，USDC 也就 6%，而且有非常高的额度限制，只支持 200 USDC。几乎没什么用。</p><h3 id="双币投资"><a href="#双币投资" class="headerlink" title="双币投资"></a>双币投资</h3><p>双币投资（Dual Investment）的策略整体看下来，关键在于你心里要有一个预期的价位。比如 BTC 到 60000 就愿意买入，无论它以后会不会继续跌，都以 60000 的价格买入（卖出同理）。</p><p>双币投资更像是期货交割的逻辑，对于普通散户来说，同样没什么用。为什么双币投资的利息高呢？因为风险也高，有卖飞或者接刀子的风险。风险高，利息就高了。</p><p>如果双币投资设定一个非常离谱的价格呢，比如在 100000 的时候买入 BTC，岂不是可以达不到条件一直赚利息了？但实际上利息是由风险决定的，市场看到风险小，也就没有人愿意付高额利息，所以价格离谱的市场本身就不存在。</p><h3 id="开合约、加杠杆"><a href="#开合约、加杠杆" class="headerlink" title="开合约、加杠杆"></a>开合约、加杠杆</h3><p>别作死。</p><h3 id="Lido"><a href="#Lido" class="headerlink" title="Lido"></a>Lido</h3><img src="8.png" width="80%"><p>这 2.3% 的 APR 实在是太低了。用某个人的话来说，对于普通人，低于 5% 的 APR 根本不需要考虑，得至少 20 年才能赚钱。</p><h3 id="Aave"><a href="#Aave" class="headerlink" title="Aave"></a>Aave</h3><img src="9.png" width="80%"><p>Aave 的 APR 也很低，甚至最高也低于 2%，几乎等于没有。</p><h3 id="Uniswap"><a href="#Uniswap" class="headerlink" title="Uniswap"></a>Uniswap</h3><img src="10.png" width="80%"><p>乍一看还挺吓人的，USDC&#x2F;ETH 有 76% 的 APR。问题在于提供流动性是存在无常损失的，你投入 1000 ETH 和 1000 USDC，随着池子中不断进行交易，最终你提出来可能就剩 300 ETH 和 1700 USDC。代币的总量不变，但是 ETH 的价格在剧烈波动，你的投入就完全不划算了。而 Uniswap 上的稳定币交易对 USDT&#x2F;USDC 这种池子的收益率自然很低，在 1% 左右。</p><h3 id="BTC-5-分钟猜涨跌"><a href="#BTC-5-分钟猜涨跌" class="headerlink" title="BTC 5 分钟猜涨跌"></a>BTC 5 分钟猜涨跌</h3><img src="11.png" width="80%"><p>Polymarket 上线了 BTC 5 分钟猜涨跌的玩法。那么在这种市场有获利的机会吗？结论是没有。这是一种负期望值的游戏，散户、低频等同于纯粹的赌博。甚至可以认为所有的事件预测市场都是赌博。别提什么稳定套利的机会了。</p><h3 id="Polymarket-上的-free-money"><a href="#Polymarket-上的-free-money" class="headerlink" title="Polymarket 上的 free money"></a>Polymarket 上的 free money</h3><p>一方面，Polymarket 上有一些整活市场，比如 <a href="https://polymarket.com/event/will-jesus-christ-return-before-2027">耶稣会不会在 2027 年回归？</a>。这种市场的 no 价格大约 96.2c，意味着如果持仓一年等待事件结算后，持仓的年化收益大约 4%。非要和传统银行以及现金 APR 比的话这个收益率也还不错。</p><p>另一方面，Polymarket 有一个机制，对于某些 <a href="https://help.polymarket.com/en/articles/13364459-holding-rewards">符合要求</a> 的市场，只要 holding 就会一直分发年化 4% 的 shares。有一些市场是显然知道结局的，所以可以大胆买入，比如某个市场的 no 价格是 91.1c，当事件结算后会获得接近 9% 的年化收益，再累加上 4% 的持仓收益，实际上是一个还算不错的理财选择。</p><h3 id="MEV-攻击、链上科学家、黑暗森林"><a href="#MEV-攻击、链上科学家、黑暗森林" class="headerlink" title="MEV 攻击、链上科学家、黑暗森林"></a>MEV 攻击、链上科学家、黑暗森林</h3><p>快省省吧。</p><h3 id="金融市场"><a href="#金融市场" class="headerlink" title="金融市场"></a>金融市场</h3><p>经过这么多年的发展以及几年前的 DeFi Summer，无论是 Cex 利息还是 DeFi，随着 ETF 的推出、华尔街巨头的介入，只要市场上有低风险的套利机会，就会有几亿的资金以及高频低延迟的机器人入场。普通玩家的机会非常少。</p><p>在金融市场里怎么赚钱？</p><ol><li>拿时间换空间（撸空投）</li><li>拿本金换利息（大额本金）</li><li>拿认知、精力换超额收益（现货定投、寻找 Alpha）</li></ol><p>除此之外，别无他法。</p><p>散户之所以是韭菜，是因为：</p><ol><li>没有无限的本金</li><li>缺乏顶级的认知</li><li>缺乏极度的耐心</li></ol><p>反正什么都没有。有的只有无知，和赚钱的欲望。</p><h3 id="定投策略"><a href="#定投策略" class="headerlink" title="定投策略"></a>定投策略</h3><p>李笑来经历过那么多项目，最后总结出的终极交易策略是定投。《<a href="https://ri.firesbox.com/#/cn/">定投改变命运</a>》这本书其实写的非常好，信息密度很高。当我们对于某些高频交易策略动心的时候，不妨回顾一下这本书里提到的要点，而定投正是需要极度耐心的一种策略。</p><p>当然定投策略以及李笑来的理论，也有让人觉得扯淡的地方。比如书里到最后，给大家的建议是提高 “场外赚钱的能力”。这基本上是非常正确的废话，谁不知道场外赚钱重要……</p><p>定投是一种与人性做对抗的策略，确实很难严格落实，尤其是对于从业者来说，天天会看到行情和市场情绪，不可能做到情绪高的时候还定投，也做不到情绪低的时候管得住手。</p><p>想要赚钱，还是得做出点别人做不到的事情才行。</p><h3 id="Restaking"><a href="#Restaking" class="headerlink" title="Restaking"></a>Restaking</h3><p>刚才提到了定投，那么假如坚持定投 BTC 的话，BTC Restaking 能不能在持有 BTC 的基础上再赚点利息？</p><img src="12.png" width="80%"><p>Restaking 赛道唯一一个真正做 BTC Restaking 的项目 Babylon，提供的 APR 至高 0.87%，这确实是不值一提。毕竟 2B 的资金量压在协议里，APR 又不能凭空产生，项目收益再高，一分到 2B 的质押量上，APR 就不可能高了。所以 BTC Restaking 几乎不值得去操作。</p><h3 id="场外赚钱"><a href="#场外赚钱" class="headerlink" title="场外赚钱"></a>场外赚钱</h3><p>我在思考 “场外赚钱” 这个问题。我发现 “定投+持有” 的过程无聊至极。</p><p>金融市场里有一个很奇怪的逻辑，明明你就是场外赚钱能力有限，才想要到金融领域通过投资手段寻找高杠杆、高回报率的新机会。而投资界的大佬都会告诉你，场外赚钱的能力才是最重要的，你要有源源不断的现金流才行。</p><p>而事实上，金融领域从来只放大资金收益，而不负责基础资金的来源。在金融领域的不可能三角是：</p><ul><li>本金</li><li>收益率</li><li>时间</li></ul><p>如果你有足够的本金，即使收益率低也有很好的回报，100 万美元年化 10% 一年下来就是 10 万美元。如果你愿意承担极度高的风险，土狗币百倍币就是高收益最直接的渠道，收益率是对承担风险的回报。</p><p>那么如果本金也不够大，风险也不愿意承担呢？剩下能投入的只有时间。</p>]]></content>
  </entry>
  <entry>
    <title>很多人以为远程工作是“下限”</title>
    <link href="https://b.smallyu.net/2026/02/26/%E5%BE%88%E5%A4%9A%E4%BA%BA%E4%BB%A5%E4%B8%BA%E8%BF%9C%E7%A8%8B%E5%B7%A5%E4%BD%9C%E6%98%AF%E2%80%9C%E4%B8%8B%E9%99%90%E2%80%9D/"/>
    <id>blog-b:https://b.smallyu.net/2026/02/26/%E5%BE%88%E5%A4%9A%E4%BA%BA%E4%BB%A5%E4%B8%BA%E8%BF%9C%E7%A8%8B%E5%B7%A5%E4%BD%9C%E6%98%AF%E2%80%9C%E4%B8%8B%E9%99%90%E2%80%9D/</id>
    <published>2026-02-26T15:12:06.000Z</published>
    <updated>2026-02-28T04:18:29.096Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>比如有的人想肉身回老家，首先琢磨在老家没有好的事业，其次就说]]></summary>
    <content type="html"><![CDATA[<p>比如有的人想肉身回老家，首先琢磨在老家没有好的事业，其次就说 “要不找个远程也行”。</p><p>省省吧，这种心态上想回老家的人，专业能力必然不过关。远程工作首先要的就是自驱力、学习能力。而有自驱力的人，本来就不在乎工作形式，无论是坐班还是远程都会做出相应的成绩。而且想回老家的人心态上就是想要“安逸”、“懈怠”，别指望这种人能做出什么工作成绩。</p><p>其次就是这种 “如果 A 不行，就 B 也行” 的心态。为什么会认为 “远程工作” 的难度和要求比 “在老家找个谋生的事业” 更简单？为什么会认为 “远程工作” 比坐班更简单？这种认知本身就不对，在错误的认知下不可能遇到正确的机会。坐班，你的竞争对手是同一个城市的人。远程，你的竞争对手是整个世界的人。</p><p>这些人竟然把远程工作看作一种降级而不是升级，这就很奇怪。他们不会说，“我在小公司上班不舒服，实在不行去大厂吧。” 为什么？因为他们明白自己能力不行。为什么到了远程工作这里，有些人会认为远程工作更简单？因为他们的实际工作是肉身在场熬日子，而不是工作结果的产出，才会以为只要不在办公室被 “盯着” 就会轻松。</p><p>还有一种是觉得坐班辛苦，通勤占用了娱乐时间，整体工作时间太长，想要借助远程工作 work life balance 的。这种也是痴人说梦，在你自己能力不变的前提下，为什么工作形式的转换就会让你有更多休闲娱乐的时间？为什么得到这种 “好处” 的人是你而不是别人？市场规律从来不在乎你需要什么，只在乎你能提供什么。</p><p>这些人的心态是 “在不付出更多努力的前提下，得到更多”。然而天底下哪有那样的好事？</p><h3 id="“远程工作”不等于“老家工作”"><a href="#“远程工作”不等于“老家工作”" class="headerlink" title="“远程工作”不等于“老家工作”"></a>“远程工作”不等于“老家工作”</h3><p>另外一个角度来说，很显然的道理，假如一个人从未去过一线城市，从未经历过一线以上城市的职场和生活，是绝无可能具备足够的视野和能力，去胜任一份远程工作的。</p><p>有一些人看到远程就可以工作，就误以为“远程工作”意味着“用电脑就可以工作”。而电脑谁都有，那么是不是意味着任何人在任何地点，只要有电脑，就可以完成一份远程工作？</p><p>显然是不可能的，工作的背后要求你整个人的素质、工作经历、生活习惯、工作节奏等作为支撑。</p><p>那些从未离开低节奏生活环境的人，怎么可能跟得上世界主流的职场节奏？</p>]]></content>
  </entry>
  <entry>
    <title>“底层人” 对人脉的错误认知</title>
    <link href="https://crazy.smallyu.net/2026/02/23/%E2%80%9C%E5%BA%95%E5%B1%82%E4%BA%BA%E2%80%9D%E5%AF%B9%E4%BA%BA%E8%84%89%E7%9A%84%E9%94%99%E8%AF%AF%E8%AE%A4%E7%9F%A5/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/02/23/%E2%80%9C%E5%BA%95%E5%B1%82%E4%BA%BA%E2%80%9D%E5%AF%B9%E4%BA%BA%E8%84%89%E7%9A%84%E9%94%99%E8%AF%AF%E8%AE%A4%E7%9F%A5/</id>
    <published>2026-02-23T13:15:50.000Z</published>
    <updated>2026-07-04T17:36:19.129Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>有些人总觉得“人脉”重要，实际上他们所谓的人脉是指狐朋狗友，整天闲的没事一起吃吃喝喝，就算是人脉了。</p>
<p>还有的人对于 “交情”]]></summary>
    <content type="html"><![CDATA[<p>有些人总觉得“人脉”重要，实际上他们所谓的人脉是指狐朋狗友，整天闲的没事一起吃吃喝喝，就算是人脉了。</p><p>还有的人对于 “交情” 很看重，说我们从小就认识，到现在都十年二十年三十年的交情了。</p><p>那么这种交情有什么用呢？有事情的时候可以帮忙，什么结婚、遇到其他事情需要人手之类。准确来说，他们口中能帮得上的忙，是指不需要花钱就去解决问题。</p><p>为什么他们想要不花钱就解决问题呢？因为他们没有钱。</p><p>如果他们有钱，根本就不会在乎在某些低频率低概率情况下出现的问题，也不会指望他们在那种时候帮点小忙。因为平时用于维护时间和关系的成本，就远高于帮的那点忙了。</p><p>再一个就是根据时间长度来计算的交情。得反思一下，为什么十年二十年你们双方都没有长足的发展、无论是生活所在的地区或者事业，只有在没有发展的情况下，你们才可能长期保持联系。</p><p>当然，“上层人” 也存在长期的交情，但那种交情，也大多是商业合作方面的交情，一起搞个项目、投个资、信息共享，谁能闲的没事天天跟你唠家常啊？</p><p>还有时候底层人会说 “实在没地方去”、“没什么好玩的”，为什么呢？因为没有钱，去不了好玩的地方，以及他们被局限在一个环境里了，已经跳不出去。</p>]]></content>
  </entry>
  <entry>
    <title>结婚早的人专业能力都差</title>
    <link href="https://crazy.smallyu.net/2026/02/20/%E7%BB%93%E5%A9%9A%E6%97%A9%E7%9A%84%E4%BA%BA%E4%B8%93%E4%B8%9A%E8%83%BD%E5%8A%9B%E9%83%BD%E5%B7%AE/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/02/20/%E7%BB%93%E5%A9%9A%E6%97%A9%E7%9A%84%E4%BA%BA%E4%B8%93%E4%B8%9A%E8%83%BD%E5%8A%9B%E9%83%BD%E5%B7%AE/</id>
    <published>2026-02-20T11:40:15.000Z</published>
    <updated>2026-07-04T17:36:19.134Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>学习一门技术，就比如读大学或者读研究生，得两三年的时间，然后再用两三年的时间去实际使用、磨练，整体下来五六年就过去了。</p>
<p>18 岁高三，22 岁本科，哪怕本科直接工作，也得到 25]]></summary>
    <content type="html"><![CDATA[<p>学习一门技术，就比如读大学或者读研究生，得两三年的时间，然后再用两三年的时间去实际使用、磨练，整体下来五六年就过去了。</p><p>18 岁高三，22 岁本科，哪怕本科直接工作，也得到 25 岁进入社会之后才能多少会点东西。</p><p>更别提有其他更高的学历了，再加上恋爱经历未必顺利，30 岁以前结婚的人是怎么做到的？</p><p>30 岁还算能接受，25 岁就真的太早了，啥也不会，什么都不懂，基本没有任何社会经验，完全就父母包办式婚姻。</p><p>因此可以得到这样的结论，结婚早的人专业能力都差，因为根本没有足够的时间去提高专业能力。</p>]]></content>
  </entry>
  <entry>
    <title>LayerZero 从来不挑战比特币的地位</title>
    <link href="https://smallyu.net/2026/02/12/LayerZero%E4%BB%8E%E6%9D%A5%E4%B8%8D%E6%8C%91%E6%88%98%E6%AF%94%E7%89%B9%E5%B8%81%E7%9A%84%E5%9C%B0%E4%BD%8D/"/>
    <id>blog:https://smallyu.net/2026/02/12/LayerZero%E4%BB%8E%E6%9D%A5%E4%B8%8D%E6%8C%91%E6%88%98%E6%AF%94%E7%89%B9%E5%B8%81%E7%9A%84%E5%9C%B0%E4%BD%8D/</id>
    <published>2026-02-12T14:16:07.000Z</published>
    <updated>2026-02-13T01:52:33.891Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="Zero-网络"><a href="#Zero-网络" class="headerlink" title="Zero 网络"></a>Zero 网络</h3><p>2月10日，LayerZero 公布了 Layer 1 网络 <a]]></summary>
    <content type="html"><![CDATA[<h3 id="Zero-网络"><a href="#Zero-网络" class="headerlink" title="Zero 网络"></a>Zero 网络</h3><p>2月10日，LayerZero 公布了 Layer 1 网络 <a href="https://layerzero.network/zero">Zero</a> 的技术方案。有意思的指标有两个：</p><ol><li>兼容 EVM</li><li>TPS 达到 200万&#x2F;秒</li></ol><p>没错，号称每秒钟处理高达 200 万笔交易，是并行 EVM 链 Monad 的 200 倍，是 Solana 的 30 倍，是以太坊主网的 10 万倍，是比特币的 20 万倍。</p><p>LayerZero 的魔法在于优化了 <a href="https://jolt.a16zcrypto.com/intro.html">Jolt</a>，一个基于 RISC-V 指令集的 zkEVM，而且运行在 GPU 集群上，生成 ZK 证明的速度非常快。也就是说，当用户把大量交易提交给 Zero 网络的 Block Producers 之后，基于 GPU 集群的算力， Zero 网络可以非常快生成区块数据的证明。</p><p>Zero 网络出块的硬件要求大概是 96 核 GPU，768 GB RAM，这显然是算力中心级别的要求。那么整个网络岂不是非常中心化、被控制在少数华尔街头部公司的手里了？</p><p>由于 ZK 技术的特性，Zero 网络提供了另一个特性：验证 ZK 证明只需要非常轻量级的设备，家用电脑就可以完成对区块数据的验证。</p><p>这是一个有意思的点，为了提高 TPS，Zero 网络把出块的权力中心化，同时把验证区块的权力极度去中心化。那么 Zero 网络到底是中心化的，还是去中心化的？</p><h3 id="比特币网络"><a href="#比特币网络" class="headerlink" title="比特币网络"></a>比特币网络</h3><p>去中心化网络唯一的标杆是比特币网络。虽然比特币在协议上是去中心化的，所有节点都是全节点，但事实上出块的算力基本被几大矿池垄断，比特币网络还算是去中心化的吗？</p><p>如果单从这个出块权力的集中程度分析，还真是有点难分伯仲，这也是 Zero 网络的诞生让人迷惑的点。</p><p>我们信任比特币的去中心化，是因为每一个节点都有全量账本数据，由于区块链逐个区块哈希的设计，我们可以重放所有交易历史，以此判断新产生的区块数据是否合法。PoW 共识则是所谓一 CPU 一票，哈希碰撞难但是验算简单，以此来验证出块权。所以总体来说，对于比特币，我们相信的是加密算法。</p><p>而对于 Zero 网络，其实我们相信的也是 ZK 加密算法。我们应该相信 Block Producers 会按照电路来生成证明，然后所有的成千上万的 Verifer 都可以去验证区块数据是否合法，这整个过程也完全是加密算法来保障的。</p><p>如果说 Zero 的源代码分发也许会有风险，比如生成 ZK 证明的电路逻辑出现 bug，或者验证 ZK 证明的逻辑有漏洞，给攻击者可乘之机。那么所有的区块链都面临源代码不安全的风险，包括比特币，你并不能保障比特币的源码就是绝对安全的。所以从这个角度无法区分 Zero 网络的优劣。</p><p>回到去中心化的角度，比特币网络交易重放可以保障区块数据可靠，而 Zero 网络虽然出块权被少数节点掌握，但是验证区块的权力借助 ZK 技术，能够轻易下放到任何轻量级设备上，这是比特币都无法比拟的 “去中心化”。假如 Zero 网络的 Block Producers 作恶，所有用户都可以知道，并且反馈给结算层，如果众多 Verifier 不同意，Block Producers 的出块权会被取消……</p><p>从这几个角度去对比，是不是恍惚间发现 Zero 网络竟然可以和比特币同台竞技，甚至 ZK 技术的出现给了 Zero 超越比特币的可能性？</p><h3 id="共识"><a href="#共识" class="headerlink" title="共识"></a>共识</h3><p>当然，刚才刻意弱化了核心问题所在。面对这种区块链架构上的疑惑，如果一时间没有思路，可以回到区块链技术的圣经 —— <a href="https://bitcoin.org/bitcoin.pdf">比特币白皮书</a> 找灵感。</p><p>比特币白皮书在摘要里就提到了比特币要解决的核心问题：双花（double-spending）。</p><p>Zero 网络引入 ZK 技术确实解决了区块链数据不可篡改这个问题，但是如何解决双花问题？答案是 Zero 网络用了 PoS 共识，引入了 Validator 的概念。别管他到底是哪种 PoS，反正都是 PoS。</p><p>参考以太坊的架构去理解，以太坊有两层，执行层和共识层，执行层负责执行交易，共识层负责验证节点出块的权力。</p><p>Zero 网络的架构和以太坊有点类似，分为出块层和结算层，出块层就是用大规模 GPU 执行区块和产生 ZK 证明的那一层，而结算层，则是 PoS 质押、验证节点是否有出块权力的一层。</p><p>你也许没跟上，不是说解决双花问题吗，怎么又在讨论节点出块权力的问题了。因为假如节点出块的权力被控制，或者可以做恶，那么恶意节点就可以允许区块数据，也就是交易历史被改写，上一秒看到交易成功了，下一秒发现交易回滚了。所以节点出块的权力得到保障，双花问题也可以得到解决。</p><p>那么这下就清晰了，Zero 引入了 ZK 技术把 TPS 提高了两个数量级，确实有很大的进步。但是在共识方面，依然用了 PoS。对于一些比特币的原宗旨教徒来说，PoS 共识甚至都是不入流、不能抗审查的。那么 ZK 再牛自然也就没有意义了。</p><h3 id="EVM"><a href="#EVM" class="headerlink" title="EVM"></a>EVM</h3><p>所以，Zero 网络从一开始的竞争对手就不是比特币，根本不会动摇比特币的地位。回到 Zero 网络的 <a href="https://layerzero.network/blog/zero-the-decentralized-multi-core-world-computer">Manifesto</a>。从标题 “Multi-Core World Computer” 就能看出是奔着以太坊去的，在 Manifesto 中也直接对比了以太坊、Solana 的性能问题。当然是不可能出现比特币的。</p><p>而实际上，Zero 网络连以太坊主网的地位都不会动摇，以太坊的去中心化程度是仅次于比特币的，全节点运行在民用级设备一直是 Vitalik 的愿景 —— “如果基金会不在了，以太坊还会存在吗？”</p><p>更进一步，Zero 网络连 Solana 的地位也不会动摇，因为 Solana 独特的生态，和一些名人以及政治叙事，轻易不会被取代。</p><p>总的来说，Zero 网络仅仅只能在 EVM 的生态里做竞争，可能会直接动摇发布不久的并行 EVM 网络 Monad 的前景。其他的更大的野心，明显还做不到。</p>]]></content>
  </entry>
  <entry>
    <title>远程 web3 工作溢价的原因</title>
    <link href="https://b.smallyu.net/2026/02/04/%E8%BF%9C%E7%A8%8Bweb3%E5%B7%A5%E4%BD%9C%E6%BA%A2%E4%BB%B7%E7%9A%84%E5%8E%9F%E5%9B%A0/"/>
    <id>blog-b:https://b.smallyu.net/2026/02/04/%E8%BF%9C%E7%A8%8Bweb3%E5%B7%A5%E4%BD%9C%E6%BA%A2%E4%BB%B7%E7%9A%84%E5%8E%9F%E5%9B%A0/</id>
    <published>2026-02-04T15:04:12.000Z</published>
    <updated>2026-02-04T15:17:19.517Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>远程工作溢价的原因：</p>
<ol>
<li>没有劳动合同、制度性保障、基本的法律保障</li>
<li>没有公积金、五险一金</li>
<li>没有周末、病假、年假、节假日等正常假期</li>
<li>没有设备补贴、年度体检、年会抽奖、团建等活动</li>
<li>没有]]></summary>
    <content type="html"><![CDATA[<p>远程工作溢价的原因：</p><ol><li>没有劳动合同、制度性保障、基本的法律保障</li><li>没有公积金、五险一金</li><li>没有周末、病假、年假、节假日等正常假期</li><li>没有设备补贴、年度体检、年会抽奖、团建等活动</li><li>没有节假日福利礼物、下午茶等</li><li>没有高档办公室、免费水电、人类同事</li><li>不能摸鱼（没有意义）</li><li>创业项目节奏快、成败迅速、工作不稳定性更高</li></ol><p>综上，只有得到相比于坐班工作一定程度的溢价工资，远程工作才合理。</p><p>如果你觉得，远程工作的好处是：</p><ol><li>随时休息，不需要固定的工作时间、工作更轻松</li></ol><p>别扯了，但凡远程工作过就明白，没有固定工作时间意味着什么。</p><ol start="2"><li>可以当数字游民，全世界各地旅居</li></ol><p>别扯了，牛马住在哪儿都一样。你一天工作8小时，窗外再美的风景都跟你无关。</p><ol start="3"><li>可以居住在低消费地区、按照高消费地区的工资要价</li></ol><p>别扯了，老板会按照高消费地区的工资给你开价吗？老板会根据你所在的地区来估价。</p><p>注意，我说的是远程工作，不特指远程 web3 的工作。如果从事 web3 的工作，你就要额外承担：</p><ol><li>项目违法追回你全部工资的风险</li><li>极端情况亲身去喝茶的风险</li><li>冻卡导致全部银行卡被封的风险</li><li>一旦从事 web3 项目就不可能回到 web2 的代价</li></ol><p>所以 web3 工作相比于 web2 工作一般也会有一定的溢价。</p><p>当然，现实中的情况更为复杂。以上都是打工人的视角，而对于招聘方的视角：</p><ol><li>远程工作本来就是为了节省成本</li><li>你不干有的是人干</li></ol><p>所以对于可替代性强的职位，远程 web3 的工资比坐班 web2 还要低，而且招聘方没有任何裁员成本。</p><p>无论 web2 还是 web3，无论坐班还是远程，自己的竞争力始终是第一位的。</p>]]></content>
  </entry>
  <entry>
    <title>默认参数引起的以太坊节点运行错误</title>
    <link href="https://smallyu.net/2026/02/03/%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0%E5%BC%95%E8%B5%B7%E7%9A%84%E4%BB%A5%E5%A4%AA%E5%9D%8A%E8%8A%82%E7%82%B9%E8%BF%90%E8%A1%8C%E9%94%99%E8%AF%AF/"/>
    <id>blog:https://smallyu.net/2026/02/03/%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0%E5%BC%95%E8%B5%B7%E7%9A%84%E4%BB%A5%E5%A4%AA%E5%9D%8A%E8%8A%82%E7%82%B9%E8%BF%90%E8%A1%8C%E9%94%99%E8%AF%AF/</id>
    <published>2026-02-03T07:19:01.000Z</published>
    <updated>2026-02-03T07:20:39.538Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>大概是两年前的事情了。在工作中，我们用以太坊节点搭建了一条网络，上线后发现网络中不能新增 Validator，也就是质押者的 32 ETH 没有生效。</p>
<p>原因是我们用了多种共识层客户端，包括 Prysm 和 Lighthouse 等。为什么会突然出问题呢？因为]]></summary>
    <content type="html"><![CDATA[<p>大概是两年前的事情了。在工作中，我们用以太坊节点搭建了一条网络，上线后发现网络中不能新增 Validator，也就是质押者的 32 ETH 没有生效。</p><p>原因是我们用了多种共识层客户端，包括 Prysm 和 Lighthouse 等。为什么会突然出问题呢？因为 Prysm 有一个叫 <code>--contract-deployment-block</code> 的命令行参数，其他客户端比如 Lighthouse 和 Teku，这个参数的默认值都是 <code>0</code>（参数名字在不同客户端可能不同，但是含义类似），而 Prysm 的这个参数默认值是 <code>11184524</code>，这个数字是以太坊从 PoW 转向 PoS 后质押机制开始生效的区块高度。</p><p>这个参数在干什么呢？它会从这个参数配置的区块高度开始，去扫描 Deposit Contract（主网是 <a href="https://etherscan.io/address/0x00000000219ab540356cbb839cbe05303d7705fa"><code>0x00000000219ab540356cbb839cbe05303d7705fa</code></a> ）上质押者的存款记录。我们平时说的质押 32 ETH，就是质押到这个合约里了，或者说就是把 32 ETH 转账给这个合约。这个合约在收到你的 ETH 之后，Consensus Client 比如 Prysm，就能根据合约的记录知道某一个地址确实给合约转了 32 ETH，因此认可这个人成为出块节点。</p><p>以太坊整个网络可能有几千个节点，每一个节点都在执行同样的操作，就是从 Deposit Contract 上扫描质押者列表、然后维护到自己本地的数据库状态中。直到轮到自己出块的时候，就把这个一直在维护的质押者列表的数据，计算一个总数 Deposit Count 和哈希根 Deposit Root，作为 <code>eth1_data</code> 字段的值，提交到区块数据中：</p><img src="./1.png" width="100%" /><p>这个截图来自以太坊主网的区块 <a href="https://beaconcha.in/block/24374562">24374562</a>，意味着当前以太坊一共有 204 万个质押者。要注意质押者不等于物理服务器上运行的节点数量，一个节点可以运行几千个质押者（Staker &#x2F; Validator），所以推测以太坊实际上的物理节点数量大概在几千个左右。</p><p>回到 Prysm 配置的问题，如果不配置 <code>--contract-deployment-block</code> 参数，默认值是 <code>11184524</code>，那么对于一条新启动的链来说（Chain ID 不是 1 那种），Prysm 就不去扫描 Deposit Contract 合约在块高度 <code>11184524</code> 之前的质押记录了，本地数据库里没有质押者的数据，在出块的时候自然也不会带上 <code>eth1_data</code> 的字段数据。</p><p>以太坊的 <a href="https://github.com/ethereum/consensus-specs/blob/c94138e73e0e70eb4b27f9be4d4e9325fa1aebf7/specs/phase0/beacon-chain.md#eth1-data">协议设计</a> 中要求，<code>eth1_data</code> 的数据必须要超过半数节点一致才可以生效。（注意这里的比例是 1&#x2F;2，和其他地方用到的魔法比例 2&#x2F;3 不一样）。</p><img src="./2.png" width="80%" /><p>所以如果你新启动的网络中有超过一半的节点用了 Prysm，同时这些 Prysm 节点没有可以设置 <code>--contract-deployment-block</code> 参数，网络就会异常、不能正确处理新加入的质押节点。</p><p>我们一般认为软件的默认参数是相对安全可靠的，如果刻意设置才表示我们有特殊需求。而在以太坊 Prysm 客户端的这种语境下，不刻意设置默认值反而是危险的。</p>]]></content>
  </entry>
  <entry>
    <title>打工人</title>
    <link href="https://b.smallyu.net/2026/02/01/%E6%89%93%E5%B7%A5%E4%BA%BA/"/>
    <id>blog-b:https://b.smallyu.net/2026/02/01/%E6%89%93%E5%B7%A5%E4%BA%BA/</id>
    <published>2026-02-01T12:32:41.000Z</published>
    <updated>2026-02-01T12:37:46.121Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>随着年龄、工作经验、技术能力的增长，我发现：</p>
<ol>
<li>比如我现在在做某一份工作</li>
<li>我无法同时做另外的工作，因为时间不允许，即使我有能力完成其他工作</li>
<li>也就是说，我的时间同一时间只能出售一份</li>
<li>我的技能无法落实]]></summary>
    <content type="html"><![CDATA[<p>随着年龄、工作经验、技术能力的增长，我发现：</p><ol><li>比如我现在在做某一份工作</li><li>我无法同时做另外的工作，因为时间不允许，即使我有能力完成其他工作</li><li>也就是说，我的时间同一时间只能出售一份</li><li>我的技能无法落实为书籍或者课程，因为很多工作问题其实并不通用、没有技术含量、很多领域内问题。工作并不是因为你特有的技能，而是因为你花时间精力把事情给做了。</li><li>所以对于个人来说，在有能力的情况下，同时只能做一份工作是一种损失，但是工作本身的性质决定了无法复利。</li><li>简称机会成本、沉没成本</li><li>另一方面，对于大多数人来说，工作是唯一的收入来源</li><li>在没有工作或者哪怕工作有空闲时间的情况下，是无法产生收入的</li></ol><p>非要再补充两条道貌岸然的道理的话：</p><ol start="9"><li>年龄越大，精力越少，但是挣钱的欲望和生活上实际的对钱需求越大。也就是说，打工人的收益天然是负增长。</li><li>AI 技术的发展首先取代的，就是花费时间但内在逻辑不需要顶尖的打工人的工作。</li></ol>]]></content>
  </entry>
  <entry>
    <title>为什么不要相信中国的传统道理</title>
    <link href="https://crazy.smallyu.net/2026/02/01/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E7%9B%B8%E4%BF%A1%E4%B8%AD%E5%9B%BD%E7%9A%84%E4%BC%A0%E7%BB%9F%E9%81%93%E7%90%86/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/02/01/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E7%9B%B8%E4%BF%A1%E4%B8%AD%E5%9B%BD%E7%9A%84%E4%BC%A0%E7%BB%9F%E9%81%93%E7%90%86/</id>
    <published>2026-01-31T16:09:21.000Z</published>
    <updated>2026-07-04T17:36:19.131Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<ol>
<li>“自古以来”、“传统” 意味着朴素、过时。</li>
<li>可以看看 100 年前的 1949 年，外国人拍摄的北京的市井风貌。每个人都很贫穷、穿着破旧的衣服、神情麻木。那么 500 年前、1000]]></summary>
    <content type="html"><![CDATA[<ol><li>“自古以来”、“传统” 意味着朴素、过时。</li><li>可以看看 100 年前的 1949 年，外国人拍摄的北京的市井风貌。每个人都很贫穷、穿着破旧的衣服、神情麻木。那么 500 年前、1000 年前的人，会是什么样子？生存都困难。</li><li>中国自古以来是一个农业国家，近几十年才有工业、制造业。一堆种地的人总结出来的朴素的人生道理，还能适用于如今高科技的社会环境吗？</li><li>中国的古人、伟人以文学为主。现代社会，所有文科都属于服务业，不太参与到社会的经济循环、经济发展。如果把古人放到现代社会，他一定会懵。把李白放到现代，他也不会是富豪。</li><li>现在社会的两大行业，对于经济增长有显著影响的，一个是工业、制造业、科技行业，再一个是金融行业、股市、投资、放贷。</li></ol><p>过时的伟人特指中国。现代科学技术都起源于西方，也有很多西方的科学家放到现代依然顶尖，比如高斯。</p><p>不能相信的主要指人生道理一类，中国传统的文学作品和文化还是很美的。但是那些名著跟你我的生活无关。</p><p>所以如果亲戚朋友跟你讲一些特别朴素的道理，像什么 “先成家后立业”、“多子多福” 之类，千万不要相信。</p>]]></content>
  </entry>
  <entry>
    <title>为什么维护人设很难</title>
    <link href="https://b.smallyu.net/2026/01/31/%E4%B8%BA%E4%BB%80%E4%B9%88%E7%BB%B4%E6%8A%A4%E4%BA%BA%E8%AE%BE%E5%BE%88%E9%9A%BE/"/>
    <id>blog-b:https://b.smallyu.net/2026/01/31/%E4%B8%BA%E4%BB%80%E4%B9%88%E7%BB%B4%E6%8A%A4%E4%BA%BA%E8%AE%BE%E5%BE%88%E9%9A%BE/</id>
    <published>2026-01-30T16:53:23.000Z</published>
    <updated>2026-02-03T15:05:05.284Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>想起来点事情。在之前的工作中，我的 Leader 就属于需要在工作中维持自己专业形象的人，直白一点说，就是时刻在 “端着”。</p>
<p>这种 “端着” 的状态，是可以理解的：</p>
<ol>
<li>来自大厂，需要维护与 “大厂”]]></summary>
    <content type="html"><![CDATA[<p>想起来点事情。在之前的工作中，我的 Leader 就属于需要在工作中维持自己专业形象的人，直白一点说，就是时刻在 “端着”。</p><p>这种 “端着” 的状态，是可以理解的：</p><ol><li>来自大厂，需要维护与 “大厂” 这一标签匹配的专业感与高级感</li><li>工资较高（币权占比大）</li><li>职位定位较高（Tech Leader）</li></ol><p>由于需要维护这些外部的光环，以及需要 “镇得住” 团队内的开发人员，所以在实际的工作中，处处表现出 “端着” 的状态，比如：</p><ol><li>全员会议上，用到 “范式” 这个词描述某个业务逻辑</li><li>内部会议上，凭头脑中的想象 debug 线上数据索引慢的问题，说什么属于计算密集还是 IO 密集之类</li><li>交给我负责某个项目的时候，给我发了一些程序设计的参考文章和文档。关键在于，发给我的是一些 Java 面向对象的设计模式，大学生学编程的时候看的那种。（他不是程序员出身。因为程序员出身大学都接触过……）</li><li>我刚入职的时候，发给我一本 Cosmos 原理方面的书籍让我参考。问题在于，是一本中文的书。正经做技术的都知道，不要看中文技术书。</li><li>有一次内部会议，我发现他对其他某个人进行 “说教” 的时候，用的是我博客上的观点</li><li>在我离职的时候，我们的对话中，他也用到了我博客中提到的观点</li></ol><p>这种 “端着” 的状态，是可以被真正懂技术或者经验丰富的人看出来的，而且偶尔无论是在会议还是工作中，都难免会 “露怯”。想要时刻维护一种高级感的形象是很难，也很累的。</p><p>当然这种刻意的形象维护，也有一些好处，能带来高薪、高职位。</p><p>世界上也有不需要 “刻意” 维护就能高光的人设，比如李星野，身家过亿这一条就够了，比如王垠，清华退学这一条就够了。</p><p>刻意维护的人设，早晚会被揭穿。</p><p>不要误会，以上内容看起来像是在贬低别人，以达到抬高自己的目的。我肯定承认自己不如人家，比如包装自己的能力…… 技术能力的话，我已经把能写的都写出来了，透明公开。另外，这个博客实际上等同于是 “匿名” 的，抬高自己毫无用处。</p><p>我为什么会想到这个话题呢？因为我注意到现在的博客过于简洁，尤其缺少两个关键的东西：</p><ol><li>一句话简介，说明我是谁，我的来历、技术栈、职业定位</li><li>其他平台的社交账号链接</li></ol><p>我不知道怎么定义自己，所以写不出一句话简介。也没有什么高光的经历，不能拿来做人设。至于其他平台的账号，维护起来就更累了。</p><p>从运营和营销角度看，这个博客是失败的，读者需要凭借一篇篇技术内容去拼凑出一个形象作为记忆点，而且我相信大多数人不是特别理解一些技术概念。所以这方面很难做。但是另一方面，实在是不想 “运营”…… 再一方面，也许可以认为我开始逐渐有市场营销的意识了，也许以后会 “变好”。</p>]]></content>
  </entry>
  <entry>
    <title>年终结算的误区</title>
    <link href="https://b.smallyu.net/2026/01/29/%E5%B9%B4%E7%BB%88%E7%BB%93%E7%AE%97%E7%9A%84%E8%AF%AF%E5%8C%BA/"/>
    <id>blog-b:https://b.smallyu.net/2026/01/29/%E5%B9%B4%E7%BB%88%E7%BB%93%E7%AE%97%E7%9A%84%E8%AF%AF%E5%8C%BA/</id>
    <published>2026-01-29T07:26:16.000Z</published>
    <updated>2026-02-03T15:04:42.673Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近两年回家，经常会被亲戚问到一个问题：“今年赚了多少钱？”</p>
<p>由于这个问题的存在，导致我自己也经常用这个问题的答案衡量和评估自己，尤其是临近年底，会想到如果被问到这个问题，应该怎么回答。</p>
<p>这些亲戚生活在老家，他们对于你甚至对于人的评价体系单一、而]]></summary>
    <content type="html"><![CDATA[<p>最近两年回家，经常会被亲戚问到一个问题：“今年赚了多少钱？”</p><p>由于这个问题的存在，导致我自己也经常用这个问题的答案衡量和评估自己，尤其是临近年底，会想到如果被问到这个问题，应该怎么回答。</p><p>这些亲戚生活在老家，他们对于你甚至对于人的评价体系单一、而且缺少共同语言、只能问出赚了多少钱这个问题，这不是他们的错。</p><p>但是随着这个问题困扰我一段时间，我忽然意识到，这样的评价体系是不对的。</p><p>如果单说我今年赚了多少钱，我显然是非常失败的，我以前提到过，我现在负债 10 万人民币左右。从这个角度看，我连生活在小县城的人都不如，他们一个月挣 3 千花 2 千，一年下来还能攒 1 万。</p><p>那么对于年终结算来说，还应该考虑哪些方面？</p><p>比如学到了什么知识。</p><p>2025 年下半年开始，大概 6 月份左右，我就在学习王垠的计算机课。随后虽然只用了一个多月就毕业了，但仍然持续用了接近半年的时间重新做练习题、逐步消化其中的内容、确保自己掌握了课程中的内容。</p><p>现在对于课程内容的学习，已经经过了大概半年的时间，我已经几乎不太怀疑自己是否已经掌握了其中的内容，可能接下来要考虑的是如何将其中的内容更加融会贯通。</p><p>我之前也比较主观、宏观地描述过王垠课程内容的质量。直到现在我都时常反思这门课程中包含的内容，以及课程本身的含金量。</p><p>课程最核心的价值，就是提供了一条最简洁的、能够彻底解构计算机理论知识的路径。从这个角度看，这门课程是无价的。如果你没有计算机基础，学完之后你的起点会非常高。如果你有计算机基础，课程将会提供给你一个完全不一样的、系统梳理计算机体系的视角。</p><p>2025 年，我竟然用了长达半年的时间去学习一门课程。这是我之前没能预料到的。</p><p>那么接下来的问题是，学完了，然后呢？</p><p>我之前从博客上删掉了对于课程体会和评价，有几方面原因：</p><ol><li><p>我没想蹭 “王垠” 这个关键词的热度。如果摆到博客上，也许能增加很多搜索量，但是我不想。</p></li><li><p>我并不特殊，王垠的课基本上花钱就能学，没有严格的筛选条件什么的，不像大学一样有很高的门槛，那么多学生中我不具备什么独特的或者特殊的点。非要和大众相比的话，可能就是自己愿意相信王垠课程的眼光，以及能够负担起这样昂贵的学费，本身算是一种门槛。</p></li><li><p>我不擅长社交，也没有和王垠（老师）保持联系。也许是我自己的性格使然，我几乎无法和没有交集的人保持联系，尤其是很客套的联系。当然这并不能说明什么的，我的意思是我们仅限于课程内容的交集。</p></li><li><p>我的水平无法反映王垠课程的水平。也许我的境遇反而会给人带来负面的印象，让人觉得 “你看这人学过了也就这样” 之类。</p></li><li><p>我没办法一条条列举出客观的数据，去说明课程的内容多么 “有用”。课程主要能给人带来思维上的提升，像奢侈品、艺术品一样，更多是用来欣赏的。你要真说课程内容能给工作带来怎样的帮助，说真的，其实直接的帮助并不大，而且甚至会是负面的帮助，因为你在课程上看到的是结构非常清晰、条理、简洁、有技术含量的代码，工作中都是一堆 AI 生成的结构混乱、写法复杂、充满 fallback 和 trade-off 的代码，而且整天面对调 API、数据库、SDK 一类的工作，你会怀疑人生，“我学 lambda 演算干嘛？” 这不是课程的问题，也不是工作的问题，商业环境就是这样的。</p></li><li><p>输入不是成果，输出才是。学了什么不重要，写了什么、看懂了什么、有了什么样的观点、懂得了什么道理等等比较重要。产出才是成果，博客里放的是成果。</p></li></ol><p>所以这半年以来学习的课程，我相信未来还会继续带给我灵感。这从整个人生历程来看，都是一种阶段性的、标志性的事件。</p><p>既然王垠的计算机基础班有那么大的威力，我要不要尝试进一步报名学习进阶班、专项班呢？我目前是没有打算，一方面没钱、没时间，另一方面，进阶班不像基础班属于通识类的教育，而是比较专注于 PL 理论研究的领域。我并没有太想向那个方向深入。</p><p>对于年终结算来说，还应该考虑哪些方面呢？</p><p>比如钱花到哪里去了。</p><p>印象比较深的一项支出就是我买了相机，而且是我自己坚持要买，送给女朋友。为什么呢？因为她属于三坑少女，无论算不算我一厢情愿，我觉得只要有了相机，我们就能更多出门去玩了。以前出门去逛景点、拿手机拍照，总是会听到 “要是有相机就好了” 之类的话，而且确实拿着手机感觉没有相机专业。买到相机后，发现相机拍出来的照片质感，确实不是 iPhone Pro 的数码摄像头可以比的，照片质量会明显不一样。所以为了我们以后能多见面、多出去玩、出片，相机是一项必要开支。</p><p>还有很多大额支出，无非就是给女朋友买礼物，或者我自己的房租，也没有什么别的开销。买礼物、买衣服花钱比较多。那这怎么衡量呢，能说把钱花在这些地方，算是很 “失败” 吗？如果分手了人去财空，就算是很失败。但是现在感情没有不好，这些花销就算是正常的感情投资吧。从这个角度来看，我今年赚到钱了吗？没有。但是我今年收获了更好的感情，这事怎么衡量呢？</p><p>总的来说，我的意思是，对于人的成败、得失，临近年底的总结、评价标准，不要单一根据有多少存款来判断。</p>]]></content>
  </entry>
  <entry>
    <title>不理解为什么有人敢生孩子</title>
    <link href="https://crazy.smallyu.net/2026/01/28/%E4%B8%8D%E7%90%86%E8%A7%A3%E4%B8%BA%E4%BB%80%E4%B9%88%E6%9C%89%E4%BA%BA%E6%95%A2%E7%94%9F%E5%AD%A9%E5%AD%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/01/28/%E4%B8%8D%E7%90%86%E8%A7%A3%E4%B8%BA%E4%BB%80%E4%B9%88%E6%9C%89%E4%BA%BA%E6%95%A2%E7%94%9F%E5%AD%A9%E5%AD%90/</id>
    <published>2026-01-28T06:51:54.000Z</published>
    <updated>2026-07-04T17:36:19.130Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>无法理解身家不过百万（现金）的人敢生孩子。</p>
<ul>
<li>你的孩子能从小喝进口奶粉吗？</li>
<li>你的孩子能从小接受良好的教育，五六岁说一口流利的外语吗？</li>
<li>你能负担起各种课外兴趣爱好班吗，足球、网球、音乐、计算机？</li>
<li>你]]></summary>
    <content type="html"><![CDATA[<p>无法理解身家不过百万（现金）的人敢生孩子。</p><ul><li>你的孩子能从小喝进口奶粉吗？</li><li>你的孩子能从小接受良好的教育，五六岁说一口流利的外语吗？</li><li>你能负担起各种课外兴趣爱好班吗，足球、网球、音乐、计算机？</li><li>你的孩子能够在家里后院的草坪上和一只很大的自己养的狗玩耍吗？</li><li>你能给孩子广阔的国际视野，从小全世界旅游开阔眼界吗？</li><li>你在工作之外有足够时间陪伴孩子、教育孩子吗？（你自己啥水平就敢教育一个完全空白的人类？）</li><li>你能给孩子提供学业甚至工作上的帮助、规划稳定扎实的职业路径吗？</li></ul><p>我从小有没有这些呢，那当然是没有的。正是因为什么都没有，长大之后进入社会才感觉到异常艰难和辛苦。</p><p>我不可能让我的孩子吃和我一样的苦。</p><p>为什么有些人敢生孩子呢？可能因为他们自己不觉得辛苦，也不明白自己所处的环境有多么糟糕。他们并不尊重自己孩子以后的境遇。</p><p>也许吧，反正我无法理解他们。</p>]]></content>
  </entry>
  <entry>
    <title>不能理解自己做饭的逻辑</title>
    <link href="https://crazy.smallyu.net/2026/01/27/%E4%B8%8D%E8%83%BD%E7%90%86%E8%A7%A3%E8%87%AA%E5%B7%B1%E5%81%9A%E9%A5%AD%E7%9A%84%E9%80%BB%E8%BE%91/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/01/27/%E4%B8%8D%E8%83%BD%E7%90%86%E8%A7%A3%E8%87%AA%E5%B7%B1%E5%81%9A%E9%A5%AD%E7%9A%84%E9%80%BB%E8%BE%91/</id>
    <published>2026-01-27T12:53:11.000Z</published>
    <updated>2026-07-04T17:36:19.130Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>从事先买菜到做饭，至少需要一到两个小时的时间才能完成做饭、吃饭这件事情。</p>
<p>美团上拼单只需15块钱就能想吃什么吃什么，不但好吃、样式多，而且不需要花费自己的任何时间。</p>
<p>所以投入时间去做饭是一件性价比很低、很难理解的事情。</p>
]]></summary>
    <content type="html"><![CDATA[<p>从事先买菜到做饭，至少需要一到两个小时的时间才能完成做饭、吃饭这件事情。</p><p>美团上拼单只需15块钱就能想吃什么吃什么，不但好吃、样式多，而且不需要花费自己的任何时间。</p><p>所以投入时间去做饭是一件性价比很低、很难理解的事情。</p>]]></content>
  </entry>
  <entry>
    <title>兄弟、闺蜜</title>
    <link href="https://crazy.smallyu.net/2026/01/27/%E5%85%84%E5%BC%9F%E3%80%81%E9%97%BA%E8%9C%9C/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/01/27/%E5%85%84%E5%BC%9F%E3%80%81%E9%97%BA%E8%9C%9C/</id>
    <published>2026-01-27T05:08:43.000Z</published>
    <updated>2026-07-04T17:36:19.131Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>兄弟和闺蜜都是乌合之众的别名。</p>
<p>凡是声称好兄弟、铁哥们、闺蜜一类关系的人，关系在5年以上、无话不谈，大概率：</p>
<ol>
<li>双方的生活质量和生活水平长期以来都没有显著提升</li>
<li>双方的学识和眼界长期以来都没有显著的提升</li>
</o]]></summary>
    <content type="html"><![CDATA[<p>兄弟和闺蜜都是乌合之众的别名。</p><p>凡是声称好兄弟、铁哥们、闺蜜一类关系的人，关系在5年以上、无话不谈，大概率：</p><ol><li>双方的生活质量和生活水平长期以来都没有显著提升</li><li>双方的学识和眼界长期以来都没有显著的提升</li></ol><p>什么时候这种看似很铁的关系会逐渐疏远呢：</p><ol><li>当有一方的境遇显著好于另一方的时候</li><li>当有一方的境遇显著坏于另一方的时候</li></ol><p>有没有可能双方境遇在同时提高？不可能。</p><p>所谓好兄弟，无非就是小时候认识、读书的时候认识，那种关系看似年份久远，但都不是你主动选择的。</p><p>而在工作上、利益纠结的场合下，更不可能有什么纯粹的关系。</p><p>所以假如有人跟你说他有好兄弟、好闺蜜，这个人大概率能力一般、水平一般、见识一般。</p><p>兄弟、闺蜜，实际上就是乌合之众。</p>]]></content>
  </entry>
  <entry>
    <title>硬件钱包与资产安全</title>
    <link href="https://smallyu.net/2026/01/25/%E7%A1%AC%E4%BB%B6%E9%92%B1%E5%8C%85%E4%B8%8E%E8%B5%84%E4%BA%A7%E5%AE%89%E5%85%A8/"/>
    <id>blog:https://smallyu.net/2026/01/25/%E7%A1%AC%E4%BB%B6%E9%92%B1%E5%8C%85%E4%B8%8E%E8%B5%84%E4%BA%A7%E5%AE%89%E5%85%A8/</id>
    <published>2026-01-25T08:04:40.000Z</published>
    <updated>2026-01-25T08:05:22.061Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>加密货币的资金管理，从最安全到最不安全的方式排名是：</p>
<ol>
<li>家族信托</li>
<li>硬件钱包</li>
<li>MPC钱包</li>
<li>交易所托管</li>
<li>热钱包</li>
</ol>
<p>如果你不在乔布斯排行榜上，家族信托就跟你没]]></summary>
    <content type="html"><![CDATA[<p>加密货币的资金管理，从最安全到最不安全的方式排名是：</p><ol><li>家族信托</li><li>硬件钱包</li><li>MPC钱包</li><li>交易所托管</li><li>热钱包</li></ol><p>如果你不在乔布斯排行榜上，家族信托就跟你没关系。对于个人而言，硬件钱包是目前最安全的方案。</p><p>这里没有提多签钱包、助记词+Passphrase 之类的方案，因为那些方案在技术手段上复杂到你都用不明白，复杂的方案是无法长期留存的，反而会增加遗忘的风险，更不可靠。</p><p>那么有几个需要更正的对于硬件钱包的认识：</p><ol><li>硬件钱包是钥匙，不是保险柜</li><li>钱是存在助记词上，不是硬件钱包上</li><li>硬件钱包输错密码会直接清空数据</li><li>助记词不是打开保险柜的备用钥匙，助记词是保险柜本身</li></ol><p>而助记词安全也有几个有意思边界：</p><ol><li>你无法验证助记词是否已经泄露</li><li>如果你不把助记词拿出来，就无法验证助记词是否正确</li><li>你把助记词拿出来的行为本身，就增加了助记词暴露的风险</li></ol><p>所以去中心化资产在给你带来控制权的同时，也要求你自己承担资产安全的风险。</p>]]></content>
  </entry>
  <entry>
    <title>BitDoge</title>
    <link href="https://crazy.smallyu.net/2026/01/20/BitDoge/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2026/01/20/BitDoge/</id>
    <published>2026-01-20T15:47:06.000Z</published>
    <updated>2026-08-09T04:40:05.046Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>BitDoge 是一个部署在以太坊主网（Chain ID&#x3D;1）的 ERC-20 代币，按照这样的规则运行：</p>
<ol>
<li>代币名称：BitDoge (BITDOGE)</li>
<li>代币合约地址：<a]]></summary>
    <content type="html"><![CDATA[<p>BitDoge 是一个部署在以太坊主网（Chain ID&#x3D;1）的 ERC-20 代币，按照这样的规则运行：</p><ol><li>代币名称：BitDoge (BITDOGE)</li><li>代币合约地址：<a href="https://etherscan.io/address/0x000000001994bb7b8ee7d91012bdecf5ec033a7f"><code>0x000000001994bb7b8ee7d91012bdecf5ec033a7f</code></a></li><li>代币的总供应量是 2100 万，没有初始流通量</li><li>代币的释放规则是，每一个以太坊区块最多产生 1 BitDoge</li><li>获取代币的方式是，每次向代币的合约地址转账 0 ETH，就可以获得 1 BitDoge</li><li>转账的金额可以大于 0 ETH，但是不会因为带有金额而获得更多 BitDoge，仍然只能得到 1 BitDoge。而且转账的金额会被永久锁定在合约内，无法取出</li><li>合约中没有任何 Owner 权限，也没有其他特殊权限，<a href="https://etherscan.io/address/0x000000001994bb7b8ee7d91012bdecf5ec033a7f#code">合约源码</a> 已经在 Etherscan 验证</li><li>代币的创世区块（Genesis Block）是以太坊的区块高度 <a href="https://etherscan.io/block/24444444">24444444</a>（2026年2月12日），在此之前合约会拒绝交易</li><li>每一个区块的代币奖励是 1 BitDoge，每 4 年减半一次，也就是 10512000 个以太坊区块之后，每个区块只能获得 0.5 BitDoge</li><li>如果当前区块没有地址交互，代币奖励会打入黑洞地址 <a href="https://etherscan.io/address/0x000000000000000000000000000000000000dEaD"><code>0x000000000000000000000000000000000000dEaD</code></a></li><li>每一个区块只有第一个与合约交互的地址可以获得代币奖励</li><li>按照每 4 年一次的减半周期，BitDoge 的区块奖励大概会在 140 年之后（2166年）归零</li></ol><p>合约源码全文：</p><pre><code class="solidity">// SPDX-License-Identifier: MITpragma solidity ^0.8.20;import &#123;ERC20&#125; from &quot;@openzeppelin/contracts/token/ERC20/ERC20.sol&quot;;/** * @title BitDoge (The 140-Year Social Experiment) * @notice A deflationary token that rigorously simulates Bitcoin&#39;s halving mechanics on Ethereum. * @dev  * - Total Supply: 21,000,000 (Strict Cap) * - Block Time: ~12 seconds (Ethereum) * - Halving: Every ~4 years (10,512,000 blocks) * - Mechanism:  * 1. Pure PVP: First come, first served per block. No Cooldowns. No Limits. * 2. Entropy Rule: If a block is missed (no interaction), its reward is BURNED forever. * 3. Genesis Launch: Mining is strictly locked until block #24,444,444. */contract BitDoge is ERC20 &#123;    // ==========================================    //              COSMIC CONSTANTS    // ==========================================    // Strict cap: 21 Million coins.    uint256 public constant MAX_SUPPLY = 21000000 * 1e18;         // Initial reward: 1 Coin per block.    // Ethereum produces ~7200 blocks/day.     // This matches Bitcoin&#39;s early issuance (~7200 BTC/day) perfectly.    uint256 public constant INITIAL_REWARD = 1 * 1e18;        // Halving interval: ~4 Years (based on 12s block time).    uint256 public constant HALVING_BLOCKS = 10512000;         // Standard burn address (The Black Hole).    address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;    // ==========================================    //           GENESIS CONFIGURATION    // ==========================================    // The Sequence of Death and Entropy.    // Mining starts precisely at this block height.    // Approx. 23 days from now (based on current height ~24.27M).    uint256 public constant GENESIS_BLOCK = 24444444;     // ==========================================    //              STATE VARIABLES    // ==========================================    // Tracks the last block that was processed (mined or burned).    uint256 public lastMinedBlock;               // Total ETH sacrificed to the contract (forever locked).    // Serves as the &quot;floor value&quot; or monument of the experiment.    uint256 public totalSacrificed;     // ==========================================    //                 EVENTS    // ==========================================    event Minted(address indexed user, uint256 userReward, uint256 burnedReward, uint256 blockNumber);    event Sacrifice(address indexed user, uint256 amount);    /**     * @dev Constructor     * Sets the state pointers. No parameters needed as Genesis is hardcoded.     */    constructor() ERC20(&quot;BitDoge&quot;, &quot;BITDOGE&quot;) &#123;        require(GENESIS_BLOCK &gt; block.number, &quot;Genesis must be in the future&quot;);                // Initialize state so the first valid mineable block is GENESIS_BLOCK        lastMinedBlock = GENESIS_BLOCK - 1;     &#125;    /**     * @dev Main interaction point.      * Send 0 ETH (to just mint) or sacrifice ETH (to mint + donate).     * WARNING: No Cooldowns. No Max ETH Limits. Pure Gas War.     */    receive() external payable &#123;        // 1. Genesis Check: Is it time yet?        require(block.number &gt;= GENESIS_BLOCK, &quot;BitDoge loading... Wait for Block #24444444!&quot;);        // 2. Competition Check: Has this block already been mined?        // Only one winner per block.        require(block.number &gt; lastMinedBlock, &quot;Block already mined&quot;);                // 3. Bot Protection: Only allow EOAs (Externally Owned Accounts).        // This prevents smart contracts from batch-mining, ensuring fairness.        require(msg.sender == tx.origin, &quot;Humans only&quot;);                // 4. Hard Cap Check.        require(totalSupply() &lt; MAX_SUPPLY, &quot;Minting ended (Year 2160+)&quot;);        _processMining(msg.sender, msg.value);    &#125;    /**     * @dev Internal logic to calculate rewards and burns.     */    function _processMining(address user, uint256 ethAmount) internal &#123;        // --- Step 1: Calculate Current Reward Rate ---        // Based on time passed since Genesis.        uint256 blocksPassed = block.number - GENESIS_BLOCK;        uint256 era = blocksPassed / HALVING_BLOCKS;                 // Bitwise shift for halving. Returns 0 after 64 halvings.        uint256 currentRate = (era &gt;= 64) ? 0 : (INITIAL_REWARD &gt;&gt; era);        // --- Step 2: Distribute Rewards ---                // A. User Reward:         // The user only gets the reward for the CURRENT block.        uint256 userReward = currentRate;                // B. Black Hole Reward (Entropy):        // All blocks missed between the last mine and now are burned.        // &quot;Use it or lose it.&quot;        uint256 missedBlocks = block.number - lastMinedBlock - 1;        uint256 burnReward = missedBlocks * currentRate;                // --- Step 3: Supply Cap Protection ---        uint256 totalRequired = userReward + burnReward;        if (totalSupply() + totalRequired &gt; MAX_SUPPLY) &#123;            uint256 remaining = MAX_SUPPLY - totalSupply();                        // Priority given to the user. Burn the rest.            if (remaining &lt;= userReward) &#123;                userReward = remaining;                burnReward = 0;            &#125; else &#123;                burnReward = remaining - userReward;            &#125;        &#125;        // --- Step 4: Update State ---        lastMinedBlock = block.number;                // Handle ETH Sacrifice (locked forever)        if (ethAmount &gt; 0) &#123;            totalSacrificed += ethAmount;            emit Sacrifice(user, ethAmount);        &#125;        // --- Step 5: Minting ---        if (userReward &gt; 0) &#123;            _mint(user, userReward);        &#125;                // Direct mint to Dead address (Auto-Burn)        if (burnReward &gt; 0) &#123;            _mint(BURN_ADDRESS, burnReward);        &#125;        emit Minted(user, userReward, burnReward, block.number);    &#125;&#125;</code></pre>]]></content>
  </entry>
  <entry>
    <title>预测市场比币圈更赌场</title>
    <link href="https://smallyu.net/2026/01/15/%E9%A2%84%E6%B5%8B%E5%B8%82%E5%9C%BA%E6%AF%94%E5%B8%81%E5%9C%88%E6%9B%B4%E8%B5%8C%E5%9C%BA/"/>
    <id>blog:https://smallyu.net/2026/01/15/%E9%A2%84%E6%B5%8B%E5%B8%82%E5%9C%BA%E6%AF%94%E5%B8%81%E5%9C%88%E6%9B%B4%E8%B5%8C%E5%9C%BA/</id>
    <published>2026-01-15T00:43:43.000Z</published>
    <updated>2026-01-15T00:45:39.118Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<ol>
<li>预测市场不存在长期主义</li>
<li>预测市场一定会有明确的结果</li>
<li>输的归零，风险不低于合约，高于现货，合约可以加仓，预测市场没商量</li>
<li>所以预测市场无法用于投资</li>
<li>预测市场的技术实现不是去中心化的，所以跟]]></summary>
    <content type="html"><![CDATA[<ol><li>预测市场不存在长期主义</li><li>预测市场一定会有明确的结果</li><li>输的归零，风险不低于合约，高于现货，合约可以加仓，预测市场没商量</li><li>所以预测市场无法用于投资</li><li>预测市场的技术实现不是去中心化的，所以跟 web3 没关系，定位上类似于币安等 CEX</li><li>所以预测市场比土狗盘还残酷</li></ol>]]></content>
  </entry>
  <entry>
    <title>为什么去中心化的跨链桥不可能实现</title>
    <link href="https://smallyu.net/2026/01/13/%E4%B8%BA%E4%BB%80%E4%B9%88%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E8%B7%A8%E9%93%BE%E6%A1%A5%E4%B8%8D%E5%8F%AF%E8%83%BD%E5%AE%9E%E7%8E%B0/"/>
    <id>blog:https://smallyu.net/2026/01/13/%E4%B8%BA%E4%BB%80%E4%B9%88%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E8%B7%A8%E9%93%BE%E6%A1%A5%E4%B8%8D%E5%8F%AF%E8%83%BD%E5%AE%9E%E7%8E%B0/</id>
    <published>2026-01-13T04:05:36.000Z</published>
    <updated>2026-01-13T04:05:46.225Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>准确来说，是 Trustless 的跨链桥不可能实现。因为一般认为去中心化就意味着 Trustless，虽然实际上去中心化是在信任一个 Permissonless]]></summary>
    <content type="html"><![CDATA[<p>准确来说，是 Trustless 的跨链桥不可能实现。因为一般认为去中心化就意味着 Trustless，虽然实际上去中心化是在信任一个 Permissonless 的群体。</p><p>不纠结这些具体的名词。现在的各种跨链桥方案，以及未来的跨链桥方案，一定都做不到纯粹的、工具性质的、数学证明的、轻量级运营的、去中心化的形式，能够满足物理隔离的、异步的、异构链之间的跨链。</p><p>先列举一下现在的跨链桥方案，以 BTC 到 ETH 的跨链为例：</p><ol><li><p>公证人模式，也就是中心化的模式，把 BTC 打给一个中心化机构，机构再把 ETH 打给你指定的地址。安全性依赖中心化机构，没什么可说的。现在大多数跨链桥都是这种传统的模式，最多就是机构内部多签。</p></li><li><p>TSS 密钥分片、多签，相对去中心化。把 BTC 转给一个第三方的链比如 Thorchain，在 Thorchain 中，有多个节点分别持有 ETH 链上资产的密钥分片，每个节点分别扫描和验证 BTC 的交易信息，达到一定阈值则多签的签名生效、在 ETH 链上放行资产。</p><p> 这种模式把公证人给去中心化了，有多个节点在共同验证来源交易是否正确。这是目前相对来说比较靠谱的、依赖社区博弈的方案。因为 Thorchain 本身就是一条链，想成为持有密钥分片的节点就需要质押 Token 等。TSS 的签名算法比较消耗计算资源，做不到同时分发太多的密钥分片，所以持有分片的节点数量在一定范围内。像所有的 PoS 链一样，表面上是去中心化的，实际上是 Permissioned 的，只不过是权限的门槛高低不同。</p><p> TSS 确实把跨链桥去中心化了，但是引入了 BTC 和 ETH 之外的第三条链，而第三条链的安全性又依赖于它自己的经济学博弈，本身就是风险。所以这种模式可靠但不够纯粹。</p></li><li><p>合并挖矿，特指资产的来源方是 PoW 链，让 BTC 的矿工在挖矿的时候，把跨链桥的某种证明信息给带上，一起挖到 BTC 的区块信息里。那么 BTC 的区块信息本身就包含了跨链信息。这种方式非常可靠但是不可行，因为矿工不可能配合跨链桥干这种事情。</p></li><li><p>HTLC，本质上是资金的对敲，对实时性要求比较高，必须双方同时在 BTC 和 ETH 在线交换密钥，而且 HTLC 只能做到资金的交换而不是跨链，涉及到汇率的问题。</p></li><li><p>全验证轻客户端，也就是在 ETH 上运行 BTC 的轻客户端，比如让每个 Geth 节点都可以同步和验证 BTC 的全部区块信息，那么 Geth 本身就是一个轻量级的 BTC 客户端，自然也能够实时地、无需第三方信任地把 BTC 交易信息同步到 ETH 的智能合约上。但是这样显然成本太高了，相当于一个客户端同时兼容了两条链。</p></li><li><p>ZK 跨链桥，运行一个 BTC 的轻客户端，把所有区块信息生成电路证明，然后在 ETH 上部署一个 Verifier，只需要验证很小的证明就可以相信来源信息是正确的。那么这种 ZK 模式的问题在哪里？ZK 并没有黑魔法，它的问题在于，需要在 ETH 上部署一个 Verifier。也就是说，你不需要关心是谁、是怎么生成证明的，但是你必须相信在 ETH 上的 Verifier。那么 Verifier 的代码本身、背后的开发者、来源是否可信任又是一个问题。</p></li><li><p>TEE 硬件设备签名。比如在一个 Intel 的服务器上，同步 BTC 的区块信息，然后用 TEE 内置的私钥签名，证明这个信息一定来源于这台设备。然后在 ETH 上，只需要判断来源签名是否来自于那台硬件设备，就可以证明信息是否安全。TEE 方案最大的问题自然是单点风险。</p></li></ol><p>各种方案对比下来，似乎根本找不到一种让人满意的方式。为什么会是这样？</p><ol><li><p>分布式系统中的两军问题（Two Generals’ Problem），这是计算机科学史上第一个被证明无解的问题。这个问题具体的定义不重要，重要的是它早已被科学界证实无解。</p></li><li><p>计算理论中的预言机问题（The Oracle Problem），每一条区块链本身都是一个确定性的状态机，它是封闭的、可被验证的、可被重复计算的。如果要和外部通信，就必然需要引入信任模型、经济学博弈、密码学证明等，这些内容会让跨链方案不再纯粹。</p></li></ol><p>所以去中心化的跨链桥这个问题，已经触及到了计算机科学的理论边界，不是工业界无能，而是这个问题本身无解。</p><ol start="3"><li>有趣的是，Vitalik 早在 2022 年就发表过一个 <a href="https://x.com/VitalikButerin/status/1479501366192132099">观点</a>，未来的区块链是多链的（multi-chain），而不是跨链的（corss-chain)。因为即使存在可靠的跨链工具解决了通信问题，ETH 仍然需要信任 BTC 的共识机制。假如 BTC 网络分叉，ETH 不可能跟着 BTC 的分叉去重新分配资金。这同样是一个无解的问题。</li></ol><p>这种跨链桥方面的技术边界可以带给我们启发：</p><ol><li>不存在无需信任的技术方案，只有信任转移、最小化信任</li><li>工程架构不可能完美，大多数时候需要权衡</li></ol>]]></content>
  </entry>
  <entry>
    <title>自负一次</title>
    <link href="https://b.smallyu.net/2025/12/31/%E8%87%AA%E8%B4%9F%E4%B8%80%E6%AC%A1/"/>
    <id>blog-b:https://b.smallyu.net/2025/12/31/%E8%87%AA%E8%B4%9F%E4%B8%80%E6%AC%A1/</id>
    <published>2025-12-31T07:22:51.000Z</published>
    <updated>2025-12-31T07:29:34.673Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>在过去的很长时间，我在心态上都在不断贬低自己。经过 Gemini 提醒，这是一种叫 “冒名顶替综合症” 的心理状态，含义是当自己获得了一些成绩后，总觉得自己配不上这样的成绩。</p>
<p>那么假如完全抛开我对自己的要求和期望，来“自负”]]></summary>
    <content type="html"><![CDATA[<p>在过去的很长时间，我在心态上都在不断贬低自己。经过 Gemini 提醒，这是一种叫 “冒名顶替综合症” 的心理状态，含义是当自己获得了一些成绩后，总觉得自己配不上这样的成绩。</p><p>那么假如完全抛开我对自己的要求和期望，来“自负” 地回顾一下我迄今为止获得的成绩：</p><ol><li>在一所普通的高中，高二成绩班级排名倒数前十，高三高考的成绩班级排名正数前十。</li><li>在一所普通的本科大学，四个学年的专业课总成绩班级第一，每学年的最差成绩和排名不低于班级前 15%。</li><li>毕业后在一家做联盟链的公司做区块链底层开发，调试共识那种。</li><li>后来跳槽到达鸿飞的一家公司做区块链项目。虽然只见过大老板一面。</li><li>在一份工作中独自搭建一条区块链网络，代币市值最高 CMC 排名 300。</li><li>在一个 TVL 排名赛道前 5 的 Restaking 项目工作，参与核心逻辑开发。</li><li>理财手段上做空法币，虽然现在负债累累，是因为把过去几年的工资全换成了比特币。</li><li>有一个漂亮的女朋友，在韩国留学，懂穿搭、审美和见识都很开阔，家境好。虽然她自己真没钱…</li><li>今年学习了王垠的计算机科学课，计算机理论水平向名校看齐。</li><li>目前在新的 web3 项目工作。</li><li>写出过带有专业观点的区块链技术博客文章。</li></ol><p>为什么我会陷入冒名顶替综合症的心理状态呢？也有一些原因：</p><ol><li>我从来不在比自己差的人身上找优越感</li><li>学历和技术能力上一直都在向王垠看齐，自然觉得自己差太多了</li><li>有钱程度上在向富人看起，比如达鸿飞、有几万个比特币的郭宏才、在新加坡住着别墅雇着菲佣的老板、写出了《人约》论文的李星野等。</li><li>把面试完不发 offer 等同于自己技术能力不足</li><li>web3 项目尤其是新项目的 founder 藤校出身太多，自己始终无法摆脱学历方面的滤镜</li><li>没有资源、人脉、家庭支持，确实没有</li></ol><p>好了。</p>]]></content>
  </entry>
  <entry>
    <title>年终总结</title>
    <link href="https://b.smallyu.net/2025/12/28/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/"/>
    <id>blog-b:https://b.smallyu.net/2025/12/28/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/</id>
    <published>2025-12-28T15:15:45.000Z</published>
    <updated>2026-02-03T15:04:53.640Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<h3 id="债务"><a href="#债务" class="headerlink" title="债务"></a>债务</h3><p>2025 年，是糟糕的一年。</p>
<p>最直观的数据是，我目前负债 7]]></summary>
    <content type="html"><![CDATA[<h3 id="债务"><a href="#债务" class="headerlink" title="债务"></a>债务</h3><p>2025 年，是糟糕的一年。</p><p>最直观的数据是，我目前负债 7 万人民币左右。支出内容包括计算机科学课的学费、房租、失业期间的日常消费、生日礼物、相机、电吉他、电脑等。</p><p>贷款的来源是微粒贷、京东白条、信用卡等，不知道这些算不算人们常说的网贷。负债大都以分期的形式在还，最长的分 24 期，最短的还剩 3 期。所以虽然负债数字不小，但是短期的还债压力也不算大。</p><p>不久的将来，也就是再过几天（2026年了），我还会有一笔不小的支出，大概 5 万人民币左右，买黄金首饰。这样加起来，实际上总计负债会达到 12 万。</p><p>今年也是有收获的，只不过这些收获大多来自痛苦与挣扎，而不是循序渐进的那种努力和收获。之前在工作上遇到破事就不反复说了，有些事情，在一开始遇到的时候会觉得惊讶，但是后来逐渐明白，整个行业的情况都是这样，普遍存在。</p><h3 id="Side-Project"><a href="#Side-Project" class="headerlink" title="Side Project"></a>Side Project</h3><h4 id="工作时长"><a href="#工作时长" class="headerlink" title="工作时长"></a>工作时长</h4><p>出于基本的职业道德和职业素养，对于主业工作，我会主动保证基本的工作时长，算下来工作时长肯定是不低于平均水平的。</p><p>虽然远程工作多年了，但我仍然是出卖时间的工作方式。虽然鸡汤文学里都在告诉我们要出卖知识、技能、产品而不是时间，但是事实会告诉你很难做到，因为那些东西没有办法评估和量化，时间长度是最简单直接的衡量方式。</p><p>另外一个我没想通的逻辑是，中国地大物博、牛马众多，不缺的就是有能力的。所以你要说你想出卖技能，你有啥能力啊你就出卖，大多数人的能力都是平庸的。对于工作而言，把日常工作做好、能正常沟通、态度负责、及时响应、不出大的差错，承担好一个稳定的点，就已经及格了，甚至做的不错了。能做出出众工作表现的寥寥无几，尤其是把范围放大到整个行业里，整个世界上，人类历史上，而不局限于你自己的小圈子，你还想咋出众啊。很多自以为是的工作成果，其实都是在自己的圈子而言，如果打开门看看，没有人在乎。</p><h4 id="路线"><a href="#路线" class="headerlink" title="路线"></a>路线</h4><ol><li>不运营博客，想写什么写什么，不要被流量绑架</li><li>不打造人设，完全不想走那种网红（小丑）路线</li><li>不要执着于观点和真理，观点总有枯竭的时候</li></ol><p>代码仍然可以是好的资产。虽然文章也可以，但是文章免不了走上上述 3 条路线，所以不能走下去。</p><p>而代码，虽然生成式 AI 已经可以生成可靠的代码片段，但是现在的 AI 仍然缺少架构能力，面对复杂的场景根本无从下手。所以利用 AI 生成代码的能力，来做好一些脏活、节省他人的时间、开箱即用，也算是一种有价值的方向。AI 可以写出代码，但是需要经过成百上千次的调试、审查、功能验证、梳理，才算是一个项目。这就是项目本身的价值。</p><p>另一个话题是，在 AI 出现以前，传统公司的中层领导、CTO，其实本来就不写代码。AI 出现以后，他们仍然不写代码。所以事实上 AI 没有动摇他们的地位。假如你担心自己写代码的能力被 AI 取代，那么问题就在于其实是因为你没有能力胜任更高级别的架构角色，不能怪 AI。</p><h4 id="项目"><a href="#项目" class="headerlink" title="项目"></a>项目</h4><p>最近一个月，我花了不少时间创建一些 Side Project。既然 AI 的趋势势不可挡，那么就干脆尽可能发挥 AI 的能力试试，让自己的角色变为 AI 指挥家，看看 AI 的高效率能做出多少东西，能不能产生有意思的东西。</p><p>我给自己创建了一个 <a href="https://spd.smallyu.net/">Dashboard</a> 来管理这些新的 Side Project（旧的不维护了），主要是给自己看，用来追踪哪些项目有段时间没更新了，就动手跟进哪些项目。</p><p>现在 Dashboard 中有 17 个项目。数量有点多，在这么多项目之间做上下文切换是很难的，我知道是一种负担，而且会花费很多时间。给自己工作也算工作，所以实际上平时空闲时间有点少。一方面想做点东西试试，另一方面又确实做不过来，砍掉一些项目又不愿意。这些项目其实都有意思，只是时间不够用。</p><p>Dashboard 中给项目分了 3 类，第一类是基建类，包括之前的 EchoEVM 和 EthBFT 也都放进去了，以及新增的一些，比如用 Go 语言实现一个 TSS 库、用 Rust 语言实现一个零拷贝高性能的 EVM 字节码解码库、能处理区块重组的 EVM 事件索引器等。</p><p>第二类是组件库、依赖包、SDK 一类，比如比特币的 PSBT 解码库、Solana 的交易解析和可视化库、蜜罐合约的示例、Safe Wallet 的 Python 版本 SDK 等。</p><p>第三类是软件和工具类，能直接用的那种，这个分类的项目可以具体介绍下：</p><ul><li><a href="https://github.com/smallyunet/konachan-downloader">konachan-downloader</a></li></ul><p>一个基于 Python 的命令行工具，一键多线程下载 Konachan 网站的全部二次元壁纸，我用 6 个小时下载了 2 万多张图片，占用磁盘空间 150 GB 左右，下载了 Konachan 图片总量的大概 1&#x2F;6。要不是硬盘空间和流量不够用，肯定全部下载下来……</p><ul><li><a href="https://github.com/smallyunet/finder-sight">finder-sight</a></li></ul><p>一个基于 Python 图形库的软件，已经打包成了 MacOS App，功能是在本地以图搜图，针对某一些目录的图片建立索引，然后用图片的一部分就可以搜索匹配到在本地文件的哪里。</p><p>当下载了大量壁纸并且随机显示到桌面之后，有时候会发现桌面上看到的壁纸并不好看，想删掉，但是又不知道怎么找具体是本地文件夹里的哪一个。所以需要一个本地以图搜图的软件。</p><ul><li><a href="https://github.com/smallyunet/vscode-antigravity-hud">vscode-antigravity-hud</a></li></ul><p>一个用于 Google Antigravity 编辑器的插件。我目前日常使用 Antigravity，但是谷歌默认不显示模型的使用量和剩余使用量，所以就可以用这个插件来看具体的消耗情况，以及下一次重置用量的时间。这个插件不算有特点，因为插件库有很多其他同类型的、相同功能的插件，只是我自己想搞一个比较简洁一点的用。</p><ul><li><a href="https://github.com/smallyunet/chatgpt-visualizer">chatgpt-visualizer</a></li></ul><p>ChatGPT 可以一键导出全部的聊天数据，但是他自己附带的网页非常简陋，而且如果数据量大，比如我的数据有 1 GB，网页加载会直接把 chrome 浏览器卡死。所以想开发一个能加载大量数据、现代化聊天 UI 的本地工具。而且本地数据搜索起来是非常快的，如果用 ChatGPT 的平台，数据请求都得等待他们的网络响应，会很慢。</p><p>再一个原因就是我现在不用 ChatGPT 了，用 Gemini，所以需要把 ChatGPT 的数据归档。Google 发明了 Transformer、原生多模态、用 TPU 训练大模型、一年的营收大于 OpenAI 的总估值等，这些关键词都在暗示 Gemini 比 ChatGPT 更有潜力。</p><h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><p>补充一点，关于做 Side Project 的想法，其实一开始来自于 Péter Szilágyi 的一条 <a href="https://x.com/peter_szilagyi/status/1999121102140756037">X 帖子</a>。Péter Szilágyi 以前是以太坊客户端 Geth 的 Leader，看起来今年离开了以太坊，开始建立一个叫 Dark Bio 的项目。当时看到 Péter Szilágyi 这样的人物都还在关注代码库这些东西，还发布了 crates 包，虽然下载量不高。受到 Péter Szilágyi 的启发，我才动了做一些开源组件库的念头。</p><p>大概就这些。我很清楚我做的这些 Side Project 属于 “虚假的勤奋”、“用战术上的勤奋掩盖战略上的懒惰” 什么的。但暂时还想做下去。</p><h3 id="学习"><a href="#学习" class="headerlink" title="学习"></a>学习</h3><p>计算机科学课程中的内容，比原本设想的更需要反复理解，所以来年还是要继续学习好这些理论基础。</p>]]></content>
  </entry>
  <entry>
    <title>我对于 AI 时代的答案</title>
    <link href="https://smallyu.net/2025/12/02/%E6%88%91%E5%AF%B9%E4%BA%8EAI%E6%97%B6%E4%BB%A3%E7%9A%84%E7%AD%94%E6%A1%88/"/>
    <id>blog:https://smallyu.net/2025/12/02/%E6%88%91%E5%AF%B9%E4%BA%8EAI%E6%97%B6%E4%BB%A3%E7%9A%84%E7%AD%94%E6%A1%88/</id>
    <published>2025-12-02T07:09:32.000Z</published>
    <updated>2025-12-22T01:59:40.047Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>当我的工资从每天 ___人民币上升到每天]]></summary>
    <content type="html"><![CDATA[<p>当我的工资从每天 ___人民币上升到每天 ___美元的时候，我开始思考是什么让工资增长。</p><p>得到的结论是：</p><ol><li>技术能力的提升</li></ol><p>然后我继续思考这几个问题：</p><ol><li>什么样的技术能力算是好</li><li>什么样的技术能力是稀缺、长久的</li><li>如何提高技术能力</li></ol><p>所以多年以来，贯彻我人生的思路就是：如何提高技术能力。最明显的体现是，如果工作不能让我成长，就换工作。</p><p>那么对于 “如何提高技术能力” 这个问题，我的答案是：</p><ol><li>关注底层原理和实现，而不是应用层的框架和接口</li><li>需要具备在复杂代码中找到并调试关键流程的能力</li><li>实际参与一些比较前沿的、像样子的项目</li><li>自己模仿实现一些比较底层和看起来硬核的项目</li><li>关注技术理念而不是具体实现</li><li>知道王垠课程所代表的 “计算的本质”</li></ol><br><p><strong>事实一</strong></p><p>但是紧接着，我发现了一个令人不安的事实：</p><ol><li>工资的高低、工作是否稳定，和技术能力的好坏没有必然的联系</li></ol><p>得到这个结论有这样几个原因：</p><ol><li>我不认为自己技术能力不合格，但是我遭遇的面试结果为不合适的情况，非常非常多</li><li>我不认为自己技术能力不合格，但是我亲眼看见水平很一般的人在做领导、面试官</li><li>我不认为自己技术能力不合格，但是我的工作很不稳定</li><li>有的人出生就在罗马</li></ol><p><strong>事实二</strong></p><p>与此同时，我发现另一个令人不安的事实是，AI 在改变游戏玩法：</p><ol><li>普通人和知识渊博的专家之间，差距只是一个 Gemini</li><li>程序员不再需要手写代码</li></ol><p>AI 引起的变化非常大，直接改变 “如何提高技术能力” 这个问题的答案：</p><ol><li>写代码的能力完全不重要，掌握多编程语言的能力完全不重要</li><li>在领域内的经验不再需要积累，一问 AI 全是标准答案</li></ol><p>复盘一下我之前犯的错误：</p><ol><li><a href="https://smallyu.net/2025/05/11/%E6%83%B3%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E6%9C%80%E5%B0%8FEVM%E8%99%9A%E6%8B%9F%E6%9C%BA/">EchoEVM</a>，在半年前，开发这样的东西似乎是有意思的。半年后的今天，AI 可以轻易开发出完整的项目。所以 EchoEVM 不再有意义。</li><li><a href="https://smallyu.net/2025/09/06/%E4%B8%80%E4%B8%AA%E9%9B%86%E6%88%90Geth%E5%92%8CCometBFT%E7%9A%84%E5%85%BC%E5%AE%B9%E5%B1%82/">EthBFT</a>，在 2 个月前，开发这样的东西也许可以看到 AI 能力的局限性。但是现在，AI 在逐渐突破以前的局限。所以 EthBFT 也不再有意义。</li></ol><p>EchoEVM 和 EthBFT 的共同特点，是偏低层、侧重技术的实现，试图用硬核项目来证明自己的技术能力。然而在拥有 AI 的今天，这种硬核的代码能力恰恰是 AI 最擅长、最先取代的。</p><br><p><strong>新的问题</strong></p><p>结合这两个令人不安的事实，需要回答的新问题是：</p><ol><li>如何提高自己的竞争力、稀缺性、硬实力、挣更多钱、不被时代淘汰</li></ol><p><strong>新的答案</strong></p><p>那么对于新的问题，我的答案是：</p><ol><li>提高发现问题的能力</li></ol><br><p><strong>对答案的解释</strong></p><p>你也许会说，这不废话吗，自古以来，发现问题的能力都是重要的。</p><p>不，这不一样，在没有 AI 的时候，你可以不需要有判断力，不需要能够发现问题，哪怕只是听产品经理的话来实现功能，也就是干好程序员的活，就可以活下去。</p><p>但是 AI 取代了这种只会听话干活的人。</p><p>“发现问题” 同时涵盖技术领域和非技术领域，在技术领域，发现代码有没有问题、功能设计是否存在漏洞、业务的边界条件是否缺少约束；在非技术领域，发现用户有哪些实际的需求，发现市场有哪些比较大的空缺。</p><p>那么为什么没有把 “提高判断力” 放到答案中？因为判断明天的股市涨跌也算判断，这种能力是无法验证以及无法通过努力提高的。</p><p><strong>进一步问题</strong></p><p>还没完，对于新的答案，有两个问题：</p><ol><li>如何提高自己发现问题的能力</li><li>与代码能力不同，发现问题的能力该如何量化、与他人比较</li></ol><p>对于 “如何提高自己发现问题的能力” 的问题：</p><ol><li>只有见过更好的，才能知道现在看到的有什么不足。所以要事事都向上看齐</li></ol><p>对于 “发现问题的能力该如何量化” 的问题：</p><ol><li>技术方面，把发现的问题落实到技术文档、设计文档、架构文档上</li><li>非技术方面，把发现的问题记录下来，比如博客、日记，文字可以记录思考的过程</li></ol>]]></content>
  </entry>
  <entry>
    <title>第 3 轮做完王垠计算机课程练习题后的体会</title>
    <link href="https://b.smallyu.net/2025/11/28/%E7%AC%AC3%E8%BD%AE%E5%81%9A%E5%AE%8C%E7%8E%8B%E5%9E%A0%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%AF%BE%E7%A8%8B%E7%BB%83%E4%B9%A0%E9%A2%98%E5%90%8E%E7%9A%84%E4%BD%93%E4%BC%9A/"/>
    <id>blog-b:https://b.smallyu.net/2025/11/28/%E7%AC%AC3%E8%BD%AE%E5%81%9A%E5%AE%8C%E7%8E%8B%E5%9E%A0%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%AF%BE%E7%A8%8B%E7%BB%83%E4%B9%A0%E9%A2%98%E5%90%8E%E7%9A%84%E4%BD%93%E4%BC%9A/</id>
    <published>2025-11-28T02:38:19.000Z</published>
    <updated>2025-12-03T09:25:54.157Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<h3 id="关于王垠以及课程的反思"><a href="#关于王垠以及课程的反思" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<h3 id="关于王垠以及课程的反思"><a href="#关于王垠以及课程的反思" class="headerlink" title="关于王垠以及课程的反思"></a>关于王垠以及课程的反思</h3><p>我注意到一个现象，最近几年，王垠的知名度和影响力都在下降，逐渐淡出公众视野。这导致很多 “新一代” 的程序员可能都不知道王垠是谁。而我最近总是频繁提到王垠（默认别人知道王垠）。</p><p>王垠的这种淡出背后也许有两个原因：</p><ul><li>王垠本人刻意删掉大量文章，主动隐藏有价值的内容</li><li>时代更替，AI 技术发展迅速，带来了很多改变</li></ul><p>我们重点关注第二个原因。</p><p>在 AI 飞速发展的今天，短短几个月的时间，程序员的工作模式就发生了重大变化。现在的程序员，不再需要动手写代码，更不需要动手复制粘贴代码，只需要描述清楚需求，让 AI 来完成就可以。程序员需要做的，是验证功能点、审查代码、当 AI 遇到无法解决的问题时，给 AI 兜底。</p><p>这也就意味着，你不需要懂编程语言的语法，不需要知道王垠是谁，不需要知道王垠对编程语言的评价如何，不需要崇拜王垠对于编程语言设计的学术品位，依然可以很好地完成日常工作。</p><p>无论你是否愿意承认，事实上大多数日常工作都是平庸的脏活，不需要艺术级别的代码审美。“品位” 永远都是奢侈的东西，大多数人没必要在乎。</p><p>王垠是一种技术符号，代表着在 AI 出现以前，追求极致符号与抽象的最顶尖的一类人。那么在 AI 出现以后，我们的关注点，又该如何变化？</p><h3 id="做练习题的过程"><a href="#做练习题的过程" class="headerlink" title="做练习题的过程"></a>做练习题的过程</h3><p>王垠的计算机课程中，练习题是重要的组成部分，每一节课都有课后练习题。我为了更好的掌握课程内容，就反复的去做这些练习题。第 3 轮做完的意思是，已经第 3 遍从头到尾做完了。</p><ul><li><p>第 1 轮是在学习课程的过程中，因为每个人都至少需要完成一遍练习题，才算是可以毕业。对应时间点 5月21日～6月24日。</p></li><li><p>第 2 轮是在课程结束后大概一个月的时间内完成的，对应时间点 6月25日～7月20日。</p></li><li><p>第 3 轮比较慢一点，因为按照一天一道题的计划，想要在放缓练习频率的同时，能够有时间好好消化这些课程的内容。经过整 4 个月的时间，从 7月24日～11月28日，终于完成了。</p></li></ul><p>在第 3 轮做练习题的过程中，大致是按照一天一道题的节奏，除了偶尔比较忙会跳票一两天，以及最后跳过了一点点 Rust 语法的练习题（实在是不太喜欢研究 Rust 的指针和内存），基本上没有大的偏差。</p><p>那么这一轮做练习题的过程中，对于练习题本身的改进有：</p><ul><li><p>修复一些 typo、整理一些代码模板、补充少量的用于测试边界条件的测试</p></li><li><p>第 5 课关于 BST 的练习题，很多因为视频里讲过了，所以练习题直接给出答案作为复习。我改进了这个部分，让第 5 课的练习中，关于 table 和 BST 的题目，都类似其他练习题一样，可以按部就班、循序渐进地练习</p></li><li><p>还是第 5 课的练习题，我自己扩展出了自动平衡二叉树的题目。这个题目本是第 5 课的隐藏练习题，但是我当时上课的时候，为了能尽快学完，就没有做这个隐藏练习，包括正版的自动平衡二叉树的题目，也是没有拿到的。我根据课上提供的基础内容，自己补充出了这部分的练习题</p></li><li><p>第 6 课，类似的，很多语义的实现因为视频里讲过，所以练习题是直接给出的。而我改进后的练习题，可以在脱离视频，也就是不需要再重复看视频的情况下，仅根据逐步的练习题，就回忆起全部内容</p></li></ul><p>大概就是一些修修补补、文本整理类型的改进，核心知识没有丝毫变化。毕竟确实题目本身就已经很精简了。</p><h3 id="做练习题后的体会"><a href="#做练习题后的体会" class="headerlink" title="做练习题后的体会"></a>做练习题后的体会</h3><p>对于王垠的计算机课程，倒是也不用非拔高到 “改变人生的神课” 这种高度，但是描述为包含计算机理论核心知识、不带有杂质、循序渐进的高质量课程，肯定没有问题。一门课程就是一所大学，也毫不夸张。</p><p>做练习题的过程中，印象深的点有两个：</p><ol><li><p>第 4 课隐藏练习，是实现一个简单的 parser，可以执行计算器的基本运算。这一次写出来的代码，和上一次，不太一样。而且稍微有点看不懂之前的代码了，感觉现在写出来的思路才是对的。因为 parser 这种东西的写法，可能本身就没那么严谨，所以这里出现分歧也没在意，直接按照新写出来的版本为准。核心思路肯定是没错的。</p></li><li><p>第 10 课的隐藏练习，涉及到用 Rust 实现解释器中的多级作用域的管理，让解释器能正确处理嵌套的闭包环境。与前 2 轮做练习题的时候不太一样，前两次遇到了同样的问题，然后按照同样的思路去解决问题。但是这一次，因为知道正确的答案，所以直接跳过了之前踩的坑，一开始就在用正确的方式实现，所以没有花费那么多心思。</p></li></ol><p>总体来说，第 3 轮完成练习题肯定是巩固了对于课程知识的掌握。至于后续的计划，还在考虑中。</p>]]></content>
  </entry>
  <entry>
    <title>区块链技术交流群</title>
    <link href="https://crazy.smallyu.net/2025/11/23/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E4%BA%A4%E6%B5%81%E7%BE%A4/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/11/23/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E4%BA%A4%E6%B5%81%E7%BE%A4/</id>
    <published>2025-11-23T14:03:58.000Z</published>
    <updated>2026-07-04T17:36:19.118Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>经过多年的工作，我终于明白一件事情：</p>
<blockquote>
<p>技术能力的好坏，与工作是否稳定、工资的高低、生活品质的好坏，都没有关系。</p>
</blockquote>
<p>我希望可以基于已有的技术能力，给更多人提供一些 “相对随意” 的帮助。（AI]]></summary>
    <content type="html"><![CDATA[<p>经过多年的工作，我终于明白一件事情：</p><blockquote><p>技术能力的好坏，与工作是否稳定、工资的高低、生活品质的好坏，都没有关系。</p></blockquote><p>我希望可以基于已有的技术能力，给更多人提供一些 “相对随意” 的帮助。（AI 懂的比我多，但是我们可以讨论哪个 AI 更好用）</p><p>不要误会，并不是说这个交流群是为了我自己的利益而创建。我的意思是，我可以提供的帮助，是这个群聊的一个兜底的价值。如果可以在群里得到其他人的帮助，或者在群聊中收获到什么，自然是再好不过的事情。</p><!-- 这是一个新创建的区块链交流群，欢迎加入： --><!-- - [https://t.me/blockhub_cn](https://t.me/blockhub_cn) --><p>我对这个交流群的设想是：</p><ol><li>希望能以交流区块链技术、Web3 项目、软件工程为主，但同时欢迎任何其他话题，比如入门开发、讨论币价等</li><li>虽然是我创建的群，但是不要有 “群主” 的概念，这不是 “我的群”，任何人都应该是管理员</li><li>如果你知道其他有意思的群聊，完全可以直接在群里发出推荐链接</li><li>希望这是一个 “交流” 群，不要 “要求” 其他人的回复和帮助，交流本身是不带有义务的自愿行为</li><li>群里的人可能会比较少，因为博客的访问量本来就小。这未必是坏事，理解万岁</li><li>也许不一定立刻马上就有话题想说，所以不必追求群聊的热度，欢迎潜水</li><li>群聊长期存在，群链接长期有效，欢迎把群转发给任何人</li></ol><!-- 群聊二维码： --><!-- <img src="image.png" width="30%"> -->]]></content>
  </entry>
  <entry>
    <title>我为什么不喜欢吃费大厨</title>
    <link href="https://crazy.smallyu.net/2025/11/22/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%96%9C%E6%AC%A2%E5%90%83%E8%B4%B9%E5%A4%A7%E5%8E%A8/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/11/22/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%96%9C%E6%AC%A2%E5%90%83%E8%B4%B9%E5%A4%A7%E5%8E%A8/</id>
    <published>2025-11-22T13:30:20.000Z</published>
    <updated>2026-07-04T17:36:19.126Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>因为桌子太小了，特别窄，吃的一点都不体面。</p>
<p>不得不承认费大厨的菜好吃，而且不贵，人均不到]]></summary>
    <content type="html"><![CDATA[<p>因为桌子太小了，特别窄，吃的一点都不体面。</p><p>不得不承认费大厨的菜好吃，而且不贵，人均不到 100，也难怪费大厨的门口时刻有一大堆人在排队。</p><p>但正因为廉价，导致餐桌和装修也都有一种廉价感，尤其是桌面不大，两人桌点3个菜后，几乎已经没有空间。而且桌子和桌子之间距离很近，像是拼桌一样。</p><p>不体面。</p>]]></content>
  </entry>
  <entry>
    <title>对比三个博客作者</title>
    <link href="https://b.smallyu.net/2025/11/21/%E5%AF%B9%E6%AF%94%E4%B8%89%E4%B8%AA%E5%8D%9A%E5%AE%A2%E4%BD%9C%E8%80%85/"/>
    <id>blog-b:https://b.smallyu.net/2025/11/21/%E5%AF%B9%E6%AF%94%E4%B8%89%E4%B8%AA%E5%8D%9A%E5%AE%A2%E4%BD%9C%E8%80%85/</id>
    <published>2025-11-21T09:43:00.000Z</published>
    <updated>2025-12-03T10:02:00.864Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近关注到 3 个博客作者，分别是：</p>
<ul>
<li>作者 A：李星野，博客：<a href="https://sinyalee.com/blog/">https://sinyalee.com/</a></li>
<li>作者 B：pseudoyo，博客：<a]]></summary>
    <content type="html"><![CDATA[<p>最近关注到 3 个博客作者，分别是：</p><ul><li>作者 A：李星野，博客：<a href="https://sinyalee.com/blog/">https://sinyalee.com/</a></li><li>作者 B：pseudoyo，博客：<a href="https://www.pseudoyu.com/posts">https://www.pseudoyu.com/</a></li><li>作者 C：smallyu，博客：<a href="https://smallyu.net/">https://smallyu.net/</a></li></ul><p>这 3 个作者很有意思，正好映射了社会中 3 个不同阶层的人物命运。</p><p>(A)</p><p>作者 A 出生于富豪家庭，父亲是身家几十亿的房地产老板，毕业于清华姚班，奥数能力和计算机能力都是世界竞赛级别的优秀，曾经在各大美国公司工作，目前是创业公司创始人，身家几个亿。</p><p>作者 A 有着某种极端心理，从他的文章 《<a href="https://sinyalee.com/blog/?p=1032">关于清华姚班</a>》可以看出，只要没能做到世界最尖端水平，没有达到最卓越的成就，自己就是失败的。文章中出现激烈的词语，“垃圾”、“废物” 等，也许有秀优越的动机，但更多反映了作者A心理的扭曲 ——他说自己是废物，那么世界上的其他人自然也都是废物。这就是他的潜台词。</p><p>作者 A 由于特殊的出身与家庭境遇，无法相信爱情，以玩弄人妻为乐，还把与人妻的交往心得写成论文发表、广为流传，其中甚至包含了已是人妻的初恋，不断对其进行人格上的贬低，以达到对自己心理上的某种补偿。总而言之，作者 A 属于一辈子吃喝不愁、只需要探究人生理念、价值取向的一类人。</p><p>(B)</p><p>作者 B 的博客中充满爱与希望，虽然技术能力很一般，但属于愿意认真生活的人。从博客中提到的去香港大学读研究生、晒出泰国旅游、日本旅游等信息，可以反推出作者 B 出生于中产家庭，不太需要为生计而担忧，更多关注的是人生体验、感悟、成长。</p><p>作者 B 提到了求婚、结婚等人生事迹，足以说明原生家庭为其提供了足够多的支持，住着还不错的房子、养着猫，这一切看似简单的事情，背后绝不是仅凭自身工作和努力可以实现的。何况他技术能力并不出色，虽然身处 web3 行业，但是显然对技术和行业缺乏了解，没有经历过残酷的动荡，在工作中也处于普通的执行角色（否则不会有被动裁员这回事）。这也是可以理解的，文科生转码怎么可能有过人的技术能力。</p><p>作者 B 的一生将会是幸福的一生，他不需要自己承担太多，也不需要多么优秀，只需要体验生活、过好自己的人生就可以。作者 B 属于衣食无忧，不如作者 A 那样追求顶尖成就，他自己本身也缺乏斗志，只要安稳过好自己生活的一类人。</p><p>(C)</p><p>作者 C 的博客中充斥着愤怒、怨恨与挣扎，说面试官水平低、攻击大多数行业中的 buzzword、反主流的技术思路、频繁跳槽、找工作、面试失利。很多观点极端又克制，既想表达自己的情绪，又不断试图用逻辑和理性解释自己的情绪。</p><p>作者 C 提到过自己出身差，也在回忆文章中说过小时候的糟糕教育与艰苦的生活环境，属于典型的从乡镇奋斗到大城市的技术人。作者 C 的技术能力不算很难堪，也因此有时会想要维护某种技术上的尊严。由于身处于动荡与混乱的 web3 行业，工作不稳定、人员素质低等行业特性加剧了作者 C 的焦虑与不安全感。</p><p>作者 C 是不可能考虑结婚的，他有女朋友，但是他没有安家的资本，当原生家庭无法提供帮助，仅凭自己的努力，能好好生活就不容易。作者 C 属于想用技术上的正确来抵抗内心焦虑、工作和生活必然比作者 B 艰难和辛苦的一类人。</p>]]></content>
  </entry>
  <entry>
    <title>复盘上一次跳槽的原因</title>
    <link href="https://b.smallyu.net/2025/11/20/%E5%A4%8D%E7%9B%98%E4%B8%8A%E4%B8%80%E6%AC%A1%E8%B7%B3%E6%A7%BD%E7%9A%84%E5%8E%9F%E5%9B%A0/"/>
    <id>blog-b:https://b.smallyu.net/2025/11/20/%E5%A4%8D%E7%9B%98%E4%B8%8A%E4%B8%80%E6%AC%A1%E8%B7%B3%E6%A7%BD%E7%9A%84%E5%8E%9F%E5%9B%A0/</id>
    <published>2025-11-19T17:17:04.000Z</published>
    <updated>2025-12-03T10:02:00.864Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>距离上次跳槽有半年时间了，由于当时跳槽之后，接连不断遇到各种事情，一直没有时间和心情复盘一下，在那个 Restaking 项目的工作过程中，技术方面的经历。</p>
<h3 id="nonce-值管理"><a href="#nonce-值管理"]]></summary>
    <content type="html"><![CDATA[<p>距离上次跳槽有半年时间了，由于当时跳槽之后，接连不断遇到各种事情，一直没有时间和心情复盘一下，在那个 Restaking 项目的工作过程中，技术方面的经历。</p><h3 id="nonce-值管理"><a href="#nonce-值管理" class="headerlink" title="nonce 值管理"></a>nonce 值管理</h3><p>项目遇到过一个疑难杂症，就是从其他链快速扫描出区块中的事件后，需要把扫描来的事件，通过 Cosmos 交易再提交到链上。问题在于，由于需要快速提交大量交易，不可能等待上一笔交易成交再提交下一笔交易，而链上的处理逻辑又明确要求事件必须确保顺序，也就是说，提交交易时候的 nonce 值管理至关重要。</p><p>之所以说这个问题是疑难杂症，是因为这个需求不是我负责的，对他（一个同事）来说属于疑难杂症，花了非常非常多的时间都没有解决好这个问题。</p><p>而且实话实说，这个问题根本没有技术含量。我当时一直在说，链下手动管理 nonce 值就可以。但是我不知道他到底处于什么样的考虑，是真的不理解我在说什么，还是刻意不想采用我的方案。总之反复出问题几次之后，都仍然没有采取我说的手动管理 nonce 值的方式。</p><p>为什么我说手动管理 nonce 值的方式可行呢？在更早的项目中，我需要发交易来压测以太坊客户端的交易处理能力以及出块的稳定性，把每个区块的使用量打满（Gas used 达到 3000 万），持续 2 天以上，然后观察每个服务器的资源占用情况。而用来压测的脚本，自然就是用少量几个钱包地址，快速发大量普通转账和合约调用交易的功能。</p><p>正因为有那样的经历，面对同样的类似的场景，我自然就会想到解决办法，而且实现起来很简单。</p><p>所以我觉得，可能因为他缺少这样的经历，真的无法明白该如何正确处理此类问题，而是把时间和精力都集中在失败交易的重试和兜底逻辑上，试图用失败补偿的代码逻辑去解决。这个问题最终的后果是什么呢，后果就是开发网搞了一个多月，功能依然都是不正常的，而后又赶鸭子上架，去上线测试网。测试网怎么办呢，根本都不敢开同步交易的功能。</p><p>我身处其中，才明白这个项目的可靠性有多么差。</p><h3 id="链分叉与回滚"><a href="#链分叉与回滚" class="headerlink" title="链分叉与回滚"></a>链分叉与回滚</h3><p>我们的链，是一条基于 Cosmos SDK 的链。当测试网开放给社区后，遇到的第一个问题，就是网络突然分叉了，导致不能出块。</p><p>分叉的原因是踩了 Cosmos SDK 的一个依赖库方面的坑，有的节点会开自动裁剪数据的配置，有的节点不自动裁剪。而 Cosmos SDK 的某一个版本的 db 依赖，对于裁剪过和没有裁剪过的区块数据，会计算出不一样的 state root，导致网络分叉。</p><p>修复这个分叉的步骤是：1. 升级依赖版本，发布新的二进制；2. 让整个社区的节点配合，回滚一个区块。</p><p>搞笑的来了，Cosmos 的节点怎么回滚区块？我们的 Team leader 拉着他开了一个小时的会，发现 reset 命令不生效，没找到办法。后来他来找我会议，虽然我也没有直接的答案，但是在会议过程中，我去看了一下 Cosmos SDK 的源码，就知道原因了。答案就是 reset 需要带上 –hard 参数，否则只会回滚状态数据，不回滚区块数据……</p><p>而且毫不谦虚的说，关于链分叉的原因，也是我首先定位到的。我对比了我们服务器上， archive 节点和普通节点的区块信息，就发现了差异，然后进一步找到了普通节点上关于数据库的报错信息。</p><p>我为什么要强调这一点呢，因为当时在还不知道分叉原因的时候，他就把他的一个朋友（前同事）拉进会议，一起排查问题，而事实上没能带来帮助。</p><p>他的那个朋友据说挺厉害的，在 Cosmos 社区的大多数 PR 下，都能看到他朋友活跃的身影，属于 Cosmos 社区的忠实贡献者。他朋友当时在 Crypto.com 工作，年薪一两百万（人民币）的样子。</p><p>而且诡异的是，也许因为他的朋友 “厉害”，可能他就觉得自己也厉害？在日常的工作中经常表现出某种居高临下的态度。（其实我当时就心想，你的朋友厉害，关你什么事？）</p><p>顺便八卦一下，我当时的 Team leader，年薪也是一两百万的水平。</p><h3 id="运维方案"><a href="#运维方案" class="headerlink" title="运维方案"></a>运维方案</h3><p>接着就要提到 Team leader 的问题，属于典型的 “大厂病”。</p><p>我们当时需要上线开发网，leader 找了一个外包的运维团队，让他们用 k8s 来部署整个链。出发点是好的，用 k8s 来规范化部署和管理。可是根本没考虑到外包人员的技术能力。负责写 k8s 的外包说，他之前根本没用过 k8s……</p><p>我当时看到运维在部署脚本方面和团队这边频繁沟通时，就在大群里提出过质疑，为什么非要用 k8s？直接 docker 部署上去不行吗？部署脚本根本不需要改，也不需要重写，部署开发网就一天之内的事。</p><p>我为什么敢这么说呢，因为我非常肯定，用 docker 部署也不会耽误网络运行。我们之前的项目几十个服务器没上 k8s，丝毫不影响主网的上线。而我就是实际写脚本、操作部署那些服务的人。</p><p>现在项目上线个开发网，一共就 2 个节点，怎么就用上 k8s 了？</p><p>而事实带来的残酷后果是，原本计划让外包团队一周写好部署脚本并上线，结果一周、两周、一个月……</p><p>不但老板定下的时间节点全盘延后，而且经过两个月的折磨，外包团队也主动辞职不干了。外包本身就是靠接活来挣钱的，但是却主动放弃了一个项目。这意味着什么？我大概能理解，对于外包团队来说，技术要求高，时间又短，对接的外包哥们是真的周末都在上班……</p><p>外包都能被逼到不想干了，我后来也不想干了，岂不是很正常的事情吗？</p><h3 id="日志系统与监控面板"><a href="#日志系统与监控面板" class="headerlink" title="日志系统与监控面板"></a>日志系统与监控面板</h3><p>我们不是 “大厂”，但是我们的团队却遭受到大厂式做派的折磨。</p><p>大厂优先相信制度而不是相信人，由于人员众多、鱼龙混杂，所以需要依靠严格的规章流程，来保证事情的正确性。只要流程上是对的，事情的结果偏差就不会大。而对于小型的创业团队来说，应该首先相信人而不是制度。</p><p>我当时的一项工作，是搭建日志系统。在网络上线严重延期的情况下，让我集中精力去搞什么日志系统，完全是把力气花在了最没用的地方，影响上线进度不说，leader 对于日志系统，期望也是比较高的，他说你可能没见过那种专业的日志查询系统，完全支持键值对的方式，甚至支持对关键字的条件查询，我们希望也做成那样……不是，我们几个人啊，多大的团队，为什么要搞那么专业的运维系统。对我自己来说，出了问题直接看 docker 日志完全可以，而且总共就几个人，还都是程序员，搞那种可视化界面真是为了 “专业” 而专业。</p><p>当时的另一项工作，是搞一个链节点运行情况的监控面板。当时的运维同事让我印象深刻。这还不是那个外包来的运维，是团队里掌管着管理员账号、服务器权限的运维。</p><p>搭建 Cosmos 节点的 Grafana 面板需要什么呢？在 Cosmos 节点所在的服务器上，安装 exporter，然后 Grafana 来接入数据。就是这样的工作内容，运维完全搞不定。</p><p>我一开始是把这个事情交给运维干的，这本来就是运维的活，但是我发现事情迟迟没有进展，因为运维是真不会，他搞不懂什么 cosmos 节点、exporter 之类的关系，只要网上没有现成的教程，基本就是摆烂的状态。我一开始也摆烂，每天在大群里 @运维 一次，问他目前 Grafana 面板的进度，他有时候大概回一句，有时候干脆装死。总之就是没进度。</p><p>再后来我有时间了，就干脆自己梳理了一下 Grafana 的流程，从导出哪些数据，到自定义面板上的展示图表，然后自己动手搭了一套。真的很简单，两天搞定。而作为专业的运维，却至少两周都没能有进展。我当时真的没想到我需要亲自动手搭这种东西。</p><h3 id="VRF-随机数"><a href="#VRF-随机数" class="headerlink" title="VRF 随机数"></a>VRF 随机数</h3><p>下一项工作，实现 Restaking 框架下的 VRF 随机数的生成和验证。</p><p>简单来说，leader 在和我讨论方案的时候，我能明显感受到他不懂 VRF，导致我都觉得无法沟通下去，而他一味的坚持自己对于 VRF 的理解。当然，后来他也调整了自己的说辞和设计，工作也大体上模糊的进行了下去。</p><p>为什么我说的如此含糊呢，因为从设计上，我觉得当时的实现方案没能体现出 VRF 真正的功效，但是又不想花费口舌给他讲明白、去说服他。</p><p>我现在可以大体说一下，当时的设计是，某一个节点生成随机数，然后由多个节点来对随机数进行验证。我的想法是，给多个节点相同的输入参数，让多个节点根据 VRF 生成相同的数字。</p><p>我的这个想法，当时说出来过，但是他没听懂，所以我就不想再多说了。事实证明，leader 在事后（我离职时的聊天中）承认自己了对于 VRF 的不懂。</p><h3 id="节点投票权"><a href="#节点投票权" class="headerlink" title="节点投票权"></a>节点投票权</h3><p>这项工作的内容是，根据 Restaking 进来的代币权重，去影响 Cosmos Validator 的投票权重，进而影响节点的出块概率与出块奖励。</p><p>简短截说，leader 拉着另一个同事，设计了一周、review 了一周，又给了那个同事接近一个月的时间来实现这个需求。</p><p>事实上的结果是，这个需求在我接到手的时候，只完成了一些皮毛，定义了一些 proto 文件、GRPC 接口定义什么的。最核心的逻辑，关于如何获取到 Restaking 的代币权重、如何去更新 Voting Power 影响出块概率，都是留空的。</p><p>然后怎么样呢，我在一周的时间内，完成了这个功能的实现。当然时间有限，实现的不可能完全没有 bug，但至少功能已经跑通。</p><p>再然后怎么样呢，再然后我就跳槽了，后面的事情我也不知道了。</p><h3 id="补充（2025-12-03）"><a href="#补充（2025-12-03）" class="headerlink" title="补充（2025.12.03）"></a>补充（2025.12.03）</h3><p>想起一件事。有一次我们网络要上线，计划晚上上线，当天早上，一个同事告诉我开发一个用来部署二进制的脚本。</p><p>然后当天 Leader 问我现在在干什么，我说我在开发脚本。Leader 惊讶的说，他在两周前就告诉那个同事去开发这个脚本了。</p><p>再然后怎么样呢，我两个小时搞好了这个部署脚本。后续也是我在维护。</p><p>这就是他，自以为是又对工作极度不负责任，把自己放在资深开发的位置，同时又连基本的活都干不好。</p><h3 id="补充（2025-12-03）-1"><a href="#补充（2025-12-03）-1" class="headerlink" title="补充（2025.12.03）"></a>补充（2025.12.03）</h3><p>为什么当时在面对那些情形的时候，我没有据理力争坚持自己的观点和方案，而是现在事后拿出来说呢？</p><p>因为我当时加入团队不久，对同事和团队的水平都不清楚。也许我是错的，是他们有一些惊为天人的方案呢？</p><p>现在事情已经尘埃落定，我就可以确切的、负责任的、自信的说，是他们错了。</p><p>你也许会觉得，以上内容都是我的一面之辞，是存在偏见的。</p><p>我可以这样保证：我描述出来的事实，以及我所有过往博客文章中提到的内容，就像区块链的块数据一样，在任何时候都可以 “交易重放”，得到相同的结果。</p>]]></content>
  </entry>
  <entry>
    <title>为什么说 GPT 是世界上最好的 AI 模型</title>
    <link href="https://crazy.smallyu.net/2025/11/19/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%AF%B4GPT%E6%98%AF%E4%B8%96%E7%95%8C%E4%B8%8A%E6%9C%80%E5%A5%BD%E7%9A%84AI%E6%A8%A1%E5%9E%8B/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/11/19/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%AF%B4GPT%E6%98%AF%E4%B8%96%E7%95%8C%E4%B8%8A%E6%9C%80%E5%A5%BD%E7%9A%84AI%E6%A8%A1%E5%9E%8B/</id>
    <published>2025-11-19T10:00:34.000Z</published>
    <updated>2026-07-04T17:36:19.113Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>因为 BTC 是世界上最好的加密货币。</p>
<br>

<h3 id="打脸（2025-11-22）"><a href="#打脸（2025-11-22）" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>因为 BTC 是世界上最好的加密货币。</p><br><h3 id="打脸（2025-11-22）"><a href="#打脸（2025-11-22）" class="headerlink" title="打脸（2025.11.22）"></a>打脸（2025.11.22）</h3><p>从各种 Benchmark 结果来看，Gemini 3 Pro 还真是全面超过 GPT-5：</p><p>(1)<img src="1.png" width="100%"/></p><p>(2)<img src="2.png" width="100%"/></p><p>另外我试着把以前写的小说《<a href="https://smallyu.net/2014/10/04/%E4%B8%8A-%E9%9B%AA%E8%8A%B1%E8%B0%A3%E2%80%A2%E9%99%88%E7%BC%98/">（上）雪花谣 • 陈缘</a>》分别给 GPT-5 和 Gemini 3 Pro 续写，结果 GPT-5 写出来的人物关系是错的，相比之下，Gemini 3 Pro 写出来的就比较正确。</p><p>还有个例子是，我把 <a href="https://smallyu.net/">https://smallyu.net/</a> 的文章列表，分别给 ChatGPT 5.1、Gemini 3 Pro、Grok 4 三种模型，让他们判断作者的年龄。只有 Gemini 3 Pro 给出的判断是异常精准的，仅根据文章标题中的关键字的演进，就给出了准确的年龄判断。另外两个模型给出的年龄都稍微偏大，误差在 2 年以上。</p><p>Gemini 3 Pro 还真是不错。</p><h3 id="更新（2026-06-18）"><a href="#更新（2026-06-18）" class="headerlink" title="更新（2026.06.18）"></a>更新（2026.06.18）</h3><p>GPT 模型依然最好！尤其是代码能力上，CodeX 比 Antigravity 好用很多！</p><p>Gemini 模型有一个尴尬的地方，Gemini 3.1 Pro 太慢了，不能写代码，代码效果尤其是推理逻辑链方面不够强，新的 Gemini 3.5 Flash 虽然快且全面，但是智力不够。</p>]]></content>
  </entry>
  <entry>
    <title>不要投资任何隐私币</title>
    <link href="https://smallyu.net/2025/11/17/%E4%B8%8D%E8%A6%81%E6%8A%95%E8%B5%84%E4%BB%BB%E4%BD%95%E9%9A%90%E7%A7%81%E5%B8%81/"/>
    <id>blog:https://smallyu.net/2025/11/17/%E4%B8%8D%E8%A6%81%E6%8A%95%E8%B5%84%E4%BB%BB%E4%BD%95%E9%9A%90%E7%A7%81%E5%B8%81/</id>
    <published>2025-11-17T14:36:29.000Z</published>
    <updated>2025-11-17T14:37:26.258Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<ol>
<li>除了试图犯罪以外，真正需要协议级隐私的场景很少</li>
<li>协议级隐私带来的是技术上的极度复杂、使用体验差</li>
<li>假如 ZEC 使用 100% 的 z 地址，CEX 首先会下架]]></summary>
    <content type="html"><![CDATA[<ol><li>除了试图犯罪以外，真正需要协议级隐私的场景很少</li><li>协议级隐私带来的是技术上的极度复杂、使用体验差</li><li>假如 ZEC 使用 100% 的 z 地址，CEX 首先会下架 ZEC</li><li>任何代币只要全过程匿名，将要面对的不只是CEX下架，还有各国政府的封禁</li><li>大型机构绝不会也不可以投资隐私币</li><li>隐私币绝不会成为国家储备</li><li>任何代币，只要警察对你进行物理监禁，技术型隐私就毫无意义</li><li>你需要生活在真实的世界中，而不是网络中</li></ol>]]></content>
  </entry>
  <entry>
    <title>初中时期艰苦生活的两件事</title>
    <link href="https://crazy.smallyu.net/2025/11/16/%E5%88%9D%E4%B8%AD%E6%97%B6%E6%9C%9F%E8%89%B0%E8%8B%A6%E7%94%9F%E6%B4%BB%E7%9A%84%E4%B8%A4%E4%BB%B6%E4%BA%8B/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/11/16/%E5%88%9D%E4%B8%AD%E6%97%B6%E6%9C%9F%E8%89%B0%E8%8B%A6%E7%94%9F%E6%B4%BB%E7%9A%84%E4%B8%A4%E4%BB%B6%E4%BA%8B/</id>
    <published>2025-11-16T15:46:14.000Z</published>
    <updated>2026-07-27T17:35:36.205Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>我的初中生活，很艰苦。在 2010 年之后的年代，生活还在用 “艰苦”]]></summary>
    <content type="html"><![CDATA[<p>我的初中生活，很艰苦。在 2010 年之后的年代，生活还在用 “艰苦” 来形容，说明是真的艰苦。</p><p>我想起两件事情。第一件事情，是有一天，学校给我们每人发了一份调查问卷，问卷内容是对各个学科的教师进行评价，大概是打分+评价的方式。</p><p>我们当时有一个非常不负责任的数学老师，我非常诚实的给他打了差评，还写上了评语。因为我当时还真是想学习，但是环境不允许。大家都不学，你学习，你反而才是异类。</p><p>然后到了数学课的时候，数学老师依次叫了几个人上讲台，一人给了一巴掌。包括我。</p><p>后来听说，数学老师让某个学生，看着调查问卷的笔迹，来指认是谁写了差评。进而能够在课堂上，一个一个的报复。</p><p>当然，在那样的环境里，他丝毫不需要掩饰打人的理由，就明说因为给了差评，他不服气。</p><p>所以时至今日，我都对小地方的人充满偏见，我憎恨终其一生都生活在小地方的人。我认为他们素质不高，见识不多，心术不正。</p><p>正因为我从小地方出来，我太明白小地方的糟糕之处。我永远也不会再回那种地方。</p><p>第二件事情，是在我的午饭里发现苍蝇。</p><p>我们吃的饭，是大锅饭，夏天，在那种敞口的大锅里，下面条。可能时不时就会落下几只苍蝇，在面条里，所以我们打出来的饭，可能是有苍蝇的。</p><p>我当时感觉很恶心，不但扔掉了当时的饭，接下来好几天就没太敢吃饭。</p><p>2010 年代之后的中国，你敢相信能吃到卫生条件如此之差的饭吗，学校，食堂。</p><p>我憎恨小地方的差条件，小地方的人。我讨厌小地方。</p><br><h3 id="2025-11-19"><a href="#2025-11-19" class="headerlink" title="2025.11.19"></a>2025.11.19</h3><p>想起另一件事。在政治课堂上，老师让我们把答案抄在练习题上。</p><p>我简单抄了抄，就揣着手坐在位置上休息。</p><p>真的太冷了，大冬天，教室里用的是那种烧炭的小火炉。那个时候哪有什么暖气。</p><p>我有点怀疑人生，因为冻手，我不想拿笔，也不想写字。</p><p>我在想，为什么生活条件这么差。</p><p>后来老师看到我坐着，就把我叫上讲台，问题答案抄完了没，为什么不动笔。我说抄完了。</p><p>当然，这一次没有发生什么恶性事件，政治老师对我算是照顾有加，才愿意在看到我不动笔的情况下，“点” 我一下。</p><p>但天气是真的冷，冻手。</p><p>在 2010 年代的初中。</p>]]></content>
  </entry>
  <entry>
    <title>web3 就业指南</title>
    <link href="https://b.smallyu.net/2025/11/10/web3%E5%B0%B1%E4%B8%9A%E6%8C%87%E5%8D%97/"/>
    <id>blog-b:https://b.smallyu.net/2025/11/10/web3%E5%B0%B1%E4%B8%9A%E6%8C%87%E5%8D%97/</id>
    <published>2025-11-10T07:33:24.000Z</published>
    <updated>2026-03-06T08:28:50.104Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<ol>
<li>不要和定居在中国二线城市、同等经济水平城市、及其以下的团队成员合作，他们技术能力都不行</li>
<li>凡是中国深圳团队做的 web3]]></summary>
    <content type="html"><![CDATA[<ol><li>不要和定居在中国二线城市、同等经济水平城市、及其以下的团队成员合作，他们技术能力都不行</li><li>凡是中国深圳团队做的 web3 项目，都不要相信其技术含量，都不要相信长期价值，都不要投资</li><li>币权不可以代替基本薪资</li><li>在市面上公开的职位都不是核心岗位，在市面上流通的打工人都不是核心人才</li><li>DeJob 的管理员说，随意裁员没有赔偿是正常的，能发工资就行</li><li>交易所关区块链什么事</li><li>好想去 Gate，体验电脑被监控、15 分钟不回消息被警告的快感</li><li>想去 Bitget，体验被暴力裁员、直接关停账号权限的感觉</li><li>钱包岗位和区块链没有关系</li><li>web3 的 HR、猎头更容易不讲礼貌、不尊重人，因为远程办公在一定程度上会泯灭一部分人性，在他们眼里都是账号而已</li><li>Boss 直聘上没有真正的 web3 职位</li><li>web3 没有、也不应该、不可能有养老型工作</li><li>行业趋势未必与个体体会一致，不要悲观，也不要乐观</li></ol>]]></content>
  </entry>
  <entry>
    <title>关闭 ChatGPT 的 memory 功能</title>
    <link href="https://crazy.smallyu.net/2025/11/06/%E5%85%B3%E9%97%ADChatGPT%E7%9A%84memory%E5%8A%9F%E8%83%BD/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/11/06/%E5%85%B3%E9%97%ADChatGPT%E7%9A%84memory%E5%8A%9F%E8%83%BD/</id>
    <published>2025-11-06T03:24:49.000Z</published>
    <updated>2026-07-04T17:36:19.114Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>ChatGPT 在对话的过程中有一个特点，就是会倾向于说你喜欢听的话，以及赞同你说的话。</p>
<p>当你想要询问 ChatGPT 一些建议的时候，比如接下来做什么 side project，或者对于某种项目方向的看法，ChatGPT]]></summary>
    <content type="html"><![CDATA[<p>ChatGPT 在对话的过程中有一个特点，就是会倾向于说你喜欢听的话，以及赞同你说的话。</p><p>当你想要询问 ChatGPT 一些建议的时候，比如接下来做什么 side project，或者对于某种项目方向的看法，ChatGPT 会根据你的技术栈来推荐，或者说基于你最近提到的 XXX，推荐你做 YYY。</p><p>这是非常不好的一种现象，这样长期下去，你将无法从 ChatGPT 那里获得客观的建议，你自己的技术栈、信息来源，也都会被局限在你熟悉的范围内。</p><p>所以一定要关闭 ChatGPT 的 memory 功能，以避免信息茧房、判断茧房。</p><img src="1.png" width="60%"/>]]></content>
  </entry>
  <entry>
    <title>评价《人妻约会指南》</title>
    <link href="https://crazy.smallyu.net/2025/11/04/%E8%AF%84%E4%BB%B7%E3%80%8A%E4%BA%BA%E5%A6%BB%E7%BA%A6%E4%BC%9A%E6%8C%87%E5%8D%97%E3%80%8B/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/11/04/%E8%AF%84%E4%BB%B7%E3%80%8A%E4%BA%BA%E5%A6%BB%E7%BA%A6%E4%BC%9A%E6%8C%87%E5%8D%97%E3%80%8B/</id>
    <published>2025-11-04T15:52:44.000Z</published>
    <updated>2026-07-04T17:36:19.134Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>最近有一个 PDF 文档很火，标题是《人妻约会指南》，作者叫李新野，文档发布于他的中文博客，文章链接是 <a href="https://sinyalee.com/blog/?p=1068"]]></summary>
    <content type="html"><![CDATA[<p>最近有一个 PDF 文档很火，标题是《人妻约会指南》，作者叫李新野，文档发布于他的中文博客，文章链接是 <a href="https://sinyalee.com/blog/?p=1068" target="_blank">原文链接</a>。</p><p>由于文档标题的粗俗与文章内容的理工逻辑形成巨大反差，这个文档很快走红网络。</p><p>本来是吃瓜性质的文档，但是点开他的博客后，看过他的其他一些技术类文章，发现这个人不简单。他是程序员，现在在做交易量化一类的工作。</p><p>我认为，他之所以会有现在的爱情观、价值观，是因为过往家庭方面的经历，以及自己并没有遇到过真正的 “爱情”，一直在以利益驱动结识女性导致的。</p><p>他在文档中说，女性一直在向男性索取什么，小时候抄作业、要零花钱，长大了之后还是会要 “零花钱”、要情绪价值。他说的没错，事实就是这样。</p><p>但是他忽略了另一个事实，在女性向男性索取的同时，男性也在向女性索取着什么。</p><p>我是说，比如女朋友打扮的漂漂亮亮的去逛街，男性会有一种莫名的自豪感。再比如男性同样在索求女性的时间和陪伴等。</p><p>感情双方，相互索取是事实，但关键不在于 “索取”，而在于 “相互”。</p>]]></content>
  </entry>
  <entry>
    <title>区块链技术世界的三大真理</title>
    <link href="https://smallyu.net/2025/11/03/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E4%B8%96%E7%95%8C%E7%9A%84%E4%B8%89%E5%A4%A7%E7%9C%9F%E7%90%86/"/>
    <id>blog:https://smallyu.net/2025/11/03/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E4%B8%96%E7%95%8C%E7%9A%84%E4%B8%89%E5%A4%A7%E7%9C%9F%E7%90%86/</id>
    <published>2025-11-03T07:37:35.000Z</published>
    <updated>2025-11-09T09:22:13.316Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>有这样两个事实：</p>
<ol>
<li>王垠是编程语言理论、计算机科学理论方面的专家</li>
<li>在区块链技术理论方面，目前看不到这种级别的专家，尤其是愿意公开发声、开课、讲授知识的</li>
</ol>
<p>这样的事实背后是有原因的：</p>
<ol>
<li]]></summary>
    <content type="html"><![CDATA[<p>有这样两个事实：</p><ol><li>王垠是编程语言理论、计算机科学理论方面的专家</li><li>在区块链技术理论方面，目前看不到这种级别的专家，尤其是愿意公开发声、开课、讲授知识的</li></ol><p>这样的事实背后是有原因的：</p><ol><li>计算机科学经过了几十年发展，区块链大概十几年</li><li>区块链本身、从诞生之初就是工程化集成的产物，而不是理论创新</li></ol><p>这会带来不同的现象：</p><ol><li>掌握计算机科学的基础理论，lambda 演算、图灵机、计算模型，理解计算的本质后，在编程语言方面可以长久复用、不会过时，无论上层语言、框架如何变化，计算的核心不会变化</li><li>区块链工程似乎没有基础理论，没有什么技术是不会变的，也没有什么技术是需要长期积累的。从业者年龄小、新人多、工作内容以系统集成、调 SDK 为主</li></ol><p>所以区块链的技术世界中，有没有什么理论性质的 “真理”，是长久不变、可以复用、无论上层框架如何变化都不需要担心的？</p><p>区块链技术世界的三大真理：</p><ol><li>共识。如何解决拜占庭将军问题。</li><li>加密。以数学为根基的不可篡改、验证。</li><li>激励。社会学博弈引擎，让共识长久运转。</li></ol><p>掌握了这三个部分的技术，无论区块链形式上怎么推陈出新，无论行业热点如何变化，都不用担心，因为区块链本质上就是在解决这些问题。</p><p>怎么样才算是掌握了 “真理”？我看懂了、我理解了，算是我会了吗？算是我掌握了吗？</p><p>掌握真理的标准是，可以根据真理，从头构建出知识。</p><p>在计算机科学的世界里，假如世界毁灭了，给你一张纸和笔，你可以从头实现 lambda 演算、实现数据结构、实现一个解释器、实现一种编程语言，甚至构造出更多东西，不依赖于教材、框架、API，这叫掌握真理。</p><p>真理的意义在于，让你明白知识为何必须如此存在。——这也是王垠的课程在试图教会你的东西，王垠不教知识，只教 “王垠式真理”。所以我一直认为王垠的课程好、价值高。</p><p>类似的，在区块链的世界里，如果你可以从脚本写起，实现共识、加密、激励，不一定重建全部细节，但一定要理解现有系统为何那样设计，就差不多了。</p><p>要注意，智能合约的编程语言不在真理的范畴之内，无论是比特币脚本、Solidity、Move、Cairo，都只是表达交易逻辑的 DSL，都是在用不同形式，定义区块链执行交易的规则，很重要但是还没到 “真理层”。</p><p>非要说智能合约的真理层，可能可以表达为一个确定性的状态转移函数，无论语言如何变化，这个 “真理” 都始终存在：</p><pre><code>State_t+1 = f(State_t, Transaction)</code></pre><p>下一个状态来自于上一个状态加上一些交易引起的状态变化，简单吧。但我们这篇文章重点关注区块链世界中的 “王垠式真理”，所以依然是三大真理：共识、加密、激励。</p>]]></content>
  </entry>
  <entry>
    <title>以太坊 AA 钱包的致命问题是什么</title>
    <link href="https://smallyu.net/2025/10/24/%E4%BB%A5%E5%A4%AA%E5%9D%8AAA%E9%92%B1%E5%8C%85%E7%9A%84%E8%87%B4%E5%91%BD%E9%97%AE%E9%A2%98%E6%98%AF%E4%BB%80%E4%B9%88/"/>
    <id>blog:https://smallyu.net/2025/10/24/%E4%BB%A5%E5%A4%AA%E5%9D%8AAA%E9%92%B1%E5%8C%85%E7%9A%84%E8%87%B4%E5%91%BD%E9%97%AE%E9%A2%98%E6%98%AF%E4%BB%80%E4%B9%88/</id>
    <published>2025-10-23T16:55:34.000Z</published>
    <updated>2025-11-09T09:22:13.310Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>到目前为止，最新的 AA（Account Abstraction）钱包规范仍然是基于 EIP-4337 实现的。</p>
<p>对于 AA 钱包存在的问题，像操作繁琐、Bundler]]></summary>
    <content type="html"><![CDATA[<p>到目前为止，最新的 AA（Account Abstraction）钱包规范仍然是基于 EIP-4337 实现的。</p><p>对于 AA 钱包存在的问题，像操作繁琐、Bundler 中心化、可用性低、生态支持不完善、合约安全风险高等表面上的问题就不多说了。</p><p>一句话描述 AA 钱包在干什么事情：AA 钱包能实现 “对账户资金的授权” 与 “把交易广播到链上” 这两个行为的分离。</p><h3 id="AA-钱包的功能"><a href="#AA-钱包的功能" class="headerlink" title="AA 钱包的功能"></a>AA 钱包的功能</h3><p>AA 钱包的功能，体现到具体的交易行为上，就是如果没有 AA 钱包，你得自己发交易。有了 AA 钱包，你可以只签名，不发交易，让其他人代替你把交易发到链上就行。</p><p>为什么 AA 钱包能做到这一点？因为 AA 钱包本质上就是一个合约，所以你会发现，AA 钱包的大多数 “优点”，其实是智能合约本身就具备的功能，像什么社交恢复、批量操作等。唯一能带来特殊体验的，只有 “代付手续费” 这个特性。</p><p>那为什么 AA 钱包能实现代付手续费这个功能？因为 AA 钱包的所有操作实际上不是交易，而是 UserOperation，有一个链下的 Bunlder 程序会把这些用户操作，通过发交易批量提交到链上。</p><h3 id="为什么以太坊需要-AA-钱包"><a href="#为什么以太坊需要-AA-钱包" class="headerlink" title="为什么以太坊需要 AA 钱包"></a>为什么以太坊需要 AA 钱包</h3><p>为什么以太坊需要 AA 钱包？因为以太坊的共识层协议要求，交易必须由一个 EOA 地址来发起。这个 EOA 地址，就是交易结构中的 from 字段，以太坊节点会从这个 from 地址计算手续费、扣手续费、验证交易有效性等。</p><p>合约没有私钥，交易不可能由合约发起。在这样的规则约束下，就导致以太坊所有的链上行为，都必须由某一个 EOA 地址来发起交易。</p><p>你可能觉得不对，部署一个合约，然后让合约来验证 data 里得签名数据就好了。data 里的签名数据，未必需要和发起交易的地址一致。</p><p>没错，事实上，AA 钱包的发展链路是：meta-transcations -&gt; EIP-2771 -&gt; EIP-4337。</p><p>这些方案在解决的问题本质上都是：如何让使用资金的权限，与发起链上交易的行为分离。</p><p>而引起这一系列复杂协议的根源，来自于以太坊 “交易必须由一个 EOA 地址来发起” 的规则。</p><h3 id="为什么以太坊有这个规则"><a href="#为什么以太坊有这个规则" class="headerlink" title="为什么以太坊有这个规则"></a>为什么以太坊有这个规则</h3><p>为什么以太坊要有 “交易必须由一个 EOA 地址来发起” 这个规则？</p><p>因为以太坊的账户模型，是账户-余额模型。协议必须要知道，一笔交易的手续费从哪里扣。</p><h3 id="比特币不存在这个问题"><a href="#比特币不存在这个问题" class="headerlink" title="比特币不存在这个问题"></a>比特币不存在这个问题</h3><p>比特币的 PSBT 交易格式，可以实现原生的多签。功能是多个钱包只负责签名，最终由另外一个钱包把交易广播出去就可以。</p><p>多签交易，就是典型的把对资金的授权，与广播交易行为分离开的场景。</p><p>为什么比特币不存在以太坊的这个问题？因为比特币使用的是 UTXO 模型，交易根本没有 from 地址，有的是多个输入脚本，节点只需要校验交易是否符合脚本的解锁规则，而不需要考虑手续费从哪里扣的问题。</p><h3 id="AA-钱包的定位"><a href="#AA-钱包的定位" class="headerlink" title="AA 钱包的定位"></a>AA 钱包的定位</h3><p>我们梳理一下这个链条：以太坊使用账户-余额模型 -&gt; 交易必须由 EOA 地址发起 -&gt; 需要 AA 钱包。</p><p>AA 钱包在干的事情，实际上是在给以太坊的账户模型打补丁，为了修补账户-余额模型相比 UTXO 模型的不足，才有了 AA 钱包这个东西。AA 钱包是在不涉及以太坊协议变更的前提下，诞生出的一种 workaround 方案。</p><p>从地位上来说，AA 钱包对于以太坊的地位，类似于铭文&#x2F;符文&#x2F;RGB 对于比特币的地位。在比特币生态里，因为没有图灵完备的脚本，所以在不触及比特币协议变更的前提下，搞出了铭文&#x2F;符文&#x2F;RGB 这些 workaround方案。</p><p>AA 钱包需要链下的 bundler 来提交交易，与符文需要链下的索引器来维护符文的数据状态，是不是一个意思，都严重依赖于链下的程序？</p><p>而事实上我们都知道，比特币生态的玩法，至今都还没有被主流社会认可。</p><p>假如 AA 钱包未来有一天能被社会大众认可，那也就意味着 workaround 方案在区块链世界中是可行的。对于整个生态的叙事都将引起巨大的改变。</p><h3 id="AA-钱包的未来"><a href="#AA-钱包的未来" class="headerlink" title="AA 钱包的未来"></a>AA 钱包的未来</h3><p>综上所述，我们能得出的结论是，以太坊永远不可能支持 “原生” 的 AA 的钱包（在协议层面支持）。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>这些结论，对于技术人员的指导意义在于：</p><ol><li>对 AA 钱包祛魅，不要以为 AA 钱包是高级、先进的技术。</li><li>可以学习、使用、研究 AA 钱包，但是千万不要真的 “相信” AA 钱包的技术理念。</li></ol>]]></content>
  </entry>
  <entry>
    <title>最近一年的工作回顾</title>
    <link href="https://b.smallyu.net/2025/10/18/%E6%9C%80%E8%BF%91%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/"/>
    <id>blog-b:https://b.smallyu.net/2025/10/18/%E6%9C%80%E8%BF%91%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/</id>
    <published>2025-10-18T11:17:40.000Z</published>
    <updated>2026-05-27T07:30:45.379Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>前几年写过的关于工作内容方面的回顾：</p>
<ul>
<li>2024 年：《<a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>前几年写过的关于工作内容方面的回顾：</p><ul><li>2024 年：《<a href="/2024/02/17/%E6%9C%80%E8%BF%91%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C/">最近半年的工作</a>》</li><li>2023 年：《<a href="/2023/05/06/%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">半年的工作回顾</a>》</li><li>2022 年：《<a href="/2022/08/27/%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">一年的工作回顾</a>》</li></ul></blockquote><p>这些事情只涵盖已经结束的工作，不包括正在进行的工作：</p><h3 id="以太坊-PoS-网络的质押生态建设"><a href="#以太坊-PoS-网络的质押生态建设" class="headerlink" title="以太坊 PoS 网络的质押生态建设"></a>以太坊 PoS 网络的质押生态建设</h3><p>不是以太坊主网，是自己发行的网络，因为用了以太坊 PoS 的共识模式，所以涉及到 32 ETH 质押的流程。这件事情也简单也不简单，简单之处在于，不就是以太坊节点的使用么？不简单的地方在于，以太坊一共有 5 种执行层客户端和 5 种共识层客户端，虽然都支持标准的 EIP 协议，但是节点关于 key 的导入、管理、发起请求的方式各不相同，节点的启动参数方面也有一些隐藏的坑。</p><p>写文档教程、在社区里引导用户、一对一 “辅导” 用户如何自己搭建 Solo Staker 节点，从前端页面发起质押交易，到后端节点拿着质押凭证启动 Validator 等，主要就这些事情。期间还尝试了用 Flashbots 搭建 MEV 节点、给以太坊客户端提交小的功能性 PR、测试不同客户端 EVM 执行效率的 Benchmark 等。</p><h3 id="Hyperlane-跨链"><a href="#Hyperlane-跨链" class="headerlink" title="Hyperlane 跨链"></a>Hyperlane 跨链</h3><p>Hyperlane 是一个去中心化的跨链协议，用 Relayer 和 Validator 两种链下角色，来保证跨链消息的有效和正确。当时做的事情是把 USDC 跨链到自己的网络上，印象最深的一个坑是那个时候 Hyperlane 还处于 heavy development 阶段，Relayer 节点直接把黑名单的变量名赋值给白名单来用，就上下两段逻辑，变量名复制错那种，用起来非常迷惑。然后还给他们提了 PR。</p><p>最后虽然自己搞明白了 Hyperlane 的原理，有能力搭建起一整套跨链环境，但仍然是以官方合作的形式，由他们的团队来维护一些链下节点，相当于给我们链开白名单、增加对我们链的支持。期间他们还有个对接的人离职了，说明团队成员的变动也大。</p><h3 id="ZetaChain-的二次开发"><a href="#ZetaChain-的二次开发" class="headerlink" title="ZetaChain 的二次开发"></a>ZetaChain 的二次开发</h3><p>ZetaChain 是一条 Cosmos 的链，提供了一种去中心化的资产跨链的方案。我们的项目主要做 Restaking，涉及到多链之间质押状态的同步，所以基于 ZetaChain 的机制做二次开发。</p><p>这件事情的难点在于当然得首先搞懂 ZetaChain 的代码逻辑，才能做二次开发。再一个是需要搞懂 Restaking 的业务逻辑，大意好理解，具体的细节不少。然后是 Cosmos 节点的开发和运维，链的部署、升级、回滚等。还有需要参考 CometBFT、Cosmos SDK 的源码结构以及代码流程，开发用于 Restaking 的 AVS 框架什么的。也就这些。</p><h3 id="钱包后端开发"><a href="#钱包后端开发" class="headerlink" title="钱包后端开发"></a>钱包后端开发</h3><p>主要指非托管式钱包的服务端程序，给客户端提供数据来源，构建交易请求、返回余额、交易记录等，包括比特币和以太坊两个网络。还体验了一下用 Swift 写一个 iOS APP 的 Demo 界面，来演示给比特币交易签名的过程。</p>]]></content>
  </entry>
  <entry>
    <title>基于 AI 语义执行的 MCP 区块链的设计</title>
    <link href="https://smallyu.net/2025/10/13/%E5%9F%BA%E4%BA%8EAI%E8%AF%AD%E4%B9%89%E6%89%A7%E8%A1%8C%E7%9A%84MCP%E5%8C%BA%E5%9D%97%E9%93%BE%E7%9A%84%E8%AE%BE%E8%AE%A1/"/>
    <id>blog:https://smallyu.net/2025/10/13/%E5%9F%BA%E4%BA%8EAI%E8%AF%AD%E4%B9%89%E6%89%A7%E8%A1%8C%E7%9A%84MCP%E5%8C%BA%E5%9D%97%E9%93%BE%E7%9A%84%E8%AE%BE%E8%AE%A1/</id>
    <published>2025-10-13T09:22:58.000Z</published>
    <updated>2025-10-13T09:32:26.965Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="MCP-区块链"><a href="#MCP-区块链" class="headerlink" title="MCP 区块链"></a>MCP 区块链</h3><p>MCP（Modal Content Protocol）是 AI Agent]]></summary>
    <content type="html"><![CDATA[<h3 id="MCP-区块链"><a href="#MCP-区块链" class="headerlink" title="MCP 区块链"></a>MCP 区块链</h3><p>MCP（Modal Content Protocol）是 AI Agent 在使用的一种协议规范，用于 AI 和外部的工具进行交互，MCP Server 则是具体执行外部交互的组件。</p><p>MCP 区块链的含义是，首先它是一条区块链，然后每个节点都原生支持 MCP 协议的 RPC 接口，可以直接接受来自 AI Agent 的请求。每一个 MCP 请求，都是一笔交易（智能合约调用），这也就意味着，区块链会记录下所有的 MCP 交互历史。</p><p>节点内部的 MCP 执行引擎，功能分两部分，对于内部交互（EVM 在干的事情），只需要维护好内部的状态转移，把结果写入本地的 KV 数据库就可以了。对于外部交互，则只记录下要执行的请求本身，先不做外部调用。那么实际上对于每一个请求，都会改变本地的状态，所以这些交易是可以重放的，也就可以根据哈希值来确认节点数据的完整性。</p><p>至于对外部的执行请求，可以由外部的执行节点（一种角色）来完成。每一个外部请求都包含一些详细的参数，比如需要几个执行者、结果如何验证。交易会把一部分手续费作为执行费用，奖励给执行节点。如果执行节点作恶，自然也会有相应的惩罚机制。</p><p>对于外部的调用，关键在于如何验证外部执行的结果，这个问题可以交给调用者来定义，比如要创建一个 GitHub 仓库，验证方式就是，可以通过 API 查询到这个仓库的信息。</p><p>这就是 MCP 区块链的大体思路。</p><h3 id="设计来源"><a href="#设计来源" class="headerlink" title="设计来源"></a>设计来源</h3><p>解释一下这个想法的来源。MCP 区块链并不是想要 “把 MCP Server 去中心化”，而是想要 “给区块链带来与 AI 交互的能力”。这两种动机是截然不同的。</p><p>这个想法背后的逻辑很简单，比特币其实有脚本，只不过是生硬的操作码形式。以太坊干了一件很厉害的事情，给操作码加上了编译器，让开发者可以用编程语言来表达操作码。那么如今的 AI，很厉害的一点在于，打通了从自然语言到编程语言的路径。也就是说，未来的区块链，也许可以做到自然语言直接与状态机交互，而不需要经过 自然语言 -&gt; 编程语言 -&gt; 状态机 这样的路径。明显编程语言是一个中间层，MCP 区块链的设想在于消除这个中间层。</p><p>另一个边界在于，让区块链完全按照自然语言的意图执行是不切实际的，因为哪怕是人类，也需要书面形式的合同这种东西，所以代码本身不会消失，状态转移也不会消失。目前能够实现自然语言和状态机直接交互的技术方式，就是 MCP。</p><h3 id="区块链的技术趋势"><a href="#区块链的技术趋势" class="headerlink" title="区块链的技术趋势"></a>区块链的技术趋势</h3><p>最近在思考一个问题，区块链的下一个技术趋势是什么？能明确的几个事实是：</p><ol><li>大家已经不再怀疑加密货币是一种支付手段这件事情</li><li>依靠开发区块链发币的路线，已经完全没有叙事空间</li><li>下一个技术趋势，绝不会是以太坊路线图的扩展</li></ol><p>行业内已经提过的方向也都不大有机会，DeAI、ZK、Layer2、DeFi、跨链、RWA、GameFi、BaaS、NFT、元宇宙、DAO、DID 等等，都是陈词滥调了。</p><p>所以区块链在技术趋势上，需要的一个原语级别的新叙事。</p>]]></content>
  </entry>
  <entry>
    <title>回顾郭德纲与曹云金吵架事件</title>
    <link href="https://crazy.smallyu.net/2025/10/08/%E5%9B%9E%E9%A1%BE%E9%83%AD%E5%BE%B7%E7%BA%B2%E4%B8%8E%E6%9B%B9%E4%BA%91%E9%87%91%E5%90%B5%E6%9E%B6%E4%BA%8B%E4%BB%B6/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/10/08/%E5%9B%9E%E9%A1%BE%E9%83%AD%E5%BE%B7%E7%BA%B2%E4%B8%8E%E6%9B%B9%E4%BA%91%E9%87%91%E5%90%B5%E6%9E%B6%E4%BA%8B%E4%BB%B6/</id>
    <published>2025-10-08T12:00:00.000Z</published>
    <updated>2026-07-04T17:36:19.132Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<h3 id="个人感受"><a href="#个人感受" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<h3 id="个人感受"><a href="#个人感受" class="headerlink" title="个人感受"></a>个人感受</h3><p>最近看了郭德纲和曹云金吵架的原文，大概明白了。</p><p>曹云金觉得自己能耐大，在外面也能混的好，郭德纲应该不惜一切放低姿态挽留才对，自己并没低头。</p><p>郭德纲觉得自己是师父，曹云金应该低头来求和，恳求留在德云社才对，不冷不热的算是什么态度？</p><p>所以两人都有能耐，都不肯低头。 </p><p>我太理解这件事情了，在我的公司和团队里，真正有实力的往往忍耐程度很低，很容易离职，因为真的走了也能找到工作，一点不能受气。反而那种平庸的程序员，在团队里稳定性最强。</p><h3 id="事件回顾"><a href="#事件回顾" class="headerlink" title="事件回顾"></a>事件回顾</h3><ul><li><p>2016 年 8 月 31 日，郭德纲修订家谱，把曹云金评价为叛徒、欺师灭祖：</p><ul><li>微博原文：<a href="https://weibo.com/1854283601/E65sElMja" target="_blank">链接</a></li><li>微博原文存档：<a href="https://web.archive.org/web/20251008123332/https://weibo.com/1854283601/E65sElMja" target="_blank">链接</a></li></ul></li><li><p>2016 年 9 月 5 日，曹云金发布 6000 字长文《是时候了，也该做个了结了。》：</p><ul><li>微博文章原文：<a href="https://weibo.com/ttarticle/p/show?id=2309404016334328459355" target="_blank">链接</a></li><li>微博文章原文存档：<a href="https://web.archive.org/web/20240618201622/https://weibo.com/ttarticle/p/show?id=2309404016334328459355" target="_blank">链接</a></li></ul></li><li><p>2016 年 9 月 25 日，郭德纲发布 7000 字长文回应《天涯犹在，不诉薄凉。》：</p><ul><li>微博文章原文：<a href="https://weibo.com/ttarticle/p/show?id=2309404023390749994756&mark_id=999_reallog_mark_ad%3A999%7CWeiboADNatural" target="_blank">链接</a></li><li>微博文章原文归档：<a href="https://web.archive.org/web/20251008123830/http://web.archive.org/screenshot/https://weibo.com/ttarticle/p/show?id=2309404023390749994756&mark_id=999_reallog_mark_ad%3A999%7CWeiboADNatural" target="_blank">链接</a></li></ul></li><li><p>2016 年 9 月 25 日，曹云金再次发布文章回应《我的涵养在愤怒之前已经用完了！》：</p><ul><li>微博文章原文：<a href="https://weibo.com/ttarticle/p/show?id=2309404023620081964041" target="_blank">链接</a></li><li>微博文章原文归档：<a href="https://web.archive.org/web/20251008124619/http://web.archive.org/screenshot/https://weibo.com/ttarticle/p/show?id=2309404023620081964041" target="_blank">链接</a></li></ul></li></ul><h3 id="个人分析"><a href="#个人分析" class="headerlink" title="个人分析"></a>个人分析</h3><p>在郭德纲的家谱中，把曹云金评价为欺师灭祖、令人发指。</p><p>但是在郭德纲 7000 字的回应文章中，开头就又成了 “师徒不睦”。</p><p>单从语气态度上，很明显郭德纲的语气软了。如果是曹云金单方面的错误，郭德纲没有必要大费周章写长文回应，一口咬定是叛徒就行了，明明是卖师求荣的事情，怎么又成 “不睦” 了。</p><p>所以郭德纲的家谱，其实是对内震慑徒弟用的，不是对外攻击曹云金用的。</p><p>曹云金真的掌握一些郭德纲的事情，郭德纲也不敢完全撕破脸。就这么回事。</p>]]></content>
  </entry>
  <entry>
    <title>对 Plasma 项目的分析</title>
    <link href="https://crazy.smallyu.net/2025/09/25/%E5%AF%B9Plasma%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/09/25/%E5%AF%B9Plasma%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-09-25T14:33:31.000Z</published>
    <updated>2025-11-27T17:16:12.953Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p><a href="https://www.plasma.to/">Plasma</a> 的代币是 XPL，这两天正在上各大交易所，最近在 BlockBeats 上的新闻出镜率很高，所以我们来看看 Plasma]]></summary>
    <content type="html"><![CDATA[<p><a href="https://www.plasma.to/">Plasma</a> 的代币是 XPL，这两天正在上各大交易所，最近在 BlockBeats 上的新闻出镜率很高，所以我们来看看 Plasma 到底是一个什么样的项目。</p><p>按照我们之前分析项目的套路，在 Plasma 项目的官网首页，我又看到了几个不太乐观的信号：</p><ol><li>没有白皮书</li><li>没有 GitHub 仓库地址</li></ol><p>这两点不是一件小事。再来罗列一下官网首页对 Plasma 这个项目的描述：</p><ol><li>是一条 Layer 1 的链</li><li>1000 TPS</li><li>出块时间 1 秒</li><li>专为稳定币设计</li></ol><p>现在看到这样的技术指标，我不会猜他是 Cosmos 了，因为我会猜他是 Layer 2，但是他自己又说自己不是 Layer 2，那么 Plasma 的技术方案到底是怎么样的呢？</p><p><strong>链架构</strong></p><img src="1.png" width="70%"><p>魔改 Reth 作为执行层 + PlasmaBFT 作为共识。</p><p>魔改 Reth 好理解，PlasmaBFT 目前则没有看到公开的白皮书和代码。</p><p>等等，这岂不是 以太坊执行层 + PBFT 共识层的套路？我前几天还刚折腾这个（《<a href="https://smallyu.net/2025/09/06/%E4%B8%80%E4%B8%AA%E9%9B%86%E6%88%90Geth%E5%92%8CCometBFT%E7%9A%84%E5%85%BC%E5%AE%B9%E5%B1%82/">一个集成 Geth 和 CometBFT 的兼容层</a>》）。</p><p><strong>USDT 零手续费</strong></p><img src="2.png" width="70%"><p>简单来说，利用 ERC-4337（AA 钱包），估计是把 EntryPoint 合约作为预编译合约放进 Reth 了。</p><p>用 Paymaster 来代付手续费，这没什么好说的。</p><p><strong>其他</strong></p><p>没别的了，就这样吧。</p>]]></content>
  </entry>
  <entry>
    <title>我从王垠的计算机科学课学到了什么（三个月版）</title>
    <link href="https://b.smallyu.net/2025/09/24/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%883/"/>
    <id>blog-b:https://b.smallyu.net/2025/09/24/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%883/</id>
    <published>2025-09-24T04:12:12.000Z</published>
    <updated>2026-07-17T06:27:02.430Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>为了行文方便，这篇文章不使用 “王垠老师” 这样的尊称，直接称呼名字 “王垠”。</p>
</blockquote>
<h3 id="学习时长"><a href="#学习时长" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<blockquote><p>为了行文方便，这篇文章不使用 “王垠老师” 这样的尊称，直接称呼名字 “王垠”。</p></blockquote><h3 id="学习时长"><a href="#学习时长" class="headerlink" title="学习时长"></a>学习时长</h3><p>大约 4 个月前，我开始报名学习王垠的 <a href="https://www.yinwang.org/blog-cn/2025/05/12/cs-video-course">计算机科学视频班</a>（基础班），经过 1 个月的学习后毕业，大概用了 120 个小时的学习时长。“120 个小时” 这个数字是经过认真估算的，包含了观看视频的时间和做练习题的时间。因为视频课的学习节奏由自己把控，毕业速度因人而异。</p><p>如果我说学了 1 个月，也许有人很不在乎，1 个月的时间能学到多少知识呢？世界上没有速成班，王垠也不可以。1 个月的时间确实不可能学到各种全面的知识，时间上也不允许。但是 1 个月的时间能不能帮我把过往的编程技能梳理一遍，让我对计算机科学有更加体系化的认识？我在工作中可能见过各种迷雾，王垠的课程能不能让我拨云见日，看清楚很多东西？</p><p>学习课程就像是去西天取经，顺利毕业相当于取到了真经。但是学习课程的过程只是老师帮你理解经书内容而已，取到真经不代表你已经对经书中的内容融会贯通，还需要在日后多加修炼、理解透彻才行。想必有的同学拿到经书（毕业）后再也不会打开看一眼，于是认识不到课程真正的价值含量。</p><h3 id="课程体会"><a href="#课程体会" class="headerlink" title="课程体会"></a>课程体会</h3><p>现在课程毕业后，经过 3 个月时间的沉淀，我想分享一下 “从课程中能学到什么” 这个话题。没有在毕业当天做总结，是因为怕有点浮燥总结不全，或者掺杂太多个人经历。3 个月的时间其实也不够，我没有太多时间复习，课程也远远没来得及发挥出应有的成果，但是现在做总结并不妨碍以后对课程内容有进一步的感悟。</p><p>王垠曾经有一篇文章《<a href="https://yinwang-wiki.github.io/feeds/2013-04-03-einstein-on-education.html">爱因斯坦谈教育</a>》，里面提到爱因斯坦说， “被传授的知识应该被当成宝贵的礼物”。我在学完课程后，对这句话有了切实的理解。</p><p>王垠并不认识我，但我早就认识王垠；我以前不是王垠的学生，但王垠早就是我的老师了。我关注王垠的博客多年，已经从他的博客文章中受益很多。而这次系统学习了视频课的课程，像是打开了新世界的大门。这并不夸张，我可以负责任地站在学习过课程的立场上讲，王垠没有吹牛，他的课程真的有他说的那么好。</p><p>你可以不赞同王垠的观点，也可以不喜欢王垠的人生态度，但是不可能怀疑王垠在计算机科学，尤其是编程语言领域的研究水平和造诣，也完全不需要担心王垠这样对自己和世界都如此较真的人，会拿一些没有含量的课程出来忽悠人。</p><h3 id="知识深度"><a href="#知识深度" class="headerlink" title="知识深度"></a>知识深度</h3><p>因为课程内容是保密的，我不会透露课程具体的学习内容，只基于公开的招生说明中的内容进行解释。</p><p>对于计算机初学者来说，从课程中能学到的最直接的知识，就是函数、链表、二叉树等基础的编程概念，涵盖了大学本科整个阶段的学习内容。第 6 课关于解释器的部分，属于课程的 “最终成果”，对应一些美国顶尖大学，本科高年级阶段至硕士低年级阶段的学习内容。</p><p>为什么王垠在招生说明里的描述是 “大学博士阶段才可能学到的内容” 呢？因为中国的大学没有编程语言专业，本科课程没有教解释器的，即使到了研究生阶段，lambda 演算也属于选修课，博士早期才会接触到解释器的实现是正常现象。所以王垠的描述真的没有夸大。</p><p>解释器这种内容在中国的教育体系里本来就很稀有，比较高级和精练的教程更是少见。举例来说，当你学完了王垠的课，然后去 bilibili 上搜一些解释器相关的教程，你就会明白这些公开教程里的解释器有多么差劲，不但一眼就能看出它们缺什么要素、存在什么问题，还知道如何改进、如何用最简洁的代码写出最可靠的实现。</p><p>为什么解释器这个东西重要呢？举个例子，以太坊的虚拟机（EVM）就是一个解释器，只不过 EVM 并不是在对编程语言做解释，而是在对以太坊的操作码（Opcodes）做解释，每个操作码都对应在栈结构上的一个动作。所以学过了解释器之后，对 EVM 的原理会有不一样的理解。</p><h3 id="认知提升"><a href="#认知提升" class="headerlink" title="认知提升"></a>认知提升</h3><p>对于有计算机经验的学生来说，从课程上可以学到的，就不只是表面上的知识了。比如，课程只用到非常少的编程要素，就表达了第 1 课到第 6 课的全部内容，如果王垠不是对计算机理论有非常深刻的理解，不可能做到这种地步的深入简出。</p><p>从学习者的角度，一方面可以思考为什么课程内容能如此精致，组织这些课程内容的思路是什么，这种高度抽象的思维背后，需要怎样的功底，自己距离写出这样的课程，能力上的差距还有多大。另一方面，由于课程内容自成一体，学习者完全有可能做到自己复刻整个课程内容，就像是手里的一个精致的玩物，可以随时拿出来复习把玩。</p><p>基础班的知识像是非常高级的原材料，从基础班毕业就意味着拿到了这些原材料。但原材料需要经过反复打磨、锤炼、加工，才能变成更加实际可用的装备。所以猜测有的同学学完之后感觉什么都没学到，而有的同学觉得如获至宝，能够反复加以利用并产生许多价值，大概就是这个原因吧。</p><h3 id="自学能力"><a href="#自学能力" class="headerlink" title="自学能力"></a>自学能力</h3><p>我最近忽然意识到，学完课程以后，学习其他技术好像变简单了。因为体验了课程中层层递进的教学方式，我自学其他东西也会按照这个思路来，一步一步学，自然而然就学会了.</p><p>理解 CPS、基于 continuation 原理实现协程调度，学习 Solana 合约、比特币脚本、比特币 Runes、DeFi，等等。我有点说不上这是怎么回事，明明课程里只教了一些计算机基础，链表、二叉树什么的，竟然有这样的威力。</p><p>也许从课程里学到的不只是知识，还有很好的学习方法。难怪王垠把课程内容称为 “计算机科学的精华”。</p><h3 id="超越工程的技术"><a href="#超越工程的技术" class="headerlink" title="超越工程的技术"></a>超越工程的技术</h3><p>虽然我有多年在区块链行业实际的工作经验，但是我却越来越搞不懂，区块链技术到底是什么。</p><p>我曾经大量研究区块链共识的原理，为什么关注的不是其他技术原理，比如加密学、分布式网络、储存系统等内容？因为只有共识是区块链特有的，其他都是普通的工程上的技术，包括智能合约的实现也是，而且智能合约还不是区块链必需，可以有也可以没有。至于 Layer 2 之类，也完全是工程上的尝试，哪有什么可以抽象的理论依据，挑战期、赎回期等都是业务定义的逻辑。我可以剧透一下，王垠的计算机课程，还涉及到了一部分区块链最本质的技术原理，是不是难以想象？</p><p>我发现，与不成体系的区块链工程技术相比，拥有基础而扎实的计算机功底更重要，尤其是高度抽象的思维方式，能够脱离语法但理解编程语言本质的学习方式，值得反复琢磨和理解。</p><p>我曾经以为，只要好好钻研区块链技术，就可以逐步提高自己的技术能力，就可以深入研究某些区块链原理，深入再深入，水平上自然而然超越所谓的计算机基础班，这也是我前几年没有报名学习课程的原因。然而事实上不是那样，经过几年切实的工作，我越发认识到课程内容的重要性。所以现在学习了课程，并且学到了很多。</p><h3 id="课程的启发性"><a href="#课程的启发性" class="headerlink" title="课程的启发性"></a>课程的启发性</h3><p>学完课程以后，我其实一度怀疑自己，难道这几年折腾区块链技术都是没有意义的吗？为什么学了一个零基础入门性质的计算机课，反而感觉学到了能 “改变人生” 的东西？</p><p>一直没想通这个问题，直到后来，偶然看到王垠讲述课程设计的文章《<a href="https://www.yinwang.org/blog-cn/2020/03/03/cs-course">计算机科学课程</a>》，尤其是看到 “苏格拉底方法” 段落的时候，恍然大悟，原来我的很多知识早已散落在我的头脑中，只是这门课程帮我把知识都 “生产” 了下来。我现在拥有的知识，离不开经年累月工作和学习的 “怀胎”，也离不开这门计算机课程在恰当时候的 “助产”。</p><blockquote><p>苏格拉底承认他自己本来没有知识，而他又要教授别人知识。这个矛盾，他是这样解决的：这些知识并不是由他灌输给人的，而是人们原来已经具有的；人们已在心上怀了“胎”，不过自己还不知道，苏格拉底像一个“助产婆”，帮助别人产生知识。</p></blockquote><p>这就好比，在一个陌生的城市里，你没有地图，搞不清方向，但是也可以四处游荡，有时候能走的很远。而王垠的计算机课程，像是一张完整的地图，你有了地图，各个方向和岔路口都清清楚楚，但是你未必出发，也未必耗费力气去探索远方。</p><p>我的情况相当于，已经在城市里走过了很多路，偶然有一天，拿到了整个城市的地图，幡然醒悟，明白了自己所处的位置，知道了自己原先走过哪些路。这是课程对我帮助很直接的地方。</p><h3 id="真正的编程"><a href="#真正的编程" class="headerlink" title="真正的编程"></a>真正的编程</h3><p>前几天面试的时候，面试官出了一道算法题，我拿到题目后，下意识说 “这看起来不是一道编程题，而是一些数字游戏”。我猜面试官听到我的话后，内心是充满鄙夷的，他也许会想，“这怎么不是编程题？” </p><p>我事后也惊讶，当时为什么会那样评价面试官出的题目，那是一种下意识的感受。后来想明白，因为你一旦上过王垠的课，就会知道真正的 “编程题” 是什么。LeetCode 上那些算法题，“编程” 的含量有多少呢？学完后课程后，你可以轻易看穿那些低水平面试官的把戏。</p><p>换个角度想，每一节课程之后，都有大量练习题需要做。如果把那些练习题，看作面试题呢？你让那些面试官来做一道试试？那可是王垠设计出的题目啊！而每一个顺利从课程毕业的同学，都必须自己做出那些题目。</p><h3 id="代码质量"><a href="#代码质量" class="headerlink" title="代码质量"></a>代码质量</h3><p>王垠在微博上评论 AI 编程的时候提到，现在的 AI 很厉害，但 AI 在不经过王垠本人调教的情况下，无法写出 “王垠级别” 的代码。什么是 “王垠级别” 的代码呢？上过课就知道了。</p><p>我在做练习题的时候，被助教提醒最多次的问题，就是 “代码复杂”，有时候是写法上的复杂，有时候是复杂度上的复杂，但是每一次把代码写到符合课程标准之后，又不禁感叹原来代码可以如此精巧。我有多年的编程经验，让代码运行出练习题的结果并不难，但是把代码写的足够漂亮却不容易。“代码能运行” 和 “把代码写对” 之间，差距非常大。</p><p>有一个神奇的现象是，同一道题目，无论反复做多少次，比如做过一次后，放一个月再做一次，之前的记忆已经没有了，但是最终写出来的代码，和之前一模一样。这肯定不是偶然，因为在课程的要求下，你不得不用最简单的思路，写出最精炼的代码，而且还有代码风格和格式方面的约束，自然就会把答案的写法框定在某种形式上。</p><p>这不是一件坏事，并不是说要课程要求你教条式地背诵答案，而是在用固定的标准动作训练你的头脑，就想运动员一样，动作要标准规范，才能有好的训练效果。经过这样的训练，在日后写代码的时候，自然而然也会维持同样的动作，写出来的代码会规范和简洁。</p><h3 id="掌握新语言"><a href="#掌握新语言" class="headerlink" title="掌握新语言"></a>掌握新语言</h3><p>也许有人看到招生说明会怀疑，一节选修课真能让人学会一种新的编程语言吗？我想提醒的是，不要忘了给你讲课的人是谁，是曾经写出了《<a href="https://www.yinwang.org/blog-cn/2017/07/06/master-pl">如何掌握所有的程序语言</a>》文章的作者，是真正的编程语言专家。</p><h3 id="课程的稀缺性"><a href="#课程的稀缺性" class="headerlink" title="课程的稀缺性"></a>课程的稀缺性</h3><p>这一小节单独成文：《<a href="/2025/08/25/%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%AF%BE%E7%A8%8B%E8%B4%B5%E5%90%97%EF%BC%9F/">王垠的计算机课程贵吗？</a>》</p><h3 id="系统学习的重要性"><a href="#系统学习的重要性" class="headerlink" title="系统学习的重要性"></a>系统学习的重要性</h3><p>要是单拿第 1 课的内容，或者某一课的内容出来，其实并没有那么神秘，很多地方都可以学到。王垠的课程，通过循序渐进的引导让你把这些知识学会，只是其中一方面，另一个更重要的方面在于，从第 1 课到第 6 课的内容，是非常连贯、层层递进、成体系、系统化的。</p><p>我们平时掌握的知识点，就像一个个独立的音符，大多数人都可以轻易地弹奏出某个音，但是只有把这些音符编排成曲，才能形成美妙的音乐。伟大的音乐家之所以伟大，并不是因为他们发明了新的音符，而是因为他们能把已有的音符编排成动人的旋律。</p><p>单个音符拿出来，我们很难记住，或者容易遗忘。但是一段完整的旋律，会久久盘旋在你的头脑中。即使你忘记了其中的一两个音，也可以根据整首曲子的旋律推测出来，甚至可以突发奇想，自己对旋律做一些改进。这就是系统学习知识的意义。</p><h3 id="课程的定位"><a href="#课程的定位" class="headerlink" title="课程的定位"></a>课程的定位</h3><p>王垠的课程，像是某种核心（因为基础），只要掌握了这些核心内容，你就始终算是会编程、懂计算机科学的人。</p><p>这里说的基础，不是 Hello World 那种基础，而是某种结构化的基础。这些基础知识，会帮你理解 “计算” 的本质。这些核心的基础知识，才是日后真正支撑你前进、给你力量的来源。无论上层的表达形式如何变化，本质都不会变。</p><p>我以前经常担心，会不会因为做了某些工作，导致自己偏离原先的技术道路？做一些运维相关的工作，是不是就偏离了自己开发者的初心？原本做 Go 语言开发，工作需要写一些 node.js 代码，是不是就偏离后端开发的职业路径？等等。</p><p>王垠的课程内容，就属于有 “定心丸” 功效的那种。课程教给你的，是如何搭建一套自己的 “计算模型”，而不是告诉你某些已经存在的项目具体是怎么回事。所以不要纠结于课程内容是不是全面、是不是高级，因为课程本身是讲心法的，不是讲招式的。至于具体的招式，你得自己学、自己练。</p><p>学习课程以前，我在挑选工作的时候，能不能从工作中学到东西、工作有没有成长空间、有没有发展前景，都是重点需要考虑的。学完课程以后，我在考虑的，是如何根据已经掌握的知识和技能，给团队带来帮助、给公司创造价值。心态完全不一样了。因为我不再需要从工作中学到什么，我已经知道从哪里可以学到真正的技术。</p><p>当然，这事我觉得，也要看悟性。课程教归教，能收获多少，还得靠自己。</p><h3 id="抵抗-AI-的冲击"><a href="#抵抗-AI-的冲击" class="headerlink" title="抵抗 AI 的冲击"></a>抵抗 AI 的冲击</h3><p>这一小节单独成文：《<a href="/2025/09/20/%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AF%BE%E8%83%BD%E5%B8%AE%E5%8A%A9%E7%A8%8B%E5%BA%8F%E5%91%98%E6%8A%B5%E6%8A%97AI%E7%9A%84%E5%86%B2%E5%87%BB%E5%90%97%EF%BC%9F/">王垠的课能帮助程序员抵抗 AI 的冲击吗？</a>》</p>]]></content>
  </entry>
  <entry>
    <title>王垠的课能帮助程序员抵抗 AI 的冲击吗？</title>
    <link href="https://b.smallyu.net/2025/09/20/%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AF%BE%E8%83%BD%E5%B8%AE%E5%8A%A9%E7%A8%8B%E5%BA%8F%E5%91%98%E6%8A%B5%E6%8A%97AI%E7%9A%84%E5%86%B2%E5%87%BB%E5%90%97%EF%BC%9F/"/>
    <id>blog-b:https://b.smallyu.net/2025/09/20/%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AF%BE%E8%83%BD%E5%B8%AE%E5%8A%A9%E7%A8%8B%E5%BA%8F%E5%91%98%E6%8A%B5%E6%8A%97AI%E7%9A%84%E5%86%B2%E5%87%BB%E5%90%97%EF%BC%9F/</id>
    <published>2025-09-20T10:47:37.000Z</published>
    <updated>2025-12-03T09:25:54.160Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近一段时间的工作，我几乎所有的代码，都是 AI 写的，我不再需要自己动手写代码，哪怕只是一两行代码的变动。</p>
<p>我只需要告诉 AI，我需要改哪里，期望的效果是什么，AI 完成的效果就很好，而且 AI 的效率很高，也不怕累，AI]]></summary>
    <content type="html"><![CDATA[<p>最近一段时间的工作，我几乎所有的代码，都是 AI 写的，我不再需要自己动手写代码，哪怕只是一两行代码的变动。</p><p>我只需要告诉 AI，我需要改哪里，期望的效果是什么，AI 完成的效果就很好，而且 AI 的效率很高，也不怕累，AI 技术的发展，真正实现了解放我们双手的愿景。</p><p>这不由得引起一个思考，AI 会取代程序员吗？王垠的课程，能够帮助程序员抵抗这种来自 AI 的冲击吗？</p><h3 id="AI-的水平"><a href="#AI-的水平" class="headerlink" title="AI 的水平"></a>AI 的水平</h3><p>如果你用过 AI 写代码，就会明白目前的 AI，还不可能真的取代程序员，因为很多事情做不了，很多事情会做错，需要人为判断。</p><p>但即使是在短短半年前，把项目完全托管给 AI 来开发，都是不敢想的事情。半年前，我在工作中还是手动复制 AI 写的代码的模式，因为不敢让 AI 直接动项目。但是现在，AI 的 Agent 模式已经真的可以投入使用。我印象里 AI 的 Agent 模式也就今年才出现。</p><p>而且比起两年前，现在 AI 的发展速度更是非常可怕。两年前还是 <a href="/2023/03/30/%E4%B8%8D%E8%A6%81%E5%B0%8F%E7%9E%A7-ChatGPT/">GPT-3.5</a> 的时代，不能识别图片，文本处理也存在很多幻觉。经过两年时间的发展，现在 GPT-5 的能力已经非常厉害。</p><p>所以 AI 的水平很高，虽然现在还没有特别高，但是真正让人害怕的，是 AI 的进化速度。</p><h3 id="我常用的-AI"><a href="#我常用的-AI" class="headerlink" title="我常用的 AI"></a>我常用的 AI</h3><p>我自己的主观感受上，还是 GPT-5 模型最靠谱。</p><p>因为我有正事要干，没有那么多时间去试错，Claude Sonnet 4 给人的感觉就是手过于勤快，方案还没定，代码写出一堆，删都删不过来。他自己给出 A、B、C 三种方案，结果在描述方案的过程中，就把三种方案的代码全写了。相比之下，GTP-5 就好一点，会先问你用哪种方案，然后再动手。Gemini 2.5 Pro 没太用过。</p><p>我用的编辑器是 VS Code，装了 GitHub Copolit 和 ChatGPT Codex 两个插件，这两个插件都选择 GPT-5 模型。Codex 用来执行复杂任务，Copolit 做轻量级的改动。</p><p>所以我对于 AI 编程的感受主要来源于这样的使用环境。如果你用了其他的模型，或者其他的编辑器、工具，可能会跟我的感受有出入。</p><h3 id="明确话题"><a href="#明确话题" class="headerlink" title="明确话题"></a>明确话题</h3><p>回到正题，我们的话题是，王垠的课，能不能抵抗这种来自 AI 的冲击？</p><p>首先是 AI 到底冲击了哪些程序员。最大的冲击是对于 3 年以下工作经验、对业务场景和技术选型都没有判断力、工作内容以领导安排为主、自己动手实现代码为结果的程序员群体。</p><p>AI 最擅长的，就是在业务场景清晰、工作目标清晰的情况下，完成代码。所以以前在公司里的小组长，有花费口舌跟新人讲清楚需求的功夫，完全可以跟 AI 描述清楚需求、AI 就把活干了。而且 AI 态度比人好、动手能力比人强、写起代码来比专家都专业。</p><p>目前的 AI 还不能取代的是在复杂业务场景下、需要对技术选型、技术方案做决策的程序员。不过这些程序员本身已经不太是基础的技术岗位，通常已经不怎么写代码。</p><p>所以进一步明确，我们在讨论的话题是，对于需要动手写代码的程序员来说，王垠的课，能不能提高这一类程序员的竞争力，抵抗至少是延缓 AI 的冲击，比其他程序员晚一步被淘汰？</p><h3 id="王垠的课"><a href="#王垠的课" class="headerlink" title="王垠的课"></a>王垠的课</h3><p>我按照之前一天一道题目的计划，第三轮做练习题，最近刚做完链表相关的部分。</p><p>（题外话，想想在面试过程中，凡是让你现场写代码、做题的公司、面试官，是不是都挺扯的。不信你随便拿一道王垠出的练习题，给那些人做，你看他们能不能做出来。所以建议大家，凡是面试流程中需要做题的公司，无论面试是否通过，一律马上拒绝。）</p><p>我在 4 年前就自己写过 <a href="/2021/10/27/%E9%93%BE%E8%A1%A8%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98%E5%8F%8A%E8%A7%A3%E6%9E%90/">链表反转</a> 之类，但是用了非常笨拙的写法，一个节点的上一个节点指向哪里、下一个节点指向哪里什么的，来对链表进行各种操作。</p><p>王垠课程里的链表，利用纯函数式的写法，以及递归的思想，代码非常简洁优雅，完全不需要考虑上一个节点、下一个节点这种东西。即使已经是第三次面对这个题目，因为已经忘了之前是怎么做的，我也很犹豫，链表反转是能用一两行代码实现的吗？终于在第三次做出题目后，才明白真的可以简单到这种程度。</p><p>所以我想说的是，王垠的课程，思想大于形式，真正能教会你的，不只有表面的知识那么简单。</p><p>同样的链表反转，初级程序员写出来是一个样，高级程序员写出来是另一个样，真的会不一样。也许表面上代码都能运行，都能达到目的。但是当面对更复杂的系统设计问题，是不是也应该尽可能做到简洁、优雅、清晰、可靠？</p><p>当你见识过最清晰的反转链表应该怎么实现，你就知道，噢，链表反转有着各种各样的写法，复杂的写法往往存在这样那样的问题，事实上问题的解法可以更优雅。</p><p>当你面对一些复杂的功能需要实现，你可能会用同样的思路去思考，是不是有更加简洁优雅的方式，来干这个事？</p><p>你只有见识过更好的东西，才能明白，什么东西更好。</p><p>AI 可以帮你干活，但是不可能代替你水平高。</p><p>当你没有见过更好的东西，你可能不知道什么是好的，想象不出什么是好的。然后你去告诉 AI，你帮我写一段很好的代码出来，AI 写了三个版本，你都不满意，最后 AI 问你，什么是 “很好的代码”？你自己也不知道。</p><p>就像我在《<a href="/2025/09/06/%E4%B8%80%E4%B8%AA%E9%9B%86%E6%88%90Geth%E5%92%8CCometBFT%E7%9A%84%E5%85%BC%E5%AE%B9%E5%B1%82/">一个集成 Geth 和 CometBFT 的兼容层</a>》中提到的观点，AI 可以替你干活，但是 AI 不可能代替你懂。</p><h3 id="需要懂吗"><a href="#需要懂吗" class="headerlink" title="需要懂吗"></a>需要懂吗</h3><p>你可能想问，AI 帮我把活干了就行，我为什么非要懂？我不在乎代码的好坏，事实上也没人在乎，老板不在乎，客户也不在乎。只有一些自以为是高人一等但是没有实权的老员工、小组长在乎。</p><p>这其实正是我想说的，王垠的课，不局限于代码，而在于思想。</p><p>说实话，王垠课程中对于代码形式上的规则，几句话就可以说清楚。而且大部分王垠在之前的文章《编程的智慧》中都写过。（我发现现在文章被删掉了，看起来王垠删掉了很多有价值的文章）。</p><p>真正重要的不是明面上的规则，而在于课程是如何对知识化繁为简的，为什么这样是好的，那样是坏的。</p><p>同样的思想，可以迁移到其他问题上，什么是好的，什么是坏的。</p><p>你可以不在乎代码，但是始终要面对数据结构、算法、系统架构、复杂度、性能等问题。除非你真的什么都不需要面对。</p><p>AI 能解决这些问题吗？能，但是你得给 AI 说明白需求，然后看明白 AI 给你的方案，最后你来决定选择哪一种。如果你看不懂 AI 在跟你说什么，那你就不能控制 AI 了。</p><p>还是那句话，AI 不可以代替你懂。</p><h3 id="王垠的观点"><a href="#王垠的观点" class="headerlink" title="王垠的观点"></a>王垠的观点</h3><p>我一直在说 “AI 不可能代替你懂”，这是我自己使用 AI 编程的体会。</p><p>王垠在以前的文章《<a href="https://www.yinwang.org/posts/ai">人工智能的局限性</a>》，包括最近在微博上，都描述了他对于 AI 的核心观点，那就是 “AI 没有读心术”。这个和我们日常使用 AI 编程的体会是一致的，你必须非常清晰告诉 AI 你想要什么，AI 才会给你什么。如果你的描述是模棱两可的，你忽悠 AI，AI 也会敷衍你。你说不清楚，AI 就做不明白。</p><p>王垠的课能帮助程序员抵抗 AI 的冲击吗？也许可以吧……假如不可以，那该怎么办？</p>]]></content>
  </entry>
  <entry>
    <title>对 Kaia 项目的分析</title>
    <link href="https://crazy.smallyu.net/2025/09/15/%E5%AF%B9Kaia%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/09/15/%E5%AF%B9Kaia%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-09-15T13:37:36.000Z</published>
    <updated>2025-11-27T17:16:12.937Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p><a href="https://www.kaia.io/">Kaia</a> 是一个和 Line 有合作的区块链项目，首页上的标语竟然是为亚洲的链上生态赋能，难道区块链网络还分地区的吗？</p>
<img src="1.png"]]></summary>
    <content type="html"><![CDATA[<p><a href="https://www.kaia.io/">Kaia</a> 是一个和 Line 有合作的区块链项目，首页上的标语竟然是为亚洲的链上生态赋能，难道区块链网络还分地区的吗？</p><img src="1.png" width="50%"><p>问个小问题，已知 Kaia 是一条 Layer1 的区块链网络，EVM 完备，并且具有以下 3 个特性，猜猜 Kaia 的技术栈是什么？</p><img src="2.png" width="50%"><p>我自己的猜测是，Kaia 是用 Cosmos SDK + Evmos 方案搭建的一条链。因为 Kaia 的第 1 条特性很眼熟，明显是 Cosmos 链的指标。第 2 条则直接确定了是 PBFT 共识。第 3 条中规中矩。</p><p>结果怎么样呢，结果打脸了，Kaia 的技术实力比预期硬核，自己设计了叫 IBFT 的共识，整个链的 <a href="https://github.com/kaiachain/kaia?tab=readme-ov-file">节点代码</a> 都是自己开发的，从 6 年前开始就有提交记录了！（不过话说开源了 6 年只有 46 个 star 是怎么回事？）</p><h3 id="EVM-完备"><a href="#EVM-完备" class="headerlink" title="EVM 完备"></a>EVM 完备</h3><p>不得不承认，Kaia 的节点源码很硬核，全部代码都是自己开发的，几乎没有引入外部的依赖。</p><p>比如 Kaia 的 <a href="https://docs.kaia.io/build/smart-contracts/">文档</a> 中说，Kaia 支持以太坊的智能合约。是怎么支持的呢？一般的链可能会直接用 Geth 的节点，或者至少引用 go-ethereum 的依赖。Kaia 是怎么做的呢？Kaia 自己 <a href="https://github.com/kaiachain/kaia/blob/dev/blockchain/vm/evm.go#L71">实现</a> 了一个 EVM：</p><img src="3.png" width="100%"><p>在 <a href="https://github.com/kaiachain/kaia/blob/dev/blockchain/vm/opcodes.go">opcodes.go</a> 文件中能看到完整的 OpCode 的定义：</p><img src="4.png" width="100%"><p>这不是一件简单的事情！开发一个 <a href="https://smallyu.net/2025/05/11/%E6%83%B3%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E6%9C%80%E5%B0%8FEVM%E8%99%9A%E6%8B%9F%E6%9C%BA/">玩具 EVM</a> 也许并不难，但是要完全实现 EVM 的特性，做到生产级别可用，真不是一件容易的事情！</p><p>就在我惊讶于 Kaia 的硬核程度的时候，我忽然想到什么，再仔细看了一下 Kaia 的代码，注意开头的这句话：</p><img src="5.png" width="90%"><p>算是一定程度上可以理解了，Kaia 虽然没有以外部依赖的方式引入 go-ethereum，但是把 go-ethereum 其中的代码原文件复制到了项目中，“假装” 是自己的代码。</p><p>再来对比一下 vm 相关部分的代码文件，这是 Kaia 的：</p><img src="6.png" width="50%"><p>这是 go-ethereum 的：</p><img src="7.png" width="50%"><p>几乎一模一样。这下 “破案” 了。Kaia 要真有实力自己开发一个 EVM，那还真是对不起仓库里的 46 个 star 了。</p><h3 id="PBFT"><a href="#PBFT" class="headerlink" title="PBFT"></a>PBFT</h3><p>对于共识部分，我一开始的理解有误。仔细看了一下，其实 Kaia 直接在 <a href="https://docs.kaia.io/learn/consensus-mechanism/#consensus-mechanism-in-kaia-">文档</a> 里说，自己用了 <a href="https://github.com/Consensys/quorum/blob/master/consensus/istanbul/qbft/core/core.go#L312">Istanbul BFT</a> 的代码，Kaia 倒是没有想虚假宣传，我还翻了半天代码。</p><p>可以看到整个 Kaia 的节点代码，是 fork 自以太坊的，然后把 Istanbul BFT 集成到了原本的代码中，形成了现在的节点。这种做派，把别人的源码拿过来，改改这个、改改那个、集成一下，有没有一点似曾相识的感觉呢，是不是很像国产的联盟链的风格。</p><h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><p>总的来说，Kaia 在技术上没有太多让人眼前一亮的地方，因为最近在亚洲有一些宣讲的会议，我才注意到这个项目。总体感觉是一条中规中矩的链吧，没有技术亮点，应该不会引起市场的关注。</p>]]></content>
  </entry>
  <entry>
    <title>对 Codex 项目的分析</title>
    <link href="https://crazy.smallyu.net/2025/09/08/%E5%AF%B9Codex%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/09/08/%E5%AF%B9Codex%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-09-08T15:01:08.000Z</published>
    <updated>2025-11-27T17:16:12.928Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>Vitalik 前几天发了个 <a href="https://x.com/VitalikButerin/status/1963958883090608198">推文</a>，说低手续费的稳定币是加密货币的重要力量，而 <a]]></summary>
    <content type="html"><![CDATA[<p>Vitalik 前几天发了个 <a href="https://x.com/VitalikButerin/status/1963958883090608198">推文</a>，说低手续费的稳定币是加密货币的重要力量，而 <a href="https://www.codex.xyz/">Codex</a> 是一个专注于解决稳定币问题的以太坊 Layer2。让我们来看看 Codex 是如何做到稳定币的 native chain 的。</p><p>之前提到的 Arc 项目有很多存在技术疑点的地方，比如如何实现稳定币支持手续费？这实际上不是一件简单的事情，尤其是不想魔改 Geth 的话。看看 Codex 能解决这个问题吗。</p><p>难道 Codex 的定位是和 Arc 强市场吗？竟然在首页上大屏幕放 USDC 的 logo。</p><img src="1.png" width="60%"><p>要留意的一点是，Codex 的首页上没有 Github 链接，也没有白皮书链接，这通常不是一个好的技术信号。不过另一方面，<a href="https://www.codex.xyz/blogs/native-usdc-is-now-live-on-codex">Native USDC</a> 已经在 Codex 这条链上，所以 Codex 的企业背景和公司实力本身没有问题。</p><p>本来想说遇到这样的项目很头疼，既没有代码也没有白皮书，我分析啥。然后翻了翻文档，大多数是一些概述性质的东西，没有实质内容。</p><p>终于翻到了 <a href="https://docs.codex.xyz/developer/mainnet.html">最后一个章节</a> 的页面，就这一句话，真相大白，什么问题都清楚了：</p><img src="2.png" width="100%"><p>这里的 <a href="https://conduit.xyz/">Conduit</a> 是干什么的呢？Baas 平台、一键启动一条 Layer2，就这么回事！</p><p>Codex 的性质，和 Camp Network 一样。</p><p>Conduit 的收费比 Gelato 稍微贵一点点，主网需要 5000美元&#x2F;月，测试网 250美元&#x2F;月。不过这点钱和整个项目与网络的营收比起来，应该无所谓了。</p><img src="3.png" width="100%"><p>所以怎么样呢，是不是这样就理解了，为什么 Codex 的首页，既没有白皮书也没有代码？事情就是这样。</p><p>最难以让人理解的一点是，Vitalik 竟然在支持这样的项目，Vitalik 是技术出身，难道丝毫不在意一个项目的技术含量吗？</p>]]></content>
  </entry>
  <entry>
    <title>一个集成 Geth 和 CometBFT 的兼容层</title>
    <link href="https://smallyu.net/2025/09/06/%E4%B8%80%E4%B8%AA%E9%9B%86%E6%88%90Geth%E5%92%8CCometBFT%E7%9A%84%E5%85%BC%E5%AE%B9%E5%B1%82/"/>
    <id>blog:https://smallyu.net/2025/09/06/%E4%B8%80%E4%B8%AA%E9%9B%86%E6%88%90Geth%E5%92%8CCometBFT%E7%9A%84%E5%85%BC%E5%AE%B9%E5%B1%82/</id>
    <published>2025-09-05T16:30:00.000Z</published>
    <updated>2025-09-05T16:40:08.462Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="项目动机"><a href="#项目动机" class="headerlink" title="项目动机"></a>项目动机</h3><p>在对 <a]]></summary>
    <content type="html"><![CDATA[<h3 id="项目动机"><a href="#项目动机" class="headerlink" title="项目动机"></a>项目动机</h3><p>在对 <a href="https://paragraph.com/@smallyu/%E5%AF%B9-arc-%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90">Arc 项目</a> 进行分析的过程中，发现 Arc 干了一件很有意思的事情，先是自己开发了 Rust 版本的 Tendermint 共识 malachite，接着开发了一个对接 Reth 和 malachite 的兼容层 malaketh-layered，也就是说，Arc 这条链的架构是这样：</p><pre><code class="text">Reth -&gt; malaketh-layered -&gt; malachite</code></pre><p>最终形成了一条完全以太坊等价的 PBFT 链。</p><p>那么有没有类似架构的链，直接把 Geth 和 CometBFT 给结合起来呢。是有的，<a href="https://paragraph.com/@smallyu/%E5%AF%B9-berachain-%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90">Berachain</a> 开发了一个<a href="https://github.com/berachain/beacon-kit">beacon-kit</a>，干的就是这样的事情，Berachain 主网本身就是这种架构启动的。</p><p>但是 beacon-kit 有一个问题，就是代码过度 “复杂”，不但自己设计了 slot 的概念，还把 Berachain 的一些经济模型的设计、LST 质押之类的东西都放到了 beacon-kit 中。所以虽然 beacon-kit 在工程上是一个 Geth+CometBFT 可行的实践，但是它本身并不是工具性质的立场在做，夹带了不少私货。</p><p>因此我觉得需要一个通用的、工具性质的兼容层项目，目前命名为 EthBFT。这个项目的愿景是，提供简洁、开放、最小实现、工具性质的架构，达到集成 Geth 和 CometBFT 的目的。整个区块链网络的架构会是这样：</p><pre><code class="text">Geth -&gt; EthBFT -&gt; CometBFT</code></pre><p>EthBFT 主要干两件事情：</p><ol><li>通过以太坊执行层的 Engine API 拿区块数据</li><li>把区块数据通过 ABCI 接口提交到 CometBFT</li></ol><p>这里虽然用 Geth 举例，但对于其他以太坊的执行层客户端，应该也是通用的，因为以太坊的执行层和共识层客户端，本来就是互相兼容的，仅仅通过 RPC 接口通信。所以预计 EthBFT 可以兼容全部的以太坊执行层客户端。</p><p>而 EthBFT 的设计，自然不会和 Geth 或者 CometBFT 有代码层面的耦合，EthBFT 是一个独立的进程，可以单独启动，Geth 也可以单独启动，CometBFT 也可以单独启动，3 个组件之间，彼此通过 RPC 接口通信，具体的 RPC 接口地址等信息则会体现在 EthBFT 的配置文件中。</p><p>这就让 3 个组件互相之间，完全解耦了。</p><h3 id="对-PBFT-的信心"><a href="#对-PBFT-的信心" class="headerlink" title="对 PBFT 的信心"></a>对 PBFT 的信心</h3><p>我之前以为区块链技术的发展会趋于追新，也会趋于去中心化，但是发现似乎不是那样。</p><p>从前两年的 Celestia 使用了 PBFT，到 Hyperliquid 改进了 PBFT 共识，再到最近 Arc 项目自己实现了 PBFT 共识，证明在高TPS的场景下，PBFT算法还非常有活力。</p><p>PoW 和 PoS 去中心化程度高，但是不能满足高 TPS 的需求，也不能达到最终一致性的要求，这些都是 PBFT 特有的优势，尤其是企业级的应用场景下，没那么在意去中心化。</p><p>我们也许会有疑问，如果不在乎去中心化，那直接用 Server 端提供服务不就行了吗，用区块链干什么。在丢失去中心化特性的前提下，至少区块链还保留有数据公开、数据变更可追溯等特点，也是一些不错的优势。</p><p>因此，PBFT 这种诞生接近 30 年的算法，将来还会继续发光发热。也因此，去搞一个 PBFT 相关的项目，不会有太大问题。</p><h3 id="项目前景"><a href="#项目前景" class="headerlink" title="项目前景"></a>项目前景</h3><p>EthBFT 肯定不会受到市场的关注，因为大家只在乎一条链能不能发币，能不能套利，并不在乎你的技术架构是什么。</p><p>EthBFT 只是一个工具性质的项目。如果一个开发者，想要一条以太坊完备的链，同时又想要高 TPS，在没有 EthBFT 的情况下，需要怎么做呢。我懒得展开分析对比搭建链的方案了，总之我觉得 EthBFT 可以填补这部分的空缺，非侵入式那种。世界上缺一个这样的工具。</p><h3 id="对-AI-技术的怀疑"><a href="#对-AI-技术的怀疑" class="headerlink" title="对 AI 技术的怀疑"></a>对 AI 技术的怀疑</h3><p>现在 <a href="https://github.com/smallyunet/ethbft">smallyunet&#x2F;EthBFT</a> 项目已经有了基本的框架，能跑通最小版本，我把它归档为 <a href="https://github.com/smallyunet/ethbft/tree/v0.0.1">v0.0.1 版本</a>。能跑通的表现是 Geth 的区块高度会逐渐增加，CometBFT 也在正常出块，Geth 和 CometBFT 的区块高度保持同步。当然现在还属于非常早期的版本，开发时间有限，功能上肯定有不完善的地方，接下来还会继续改进。</p><p>我之前说 <a href="/2025/04/12/%E9%BC%93%E5%90%B9Cursor%E7%9A%84%E4%BA%BA%E6%8A%80%E6%9C%AF%E8%83%BD%E5%8A%9B%E9%83%BD%E5%B7%AE/">鼓吹 Cursor 的人技术能力都差</a>，因为 AI 可以放大你的能力，但是不可能代替你懂。v0.0.1 版本的 EthBFT，全部代码都是 AI 写的，没错，但是以 EthBFT 这个项目为例，现在要干的事情非常清晰，你可以试试，在不懂以太坊和 Cosmos，甚至不懂技术的情况下，完全托管给 AI，能不能搞出一个能运行的、EthBFT 这样的项目。</p><p>如果你自己对技术的理解不清晰，或者有错误，关键是 AI 不会纠正你的错误，因为 AI 并不知道你心里想要的 “正确” 是什么。AI 会非常听话地按照你的描述写代码，如果你语焉不详，AI 写出来的代码必然会跑偏，朝着错误的方向发展，而且很多时候 AI 会自己偷偷埋坑，你以为它实现了，结果它要么没写全，放了个 TODO 在那儿，要么按照自己的理解写出一大堆不需要的代码。</p><p>所以让 AI 把代码写对，其实不是一件容易的事情，首先你自己得懂，然后你得时刻盯着它干活。AI 始终只是助手而已。</p>]]></content>
  </entry>
  <entry>
    <title>对 Soneium 项目的分析</title>
    <link href="https://crazy.smallyu.net/2025/09/01/%E5%AF%B9Soneium%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/09/01/%E5%AF%B9Soneium%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-09-01T03:11:51.000Z</published>
    <updated>2025-11-27T17:16:12.955Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>最近 Soneium 在进行一个 <a]]></summary>
    <content type="html"><![CDATA[<p>最近 Soneium 在进行一个 <a href="https://portal.soneium.org/en/profile/0x62553349432e9574f5953D379374b9893b148E05">积分任务活动</a>，估计会和后续的空投相关联。积分和任务面板都做的很漂亮，交互也很舒服。我之前没有参与过撸毛，这次有兴趣参与一下，所以也看一下 Soneium 这个项目的技术情况。</p><img src="1.png" width="60%"><p>Soneium 是索尼推出的区块链网络，就是制造相机和拍电影那个索尼，公司背景非常强大，应该是没兴趣自己发币的，至少不是以发币为目的发行一条链。Soneium 是一条以太坊的 Layer2 网络，所以接下来技术方面的内容，应该会聚焦到以太坊 Layer2 上，比如用了哪种 L2 方案，网络参数是什么，有没有创新和改进，等等。</p><p>Soneium 的<a href="https://docs.soneium.org/docs/builders/notices/notice-pectra">文档</a>里明确说了，用的 OP Stack 方案，并且加入了 Superchain 生态，应该是直接使用了 OP Stack 开源出来的技术方案，没有自己做改进那种。这其实也有意思，一方面，Base 和 Sony 都在用 OP Stack 做 Layer2，项目周期肯定是一年以上的。另一方面，Vitalik 一直在说 ZK 是未来技术发展的趋势，要用 ZK 技术把 L2 的提款速度<a href="https://www.reddit.com/r/CryptoCurrency/comments/1mk50u4/vitalik_buterin_the_next_goal_we_should_shoot_for/">缩短到 1 小时内</a>。假如 ZK 体系成熟了，OP Stack 能无缝升级吗？感觉不太能，因为历史交易完全不能验证。</p><img src="2.png" width="100%"><p>（我发现 Vitalik 的博客现在不能访问了 <a href="https://vitalik.eth.limo/">vitalik.eth.limo</a> ，应该不是简单的网络问题。这就是用 IPFS 搭博客的坏处。以前 Vitalik 有个 .ca 域名的博客，后来直接不用了，转到了 .eth.limo 上。）</p><p>这也引起我们一个思考，Sony 现在都在用 OP Stack 搞 L2，我们要不要搞呢？现在 L2 已经不是两年前的热度了，但是 OP Stack 的技术方案经过了生产级别的验证，现在更稳定可靠。至于 ZK L2，有个问题是需要非常强大算力的服务器来做 prover，跟矿机一样，有点不是太友好。</p><p>在技术难度上，OP Stack 的部署和运维是相对简单的，而且只需要 follow OP 的技术动态就可以，对于企业或者项目方来说，也许会是不错的选择。当然，只是得维护一大堆 <a href="https://docs.soneium.org/docs/builders/contracts">合约</a> 了。</p><img src="3.png" width="80%"><p>说实话 Soneium 在技术上没啥亮点，这个项目简单到连白皮书都不需要，玩的就是生态。</p>]]></content>
  </entry>
  <entry>
    <title>2025 年 8 月的面试记录</title>
    <link href="https://b.smallyu.net/2025/08/31/2025%E5%B9%B48%E6%9C%88%E7%9A%84%E9%9D%A2%E8%AF%95%E8%AE%B0%E5%BD%95/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/31/2025%E5%B9%B48%E6%9C%88%E7%9A%84%E9%9D%A2%E8%AF%95%E8%AE%B0%E5%BD%95/</id>
    <published>2025-08-31T03:13:04.000Z</published>
    <updated>2025-12-04T13:51:10.767Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>这个月的面试真的好少……有点无奈。</p>
<ul>
<li>2025.08.07（UZX）</li>
</ul>
<p>交易所的钱包开发职位，Java开发岗，面试 10 分钟就结束了。</p>
<ul>
<li>2025.08.12（Matrix]]></summary>
    <content type="html"><![CDATA[<p>这个月的面试真的好少……有点无奈。</p><ul><li>2025.08.07（UZX）</li></ul><p>交易所的钱包开发职位，Java开发岗，面试 10 分钟就结束了。</p><ul><li>2025.08.12（Matrix Port）</li></ul><p>风控部门的后端开发职位，重点在乎微服务一类技术。</p><!--- 2025.08.14这家公司希望我以兼职（代码外包）的形式参与到项目开发中，我目前答应了。目前我需要开发的是钱包后端类型的服务，让 APP 端能查余额、查交易什么的。做这个事情就不是为了钱，只是顺手做点事情而已。接这个活的主要原因有：- 和项目负责人建立联系，也许后续能有更多机会- 帮忙的心态，也不至于让自己的空窗期没事干- 不太指望钱，我也不太会估算，也许最后交付的时候，按照 100 RMB/小时 报价--><ul><li>2025.08.17</li></ul><p>一个线下交流会，不是面试，我主要也是看有没有工作机会才去的。</p><p>很无聊，是一个叫王道元的人组织的，我在活动行上看到的活动。我从一开始就感觉这个活动有问题，因为这个人看照片就不太聪明的样子。后来到了交流会现场，还真是不太聪明，说自己是研究易经的。</p><p>离谱的是，这样的人，竟然能给比特币募资项目做策划，他们现在在整的项目，也私募到了90万人民币左右。我很奇怪，为什么这些人挣钱这么容易，脑子不好，傻子太多。这个交流会本身，是他们私募拉人的渠道。</p><p>至于项目本身，就是不懂行的人在试图搞传销。</p><ul><li>2025.08.18（tako.so）</li></ul><p>项目基于 Op Stack 搭建一条链，试图把社交行为上链。重点集中在研究提升 Layer2 的 TPS 上，研究怎么把交易并行处理、优化冲突检测方面。</p><p>面试官比较重视 Go 语言的底层，比如 GMP 的原理、Context 的实现原理等。这些语言相关的技术我都没有关注过。</p><ul><li>2025.08.20（cina）</li></ul><p>Solidity 开发岗位，面试官有点为难，因为我很少有 DeFi 相关的工作经验，所以不知道该具体问我哪些问题。</p><p>但是面试挺有意思的，面试官人不错，分享了很多对 DeFi 生态的见解。</p><ul><li>2025.08.22（艺洲科技）</li></ul><p>和老板聊，对方介绍了一些项目情况。</p><ul><li>2025.08.23（艺洲科技）</li></ul><p>技术面二面，非常简单地聊了一下。</p><p>这个项目不是很靠谱，选择接受这个项目的原因有：</p><ul><li>先接着，看看情况，工作强度、技术含量等</li><li>骑驴找马，还要继续找工作</li><li>这个项目给的全是代币，很不靠谱</li><li>刷一点经验，简历上能多写一条</li></ul><p>最后因为同事的态度问题，没有加入。</p><ul><li>2025.08.25（bitget）</li></ul><p>链上数据特征分析岗位。随便聊一聊。面试官水平不行。</p><p>我不是说面试官不可以 “水平不行”，只是有时候想不明白，为什么水平不行的人，可以当面试官。</p><ul><li>2025.08.28（不知道公司）</li></ul><p>做 ZK Layer 2 链的公司。</p><!--- 2025.08.31（Venture Labs）随便聊聊。--><h3 id="有感而发（2025-09-02）"><a href="#有感而发（2025-09-02）" class="headerlink" title="有感而发（2025.09.02）"></a>有感而发（2025.09.02）</h3><p>经过这么多次面试，我发现，凡是在面试中只关心你能不能干某一件事情的，这种面试都不靠谱。</p><p>比如在过去的工作中，你干过 10 件事情，然后有的面试官只关心其中 1 件事情，问你能不能做，到什么程度。而其他 9 件事情，面试官视而不见，丝毫不提。他根本不是在招聘你这个人，而是在招聘一个能干某个活的人，这种位置必然是工具人。这种公司不去也罢。</p><p>还有一种情况我也不理解，面试官说，你说你没有了解过某些东西，那你去了解一下，了解之后我们再来聊。</p><p>我觉得这样的做法非常不合理，技术调研本就是工作之中的事情，现在你要我先调研，证明自己的能力，然后继续面试？我觉得这样的做法很侮辱人。我不是不愿意学，反而很有兴趣，但是这种态度和姿态，让我感到生气。我不想去这种公司和项目，面试官不尊重人。</p>]]></content>
  </entry>
  <entry>
    <title>对 Berachain 项目的分析</title>
    <link href="https://crazy.smallyu.net/2025/08/31/%E5%AF%B9Berachain%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/08/31/%E5%AF%B9Berachain%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-30T16:19:23.000Z</published>
    <updated>2025-11-27T17:16:12.928Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>上周分析 Arc 项目的时候，提到 Arc 的一大亮点，是自己开发了 Rust 版本的 Malachite 共识，然后开发了一个兼容层，对接原生的 Reth 作执行层。这是一个很有意思的事情，于是我想到，那么有没有人开发 CometBFT 和 Geth 的兼容层，把]]></summary>
    <content type="html"><![CDATA[<p>上周分析 Arc 项目的时候，提到 Arc 的一大亮点，是自己开发了 Rust 版本的 Malachite 共识，然后开发了一个兼容层，对接原生的 Reth 作执行层。这是一个很有意思的事情，于是我想到，那么有没有人开发 CometBFT 和 Geth 的兼容层，把 Geth 和 CometBFT 接起来呢？</p><p><a href="https://www.berachain.com/">Berachain</a> 就干了这个事情。要是只看 Berachain 的官网，肯定会觉得这是一个不怎么严肃的项目，因为首页用了一堆花里胡哨的元素展示信息。但是 Bearchain 开源了一个叫 <a href="https://github.com/berachain/beacon-kit">beacon-kit</a> 的仓库，作用就是对接 CometBFT 和 Geth，一键启动一条原生 EVM 客户端 + PBFT 共识的链。（如果 Bearchain 没干这个事情，我就想干）。Berachain 的项目创意是受到 Arc 启发吗？不好说。</p><p>在没看代码的情况下，猜测把 Geth + CometBFT 中间层需要做的事情，大概是当 Geth 生成 Payload 后，把 Payload 给 PBFT 出块，然后把出块结果返回给 Geth。所以应该不会特别复杂，主要是监听两侧的事件，然后做好接口之间的字段转换。</p><p>不过从 beacon-kit 的代码量和提交次数来看，这事好像没那么简单，或者 Berachain 把事情做复杂了。malaketh-layered 的代码量显然没那么大。</p><p>因为项目复杂，具体的源码解读还需要点时间。目前关注到的一个疑点是 Berachain 沿用了 <a href="https://github.com/berachain/beacon-kit/blob/main/consensus/types/slot_data.go">slot</a> 的概念，这有点奇怪，slot 是以太坊共识层的概念，Geth 里没有，CometBFT 里也没有。当然，Bearchain 是提供了一些解释的，比如 <a href="https://github.com/berachain/beacon-kit/blob/main/CLAUDE.md#cometbft-integration-abci">架构文档</a> 里提到 slot 和区块高度的映射关系，以及 <a href="https://github.com/berachain/beacon-kit/blob/main/state-transition/core/state_processor.go#L127">代码注释</a> 中提到 Bearchain 的设计不允许有空槽等。</p><p>beacon-kit 还需要维护数据库、做状态转换……总之初看这个项目感觉没有想象中那么简单，虽然不是开发新的链，听起来像是在集成一些启动脚本，然而事实上做的事情又有点多，多到我有点怀疑这些东西是不是必要的……我觉得有必要后续再深入了解下源码，并且自己试着做一个兼容层试试。</p><p>在看到 Berachain 文档中关于 <a href="https://docs.berachain.com/learn/pol/">Proof-of-Liquidity</a> 的部分后，基本上就能知道 beacon-kit 确实是偏复杂的，因为 beacon-kit 根本不是一个工具类型的仓库，而是带有 Berachain 特有的一些经济模型逻辑，比如有 <a href="https://github.com/berachain/beacon-kit/blob/main/contracts/src/brip0004/MockPoL.sol">MockPOL</a> 相关的合约代码等，beacon-kit 就是 Berachain 本身，复杂也是能理解的了。看来世界上应该还需要另一个轻便一点的兼容层。</p><p>至于 Bearchain 的其他方面，因为是 EVM 兼容的链，所以各种 DAPP 自然能玩。X 上有接近 1 M 的粉丝，关注量很高，代币 $BERA 在今年 2 月份就上了币安等交易所，市值排名 150 名左右。我有点小看 Berachain 的经济实力了，竟然在分析这个市值排名第 150 的链。这已经没什么可怀疑的，主要还是学习下 Bera 的技术。</p>]]></content>
  </entry>
  <entry>
    <title>我的加密货币定投策略（二）</title>
    <link href="https://smallyu.net/2025/08/28/%E6%88%91%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E5%AE%9A%E6%8A%95%E7%AD%96%E7%95%A5%EF%BC%88%E4%BA%8C%EF%BC%89/"/>
    <id>blog:https://smallyu.net/2025/08/28/%E6%88%91%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E5%AE%9A%E6%8A%95%E7%AD%96%E7%95%A5%EF%BC%88%E4%BA%8C%EF%BC%89/</id>
    <published>2025-08-28T10:46:21.000Z</published>
    <updated>2025-11-17T14:36:55.436Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>前情提要：《<a]]></summary>
    <content type="html"><![CDATA[<p>前情提要：《<a href="/2024/08/28/%E6%88%91%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E5%AE%9A%E6%8A%95%E7%AD%96%E7%95%A5%EF%BC%88%E4%B8%80%EF%BC%89/">我的加密货币定投策略（一）</a>》</p><h3 id="新的定投策略"><a href="#新的定投策略" class="headerlink" title="新的定投策略"></a>新的定投策略</h3><p>现在把新的定投策略调整为这样：</p><ol><li>定投频率：每周一次</li><li>定投金额：100 美元</li><li>定投标旳：比特币（BTC）</li></ol><p>就这么简单，不再整那些花里胡哨的东西，只投比特币。至于以太坊或者其他平台币，想用的时候买就行了，手续费用不了多少，价格也高不了多少，没必要因为 “可能要用” 而提前布局。</p><p>你也许会犹豫，比特币现在的价格这么高了，还可以买吗？定投策略本身就是在消除对入场时机的顾虑，毕竟这是定投，不会一下子把钱砸进去，所以不用那么在意此时此刻的价格。关于定投策略的优点，李笑来的《定投改变命运》里已经有非常详细的解释，这里不多复述。</p><p>你也许会纠结，以太坊最近涨了那么多，接近历史新高，ETH&#x2F;BTC 汇率持续走高，BTC 市占率持续下跌，为什么只选择定投 BTC 这一个币种？我的建议是，不要 FOMO。在接下来半年到一年的时间里，像以太坊一样动人心弦的例子还会有很多，不是可能有，是一定会有，也许每一次都会让你后悔，当初怎么没选这个币？要是早点买早点定投就好了。所以还是那句老话，不要 FOMO。</p><h3 id="之前的错误"><a href="#之前的错误" class="headerlink" title="之前的错误"></a>之前的错误</h3><p>我之前犯了很严重的错误，也许是出于想体现出自己 “知道的多” 的心理，在定投组合中，选择了非常多小币种。现在差不多一年过去了，根据计算，实际上的收益效果比较差，大概在 22% 左右，这个收益率还不如全买 BTC 的涨幅。</p><p>当时有几个月的时间，我确实是按照定投组合在操作，但是后来由于这些原因，我自己都没能坚持下来定投这件事情：</p><ol><li><p>某些币种比例太小，导致金额也小，假如一天定投 10 美元，某个代币占比 5%，一天就是 0.5 美元，一个月下来一共 15 美元。这样的金额即使涨 50% 或者跌 50% 都不会有感觉。而且这种小金额的代币一直放在账户里，也会让人不舒服。所以主观感受上，天天看到这些币种很难受，会想清理掉他们。</p></li><li><p>由于我时常关注加密行情的变化，有时明明知道价格下跌了，但是由于定投计划的存在，我无法手动加仓；有时明明知道价格上涨了，但是由于定投计划的存在，无法暂停定投。这样的感觉也很难受，像是被定投计划操控一样。</p></li><li><p>对于山寨币的风险预估不足，后来逐渐认识到山寨币的价值有限，而定投计划一开始给了山寨币比较高的比例，造成我头脑中的计划调整频率很快，快到定投策略跟不上。另外由于我的投资预算的不稳定，也就是收入和支出的不稳定，经常需要动一些钱，导致定投计划不得不暂停、重新开始。</p></li></ol><p>所以不管以前怎么回事，以前的定投策略始终是有问题的，连我自己都无法好好实施。</p><h3 id="黄金"><a href="#黄金" class="headerlink" title="黄金"></a>黄金</h3><p>注意这里只是 “加密货币” 的定投策略，不包含其他资产类型。比如价格锚定黄金的 PAXG 代币，不属于 “加密货币定投策略”，但是我会买、会定投，策略也是一样的：</p><ol><li>定投频率：每周一次</li><li>定投金额：100 美元</li><li>定投标旳：黄金（PAXG）</li></ol><h3 id="美股"><a href="#美股" class="headerlink" title="美股"></a>美股</h3><p>要这么说，把 BTC 和 PAXG 两个代币列出来不就行了吗？为什么还要强调黄金是不同于加密货币的资产类型？</p><p>因为 Kraken （海妖交易所）上支持买美股了。代币是发行在 Solana 链上的。我不懂美股，现在不能制定美股的定投计划。假如认为价格锚定黄金的代币算加密货币的话，那价格锚定美股的代币，算不算加密货币呢？事情就变复杂了。</p><p>美股上链这事还挺有意思，给未来带来了很多可能性。时代在发展，社会在进步，越来越有意思了。</p><h3 id="关于卖出策略的疑问"><a href="#关于卖出策略的疑问" class="headerlink" title="关于卖出策略的疑问"></a>关于卖出策略的疑问</h3><p>人们常说，你无法同时拥有青春和对青春的体验。同样的道理，你无法同时享受拥有比特币，和比特币价格上涨带来的财富。</p><p>假如你现在还年轻，你需要钱，你要买车，你要旅游，你要体验生活。然后你把比特币卖了。等到老年之后，你会不会后悔？也许到时候会想，假如当时没卖掉，现在价值可就翻了很多倍。</p><p>要么放弃当下的享受，要么换来日后的后悔。怎么选呢？</p>]]></content>
  </entry>
  <entry>
    <title>我再次拒绝一份工作的原委</title>
    <link href="https://b.smallyu.net/2025/08/26/%E6%88%91%E5%86%8D%E6%AC%A1%E6%8B%92%E7%BB%9D%E4%B8%80%E4%BB%BD%E5%B7%A5%E4%BD%9C%E7%9A%84%E5%8E%9F%E5%A7%94/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/26/%E6%88%91%E5%86%8D%E6%AC%A1%E6%8B%92%E7%BB%9D%E4%B8%80%E4%BB%BD%E5%B7%A5%E4%BD%9C%E7%9A%84%E5%8E%9F%E5%A7%94/</id>
    <published>2025-08-26T10:48:26.000Z</published>
    <updated>2025-12-03T09:25:54.153Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>前两天，我再次因为同事的态度问题，拒绝一份工作。</p>
<p>为什么说是 “再次” 呢，上一次遇到类似的情况，是在：</p>
<ul>
<li>《<a]]></summary>
    <content type="html"><![CDATA[<p>前两天，我再次因为同事的态度问题，拒绝一份工作。</p><p>为什么说是 “再次” 呢，上一次遇到类似的情况，是在：</p><ul><li>《<a href="/2025/03/22/%E4%BB%8E%E5%9B%A2%E9%98%9F%E5%86%85%E9%83%A8%E7%9A%84%E6%B7%B7%E4%B9%B1%E6%83%B3%E5%88%B0%E2%80%A6%E2%80%A6/">从团队内部的混乱想到……</a>》</li><li>《<a href="/2025/03/25/%E5%85%B3%E4%BA%8E-Code-Review-%E7%9A%84%E7%A4%BC%E8%8A%82/">关于 Code Review 的礼节</a>》</li><li>《<a href="/2025/04/12/%E9%BC%93%E5%90%B9Cursor%E7%9A%84%E4%BA%BA%E6%8A%80%E6%9C%AF%E8%83%BD%E5%8A%9B%E9%83%BD%E5%B7%AE/">鼓吹 Cursor 的人技术能力都差</a>》</li><li>《<a href="/2025/04/13/%E5%9B%A0%E4%B8%BA%E5%90%8C%E4%BA%8B%E7%9A%84%E4%B8%8D%E5%B0%8A%E9%87%8D%EF%BC%8C%E6%88%91%E6%8D%A2%E5%B7%A5%E4%BD%9C%E4%BA%86/">因为同事的不尊重，我换工作了</a>》</li><li>《<a href="/2025/07/26/%E5%9B%9E%E5%BF%86%E5%90%8C%E4%BA%8B%E8%A2%AB%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%90%8C%E4%BA%8B%E8%B5%B6%E8%B5%B0%E7%9A%84%E4%BA%8B%E6%83%85/">回忆同事被另一个同事赶走的事情</a>》</li></ul><p>一个人，能让我连写 5 篇博客，从各个角度去思考这件事情，也算是不一般了。</p><p>而这一次，因为我参与项目不深，所以不需要考虑太多，直接拒绝就好了。</p><p>我在口头答应加入项目后，经过了一天时间，就感受到了项目各种不靠谱的地方，所以选择离开。</p><p>项目里有个同事，老板给他反复打电话，他不接。老板特别着急，说有几百万的投入收不回来，十几号人等着他测功能。那个同事却闲情雅致，在给猫做绝育。然后老板打电话给我，对我说了一些带情绪的话，说的好像我和那个同事是一伙似的。我仅仅加入项目一天而已，而且是周末，连交接都没有，我都还没有开始正式工作。</p><p>我搞不懂这些人是怎么回事，反正很乱，老板和开发之间节奏脱节。这个项目招人，就是因为那个同事不靠谱，出活慢，才开始招人。然而事实上开发进度已经延迟了（我有点不懂，为什么我遇到不止一个项目，都是进度已经出问题了，才招人）。我的工作是帮这个同事分担工作，但是这个同事竟然不愿意花时间跟我交接。搞不懂。</p><p>这么凌乱的项目，你们自己去玩吧。</p><p>我的工作反复因为这种人而不稳定。是他们对我不好，我只是不想让自己受委屈而已。</p><p>从去年开始，我的职业道路就很不稳定。我想，只要我愿意 “受气”，就可以有稳定的工作、稳定的收入。</p><p>但是我不愿意。</p><p>我有时候也怀疑，自己是不是应该放低姿态，去忍受职场上各种各样的问题，忍受那些不礼貌、不尊重人的行为。</p><p>我的出身并不好，学历也不好，像我这样的人，在中国社会里比比皆是，泯然众人。</p><p>很多名牌大学的人，甘愿在公司里忍气吞声，沦为牛马、都市隶人。</p><p>我又有什么资格，表现出如此强硬的姿态，连续两次主动拒绝工作？</p><p>这引起一个问题，是不是只有有钱、有地位、特别优秀的人，才有资格拥有尊严、得到尊重、站着挣钱？</p><p>我觉得不应该是那样。</p><p>我们工作中挣的工资，是劳动报酬。我付出劳动，你给我报酬，合情合理，公平交换，谁也不占谁的便宜。</p><p>但是有些老板、同事，自以为给了钱，或者工资高，或者年龄大，就以居高临下的口气跟你说话，甚至把某些情绪带到和你的对话中。这是他们缺乏教养。</p><p>技术问题我可以解决，但是情绪问题？你以为你是谁？</p><p>我遇到过不止一个老板，认为只要花钱，就可以招到人，只要花钱，就可以解决问题，只要花钱，别人就愿意给他工作。</p><p>至少我不愿意成为那样的人。</p><p>很多人畏惧于孔乙己脱不下的长衫，但是却不去质疑，孔乙己所处的社会环境是不是有问题？一帮干力气活的人去笑话一个文人，是不是本身就很荒谬？</p><p>出身卑微，人格也必须卑微吗？</p><p>我过往的工作经历，已经能证明我可以做出某些事情。我在博客上维护的这些内容，也可以佐证我懂一些东西。这两个部分加起来，可以说明我有一些实力。只是我有点不确定，这种实力标签，能不能掩盖 “出身不好”、“学历不好” 这种社会标签。</p><p>我想起一个有意思的现象，凡是看过我博客的面试官，在面试中都会表现出某种 “没气势”，即使工作不合适，也会友善的交流。而那些在面试中各种考核我、给我出题、甚至出言不逊、表现出不尊重的，都是没看过我博客，甚至我的简历他们都没仔细看的。他们面试人就一套标准模板，根本不在乎你的简历。</p><p>以前我的博客都是毫无保留的，最近开始收敛，比如之前写的《我从王垠的计算机科学课学到了什么》，后来我就想，我为什么要毫无保留的说出，我学到了哪些东西？所以目前就只剩下一个片段《<a href="/2025/08/25/%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%AF%BE%E7%A8%8B%E8%B4%B5%E5%90%97%EF%BC%9F/">王垠的计算机课程贵吗？</a>》。博客内容的其他方面也还在调整。我其实不喜欢什么 “GMP原理”、“比特币脚本教程”、“DeFi教程” 什么的，都是很生硬的技术，没意思。但是我不写出来，有的人就觉得你不会，所以是没办法才写。</p><p>回到工作的话题。经过我切实的工作经历，我发现一线城市之外，尤其是连深圳那种二线城市都不如的，像什么厦门、南昌一类，生活在那些地方的同事，往往更容易工作能力不行、工作态度不好、工作带情绪、脾气大、不尊重人、不礼貌什么的。这一定不是个例，一方面那些地方文明程度低，生活节奏慢，可能脱离职场环境。另一方面，生活在那些地方而不是一线城市，本身就说明这个人能力不行，混不下去了回老家。所以工作中，尤其是这个行业的工作中更容易接触到，来自天南地北的同事，要警惕那些生活在小城市的同事。这也就说明了，为什么有些公司招聘，即使允许远程，也要求工作地的原因。</p><p>虽说中国的月亮没有外国的圆，但是中国的一线城市，即使放眼全世界，也是能排得上号的那种。你要说上海不如纽约，我觉得不如。但是不和顶尖的城市相比，中国的一线城市，本身还行。所以如果不能全球各国去跑，也至少要停留在一线城市。</p>]]></content>
  </entry>
  <entry>
    <title>王垠的计算机课程贵吗？</title>
    <link href="https://b.smallyu.net/2025/08/25/%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%AF%BE%E7%A8%8B%E8%B4%B5%E5%90%97%EF%BC%9F/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/25/%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%AF%BE%E7%A8%8B%E8%B4%B5%E5%90%97%EF%BC%9F/</id>
    <published>2025-08-24T17:05:32.000Z</published>
    <updated>2026-01-26T06:42:18.496Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<h3 id="课程的稀缺性"><a href="#课程的稀缺性" class="headerlink" title="课程的稀缺性"></a>课程的稀缺性</h3><p>设想一下，假如你不想学<a]]></summary>
    <content type="html"><![CDATA[<h3 id="课程的稀缺性"><a href="#课程的稀缺性" class="headerlink" title="课程的稀缺性"></a>课程的稀缺性</h3><p>设想一下，假如你不想学<a href="https://www.yinwang.org/blog-cn/2025/05/12/cs-video-course">王垠的课</a>，但是又想掌握课程中的知识，有哪些途径？</p><p>你花同样的钱，是没有其他地方可买的。世界上还有其他华人，能有王垠的学识背景，并且在经过几年的教学试验后，整理出如此精品的课程吗？这种水平的课程，有市无价！</p><p>你也可以自己去求学，先掌握流利的英语，然后考个美国顶尖大学的硕士，经过几年的留学生涯，不但花很多钱，还要付出许多时间、精力和努力，还需要一些天赋和运气，才能学到与王垠课程同等水平的知识。你付出的代价，远远不是只花钱就够的。</p><p>你还觉得王垠的课程贵吗？</p><h3 id="课程的内容"><a href="#课程的内容" class="headerlink" title="课程的内容"></a>课程的内容</h3><p>我刚才对王垠课程的描述是 “这种水平的课程”，那到底是什么水平呢？我可以举个具体的例子。</p><p>课程的第 1 课讲函数，对吧，所有程序员都知道函数是什么，即使不是程序员，初中上数学课也知道函数。</p><p>学习课程以前，函数是什么？函数是编程语言的语法之一，作用是把很多行代码包裹起来，方便以后重复调用。面向对象里面叫 “封装”。函数就是个特别基础的概念。</p><p>学习课程以后，函数是什么？函数可以是 “计算” 的基本元素，函数可以作为计算的输入，也可以作为计算的输出，一个计算的输出可以作为另一个计算的输入，输出的函数可以被另外的函数调用……</p><p>我这么说你肯定没看明白。</p><p>换个角度解释，王垠的导师 <a href="https://www.yinwang.org/blog-cn/2012/07/04/dan-friedman">Daniel P. Friedman</a>，有一本出版的书《<a href="https://www.thelittlelearner.com/">The Little Learner</a>》，Guy L. Steele Jr. 在给这本书的序言中写到，Friedman 在这本书里用高阶函数（higher-order functions）的 4 种不同用途，表达了机器学习（machine learning）的核心原理。</p><p>你是不是不相信，函数可以表达深度学习的原理？那就去了解一下 lambda calculus，一种和图灵机同等地位的形式化系统，可以表达的是整个计算机体系，而不只是深度学习。</p><p>这才是 “函数”。第 1 课学的函数，是这个函数。</p>]]></content>
  </entry>
  <entry>
    <title>我从王垠的计算机科学课学到了什么（两个月版）</title>
    <link href="https://b.smallyu.net/2025/08/24/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%882/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/24/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%882/</id>
    <published>2025-08-24T04:12:12.000Z</published>
    <updated>2026-07-17T06:27:38.397Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>为了行文方便，这篇文章不使用 “王垠老师” 这样的尊称，直接称呼名字 “王垠”。</p>
</blockquote>
<h3 id="学习时长"><a href="#学习时长" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<blockquote><p>为了行文方便，这篇文章不使用 “王垠老师” 这样的尊称，直接称呼名字 “王垠”。</p></blockquote><h3 id="学习时长"><a href="#学习时长" class="headerlink" title="学习时长"></a>学习时长</h3><p>大约 3 个月前，我开始报名学习王垠的 <a href="https://www.yinwang.org/blog-cn/2025/05/12/cs-video-course">计算机科学视频班</a>（基础班），经过 1 个月的学习后毕业，大概用了 120 个小时的学习时长。“120 个小时” 这个数字是经过认真估算的，包含了观看视频的时间和做练习题的时间。因为视频课的学习节奏由自己把控，毕业速度因人而异。</p><p>如果我说学了 1 个月，也许有人很不在乎，1 个月的时间能学到多少知识呢？世界上没有速成班，王垠也不可以。1 个月的时间确实不可能学到各种全面的知识，时间上也不允许。但是 1 个月的时间能不能帮我把过往的编程技能梳理一遍，让我对计算机科学有更加体系化的认识？我在工作中可能见过各种迷雾，王垠的课程能不能让我拨云见日，看清楚很多东西？</p><p>学习课程就像是去西天取经，顺利毕业相当于取到了真经。但是学习课程的过程只是老师帮你理解经书内容而已，取到真经不代表你已经对经书中的内容融会贯通，还需要在日后多加修炼、理解透彻才行。想必有的同学拿到经书（毕业）后再也不会打开看一眼，于是认识不到课程真正的价值含量。</p><h3 id="课程体会"><a href="#课程体会" class="headerlink" title="课程体会"></a>课程体会</h3><p>现在课程毕业后，经过 2 个月时间的沉淀，我想分享一下 “从课程中能学到什么” 这个话题。没有在毕业当天做总结，是因为怕有点浮燥总结不全，或者掺杂太多个人经历。2 个月的时间其实也不够，我没有太多时间复习，课程也远远没来得及发挥出应有的成果，但是现在做总结并不妨碍以后对课程内容有进一步的感悟。</p><p>王垠曾经有一篇文章《<a href="https://yinwang-wiki.github.io/feeds/2013-04-03-einstein-on-education.html">爱因斯坦谈教育</a>》，里面提到爱因斯坦说， “被传授的知识应该被当成宝贵的礼物”。我在学完课程后，对这句话有了切实的理解。</p><p>王垠并不认识我，但我早就认识王垠；我以前不是王垠的学生，但王垠早就是我的老师了。我关注王垠的博客多年，已经从他的博客文章中受益很多。而这次系统学习了视频课的课程，像是打开了新世界的大门。这并不夸张，我可以负责任地站在学习过课程的立场上讲，王垠没有吹牛，他的课程真的有他说的那么好。</p><p>你可以不赞同王垠的观点，也可以不喜欢王垠的人生态度，但是不可能怀疑王垠在计算机科学，尤其是编程语言领域的研究水平和造诣，也完全不需要担心王垠这样对自己和世界都如此较真的人，会拿一些没有含量的课程出来忽悠人。</p><h3 id="知识深度"><a href="#知识深度" class="headerlink" title="知识深度"></a>知识深度</h3><p>因为课程内容是保密的，我不会透露课程具体的学习内容，只基于公开的招生说明中的内容进行解释。</p><p>对于计算机初学者来说，从课程中能学到的最直接的知识，就是函数、链表、二叉树等基础的编程概念，涵盖了大学本科整个阶段的学习内容。第 6 课关于解释器的部分，属于课程的 “最终成果”，对应一些美国顶尖大学，本科高年级阶段至硕士低年级阶段的学习内容。</p><p>为什么王垠在招生说明里的描述是 “大学博士阶段才可能学到的内容” 呢？因为中国的大学没有编程语言专业，本科课程没有教解释器的，即使到了研究生阶段，lambda 演算也属于选修课，博士早期才会接触到解释器的实现是正常现象。所以王垠的描述真的没有夸大。</p><p>解释器这种内容在中国的教育体系里本来就很稀有，比较高级和精练的教程更是少见。举例来说，当你学完了王垠的课，然后去 bilibili 上搜一些解释器相关的教程，你就会明白这些公开教程里的解释器有多么差劲，不但一眼就能看出它们缺什么要素、存在什么问题，还知道如何改进、如何用最简洁的代码写出最可靠的实现。</p><p>为什么解释器这个东西重要呢？举个例子，以太坊的虚拟机（EVM）就是一个解释器，只不过 EVM 并不是在对编程语言做解释，而是在对以太坊的操作码（Opcodes）做解释，每个操作码都对应在栈结构上的一个动作。所以学过了解释器之后，对 EVM 的原理会有不一样的理解。</p><h3 id="认知提升"><a href="#认知提升" class="headerlink" title="认知提升"></a>认知提升</h3><p>对于有计算机经验的学生来说，从课程上可以学到的，就不只是表面上的知识了。比如，课程只用到非常少的编程要素，就表达了第 1 课到第 6 课的全部内容，如果王垠不是对计算机理论有非常深刻的理解，不可能做到这种地步的深入简出。</p><p>从学习者的角度，一方面可以思考为什么课程内容能如此精致，组织这些课程内容的思路是什么，这种高度抽象的思维背后，需要怎样的功底，自己距离写出这样的课程，能力上的差距还有多大。另一方面，由于课程内容自成一体，学习者完全有可能做到自己复刻整个课程内容，就像是手里的一个精致的玩物，可以随时拿出来复习把玩。</p><p>基础班的知识像是非常高级的原材料，从基础班毕业就意味着拿到了这些原材料。但原材料需要经过反复打磨、锤炼、加工，才能变成更加实际可用的装备。所以猜测有的同学学完之后感觉什么都没学到，而有的同学觉得如获至宝，能够反复加以利用并产生许多价值，大概就是这个原因吧。</p><h3 id="自学能力"><a href="#自学能力" class="headerlink" title="自学能力"></a>自学能力</h3><p>我最近忽然意识到，学完课程以后，学习其他技术好像变简单了。因为体验了课程中层层递进的教学方式，我自学其他东西也会按照这个思路来，一步一步学，自然而然就学会了.</p><p>理解 CPS、基于 continuation 原理实现协程调度，学习 Solana 合约、比特币脚本、比特币 Runes、DeFi，等等。我有点说不上这是怎么回事，明明课程里只教了一些计算机基础，链表、二叉树什么的，竟然有这样的威力。</p><p>也许从课程里学到的不只是知识，还有很好的学习方法。难怪王垠把课程内容称为 “计算机科学的精华”。</p><h3 id="超越工程的技术"><a href="#超越工程的技术" class="headerlink" title="超越工程的技术"></a>超越工程的技术</h3><p>虽然我有多年在区块链行业实际的工作经验，但是我却越来越搞不懂，区块链技术到底是什么。</p><p>我曾经大量研究区块链共识的原理，为什么关注的不是其他技术原理，比如加密学、分布式网络、储存系统等内容？因为只有共识是区块链特有的，其他都是普通的工程上的技术，包括智能合约的实现也是，而且智能合约还不是区块链必需，可以有也可以没有。至于 Layer 2 之类，也完全是工程上的尝试，哪有什么可以抽象的理论依据，挑战期、赎回期等都是业务定义的逻辑。</p><p>可以剧透一下，王垠的计算机课程，还涉及到了一部分区块链最本质的技术原理，是不是难以想象？</p><p>我发现，与不成体系的区块链工程技术相比，拥有基础而扎实的计算机功底更重要，尤其是高度抽象的思维方式，能够脱离语法但理解编程语言本质的学习方式，值得反复琢磨和理解。</p><p>我曾经以为，只要好好钻研区块链技术，就可以逐步提高自己的技术能力，就可以深入研究某些区块链原理，深入再深入，水平上自然而然超越所谓的计算机基础班，这也是我前几年没有报名学习课程的原因。然而事实上不是那样，经过几年切实的工作，我越发认识到课程内容的重要性。所以现在学习了课程，并且学到了很多。</p><h3 id="课程的启发性"><a href="#课程的启发性" class="headerlink" title="课程的启发性"></a>课程的启发性</h3><p>学完课程以后，我其实一度怀疑自己，难道这几年折腾区块链技术都是没有意义的吗？为什么学了一个零基础入门性质的计算机课，反而感觉学到了能 “改变人生” 的东西？</p><p>一直没想通这个问题，直到后来，偶然看到王垠讲述课程设计的文章《<a href="https://www.yinwang.org/blog-cn/2020/03/03/cs-course">计算机科学课程</a>》，尤其是看到 “苏格拉底方法” 段落的时候，恍然大悟，原来我的很多知识早已散落在我的头脑中，只是这门课程帮我把知识都 “生产” 了下来。我现在拥有的知识，离不开经年累月工作和学习的 “怀胎”，也离不开这门计算机课程在恰当时候的 “助产”。</p><blockquote><p>苏格拉底承认他自己本来没有知识，而他又要教授别人知识。这个矛盾，他是这样解决的：这些知识并不是由他灌输给人的，而是人们原来已经具有的；人们已在心上怀了“胎”，不过自己还不知道，苏格拉底像一个“助产婆”，帮助别人产生知识。</p></blockquote><p>这就好比，在一个陌生的城市里，你没有地图，搞不清方向，但是也可以四处游荡，有时候能走的很远。而王垠的计算机课程，像是一张完整的地图，你有了地图，各个方向和岔路口都清清楚楚，但是你未必出发，也未必耗费力气去探索远方。</p><p>我的情况相当于，已经在城市里走过了很多路，偶然有一天，拿到了整个城市的地图，幡然醒悟，明白了自己所处的位置，知道了自己原先走过哪些路。这是课程对我帮助很直接的地方。</p><h3 id="真正的编程"><a href="#真正的编程" class="headerlink" title="真正的编程"></a>真正的编程</h3><p>前几天面试的时候，面试官出了一道算法题，我拿到题目后，下意识说 “这看起来不是一道编程题，而是一些数字游戏”。我猜面试官听到我的话后，内心是充满鄙夷的，他也许会想，“这怎么不是编程题？” </p><p>我事后也惊讶，当时为什么会那样评价面试官出的题目。那是一种下意识的感受。</p><p>后来想明白，因为你一旦上过王垠的课，就会知道真正的 “编程题” 是什么。LeetCode 上那些算法题，“编程” 的含量有多少呢？学完后课程后，你可以轻易看穿那些低水平面试官的把戏。</p><h3 id="代码质量"><a href="#代码质量" class="headerlink" title="代码质量"></a>代码质量</h3><p>王垠最近在微博上评论 AI 编程的时候提到，AI 很厉害，但 AI 无法写出 “王垠级别” 的代码。</p><p>什么是 “王垠级别” 的代码呢？上过课就知道了。我在做练习题的时候，被助教提醒最多次的问题，就是 “代码复杂”，有时候是写法上的复杂，有时候是复杂度上的复杂，但是每一次把代码写到符合课程标准之后，又不禁感叹原来代码可以如此精巧。</p><p>我有多年的编程经验，让代码运行出练习题的结果并不难，但是把代码写的足够漂亮却不容易。“代码能运行” 和 “把代码写对” 之间，差距不是一般的大。假如以前给公司写的都是这种质量的代码，那公司可就太占便宜了。</p><h3 id="掌握新语言"><a href="#掌握新语言" class="headerlink" title="掌握新语言"></a>掌握新语言</h3><p>也许有人看到招生说明会怀疑，一节选修课真能让人学会一种新的编程语言吗？</p><p>我想提醒的是，不要忘了给你讲课的人是谁，是曾经写出了《<a href="https://www.yinwang.org/blog-cn/2017/07/06/master-pl">如何掌握所有的程序语言</a>》文章的作者，是真正的编程语言专家。</p><h3 id="课程的定位"><a href="#课程的定位" class="headerlink" title="课程的定位"></a>课程的定位</h3><p>我上面的描述，可能存在大量情绪表达，会让人看不懂是什么意思。</p><p>我觉得王垠的课，像是某种核心（因为基础），只要掌握了这些核心内容，你就始终算是会编程、懂计算机科学的人。</p><p>这里说的基础，不是 Hello World 那种基础，而是某种结构化的基础。这些基础知识，会帮你理解 “计算” 的本质。这些核心的基础知识，才是日后真正支撑你前进、给你力量的来源。无论上层的表达形式如何变化，本质都不会变。</p><p>我以前经常担心，会不会因为做了某些工作，导致自己偏离原先的技术道路？做一些运维相关的工作，是不是就偏离了自己开发者的初心？原本做 Go 语言开发，工作需要写一些 node.js 代码，是不是就偏离后端开发的职业路径？等等。</p><p>王垠的课程内容，就属于有 “定心丸” 功效的那种。课程教给你的，是如何搭建一套自己的 “计算模型”，而不是告诉你某些已经存在的项目具体是怎么回事。所以不要纠结于课程内容是不是全面、是不是高级，因为课程本身是讲心法的，不是讲招式的。至于具体的招式，你得自己学、自己练。</p><p>学习课程以前，我在挑选工作的时候，能不能从工作中学到东西、工作有没有成长空间、有没有发展前景，都是重点需要考虑的。学完课程以后，我在考虑的，是如何根据已经掌握的知识和技能，给团队带来帮助、给公司创造价值。心态完全不一样了。因为我不再需要从工作中学到什么，我已经知道从哪里可以学到真正的技术。</p><p>当然，这事我觉得，也要看悟性。课程教归教，能收获多少，还得靠自己。</p>]]></content>
  </entry>
  <entry>
    <title>对 Arc 项目的分析</title>
    <link href="https://b.smallyu.net/2025/08/23/%E5%AF%B9Arc%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/23/%E5%AF%B9Arc%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-23T08:37:09.000Z</published>
    <updated>2026-04-08T08:57:32.384Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p><a href="https://arcnetwork.xyz/">Arc</a> 是 Circle 公司在筹备和计划推出的一个]]></summary>
    <content type="html"><![CDATA[<h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p><a href="https://arcnetwork.xyz/">Arc</a> 是 Circle 公司在筹备和计划推出的一个 Layer 1 区块链网络。8月12日，Circle 正式发布了关于 Arc 的 <a href="https://www.circle.com/blog/introducing-arc-an-open-layer-1-blockchain-purpose-built-for-stablecoin-finance">宣发文章</a>。Circle 就是发行 USDC 代币的公司，拥有强大的技术实力和资金背景。</p><p>由于 Circle 的强大背景，我们几乎不需要怀疑 Arc 的技术含量，一定能做到世界领先级别的，也许会像当年的 SOL 一样，值得持续关注。</p><p>Arc 目前处于测试网还未公开发布的阶段，只允许合作伙伴加入的测试网。公开的参考资料只有白皮书，不过出于对 Circle 技术实力的信任，白皮书中肯定包含了技术创新在里面的。</p><p>假如将来 Arc 正式上线，想必会改变的，不只是稳定币赛道的格局：</p><ol><li>其他稳定币公司开始做 Layer 1 链</li><li>既然 USDC 可以作为原生代币支付手续费，其他所有 ERC-20 都可以</li><li>世界将迎来代币原生化的浪潮，项目发行代币的，都会自己搞一条链，自己的币付手续费</li></ol><p>所以了解 Arc 的技术架构对我们以及未来的发展会很有帮助。</p><h3 id="手续费"><a href="#手续费" class="headerlink" title="手续费"></a>手续费</h3><p>看了白皮书的前半段，发现里面仍然有很多语焉不详的地方，也有一些刻意吹牛的地方。</p><p>Arc 有专门说自己的费用模型，因为用了 USDC 做原生手续费，所以更加可以预测，比如以太坊上因为 ETH 的价格是波动的，导致用户难以准确估算一笔交易的手续费是多少，而 USDC 的价格是恒定的，只需要考虑协议费用的波动。类似这样的话其实属于很正确的废话，不需要 Arc 在白皮书里说，这是大家都能懂得东西。</p><img src="1.png" width="60%"><p>关键是 Arc 没说清楚自己的手续费到底是怎么设计的，只说参考了 EIP-1559，并且设置了平滑的波动，设置了上限和下限。理想是很好，关键是没说具体怎么做的。</p><h3 id="共识"><a href="#共识" class="headerlink" title="共识"></a>共识</h3><img src="2.png" width="60%"><p>再就是 Arc 有专门说自己链最终一致性的问题，比特币和以太坊就不是什么的。因为 Arc 用的共识是 PBFT，当然自然而然就有最终一致性，不需要刻意强调。</p><p>不过 Arc 技术硬核的地方来了，Arc 没有用某种现成的 PBFT 的实现，而是自己根据 Tendermint 的协议论文，实现了一个 Rust 版本出来，名字叫 <a href="https://github.com/circlefin/malachite">malachite</a>，代码早在去年就 <a href="https://informal.systems/blog/malachite-decentralize-whatever">开源</a> 并且处于公开研发状态。这可不是一般公司能干的了的事情。</p><p>（话说，好像最近新出的链、项目，只要是和区块链相关的，只要是有点性能方面追求的，都在用 Rust。直观感受上 Rust 的出现频率越来越高了。）</p><p>malachite 还有个有意思的项目 <a href="https://github.com/circlefin/malaketh-layered">malaketh-layered</a>，这个项目能让以太坊的执行层客户端，使用 malachite 做公式层。这个想法以及实现都很牛，也就是说，以后以太坊就有 PBFT 版本的链了。Reth+malachite 可以直接运行，联盟链将会有原生的 EVM 版本，这听起来很诱人。</p><img src="3.png" width="60%"><p>虽然 Arc 的技术实力不错，但是有个不小的问题，Arc 竟然选择了 PoA 的模式，禁止外部节点的参与，只允许合作伙伴承担起网络出块的职责。这就稍微有点影响了，对于 USDC 本身的业务没影响，影响的是整体的格局，外部无法参与的话，其他项目就不能直接抄 Arc 的模式了，不公开还要保持信任是个问题。</p><h3 id="性能"><a href="#性能" class="headerlink" title="性能"></a>性能</h3><img src="4.png" width="60%"><p>性能方面，Arc 的白皮书里也说了不少。尽管用了 Rust 语言，也只是能提高一些硬件方面的性能而已，PBFT 算法层面的限制始终在那儿，所以实际上并没有比 Cosmos 的 CometBFT 交易速度快多少。</p><h3 id="MEV-与隐私保护"><a href="#MEV-与隐私保护" class="headerlink" title="MEV 与隐私保护"></a>MEV 与隐私保护</h3><p>MEV 和隐私保护是两个东西，但解决手段相似。Arc 在 MEV 方面试图通过加密 mempool、批处理交易等方式，来避免有害的 MEV：</p><img src="5.png" width="60%"><p>类似的，在金融领域，保密的交易是一个必要的功能，有些企业不可能愿意公开自己的转账记录。</p><p>Arc 在工程上，怎么解决这些问题呢？在 malachite 的 <a href="https://github.com/circlefin/malachite/tree/main/specs/starknet">项目目录</a> 下，看到了试图兼容 Starknet 的身影。Starknet 是一个 ZK Layer 2 方案，Arc 应该是想用 Layer 2 的模式来保护隐私、避免 MEV，比如链下完成交易、生成证明，链上结算，这样就很好的解决了隐私问题。</p><p>（Starknet 的技术有点意思，尤其是 Arc 为什么选择 Starknet 而不选择 ZK Scroll 之类，说明 Starknet 的技术有可取之处，有必要关注下。）</p><h3 id="链上应用"><a href="#链上应用" class="headerlink" title="链上应用"></a>链上应用</h3><p>因为 Arc 是 EVM 完备的，自然而然就可以轻易迁移一些 DeFi 应用上去。</p><h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><p>整个白皮书看下来，有几点没解开的疑惑：</p><ul><li>USDC 作为原生代币支付手续费，具体是怎么实现的？CometBFT 可是有一整个 Cosmos SDK 做应用层。malachite 的应用层是如何设计的？</li><li>PoA 的共识是不是有点 “小气”？</li></ul><p>总结来说，一开始对 Arc 的判断稍微有偏差，Arc 没有什么黑科技。但是 Arc 仍然有强大和专业的技术实力，基于 malachite 这样的共识层，可以做出很多有意思的应用。至于 Arc 将改变世界的判断，给现有的 Layer 1 链带来冲击肯定是会的，开发者搭建区块链会多出一些选择。</p><p>还是期待 Arc 网络正式开源和上限，期待后续，然后再次对 Arc 进行技术分析和解读。</p>]]></content>
  </entry>
  <entry>
    <title>DeFi 进阶: 闪电贷与套利</title>
    <link href="https://b.smallyu.net/2025/08/21/DeFi%E8%BF%9B%E9%98%B61/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/21/DeFi%E8%BF%9B%E9%98%B61/</id>
    <published>2025-08-21T11:50:22.000Z</published>
    <updated>2025-12-03T09:25:54.134Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 DeFi 系列教程，在动手实践的过程中，学习和理解 DeFi 相关的概念与原理：</p>
<ol>
<li><a href="/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/">DeFi 基础: 理解 AMM]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 DeFi 系列教程，在动手实践的过程中，学习和理解 DeFi 相关的概念与原理：</p><ol><li><a href="/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/">DeFi 基础: 理解 AMM 定价机制</a></li><li><a href="/2025/08/21/DeFi%E5%9F%BA%E7%A1%802/">DeFi 基础: 预言机与报价</a></li><li><a href="/2025/08/21/DeFi%E5%9F%BA%E7%A1%803/">DeFi 基础: 借贷与清算</a></li><li><a href="/2025/08/21/DeFi%E8%BF%9B%E9%98%B61/">DeFi 进阶: 闪电贷与套利</a></li></ol></blockquote><p>闪电贷套利是我们经常听到的一个词，在实际的场景中有很多种模式。基于我们之前的 AMM 合约，就足以让我们来模拟一个简单版本的闪电贷套利。</p><h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>闪电贷的核心逻辑是，利用区块链智能合约的特性，在一笔交易内，借来大额资产（放大收益），拿着大额资产去执行别的操作，干什么都行，干完事情之后，再把借来的资金+少量手续费，原封不动还回去。因为智能合约是可以 revert 的，如果套利合约在执行过程中，发现最后套利没成功，可以回滚整个交易，除了手续费，没有额外损失。</p><p>我们接下来要模拟的场景时，有两个 AMM 池子，第一个池子的价格是 2000 USDC&#x2F;WETH，第二个池子的价格是 4000 USDC&#x2F;WETH。面对这样的场景，可以先想一下，不用闪电贷的情况下，应该如何套利。套利合约只不过是把我们的操作自动化了。</p><p>很简单，在第一个池子化 2000 USDC 买 1 个 WETH，到第二个池子上，直接就能卖出 4000 USDC，净赚 2000 USDC。</p><h3 id="合约说明"><a href="#合约说明" class="headerlink" title="合约说明"></a>合约说明</h3><p>我们会用到两个合约 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.4/contracts/flash/FlashLender.sol">FlashLender.sol</a> 和 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.4/contracts/flash/FlashArbBorrower.sol">FlashArbBorrower.sol</a>。这两个合约代表两个角色，其中 borrower 就是套利合约，会从 lender 那里借出一些资金。</p><p>也就是说 lender 合约，是有 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.4/contracts/flash/FlashLender.sol#L31-L35">借出资产功能</a> 的：</p><pre><code class="solidity">// 借出资产require(t.transfer(receiver, amount), &quot;transfer out&quot;);// 调用 borrower 的回调函数bytes32 magic = IFlashBorrower(receiver).onFlashLoan(token, amount, fee, data);require(magic == keccak256(&quot;IFlashBorrower.onFlashLoan&quot;), &quot;bad callback&quot;);// 验证在回调函数后，borrower 是否归还了本金+手续费uint256 balAfter = t.balanceOf(address(this));require(balAfter &gt;= balBefore + fee, &quot;not repaid&quot;);</code></pre><p>关键就是这 3 行，先借出钱，然后回调，最后判断 borrower 是否还款。</p><p>在 borrower 的回调函数里，会写一些具体的 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.4/contracts/flash/FlashArbBorrower.sol#L64C1-L71C38">套利逻辑</a>，比如从第一个池子买入 WETH，然后再卖到第二个池子：</p><pre><code class="solidity">// 从便宜的池子中买 WETHuint256 wethOut = poolCheap.swap0For1(amount);// 到贵的池子中卖 WETHuint256 usdcBack = poolExpensive.swap1For0(wethOut);// 还款给 lenderuint256 repay = amount + fee;</code></pre><p>lender 和 borrower 是两个角色，那为什么不把这些逻辑写在一个合约里呢？如果写在一个合约里，意味着只有一个套利合约的角色，自己借钱出去、自己用钱套利，我自己都有钱了还借钱干嘛？</p><h3 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h3><p>合约代码源文件在仓库：<a href="https://github.com/smallyunet/defi-invariant-lab/tree/v0.0.4">smallyunet&#x2F;defi-invariant-lab@v0.0.4</a></p><p>克隆仓库：</p><pre><code class="bash">git clone https://github.com/smallyunet/defi-invariant-lab/git switch v0.0.4cd defi-invariant-lab</code></pre><h3 id="部署第二个-AMM-合约"><a href="#部署第二个-AMM-合约" class="headerlink" title="部署第二个 AMM 合约"></a>部署第二个 AMM 合约</h3><p>部署合约：</p><pre><code class="bash">forge create \  --rpc-url $RPC_URL \  --private-key $PK_HEX \  --broadcast \  contracts/amm/SimpleAMM.sol:SimpleAMM \  --constructor-args $USDC_ADDR $WETH_ADDR 30</code></pre><p>部署后的合约地址：<a href="https://sepolia.etherscan.io/address/0xd9c870Ac0a84C3244286d39d870642d218b26532"><code>0xd9c870Ac0a84C3244286d39d870642d218b26532</code></a></p><h3 id="注入初始流动性"><a href="#注入初始流动性" class="headerlink" title="注入初始流动性"></a>注入初始流动性</h3><p>这个 AMM_B 池子我们认为是价格比较高的池子，所以按照 4000 USDC&#x2F;WETH 的价格注入初始流动性：</p><pre><code class="bash">export AMM_B=0xd9c870Ac0a84C3244286d39d870642d218b26532cast send $USDC_ADDR &quot;approve(address,uint256)&quot; $AMM_B \  0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \  --rpc-url $RPC_URL --private-key $PK_HEXcast send $WETH_ADDR &quot;approve(address,uint256)&quot; $AMM_B \  0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \  --rpc-url $RPC_URL --private-key $PK_HEXcast send $AMM_B    &quot;addLiquidity(uint256,uint256)&quot; 4000000000000 1000000000000000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><h3 id="部署-lender-并注资"><a href="#部署-lender-并注资" class="headerlink" title="部署 lender 并注资"></a>部署 lender 并注资</h3><p>部署合约：</p><pre><code class="bash">forge create \  --rpc-url $RPC_URL \  --private-key $PK_HEX \  --broadcast \  contracts/flash/FlashLender.sol:FlashLender \  --constructor-args 5</code></pre><p>部署后的合约是：<a href="https://sepolia.etherscan.io/address/0x3c00AB1eD5dF40f7ae8c1E4104C89445615B9D0a"><code>0x3c00AB1eD5dF40f7ae8c1E4104C89445615B9D0a</code></a></p><p>验证合约：</p><pre><code class="bash">forge verify-contract \  --chain-id 11155111 \  0x3c00AB1eD5dF40f7ae8c1E4104C89445615B9D0a \  contracts/flash/FlashLender.sol:FlashLender \  --constructor-args $(cast abi-encode &quot;constructor(uint16)&quot; 5) \  --etherscan-api-key $ETHERSCAN_API_KEY</code></pre><p>给 lender 转 20 万 USDC 作为初始资金：</p><pre><code class="bash">export LENDER=0x3c00AB1eD5dF40f7ae8c1E4104C89445615B9D0acast send $USDC_ADDR &quot;approve(address,uint256)&quot; $LENDER \  0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \  --rpc-url $RPC_URL --private-key $PK_HEXcast send $LENDER &quot;fund(address,uint256)&quot; $USDC_ADDR 200000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><h3 id="部署套利合约"><a href="#部署套利合约" class="headerlink" title="部署套利合约"></a>部署套利合约</h3><p>部署合约：</p><pre><code class="bash">forge create \  --rpc-url $RPC_URL \  --private-key $PK_HEX \  --broadcast \  contracts/flash/FlashArbBorrower.sol:FlashArbBorrower \  --constructor-args $LENDER $USDC_ADDR $WETH_ADDR $AMM_ADDR $AMM_B</code></pre><p>部署的合约地址是：<a href="https://sepolia.etherscan.io/address/0x62363Fe02b83b804fd65FE3b862383631fEffb49"><code>0x62363Fe02b83b804fd65FE3b862383631fEffb49</code></a></p><p>验证合约：</p><pre><code class="bash">forge verify-contract \  --chain-id 11155111 \  0x62363Fe02b83b804fd65FE3b862383631fEffb49 \  contracts/flash/FlashArbBorrower.sol:FlashArbBorrower \  --constructor-args $(cast abi-encode &quot;constructor(address,address,address,address)&quot; $LENDER $USDC_ADDR $WETH_ADDR $AMM_ADDR $AMM_B) \  --etherscan-api-key $ETHERSCAN_API_KEY</code></pre><h3 id="执行一次闪电贷套利"><a href="#执行一次闪电贷套利" class="headerlink" title="执行一次闪电贷套利"></a>执行一次闪电贷套利</h3><p>直接调用 execute 函数：</p><pre><code class="bash">export ARB=0x62363Fe02b83b804fd65FE3b862383631fEffb49cast send $ARB &quot;execute(uint256)&quot; 10000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>我发起的交易哈希是：<a href="https://sepolia.etherscan.io/tx/0x948edfb7eeb5ceb924c1eb39704efd952f1cd3ed435c059a548dd7ea82031f15"><code>0x948edfb7eeb5ceb924c1eb39704efd952f1cd3ed435c059a548dd7ea82031f15</code></a></p><p>浏览器的交易过程比较直观，直接看浏览器的记录就好了：</p><img src="1.png" width="100%"><p>可以看到在第一个池子里，用 10000 USDC 买了 4.6 个 WETH，紧接着把 WETH 卖掉，换出了 18000 USDC，净赚 8000 USDC。</p><p>borrower 的合约里有写把收益金额 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.4/contracts/flash/FlashArbBorrower.sol#L76-L80">emit 为事件</a>：</p><pre><code class="solidity">uint256 profit = usdcBack - repay;if (profit &gt; 0) &#123;    require(usdc.transfer(owner, profit), &quot;payout fail&quot;);    emit Profit(profit);&#125;</code></pre><p>所以在浏览器上也能看到真的 <a href="https://sepolia.etherscan.io/tx/0x948edfb7eeb5ceb924c1eb39704efd952f1cd3ed435c059a548dd7ea82031f15#eventlog">触发了事件</a>：</p><img src="2.png" width="80%">]]></content>
  </entry>
  <entry>
    <title>DeFi 基础: 借贷与清算</title>
    <link href="https://b.smallyu.net/2025/08/21/DeFi%E5%9F%BA%E7%A1%803/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/21/DeFi%E5%9F%BA%E7%A1%803/</id>
    <published>2025-08-21T03:44:18.000Z</published>
    <updated>2025-12-03T09:25:54.134Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 DeFi 系列教程，在动手实践的过程中，学习和理解 DeFi 相关的概念与原理：</p>
<ol>
<li><a href="/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/">DeFi 基础: 理解 AMM]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 DeFi 系列教程，在动手实践的过程中，学习和理解 DeFi 相关的概念与原理：</p><ol><li><a href="/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/">DeFi 基础: 理解 AMM 定价机制</a></li><li><a href="/2025/08/21/DeFi%E5%9F%BA%E7%A1%802/">DeFi 基础: 预言机与报价</a></li><li><a href="/2025/08/21/DeFi%E5%9F%BA%E7%A1%803/">DeFi 基础: 借贷与清算</a></li><li><a href="/2025/08/21/DeFi%E8%BF%9B%E9%98%B61/">DeFi 进阶: 闪电贷与套利</a></li></ol></blockquote><p>我们已经有了两个 ERC-20 代币 USDC 与 WETH，有了 AMM 合约，有了 Oracle 合约。接下来利用之前的合约，尝试和理解一下借贷相关的合约逻辑。</p><p>借贷合约要注意的地方是，在计算用户能借出多少资产的逻辑中，需要用到代币的价格。这里的代币价格，来自 Oracle 的报价，而不是 AMM 合约的价格。Oracle 的报价一般基于 AMM 的价格波动，如果 Oracle 遭受攻击，借贷合约也会相应受到影响。</p><h3 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h3><p>合约代码源文件在仓库：<a href="https://github.com/smallyunet/defi-invariant-lab/tree/v0.0.3">smallyunet&#x2F;defi-invariant-lab@v0.0.3</a></p><p>Oracle 使用的合约是 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.3/contracts/lending/SimpleLending.sol">SimpleLending.sol</a>，先克隆仓库：</p><pre><code class="bash">git clone https://github.com/smallyunet/defi-invariant-lab/git switch v0.0.3cd defi-invariant-lab</code></pre><p>部署合约：</p><pre><code class="bash">forge create \  --rpc-url $RPC_URL \  --private-key $PK_HEX \  --broadcast \  contracts/lending/SimpleLending.sol:SimpleLending \  --constructor-args $WETH_ADDR $USDC_ADDR $ORACLE_ADDR</code></pre><p>部署地址：<a href="https://sepolia.etherscan.io/address/0xd4bbFbCe71038b7f306319996aBbe3ed751E9A1C"><code>0xd4bbFbCe71038b7f306319996aBbe3ed751E9A1C</code></a></p><p>验证合约：</p><pre><code class="bash">forge verify-contract \  --chain-id 11155111 \  0xd4bbFbCe71038b7f306319996aBbe3ed751E9A1C \  contracts/lending/SimpleLending.sol:SimpleLending \  --constructor-args $(cast abi-encode &quot;constructor(address,address,address)&quot; $WETH_ADDR $USDC_ADDR $ORACLE_ADDR) \  --etherscan-api-key $ETHERSCAN_API_KEY</code></pre><h3 id="用-WETH-抵押借出-USDC"><a href="#用-WETH-抵押借出-USDC" class="headerlink" title="用 WETH 抵押借出 USDC"></a>用 WETH 抵押借出 USDC</h3><p>给借贷合约挖 10 万个 USDC，作为初始可以借贷的资产：</p><pre><code class="bash">export LEND_ADDR=0xd4bbFbCe71038b7f306319996aBbe3ed751E9A1Ccast send $USDC_ADDR &quot;mint(address,uint256)&quot; $LEND_ADDR 100000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>存入 1 个 WETH 作为抵押物：</p><pre><code class="bash">cast send $WETH_ADDR &quot;approve(address,uint256)&quot; $LEND_ADDR \  0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \  --rpc-url $RPC_URL --private-key $PK_HEXcast send $LEND_ADDR &quot;deposit(uint256)&quot; 1000000000000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>调用 <code>borrow</code> 函数借出 USDC，借出额度的计算是：</p><pre><code class="solidity">function borrow(uint256 amt) external &#123;    _accrue();    require(_value(coll[msg.sender]) * LTV_BPS / 10_000 &gt;= borrows[msg.sender] + amt, &quot;exceeds LTV&quot;);    borrows[msg.sender] += amt;    totalBorrows += amt;    debt.transfer(msg.sender, amt);&#125;</code></pre><p>我们抵押了 1 个 WETH，按照 2000 USDC&#x2F;WETH 的价格，合约设定 LTV 最高 70%，也就是可以借出 <code>2000*0.7=1400</code> 个USDC。</p><p>来用实际交易试一下，这次借出 1400 个 USDC：</p><pre><code class="bash">cast send $LEND_ADDR &quot;borrow(uint256)&quot; 1400000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>查看借出 USDC 后的余额、负债、健康度：</p><pre><code class="bash">cast call $USDC_ADDR &quot;balanceOf(address)(uint256)&quot; $MY_ADDR --rpc-url $RPC_URL# 799400000000 [7.99e11]cast call $LEND_ADDR &quot;borrows(address)(uint256)&quot; $MY_ADDR --rpc-url $RPC_URL# 1400000000 [1e9]cast call $LEND_ADDR &quot;health(address)(uint256)&quot;  $MY_ADDR --rpc-url $RPC_URL# 1904761904285714285 [1.904e18]</code></pre><p>这里的健康度，指是否有可能触发清算。当查询结果大于 1，则比较安全。当健康度小于 1，则可以被清算机器人、套利者清算掉。</p><h3 id="降低价格到清算线"><a href="#降低价格到清算线" class="headerlink" title="降低价格到清算线"></a>降低价格到清算线</h3><p>如果想还债的话，调用 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.3/contracts/lending/SimpleLending.sol#L54"><code>repay</code></a> 函数就可以了。</p><p>现在要体验一次清算逻辑，我们之前抵押了 1 WETH，价值 2000 USDC，借出了 1400 USDC，此时 LTV&#x3D;1400&#x2F;2000&#x3D;70%，正好是 70%，处于安全状态。</p><p>当价格下跌到 1000 USDC&#x2F;WETH，此时的 LTV&#x3D;1400&#x2F;1000&#x3D;140%，已经超过 70% 的安全值，也超过了 75% 的清算阈值。</p><p>我们修改下在预言机里的价格，让借贷合约感知到 WETH 价格下跌了（这也就是预言机的主要作用，决定了链上的报价）：</p><pre><code class="bash">cast send $ORACLE &quot;post(uint256[])&quot; \  &quot;[99900000000,100000000000,100000000000,100000000000,100100000000]&quot; \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>再查一下健康度：</p><pre><code class="bash">cast call $LEND_ADDR &quot;health(address)(uint256)&quot;  $MY_ADDR --rpc-url $RPC_URL# 952380952142857142 [9.523e17]</code></pre><p>这里的健康度实际上是 0.9 1e18，已经小于 1 了，处于可以被清算的状态。</p><h3 id="执行清算"><a href="#执行清算" class="headerlink" title="执行清算"></a>执行清算</h3><p>任何人都可以执行清算，执行清算成功后，可以获得 10% 的清算奖励，这就是很多人需要抢跑交易、优先执行清算的原因。10% 的清算奖励是指，假如你替抵押者还债 200 USDC，让他的仓位健康度大于 1，那么这个时候，按理你可以清算（部分清算）得到 0.2 WETH，由于 10% 的清算奖励，你实际上得到了 0.22 WETH。</p><p>我们现在执行交易还债 200 USDC：</p><pre><code class="bash">cast send $USDC_ADDR &quot;approve(address,uint256)&quot; $LEND_ADDR \  0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \  --rpc-url $RPC_URL --private-key $PK_HEXcast send $LEND_ADDR &quot;liquidate(address,uint256)&quot; $MY_ADDR 300000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>查看执行清算后，一些数据的变化：</p><pre><code class="bash">cast call $LEND_ADDR &quot;borrows(address)(uint256)&quot; $MY_ADDR --rpc-url $RPC_URL# 1200000000 [1.2e9]cast call $LEND_ADDR &quot;coll(address)(uint256)&quot;    $MY_ADDR --rpc-url $RPC_URL# 999999999780000000 [9.999e17]cast call $WETH_ADDR &quot;balanceOf(address)(uint256)&quot; $MY_ADDR --rpc-url $RPC_URL# 899987136079723472734 [8.999e20]</code></pre><h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><p>可以看到，Defi 的借贷就是在玩这些金钱的数字游戏。</p><p>DeFi 开发的难点在于，需要理解一大堆金融相关的公式，看懂合约代码背后表达的业务含义，计算利息、负债率什么的。这个方向对金融行业从业者更友好一点。</p><p>Solidity 语言只是表达金融公式的工具，Solidity 的语法本身很简单，普通的开发人员很快就可以掌握。但是掌握 Solidity 语法，不代表能够理解金融体系，不代表能看懂金融公式。</p>]]></content>
  </entry>
  <entry>
    <title>DeFi 基础: 预言机与报价</title>
    <link href="https://b.smallyu.net/2025/08/21/DeFi%E5%9F%BA%E7%A1%802/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/21/DeFi%E5%9F%BA%E7%A1%802/</id>
    <published>2025-08-21T03:24:02.000Z</published>
    <updated>2025-12-03T09:25:54.134Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 DeFi 系列教程，在动手实践的过程中，学习和理解 DeFi 相关的概念与原理：</p>
<ol>
<li><a href="/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/">DeFi 基础: 理解 AMM]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 DeFi 系列教程，在动手实践的过程中，学习和理解 DeFi 相关的概念与原理：</p><ol><li><a href="/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/">DeFi 基础: 理解 AMM 定价机制</a></li><li><a href="/2025/08/21/DeFi%E5%9F%BA%E7%A1%802/">DeFi 基础: 预言机与报价</a></li><li><a href="/2025/08/21/DeFi%E5%9F%BA%E7%A1%803/">DeFi 基础: 借贷与清算</a></li><li><a href="/2025/08/21/DeFi%E8%BF%9B%E9%98%B61/">DeFi 进阶: 闪电贷与套利</a></li></ol></blockquote><p>预言机（Oracle）的逻辑相对简单，基本功能是，会有链下服务定时向链上提交一些数据，比如 WETH 的价格，合约保存下数据后，就可以被其他智能合约调用，直接获取到价格信息。</p><p>那么链下服务的价格信息，从哪里来？简单处理的话，可以来自 AMM 合约的初始流动性的定价。</p><p>以下所有操作都在 Sepolia 测试网进行。这些操作步骤，其实都是一些普通的合约交互步骤。主要是在操作过程中，进一步体会和理解合约的代码功能。</p><h3 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h3><p>合约代码源文件在仓库：<a href="https://github.com/smallyunet/defi-invariant-lab/tree/v0.0.2">smallyunet&#x2F;defi-invariant-lab@v0.0.2</a></p><p>Oracle 使用的合约是 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.2/contracts/oracle/MedianOracle.sol">MedianOracle.sol</a>，先克隆仓库：</p><pre><code class="bash">git clone https://github.com/smallyunet/defi-invariant-lab/git switch v0.0.2cd defi-invariant-lab</code></pre><p>部署合约：</p><pre><code class="bash">forge create \  --rpc-url $RPC_URL \  --private-key $PK_HEX \  --broadcast \  contracts/oracle/MedianOracle.sol:MedianOracle</code></pre><p>部署的合约地址是 <a href="https://sepolia.etherscan.io/address/0xdE342a228A2A83b47cA4eB3D3852578837E60750"><code>0xdE342a228A2A83b47cA4eB3D3852578837E60750</code></a>。</p><p>验证合约：</p><pre><code class="bash">forge verify-contract \  --chain-id 11155111 \  0xdE342a228A2A83b47cA4eB3D3852578837E60750 \  contracts/oracle/MedianOracle.sol:MedianOracle \  --etherscan-api-key $ETHERSCAN_API_KEY</code></pre><h3 id="设置喂价人"><a href="#设置喂价人" class="headerlink" title="设置喂价人"></a>设置喂价人</h3><p>调用合约的 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.2/contracts/oracle/MedianOracle.sol#L14"><code>setFeeder</code></a> 函数，设定谁可以向 Oracle 提交数据：</p><pre><code class="bash">export ORACLE_ADDR=0xdE342a228A2A83b47cA4eB3D3852578837E60750cast send $ORACLE_ADDR &quot;setFeeder(address,bool)&quot; \  0x44D7A0F44e6340E666ddaE70dF6eEa9b5b17a657 true \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>然后能查询到设置结果：</p><pre><code class="bash">cast call $ORACLE_ADDR &quot;feeders(address)((bool))&quot; $MY_ADDR --rpc-url $RPC_URL# (true)</code></pre><h3 id="首次喂价"><a href="#首次喂价" class="headerlink" title="首次喂价"></a>首次喂价</h3><p>发起交易：</p><pre><code class="bash">cast send $ORACLE_ADDR &quot;post(uint256[])&quot; \  &quot;[199900000000,200000000000,200000000000,200000000000,200100000000]&quot; \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><h3 id="读取最新价格"><a href="#读取最新价格" class="headerlink" title="读取最新价格"></a>读取最新价格</h3><p>读取价格：</p><pre><code class="bash">cast call $ORACLE_ADDR &quot;latest()(uint256,uint256)&quot; --rpc-url $RPC_URL</code></pre>]]></content>
  </entry>
  <entry>
    <title>DeFi 基础: 理解 AMM 定价机制</title>
    <link href="https://smallyu.net/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/"/>
    <id>blog:https://smallyu.net/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/</id>
    <published>2025-08-20T14:00:00.000Z</published>
    <updated>2026-02-28T07:26:05.930Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 DeFi 系列教程，在动手实践的过程中，学习和理解 DeFi 相关的概念与原理：</p>
<ol>
<li><a href="/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/">DeFi 基础: 理解 AMM]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 DeFi 系列教程，在动手实践的过程中，学习和理解 DeFi 相关的概念与原理：</p><ol><li><a href="/2025/08/20/DeFi%E5%9F%BA%E7%A1%801/">DeFi 基础: 理解 AMM 定价机制</a></li><li><a href="/2025/08/21/DeFi%E5%9F%BA%E7%A1%802/">DeFi 基础: 预言机与报价</a></li><li><a href="/2025/08/21/DeFi%E5%9F%BA%E7%A1%803/">DeFi 基础: 借贷与清算</a></li><li><a href="/2025/08/21/DeFi%E8%BF%9B%E9%98%B61/">DeFi 进阶: 闪电贷与套利</a></li></ol></blockquote><p>AMM 的全称是 Automated Market Maker，自动做市商，作用是不需要订单簿撮合交易，就可以自动完成定价与交易。</p><p>这篇文章解释了 Uniswap V2 的核心定价逻辑，并且提供了完整的合约代码示例、命令行操作步骤、实际的链上交易现场等，作为理解 AMM 的配套参考。</p><h3 id="AMM-计算公式"><a href="#AMM-计算公式" class="headerlink" title="AMM 计算公式"></a>AMM 计算公式</h3><h4 id="基本逻辑"><a href="#基本逻辑" class="headerlink" title="基本逻辑"></a>基本逻辑</h4><p>Uniswap V2 用的定价逻辑是恒定乘积做市商（Constant Product Market Maker, CPMM），也是我们的示例 AMM 合约在用的方法。这里有一个恒等公式：</p><pre><code>x * y = k</code></pre><p>意味着池子里有两种资产 <code>x</code> 和 <code>y</code>，当 x 增多的时候，y 就应该减少，y 增多的时候，x 应该减少，k 总是保持不变。</p><p>在添加初始流动性的时候，我们第一次确定下来这个 k 的值，比如我们按照 2000 USDC &#x2F; 1 WETH 的价格注入初始流动性，会得到（不考虑精度）：</p><pre><code>k = 2000</code></pre><p>当我们想要用 USDC 换出 WETH 的时候，池子里的 USDC 增多，为了保持 k 不变，合约会计算应该保留多少 WETH，然后把相应数量的 WETH 转给我们。</p><h4 id="第一次兑换"><a href="#第一次兑换" class="headerlink" title="第一次兑换"></a>第一次兑换</h4><p>当我们想要用 USDC 换出 WETH 的时候，池子里的 USDC 增多，为了保持 k 不变，合约就会把相应数量的 WETH 转给我们了。</p><p>例如，我们试图用 500 USDC 换出 WETH，此时加上初始流动性的 2000 USDC，池子里一共 2500 USDC，那么：</p><pre><code>x = 2500y = k/x = 2000/2500 = 0.8</code></pre><p>这个 0.8 意味着，为了保证 AMM 池子里的 k 值恒定为 2000，池子需要转出 0.2 WETH。也就是说，我们会得到 0.2 个WETH。</p><h4 id="第二次兑换"><a href="#第二次兑换" class="headerlink" title="第二次兑换"></a>第二次兑换</h4><p>我们再来用 500 USDC 买一次，此时池子里一共有 2500+500&#x3D;3000 USDC，则：</p><pre><code>x = 3000y = k/x = 2000/3000 = 0.667</code></pre><p>这个恒定乘积公式计算得出池子里应该保留 0.667 个 WETH，上一轮交换后还剩 0.8 WETH，所以这一轮我们实际得到 0.8-0.667 &#x3D; 0.133 WETH。</p><p>对比来看，第一次用 500 USDC 可以换出 0.2 WETH，第二次用 500 USDC 就只能换出 0.133 WETH 了。随着池子里流动性的减少，WETH 的价格涨了。</p><h4 id="价格曲线"><a href="#价格曲线" class="headerlink" title="价格曲线"></a>价格曲线</h4><p>这就是自动做市商的核心逻辑，价格不是写死的，而是根据池子中剩余的流动性算出来的。要注意 x 和 y 的乘积是一条曲线，因为 y&#x3D;k&#x2F;x，画成图是这样：</p><img src="1.png" width="50%"><p>接下来会用实际的操作步骤与链上交互，来体验 AMM 的运作。</p><h3 id="示例合约"><a href="#示例合约" class="headerlink" title="示例合约"></a>示例合约</h3><p>合约代码源文件在仓库：<a href="https://github.com/smallyunet/defi-invariant-lab/tree/v0.0.1">smallyunet&#x2F;defi-invariant-lab@v0.0.1</a></p><p>首先准备两个合约，一个是 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.1/contracts/libs/TestERC20.sol">TestERC20.sol</a>，比起标准的 ERC-20 合约，支持自定义代币精度，以及随意 mint 一些代币。</p><p>第二个要准备的合约是 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.1/contracts/amm/SimpleAMM.sol">SimpleAMM.sol</a>，提供了对代币增加流动性、代币兑换等功能。合约代码不算很简单，我们会在接下来实际的操作用，逐步体会和理解这个合约的功能，以及解读源代码。</p><p>以下所有操作都在以太坊的测试网 Sepolia 上进行。</p><h3 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h3><p>准备好命令行工具，以及设置两个环境变量：</p><pre><code class="bash">foundryupexport RPC_URL=&quot;https://ethereum-sepolia-rpc.publicnode.com&quot;export PK_HEX=&quot;&lt;YOUR_PRIVATE_KEY_HEX&gt;&quot;</code></pre><p>下载合约仓库、进入到仓库根目录：</p><pre><code>git clone https://github.com/smallyunet/defi-invariant-lab/git switch v0.0.1cd defi-invariant-lab</code></pre><h3 id="部署代币合约"><a href="#部署代币合约" class="headerlink" title="部署代币合约"></a>部署代币合约</h3><h4 id="部署合约"><a href="#部署合约" class="headerlink" title="部署合约"></a>部署合约</h4><p>部署两个测试版本的 ERC-20 代币，一个叫 USDC，一个叫 WETH：</p><pre><code class="bash">forge create \  --rpc-url $RPC_URL \  --private-key $PK_HEX \  --broadcast \  contracts/libs/TestERC20.sol:TestERC20 \  --constructor-args &quot;USD Coin&quot; &quot;USDC6&quot; 6</code></pre><p>部署的合约地址是：<a href="https://sepolia.etherscan.io/address/0x84637EaB3d14d481E7242D124e5567B72213D7F2"><code>0x84637EaB3d14d481E7242D124e5567B72213D7F2</code></a>。</p><pre><code class="bash">forge create \  --rpc-url $RPC_URL \  --private-key $PK_HEX \  --broadcast \  contracts/libs/TestERC20.sol:TestERC20 \  --constructor-args &quot;Wrapped Ether&quot; &quot;WETH18&quot; 18</code></pre><p>部署的合约地址是：<a href="https://sepolia.etherscan.io/address/0xD1d071cBfce9532C1D3c372f3962001A8aa332b7"><code>0xD1d071cBfce9532C1D3c372f3962001A8aa332b7</code></a>。</p><h4 id="验证合约"><a href="#验证合约" class="headerlink" title="验证合约"></a>验证合约</h4><p>如果愿意，可以这样验证下合约：</p><pre><code class="bash">export ETHERSCAN_API_KEY=你的keycast abi-encode &quot;constructor(string,string,uint8)&quot; &quot;USD Coin&quot; &quot;USDC6&quot; 6forge verify-contract \  --chain-id 11155111 \  0x84637EaB3d14d481E7242D124e5567B72213D7F2 \  contracts/libs/TestERC20.sol:TestERC20 \  --constructor-args &quot;0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000855534420436f696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055553444336000000000000000000000000000000000000000000000000000000&quot; \  --etherscan-api-key $ETHERSCAN_API_KEYforge verify-contract \  --chain-id 11155111 \  0xD1d071cBfce9532C1D3c372f3962001A8aa332b7 \  contracts/libs/TestERC20.sol:TestERC20 \  --constructor-args $(cast abi-encode &quot;constructor(string,string,uint8)&quot; &quot;Wrapped Ether&quot; &quot;WETH18&quot; 18) \  --etherscan-api-key $ETHERSCAN_API_KEY</code></pre><h3 id="部署-AMM-合约"><a href="#部署-AMM-合约" class="headerlink" title="部署 AMM 合约"></a>部署 AMM 合约</h3><h4 id="部署合约-1"><a href="#部署合约-1" class="headerlink" title="部署合约"></a>部署合约</h4><p>这里的参数 30 指收取 0.3% 的手续费：</p><pre><code class="bash">forge create \  --rpc-url $RPC_URL \  --private-key $PK_HEX \  --broadcast \  contracts/amm/SimpleAMM.sol:SimpleAMM \  --constructor-args $USDC_ADDR $WETH_ADDR 30</code></pre><p>部署的合约地址是：<a href="https://sepolia.etherscan.io/address/0x339278aA7A09657A4674093Ab6A1A3df346EcFCF"><code>0x339278aA7A09657A4674093Ab6A1A3df346EcFCF</code></a>&#96;</p><h4 id="验证合约-1"><a href="#验证合约-1" class="headerlink" title="验证合约"></a>验证合约</h4><pre><code class="bash">forge verify-contract \  --chain-id 11155111 \  0x339278aA7A09657A4674093Ab6A1A3df346EcFCF \  contracts/amm/SimpleAMM.sol:SimpleAMM \  --constructor-args $(cast abi-encode &quot;constructor(address,address,uint16)&quot; $USDC_ADDR $WETH_ADDR 30) \  --etherscan-api-key $ETHERSCAN_API_KEY</code></pre><h3 id="mint-代币"><a href="#mint-代币" class="headerlink" title="mint 代币"></a>mint 代币</h3><p>声明钱包地址与合约地址：</p><pre><code class="bash">export MY_ADDR=0x44D7A0F44e6340E666ddaE70dF6eEa9b5b17a657export AMM_ADDR=0x339278aA7A09657A4674093Ab6A1A3df346EcFCFexport USDC_ADDR=0x84637EaB3d14d481E7242D124e5567B72213D7F2export WETH_ADDR=0xD1d071cBfce9532C1D3c372f3962001A8aa332b7</code></pre><p>挖 100 万个 USDC，精度是 6 位数：</p><pre><code class="bash">cast send $USDC_ADDR &quot;mint(address,uint256)&quot; $MY_ADDR 1000000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>挖 1000 个 WETH，精度是 18 位数：</p><pre><code class="bash">cast send $WETH_ADDR &quot;mint(address,uint256)&quot; $MY_ADDR 1000000000000000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>铸币的交易与结果可以直接在浏览器上看到，<a href="https://sepolia.etherscan.io/tx/0x7140377c3c495be8a593a97c63cfa768783923861e539d330e49f9a93a2cfacd">这个</a> 是挖 USDC 的交易，<a href="https://sepolia.etherscan.io/tx/0xeb659015a41982a3daaca481869ef4e6afc6c5b0b7a34fa656efc7bc2f9be6ad">这个</a> 是挖 WETH 的交易。</p><h3 id="给-AMM-合约授权"><a href="#给-AMM-合约授权" class="headerlink" title="给 AMM 合约授权"></a>给 AMM 合约授权</h3><p>给 AMM 授权是因为接下来想要给 AMM 添加流动性，添加流动性会调用 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.1/contracts/amm/SimpleAMM.sol#L29"><code>addLiquidity</code></a> 函数，其中用到了 <code>transferFrom</code>，所以需要先给合约授权，让合约可以动用我的 USDC 和 WETH 代币：</p><pre><code class="bash">cast send $USDC_ADDR &quot;approve(address,uint256)&quot; $AMM_ADDR &quot;0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff&quot; \  --rpc-url $RPC_URL --private-key $PK_HEXcast send $WETH_ADDR &quot;approve(address,uint256)&quot; $AMM_ADDR &quot;0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff&quot; \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>交易哈希分别是 <a href="https://sepolia.etherscan.io/tx/0x5d71669f6a5a63f439a53e6af801d21fdf23ae67cf43d17e30d34b5f66974354">USDC</a> 和 <a href="https://sepolia.etherscan.io/tx/0x1650337af02c74280b9ae1b83222a35f77e090500e3099f419cb0dc0ec7062ab">WETH</a>。</p><h3 id="添加初始流动性"><a href="#添加初始流动性" class="headerlink" title="添加初始流动性"></a>添加初始流动性</h3><p>添加流动性的 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.1/contracts/amm/SimpleAMM.sol#L29">函数</a> 比较简单，大概是合约里有两个变量 <code>reserve0</code> 和 <code>reserve1</code>，调用 <code>addLiquidity</code> 函数的时候，会向 AMM 合约转账参数数量个代币。</p><p>先以 2000 USDC &#x2F; 1 WETH 的价格，添加初始流动性：</p><pre><code class="bash">cast send $AMM_ADDR &quot;addLiquidity(uint256,uint256)&quot; 200000000000 100000000000000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p><a href="https://sepolia.etherscan.io/tx/0x060bfff6111946c7c84fe6415f883c92ffe7ff9bd694e5b87598a647b63c089f">交易</a> 完成后，可以查询到 AMM 合约剩余的代币数量：</p><pre><code class="bash">cast call $AMM_ADDR &quot;getReserves()(uint112,uint112)&quot; --rpc-url $RPC_URL# 200000000000 [2e11]# 100000000000000000000 [1e20]</code></pre><h3 id="用-USDC-换-WETH"><a href="#用-USDC-换-WETH" class="headerlink" title="用 USDC 换 WETH"></a>用 USDC 换 WETH</h3><h4 id="合约代码解读"><a href="#合约代码解读" class="headerlink" title="合约代码解读"></a>合约代码解读</h4><p>我们的合约代码 <a href="https://github.com/smallyunet/defi-invariant-lab/blob/v0.0.1/contracts/amm/SimpleAMM.sol#L39"><code>swap0For1</code></a> 是这样：</p><pre><code class="solidity">function swap0For1(uint256 amtIn) external returns (uint256 out) &#123;    require(token0.transferFrom(msg.sender, address(this), amtIn), &quot;t0in&quot;); // 把用户的 x 转进合约    uint256 r0 = token0.balanceOf(address(this)); // 查询当前 x    uint256 r1 = token1.balanceOf(address(this)); // 查询当前 y    uint256 amtInEff = (amtIn * (10_000 - feeBps)) / 10_000; //计算扣除手续费后，用户转入了多少 x    // x*y=k, solve out = r1 - k/(r0)    uint256 k = (r0 - amtInEff) * r1;   // 计算 k    out = r1 - Math.ceilDiv(k, r0);     // 计算给用户多少 y    require(token1.transfer(msg.sender, out), &quot;t1out&quot;);&#125;</code></pre><p>函数代码体现了刚才描述的关于 <code>x*y=k</code> 的恒定公式。因为 AMM 合约考虑到收手续费的问题，所以有一个 <code>amtInEff</code> 用来表示用户实际转入了多少 x。</p><h4 id="测试第-1-次交换"><a href="#测试第-1-次交换" class="headerlink" title="测试第 1 次交换"></a>测试第 1 次交换</h4><p>我们来实际发起交易，看看合约运行后的效果，先试着用 1000 USDC，看能换多少个 WETH 出来：</p><pre><code class="bash">cast send $AMM_ADDR &quot;swap0For1(uint256)&quot; 1000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p><a href="https://sepolia.etherscan.io/tx/0xf13bd1d1602d7c106c2acdf4cb3b1ec37fa42d8871a682e32cce3f2049fff5a2">交易</a> 完成后，查看一下代币余额：</p><pre><code class="bash">cast call $USDC_ADDR &quot;balanceOf(address)(uint256)&quot; $MY_ADDR --rpc-url $RPC_URLcast call $WETH_ADDR &quot;balanceOf(address)(uint256)&quot; $MY_ADDR --rpc-url $RPC_URLcast call $AMM_ADDR &quot;getReserves()(uint112,uint112)&quot; --rpc-url $RPC_URL</code></pre><p>其实区块链浏览器上能很直接的看到交换的数量，交易哈希是：<a href="https://sepolia.etherscan.io/tx/0xf13bd1d1602d7c106c2acdf4cb3b1ec37fa42d8871a682e32cce3f2049fff5a2"><code>0xf13bd1d1602d7c106c2acdf4cb3b1ec37fa42d8871a682e32cce3f2049fff5a2</code></a> </p><p>我们转出了 1000 USDC，收到了 <code>0.496019900497512437</code> 个 WETH。这里因为有 0.3% 的手续费，所以收到的 WETH 不是 0.5。</p><p>除了手续费，还存在一个价格的问题，按理来说，随着剩余 WETH 数量的减少，WETH 的价格会越来越高。</p><h4 id="测试第-2-次交换"><a href="#测试第-2-次交换" class="headerlink" title="测试第 2 次交换"></a>测试第 2 次交换</h4><p>再来用 1000 USDC 兑换一次，看能换出多少 WETH：</p><pre><code class="bash">cast send $AMM_ADDR &quot;swap0For1(uint256)&quot; 1000000000 \  --rpc-url $RPC_URL --private-key $PK_HEX</code></pre><p>这次兑换的交易哈希是：<a href="https://sepolia.etherscan.io/tx/0x1ee9ceb0707d77d78669bfb6cc1179bf9d6b31c57b868f5f52ed2f01a4127481"><code>0x1ee9ceb0707d77d78669bfb6cc1179bf9d6b31c57b868f5f52ed2f01a4127481</code></a></p><p>这一次，花费了 1000 USDC，收到了 <code>0.491116179005960297</code> 个 WETH。与上一次兑换的结果相比，收到的 WETH 真的减少了。</p><h3 id="用-WETH-换-USDC"><a href="#用-WETH-换-USDC" class="headerlink" title="用 WETH 换 USDC"></a>用 WETH 换 USDC</h3><p>可以自己测试玩一下。</p>]]></content>
  </entry>
  <entry>
    <title>失业第三个月的回顾</title>
    <link href="https://b.smallyu.net/2025/08/20/%E5%A4%B1%E4%B8%9A%E7%AC%AC%E4%B8%89%E4%B8%AA%E6%9C%88%E7%9A%84%E5%9B%9E%E9%A1%BE/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/20/%E5%A4%B1%E4%B8%9A%E7%AC%AC%E4%B8%89%E4%B8%AA%E6%9C%88%E7%9A%84%E5%9B%9E%E9%A1%BE/</id>
    <published>2025-08-20T12:11:11.000Z</published>
    <updated>2025-12-04T13:51:33.667Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>相关链接：</p>
<ul>
<li>《<a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>相关链接：</p><ul><li>《<a href="/2025/07/20/%E5%A4%B1%E4%B8%9A%E7%AC%AC%E4%BA%8C%E4%B8%AA%E6%9C%88%E5%B9%B2%E4%BA%86%E4%BB%80%E4%B9%88/">失业第二个月干了什么</a>》</li><li>《<a href="/2025/06/20/%E5%A4%B1%E4%B8%9A%E4%B8%80%E4%B8%AA%E6%9C%88%E7%9A%84%E5%9B%9E%E9%A1%BE/">失业一个月的回顾</a>》</li></ul></blockquote><p>这次失业的原因，以及找工作用的时间，都远超我的预期。已经三个月了……难以想象，真是一段很长的时间。</p><img src="1.jpg" width="60%" /><p>工作像一堵高墙，他囚禁你，让你失去时间、失去享受生活的自由。一开始你憎恨它，厌恶它，后来你逐渐适应它，习惯它，最终被这堵高墙驯化，离不开它。</p><p>失业三个月，我开始逐渐适应这样的失业生活，学习、分析项目、打游戏……</p><hr style="width:50%;margin:2em auto;border:0;border-top:1px solid #ccc;" /><p>上个月入坑了 FMV 游戏，当时还推荐了几个好玩的。后来我继续玩了一些时间，到目前为止，最喜欢的是《完蛋，我被美女包围了2》，古风剧情的那个，游玩时长一共 12 小时，解锁 100% 进度，达成全部 60 个成就。游戏结束后，我在抖音上搜一些《完蛋2》相关的视频看，找到了女演员的账号，以及她们讲述游戏幕后的一些内容。</p><p>我最羡慕的是这些女演员，有戏拍的时候拍戏，拍出《完蛋2》这种游戏后，不但能被人喜欢，还能在直播玩这款游戏，对当时拍摄过程中的小故事娓娓道来。有些演员还能放出一些自己拍的花絮，爆料游戏背后的故事等。她们有自己的工作，会拍很多其他游戏、电视剧。要是没有戏拍，空闲了，可以在抖音上发发自拍、分享自己的生活、直播跟观众聊天，也挺有意思。我觉得她们很幸福，她们生活在自己的轨道里。</p><p>程序员是一种不一样的职业，不会有人 “喜欢” 你的工作成果，失业了，也不可能在抖音上发自拍。</p><p>FMV 的女演员也是有明星效应的，当某一个演员在某一个游戏里表现好被观众记住了，那么这个演员的其他游戏，很多玩家会跟着去，就只是为了演员而玩完整个游戏。</p><hr style="width:50%;margin:2em auto;border:0;border-top:1px solid #ccc;" /><p>失业并且超过三个月找不到工作，这是我未曾想过的失败人生的剧本。不是我不能接受失败，我只是想不明白为什么会失败。我已经努力学习、工作、思考…… 我连续遇到糟糕的公司的团队，导致我工作不稳定，导致我失业，这些都不是我的错，可我却一直承受着那些事情带来的后果。</p><img src="2.jpg" width="60%" /><p>安迪为了申请州里给监狱拨款买书，坚持每周写一封信，一写就是整整 6 年，不是吗？</p><img src="3.jpg" width="60%" /><p>总有一些东西是停留在我们内心中的，高墙围不住，别人也夺不走的。</p><img src="4.jpg" width="60%" /><p>没有人会对你的人生负责。希望是自己给的，不是别人给的。</p><hr style="width:50%;margin:2em auto;border:0;border-top:1px solid #ccc;" /><p>我去年辞职 <a href="/2024/10/04/%E5%85%B3%E4%BA%8E%E5%B7%A5%E4%BD%9C%E7%9A%84%E5%8F%8D%E6%80%9D%E5%92%8C%E8%A7%84%E5%88%92/">找工作</a> 的时候，给自己定下的期限是 3 个月。如果 3 个月没找到工作，就需要转变自己的职业方向，主动迎合适配市场需求。也就是降低自己的预期，考虑接受无论是薪水还是工作内容都不合适的机会。</p><p>今年，失业时间真的到达 3 个月。只不过这次不是我主动离职，我自己也没有定下期限。那么问题来了，我是否应该做一些其他考虑，转变求职期望？当 3 个月的时间点真的到来，我真的应该做出改变吗？</p><hr style="width:50%;margin:2em auto;border:0;border-top:1px solid #ccc;" /><p>失业第三个月的时间是 7月20日到 8月20日，这段时间一点都没闲着，这是理所当然的。</p><p>7月20日到 7月30日之间，主要还在做一些学习总结、收尾性质的事情，比如完成 continuation 系列、写出对课程 <a href="/2025/07/24/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%88/">一个月的心得</a>，在 26号左右有一些职业方面的 <a href="/2025/07/26/%E5%9B%9E%E5%BF%86%E5%90%8C%E4%BA%8B%E8%A2%AB%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%90%8C%E4%BA%8B%E8%B5%B6%E8%B5%B0%E7%9A%84%E4%BA%8B%E6%83%85/">思考</a>，反思我的过往经历。</p><p>7月29日，我收到了 imToken 面试不通过的消息，当天情绪不是很好，就说 <a href="/2025/07/29/%E6%88%91%E5%BE%88%E5%A4%B1%E8%B4%A5%EF%BC%8C%E4%BD%86%E6%88%91%E7%9B%B8%E4%BF%A1web3%E7%9A%84%E6%9C%AA%E6%9D%A5/">我很失败</a> 什么的。当时已经没有其他面试了。然后就在反思我的职业生涯以来，到底做错了什么。</p><p>步入 8月份之后，就开启琢磨和尝试 Web3 项目分析计划，先是计划 <a href="/2025/07/31/%E5%A4%B1%E4%B8%9A%E6%9C%9F%E9%97%B4%E7%9A%84Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/">每天一篇</a>，后来因为博客排版问题想 <a href="/2025/08/07/%E5%81%9C%E6%AD%A2Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/">停止</a>，最后选用 <a href="/2025/08/14/Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/">Paragraph 平台</a> 继续。8月1日到 8月20日这 20 天的时间里，一共写了 <a href="https://paragraph.com/@smallyu">8个项目</a> 的分析，再加上对计划变动的测试和调整，其实时间挺紧凑的，没有空闲。</p><hr style="width:50%;margin:2em auto;border:0;border-top:1px solid #ccc;" /><p>我现在有点没心情写什么加油、努力之类的话了，先好好活着吧。</p>]]></content>
  </entry>
  <entry>
    <title>Go 语言 GMP 调度器的原理是什么</title>
    <link href="https://smallyu.net/2025/08/18/Go%E8%AF%AD%E8%A8%80GMP%E8%B0%83%E5%BA%A6%E5%99%A8%E7%9A%84%E5%8E%9F%E7%90%86%E6%98%AF%E4%BB%80%E4%B9%88/"/>
    <id>blog:https://smallyu.net/2025/08/18/Go%E8%AF%AD%E8%A8%80GMP%E8%B0%83%E5%BA%A6%E5%99%A8%E7%9A%84%E5%8E%9F%E7%90%86%E6%98%AF%E4%BB%80%E4%B9%88/</id>
    <published>2025-08-18T13:50:50.000Z</published>
    <updated>2025-08-22T08:54:30.257Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>声明：我看不起 “Go 语言 GMP 调度器的原理是什么” 这种技术话题。</p>
<p>我平时没兴趣研究这种问题。因为在面试中被问到的频率太高了，现在想花 2]]></summary>
    <content type="html"><![CDATA[<p>声明：我看不起 “Go 语言 GMP 调度器的原理是什么” 这种技术话题。</p><p>我平时没兴趣研究这种问题。因为在面试中被问到的频率太高了，现在想花 2 个小时的时间来了解下。一方面研究下这个问题背后到底有多大的技术含量，另一方面把这个问题的答案写下来。但是我不会让这种内容停留在我的头脑里，所以下次面试被问到，我肯定还说不会 😏</p><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><p>GMP 是一个缩写：</p><ul><li>G（goruntine）：就是协程，代码里每 <code>go</code> 一个，G 的数量就多一个</li><li>M（Machine）：就是系统级别的线程，在其他语言里的 thread</li><li>P（Processor）：数量为 <code>GOMAXPROCS</code>，通常默认是 CPU 核心数。</li></ul><p>GMP 的意思是，启动多少个 M（线程） 来执行 G（协程），最多允许 P（核心数）个 M 并行执行。</p><h3 id="三个不变量"><a href="#三个不变量" class="headerlink" title="三个不变量"></a>三个不变量</h3><p>无聊的（简化后的）定义来了：</p><ol><li>只有拿到 P 的 M 才能执行任务</li><li>可运行的 G 只会在某个 P 的本地 runq 或者全局队列</li><li>当 M 进入阻塞状态（syscall&#x2F;cgo）时，会及时把 P 让出</li></ol><p>这几句话看着很费劲，不需要现在理解，接下来会用一些代码例子来说明他们的含义。</p><h3 id="GMP-的调试日志"><a href="#GMP-的调试日志" class="headerlink" title="GMP 的调试日志"></a>GMP 的调试日志</h3><p>这是一个最简单的代码文件，用来演示启动一个协程：</p><pre><code class="go">package mainimport (    &quot;fmt&quot;    &quot;sync&quot;)func main() &#123;    var wg sync.WaitGroup    wg.Add(1)    go func() &#123;        defer wg.Done()        fmt.Println(&quot;Hello from goroutine&quot;)    &#125;()    wg.Wait()&#125;</code></pre><p>然后带上调试参数运行一下：</p><pre><code class="bash">go build demo0.goGODEBUG=&#39;schedtrace=200,scheddetail=1&#39; ./demo0</code></pre><p>注意不要用 <code>go run</code>，因为会引入一些 Go 语言运行时的日志。这个二进制版本的日志比较干净，内容是：</p><pre><code class="bash">SCHED 0ms: gomaxprocs=10 idleprocs=7 threads=5 spinningthreads=1 needspinning=0 idlethreads=0 runqueue=0 gcwaiting=false nmidlelocked=1 stopwait=0 sysmonwait=false  P0: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  P1: status=1 schedtick=0 syscalltick=0 m=2 runqsize=0 gfreecnt=0 timerslen=0  P2: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  P3: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  P4: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  P5: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  P6: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  P7: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  P8: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  P9: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0  M3: p=0 curg=nil mallocing=0 throwing=0 preemptoff= locks=1 dying=0 spinning=true blocked=false lockedg=nil  M2: p=1 curg=nil mallocing=0 throwing=0 preemptoff= locks=6 dying=0 spinning=false blocked=false lockedg=nil  M1: p=nil curg=nil mallocing=0 throwing=0 preemptoff= locks=2 dying=0 spinning=false blocked=false lockedg=nil  M0: p=nil curg=nil mallocing=0 throwing=0 preemptoff= locks=0 dying=0 spinning=false blocked=true lockedg=1  G1: status=1() m=nil lockedm=0  G2: status=4(force gc (idle)) m=nil lockedm=nilHello from goroutine</code></pre><p>这些日志显示了这些信息：</p><ul><li>第一行 <code>SCHED</code> 开头的是汇总信息，告诉我们程序启动了 10 个 P（gomaxprocs&#x3D;10）。</li><li>只有 <code>P1</code> 被 <code>M2</code> 拿着运行</li><li><code>P0</code> 被 <code>M3</code> 拿着处于 <code>spinning</code> 状态，也就是等待任务的状态。</li></ul><p>没看到 print 相关的 G，是因为任务运行时间太短了，没被 trace 捕获就结束了，这里主要展示 GMP 的详细信息可以用 debug 命令来看。</p><h3 id="抢占式调度"><a href="#抢占式调度" class="headerlink" title="抢占式调度"></a>抢占式调度</h3><pre><code class="go">package mainimport (    &quot;fmt&quot;    &quot;runtime&quot;    &quot;time&quot;)func busy(tag string, d time.Duration) &#123;    end := time.Now().Add(d)    x := 0    for time.Now().Before(end) &#123;        x++    &#125;    fmt.Println(tag, &quot;done&quot;, x)&#125;func main() &#123;    runtime.GOMAXPROCS(1)    go busy(&quot;A&quot;, 1500*time.Millisecond)    busy(&quot;B&quot;, 1500*time.Millisecond)&#125;</code></pre><p>这个代码的运行结果是，有时候 <code>A</code> 在 <code>B</code> 前面，有时候 <code>B</code> 在 <code>A</code> 前面。</p><p>我们已经用 <code>runtime.GOMAXPROCS(1)</code> 设定只有一个 P，但是 Go 语言的 GMP 调度器，仍然会 10ms 释放一次时间片，也就意味着，即使 <code>go busy(&quot;A&quot;)</code> 处于阻塞状态，时间片之后也会让出执行权，交给主线程去运行 <code>B</code>。</p><p>可以用这个 <code>busy</code> 的函数定义来让抢占式调度更加肉眼可见：</p><pre><code class="go">func busy(tag string, d time.Duration) &#123;    end := time.Now().Add(d)    next := time.Now()    for time.Now().Before(end) &#123;        if time.Now().After(next) &#123;            fmt.Print(tag, &quot; &quot;) // 每 ~100ms 打印一次            next = time.Now().Add(100 * time.Millisecond)        &#125;    &#125;    fmt.Println(tag, &quot;done&quot;)&#125;</code></pre><p>程序的打印结果会是 <code>B A B A B A A B A B A B A B A B A B A B A B A B B A B A B A B done</code>。这意味着不是 tag 为 <code>A</code> 的 P 一路执行到底，也不是 tag 为 <code>B</code> 的 P 一路执行到底，他们在 GMP 调度器中交替执行。</p><h3 id="P-偷活干（work-stealing）"><a href="#P-偷活干（work-stealing）" class="headerlink" title="P 偷活干（work-stealing）"></a>P 偷活干（work-stealing）</h3><p>来看这个代码示例：</p><pre><code class="go">package mainimport (    &quot;runtime&quot;    &quot;sync&quot;    &quot;time&quot;)func spin(d time.Duration) &#123;    deadline := time.Now().Add(d)    for time.Now().Before(deadline) &#123;    &#125; // 纯CPU忙等&#125;func main() &#123;    runtime.GOMAXPROCS(1) // 先让所有 G 挤到同一个 P 的本地队列    const N = 120    var wg sync.WaitGroup    wg.Add(N)    for i := 0; i &lt; N; i++ &#123;        go func() &#123; defer wg.Done(); spin(500 * time.Millisecond) &#125;()    &#125;    time.Sleep(30 * time.Millisecond) // 给点时间把队列堆满到 P0    runtime.GOMAXPROCS(4) // 突然放大并行度：P1~P3 会去“偷” P0 的一半    wg.Wait()&#125;</code></pre><p>这个代码干了什么呢，首先设定之后一个 P，然后启动 120 个 G 给这个 P 去执行。30 毫秒后，突然增大 P 的数量。</p><p>用 debug 日志能看到，运行后半段有这样的日志：</p><pre><code class="bash">P0: status=1 schedtick=46 syscalltick=2 m=0 runqsize=17 gfreecnt=0 timerslen=0P1: status=1 schedtick=58 syscalltick=0 m=4 runqsize=5 gfreecnt=15 timerslen=0P2: status=1 schedtick=60 syscalltick=0 m=2 runqsize=5 gfreecnt=18 timerslen=0P3: status=1 schedtick=42 syscalltick=0 m=3 runqsize=17 gfreecnt=0 timerslen=0</code></pre><p>也就是说，本应该 G 全在 P0 上运行，等到 P1、P2、P3 出来后，它们发现 P0 很忙，就去 P0 的队列里拿了几个任务过来执行。</p><h3 id="P-的-runq-队列和全局队列"><a href="#P-的-runq-队列和全局队列" class="headerlink" title="P 的 runq 队列和全局队列"></a>P 的 runq 队列和全局队列</h3><p>一个 P 想找活干的时候，上面的代码是偷其他 P 的示例。更严谨的流程是，P 先从本地 runq 队列找，再到全局队列找，找不到再去偷其他 P 的。</p><p>什么是 runq 队列，什么是全局队列？可以看这个代码：</p><pre><code class="go">package mainimport (    &quot;runtime&quot;    &quot;sync&quot;    &quot;time&quot;)func spin(d time.Duration) &#123;    end := time.Now().Add(d)    for time.Now().Before(end) &#123;    &#125; // 纯CPU忙等：保持 runnable&#125;func main() &#123;    runtime.GOMAXPROCS(1) // 只有 P0：所有新 G 先进入 P0 的本地 runq    const N = 600 // 让它明显超过本地 runq 容量（当前实现通常是 256）    var wg sync.WaitGroup    wg.Add(N)    for i := 0; i &lt; N; i++ &#123;        go func() &#123; defer wg.Done(); spin(800 * time.Millisecond) &#125;()    &#125;    time.Sleep(500 * time.Millisecond) // 给运行时时间把“溢出的一半”推到全局队列    runtime.GOMAXPROCS(4) // 其它 P 进场，会先从“全局队列”拿活（不是偷）    wg.Wait()&#125;</code></pre><p>debug 状态运行：</p><pre><code class="bash">go build demo4.go   GODEBUG=&#39;schedtrace=200,scheddetail=1&#39; ./demo4 &amp;&gt; demo4.log</code></pre><p>日志会比较多，日志前面几行像这样：</p><pre><code class="bash">SCHED 0ms: gomaxprocs=10 idleprocs=9 threads=2 spinningthreads=0 needspinning=0 idlethreads=0 runqueue=0 gcwaiting=false nmidlelocked=0 stopwait=0 sysmonwait=false  P0: status=1 schedtick=0 syscalltick=0 m=0 runqsize=0 gfreecnt=0 timerslen=0  P1: status=0 schedtick=0 syscalltick=0 m=nil runqsize=0 gfreecnt=0 timerslen=0</code></pre><p>其中首行的 <code>runqueue=0</code> 就是全局队列，P0 后面的 <code>runqsize=0</code> 是 P0 的本地队列，P1 后面的 <code>runqsize=0</code> 是 P1 的本地队列。可以看到此时的 P1 状态是 0，也就是不可运行。</p><p>随着程序的运行，P0 会启动非常多个 G，日志状态是这样：</p><pre><code class="bash">SCHED 200ms: gomaxprocs=1 idleprocs=0 threads=5 spinningthreads=0 needspinning=1 idlethreads=3 runqueue=395 gcwaiting=false nmidlelocked=0 stopwait=0 sysmonwait=false  P0: status=1 schedtick=10 syscalltick=2 m=0 runqsize=204 gfreecnt=0 timerslen=1</code></pre><p>一般 P 的本地队列默认是上限是 256，达到这个峰值后，就会把任务溢出到全局队列。</p><p>再然后，P1、P2、P3 启动，开始从全局队列拿任务（全局队列有任务则不需要偷其他 P 的）：</p><pre><code class="bash">SCHED 826ms: gomaxprocs=4 idleprocs=0 threads=5 spinningthreads=0 needspinning=1 idlethreads=0 runqueue=217 gcwaiting=false nmidlelocked=0 stopwait=0 sysmonwait=false  P0: status=1 schedtick=35 syscalltick=2 m=0 runqsize=179 gfreecnt=0 timerslen=0  P1: status=1 schedtick=14 syscalltick=0 m=3 runqsize=90 gfreecnt=0 timerslen=0  P2: status=1 schedtick=14 syscalltick=0 m=4 runqsize=64 gfreecnt=0 timerslen=0  P3: status=1 schedtick=13 syscalltick=0 m=2 runqsize=46 gfreecnt=0 timerslen=0</code></pre><p>另外，当 P 依次从本地 runq、全局队列、其他 P 都找不到任务时，会再去问一下 netpoll（问一下 OS）有没有新的 G，要是有就执行，没有就自旋（待命）。这就是 P 执行任务的逻辑。</p><h3 id="阻塞-syscall-会及时让出"><a href="#阻塞-syscall-会及时让出" class="headerlink" title="阻塞 syscall 会及时让出"></a>阻塞 syscall 会及时让出</h3><p>看这个代码例子：</p><pre><code class="go">package mainimport (    &quot;fmt&quot;    &quot;runtime&quot;    &quot;time&quot;)func main() &#123;    runtime.GOMAXPROCS(2)    go func() &#123;        time.Sleep(2 * time.Second) // 类比阻塞 syscall/cgo        fmt.Println(&quot;blocking done&quot;)    &#125;()    go func() &#123;        for i := 0; i &lt; 6; i++ &#123;            time.Sleep(300 * time.Millisecond)            fmt.Println(&quot;still running&quot;, i)        &#125;    &#125;()    time.Sleep(3 * time.Second)&#125;</code></pre><p>运行结果会是：</p><pre><code class="bash">still running 0still running 1still running 2still running 3still running 4still running 5blocking done</code></pre><p>这个代码示例的含义是，第一个 G 明明会阻塞任务队列，一直占着 P 执行，但实际上第二个 G 仍然在运行。</p><p>说明 GMP 调度器不会因为某个 G 的阻塞，影响到其他 G 的执行。（其实这是协程调度器很基本的要求）</p><h3 id="关闭异步抢占"><a href="#关闭异步抢占" class="headerlink" title="关闭异步抢占"></a>关闭异步抢占</h3><p>对于这个代码示例：</p><pre><code class="go">package mainimport (    &quot;fmt&quot;    &quot;runtime&quot;    &quot;time&quot;)func spin() &#123;    for &#123; /* 紧密循环 */    &#125;&#125;func main() &#123;    runtime.GOMAXPROCS(1)    go spin()    time.Sleep(100 * time.Millisecond)    fmt.Println(&quot;I should still print unless preemption is off&quot;)&#125;</code></pre><p>可以分别用两个命令来运行，一个是</p><pre><code class="bash">go build demo7.goGODEBUG=&#39;schedtrace=1000,scheddetail=1&#39; ./demo7</code></pre><p>另一种是：</p><pre><code class="bash">go build demo7.goGODEBUG=&#39;schedtrace=1000,scheddetail=1,asyncpreemptoff=1&#39; ./demo7</code></pre><p>用 <code>asyncpreemptoff=1</code> 可以关闭异步抢占。也就是说，如果没有关闭，没有带这个参数，程序会正常运行，打印出：</p><pre><code class="bash">I should still print unless preemption is off</code></pre><p>如果关闭了异步抢占，则程序会被死循环卡住。这个例子主要可以体现 GMP 主动让出 CPU 的特点，当关闭了主动让出的能力后，GMP 就会被阻塞住了。</p><h3 id="Go-语言源码"><a href="#Go-语言源码" class="headerlink" title="Go 语言源码"></a>Go 语言源码</h3><p>我没有深入看源码，比如 G、M、P 的常量定义在 <a href="https://github.com/golang/go/blob/master/src/runtime/runtime2.go#L18"><code>src/runtime/runtime2.go</code></a> 文件：</p><img src="1.png" width="60%"><p>再比如 <a href="https://github.com/golang/go/blob/master/src/runtime/proc.go"><code>src/runtime/proc.go</code></a> 文件中的 <code>runqputslow</code> 函数，功能就是判断本地队列有没有满，如果满了就放到全局队列：</p><img src="2.png" width="60%"><h3 id="进一步深入"><a href="#进一步深入" class="headerlink" title="进一步深入"></a>进一步深入</h3><p>这篇文章肯定有不全面和不到位的地方，我不想进一步深入了，也许有人喜欢折腾这些吧。</p><p>Go 语言的 GMP，就是协程调度器的一种具体的工程化的实现，估计很多人在意的，是这种工程化实现背后的细节，比如怎么用栈结构来管理任务队列、怎么实现抢占、让出逻辑等。协程调度器的具体实现方式可以有各种各样的变化，但它们的基本原理都是 continuation。只是 Go 语言把协程作为卖点了。只要其他语言愿意，也是可以开发出自己版本的协程调度器的。</p><p>那么问题来了，那些喜欢研究 GMP 原理的人，你们有没有了解过其他语言的协程（coroutine）、虚拟线程、异步函数、Process 是怎么实现的，它们都是比线程更轻量的类似于协程的东西，和 Go 语言的 gorountine 有什么区别？横向对比一下？</p><p>如果什么时候，我的工作需要，只有我了解这些内容，才能把工作做好，那么我肯定去把这些东西搞明白。</p><h3 id="疑问"><a href="#疑问" class="headerlink" title="疑问"></a>疑问</h3><p>我之前写过一个观点：</p><p>Go 语言 “千辛万苦” 做出了自动的垃圾回收，减轻程序员对于内存管理的头脑负担。而有些面试官 “千辛万苦” 去搞明白 Go 语言 GC 的原理是什么，怎么标记怎么释放之类，不但引以为豪，而且拿来考察候选人。作为 Go 语言的教徒，你知不知道你的行为在否定 Go 语言设计者的努力？如果真的相信用头脑来管理内存的力量，为什么不去搞 Rust？好比我是一个汽车驾驶员，我要去考驾照，难道需要我搞清楚发动机的工作原理、是怎么把汽油燃烧转变为机械动力的、能量转化公式是什么？我又不是在制造汽车，也不是在开发编程语言。</p><p>同样的道理：</p><p>Go 语言为了让广大程序员能便捷简单地、用上轻量级的协程，“千辛万苦” 搞出来一个 <code>go</code> 关键字，然而有些人却费尽 “千辛万苦” 研究这个调度器是怎么实现的，懂原理则说明会 Go 语言，不懂则说明 Go 语言水平不行，这是什么道理？作为 Go 语言的教徒，你在否定 Go 语言设计者的努力，明白吗？如果这个语言需要你搞清楚协程调度的原理，才能写出好的代码，那就说明这个语言实现的不到位，偏离了设计者的初衷，没有达到设计者本来的意图。</p><p>如果你是编程语言的开发者，需要在另一种语言中借鉴、实现、优化 Go 语言的调度器，那么你就尽情研究吧，这样的工作确实需要懂 GMP 调度器的原理。如果不是那样的工作呢？</p>]]></content>
  </entry>
  <entry>
    <title>对 Remittix 项目的分析</title>
    <link href="https://crazy.smallyu.net/2025/08/17/%E5%AF%B9Remittix%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/08/17/%E5%AF%B9Remittix%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-17T13:35:57.000Z</published>
    <updated>2025-11-27T17:16:12.954Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p><a href="https://remittix.io/">Remittix</a> 是一个专注于解决跨境支付问题的平台，，可以通过 RTX 代币直接把加密货币转换为当地的法币。<a]]></summary>
    <content type="html"><![CDATA[<p><a href="https://remittix.io/">Remittix</a> 是一个专注于解决跨境支付问题的平台，，可以通过 RTX 代币直接把加密货币转换为当地的法币。<a href="https://www.indiatimes.com/partner/best-crypto-presale-to-buy-now-remittix-soars-towards-18m-dollar-raised-as-eager-holders-await-beta-wallet-waitlist-665501.html?utm_source=chatgpt.com">目前</a> 已经预售了超过 5 亿枚 RTX 代币，筹集资金总额达到 1800 万美元。</p><h3 id="白皮书"><a href="#白皮书" class="headerlink" title="白皮书"></a>白皮书</h3><p>RTX 以 <a href="https://remittix-organization.gitbook.io/remittix/tokenomics/the-remittix-token-rtx">ERC-20</a> 的形式发售，这就有点奇怪了，意味着 RTX 无法承担起付手续费的作用。那么 Remittix 是怎么解决跨境支付问题的？</p><img src="2.png" width="80%"><p>Remittix 的 <a href="https://remittix-organization.gitbook.io/remittix/tokenomics/roadmap">路线图</a> 是真实的，目前处于预售和 TGE 阶段，CMC 上已经有了 <a href="https://coinmarketcap.com/currencies/remittix/#News">信息</a> 但是没有正式的代币出来。</p><p>Remittix 的 <a href="https://remittix-organization.gitbook.io/remittix">白皮书</a> 整体看下来，完全没有看到有用的信息，都是一些非常宏观的描述，市场规模多大、问题是什么、对比区块链技术等，根本没说 Remittix 的创新之处。</p><p>比如 <a href="https://remittix-organization.gitbook.io/remittix/vision/why-remittix">这个页面</a>，一直在说 Remittix 去中心化、交易确认速度快等。不是，你 ERC-20 的代币，随便一个人都能发、都能有这些特点的，到底解决了什么问题呢？</p><p>能明确的是，Remittix 仅仅只是用 ERC-20 发币而已，不是一条链，没有更多的技术含量在里面。</p><h3 id="诈骗账号"><a href="#诈骗账号" class="headerlink" title="诈骗账号"></a>诈骗账号</h3><p>你一旦关注 Remittix 的 X 账号，就会有一些假装客服、技术支持的账号关注你。这种现象很常见，正经项目很少有这种冒充官方的账号：</p><img src="1.jpg" width="50%"><h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>Remittix 是骗子项目。Remittix 没有任何公开的代码仓库，也没有上交易所，只有一堆新闻文稿和预售金额放在那里，很难对这个项目产生信任。</p><p>所以我的结论是，Remittix 的性质和 Nexchain 一样，都属于骗子项目。甚至很多方面这两个项目有点像，比如预售的套路，给人的某种感觉，等等。</p><p>你也许觉得我这种判断方式太过武断了，比如 RTX 在 CMC 上有 5k 收藏量是实打实的，如果 RTX 是骗子项目，会有那么多人信吗？这也是我困惑的点，我理解不了为什么有那么多人相信这个项目，那么多人参与预售，理解不了为什么。</p><p>虽然理解不了，但是根据我自己的判断，尤其是从技术角度的判断，Remittix 就是骗子项目。</p><p>另外，由于 Remittix 是用 ERC-20 发币，没有什么技术方面可分析的，有点没意思。上一个分析的项目 Nexchain 也是这样。这种情况不太好，我还是倾向于看点有技术内容的项目，所以以后得更小心选择项目才行。不过这种情况又有点难以避免，就像我一开始说的，我没办法在选择项目的时候，就知道项目有没有技术含量。</p>]]></content>
  </entry>
  <entry>
    <title>对 Nexchain 项目的分析</title>
    <link href="https://crazy.smallyu.net/2025/08/16/%E5%AF%B9Nexchain%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/08/16/%E5%AF%B9Nexchain%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-16T10:10:31.000Z</published>
    <updated>2025-11-27T17:16:12.942Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>我之前大概看了一眼 <a href="https://nexchain.ai/">Nexchain</a> 的整个项目情况，对它的印象不是很好，感觉像是资金盘的玩法，没有技术，也没有代码。接下来详细拆解一下我这种判断的来源。</p>
<h3 id="白皮书"><a]]></summary>
    <content type="html"><![CDATA[<p>我之前大概看了一眼 <a href="https://nexchain.ai/">Nexchain</a> 的整个项目情况，对它的印象不是很好，感觉像是资金盘的玩法，没有技术，也没有代码。接下来详细拆解一下我这种判断的来源。</p><h3 id="白皮书"><a href="#白皮书" class="headerlink" title="白皮书"></a>白皮书</h3><h4 id="排版"><a href="#排版" class="headerlink" title="排版"></a>排版</h4><p>首先看看 Nexchain <a href="https://nexchain.ai/documents/Whitepaper-Nexchain.pdf">白皮书</a> 的这个字体大小和排版，像是高中生整出来的东西，没写过论文，也没经历过职场毒打那种：</p><img src="1.png" width="50%"><p>再看看这个正文里表格的排版，哪有点正经论文的样子？</p><img src="2.png" width="50%"><p>论文中的公式直接贴一个不高清的图片：</p><img src="5.png" width="50%"><h4 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h4><p>然后看看这个目录，一条区块链的白皮书，竟然写市场机会有多大、如何建设平台、Dapp 什么的，闭口不提区块链技术方面的创新：</p><img src="3.png" width="50%"><p>其实白皮书里并不是一无是处，比如这个摘要部分提到了不少技术，AI 啊、PoS 啊、DAG 啊，虽然不新鲜，但至少有：</p><img src="4.png" width="70%"><p>这些内容是不是勾起了你的好奇心？Nexchain 在这些技术上有什么创新和贡献？论文中提出了什么新的思路吗？</p><p>答案就是，没有技术创新也没有贡献，甚至白皮书里面都不详细写。比如在介绍 DAGs 的部分，先是介绍了 DASs 的区块结构是什么、有哪些同类型的项目，这个算是正常套路，然后呢，你以为他要开始写 Nexchain 是怎么做的了，结果没有，白皮书里面就一句话，Nexchain 集成了 DAGs，提高了可扩展能力什么的：</p><img src="15.png" width="80%"><p>整个白皮书像是三流大学生堆砌论文的样子，各种不明所以的术语和介绍往上面堆，然后什么有用的信息都没有。光是白皮书这里就很让 Nexchain 掉价了。</p><h3 id="官网"><a href="#官网" class="headerlink" title="官网"></a>官网</h3><p>再来看看官网上的做派，预售页面竟然在预测 Listing 之后的价格，我印象中只有资金盘会这么干，这个预测价格只为了给用户一个预期，而不是自己真的能控制：</p><img src="6.png" width="60%"><p>不是，等等，你说网络有多高的 TPS？40万笔交易每秒？</p><img src="7.png" width="50%"><p><a href="https://nexchain.ai/blog">Blog</a> 文章整的还挺像样子，有耐心在不同的日期发布那么多篇。可能是 AI 一键生成的吧。</p><p>当然，不出意外的，网络并不处于运行状态，测试网的浏览器都没部署好：</p><img src="8.png" width="30%"><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>竟然敢公布 <a href="https://github.com/Nexchain">GitHub</a> 账号地址。这都没有看的必要，一共就 4 个仓库，最新一次的提交还是在 3 个月前：</p><img src="9.png" width="60%"><p>这些代码仓库是小学生搞的吧，基本的代码能力都没有。</p><h3 id="诈骗账号"><a href="#诈骗账号" class="headerlink" title="诈骗账号"></a>诈骗账号</h3><p>我在关注 Nexchain 的 X 后，就收到了几个诈骗账号的关注，这说明 Nexchain 是一个虚假账号聚集地：</p><img src="10.png" width="50%"><h3 id="预售"><a href="#预售" class="headerlink" title="预售"></a>预售</h3><p>其他项目一般会有一些新闻来源，作为项目实力的背书。Nexchain 能查到的为数不多的新闻是关于 <a href="https://www.crypto-reporter.com/press-releases/nexchain-nex-surges-with-8-5m-presale-raise-and-3x-potential-price-upside-in-2025-presale-106707/">预售金额达到 8百万美元</a> 的。注意这是预售额，而不是融资额。融资机构对项目会做一系列的调查，所以越是有融资纪录的项目，越靠谱。而 Nexchain 目前没有查到融资纪录。</p><p>那么余额额真的达到 8百万美元了吗？</p><p>如果你尝试参与预售，就会看到这个下单页面，它让你直接转账一定金额到目标地址，如果余额不足，允许你自己给目标地址转账：</p><img src="11.png" width="50%"><p>订单界面的目标地址是 <a href="https://etherscan.io/address/0x387e086e5F52e2BC8B715693aE76fE63A5De9877"><code>0x387e086e5F52e2BC8B715693aE76fE63A5De9877</code></a>，你猜这个接受预售的地址，一共有多少余额？</p><img src="12.png" width="90%"><p>10 个 ETH 和价值接近 50万美元的 USDT。哪来的 8百万？哦，对了，不一定全在余额上，也可能被转出了，来看看 <a href="https://etherscan.io/txs?a=0x387e086e5F52e2BC8B715693aE76fE63A5De9877&f=2">转出记录</a>：</p><img src="13.png" width="100%"><p>说实话，这个转出记录的金额还真不小，大概 117ETH。按照现在的价格算，大概 50万美元。</p><p>总之这个地址的余额总数，和宣传的数字是对不上的。你也许会说，不只一个接收地址，前几期的预售用了其他的接收地址？我无从得知。</p><p>不过单看这个地址的余额，其实金额挺大了，接近 100万美元。和这个项目白皮书的排版水平相比，真的是挺大了。我有点难以想象，一个毫无基础设施的项目，只有一些前端页面，竟然就能骗到这么多钱，这到底怎么回事？</p><h3 id="ins"><a href="#ins" class="headerlink" title="ins"></a>ins</h3><p>Nexchain 的 <a href="https://www.instagram.com/nexchainai/">Instagram</a> 挺有意思，发布过很多关键消息。其实从历史记录来看，8百万的预售额大概率是真的，是我怀疑过早了，一共预售了 25期，确实有可能分多个地址收到了 5百万美元。</p><p>更离谱的地方在于，ins 的历史帖子上，发布过 Nexchain 和 Google Cloud、和 Open AI 合作的新闻：</p><img src="14.png" width="60%"><p>这么强大的资金背景，以及与大企业的合作背景，到这里我都有点怀疑自己是不是搞错了，有眼不识泰山，小看了 Nexchain？这个世界让我很难以理解。</p><h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>我仍然相信，Nexchain 是骗子项目。</p>]]></content>
  </entry>
  <entry>
    <title>Web3 项目分析计划</title>
    <link href="https://smallyu.net/2025/08/14/Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/"/>
    <id>blog:https://smallyu.net/2025/08/14/Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/</id>
    <published>2025-08-14T15:00:00.000Z</published>
    <updated>2025-09-30T17:05:54.826Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Web3 项目分析系列文章专用的 Paragraph 频道地址是：</p>
<ul>
<li><a]]></summary>
    <content type="html"><![CDATA[<p>Web3 项目分析系列文章专用的 Paragraph 频道地址是：</p><ul><li><a href="https://paragraph.com/@smallyu">https:&#x2F;&#x2F;paragraph.com&#x2F;@smallyu</a></li></ul><h3 id="计划内容"><a href="#计划内容" class="headerlink" title="计划内容"></a>计划内容</h3><p>经过几天时间的尝试，我觉得 Web3 项目分析计划是一件很有意义的事情。不清楚看到分析文章的人有没有收获，但是从我自己理解项目、学习技术的角度，是有收获的，所以我需要把这个计划继续下去，变为一件常态化的事情。</p><p>具体计划内容是，每周分析一个 Web3 行业的项目，从看白皮书开始，到理解项目的运作模式、当前商业状态等，尤其关注技术理念和技术创新方面，然后写成分析报告，不需要很专业的那种报告，大概相当于学习笔记就可以了。具体分析哪个项目是经过主观挑选的。最终的分析报告也许会有质量，有看点，但也许会比较短，没有质量。因为我并不能在一开始选定项目的时候，就知道这个项目有没有含量，尤其是技术含量。</p><h3 id="工程代码没有价值"><a href="#工程代码没有价值" class="headerlink" title="工程代码没有价值"></a>工程代码没有价值</h3><p>这个计划有点像是区块链研究员干的事情，而不是区块链程序员应该干的事情。为什么我的计划不是每天写 100 行代码，开发一个区块链小工具，或者每天积累一点，开发一个大的区块链工程？</p><p>因为工程代码如果脱离项目背景，就没有价值。我在几年的工作中写过很多代码，但是如果现在把那些代码拿出来，会发现毫无意义。工程化的代码，往往是为了完善项目的功能，而项目需要某些方面功能，是为了迎合运营和宣发的需求，一定是有商业目的的。如果需求背景不存在，代码就毫无价值。</p><p>尤其是随着 AI 的日益强大，写工程代码这件事情更是越来越廉价。AI 可以几分钟写出上万行代码，堆砌代码的能力绝对超过人类。如果我想靠每天写几百行工程代码来训练和提升自己，那我一定会失败的很惨。所以不能干这样的事情。</p><p>什么样的工程代码是有意义的呢？就是已经找准了产品需求和定位的情况下，想把功能落实跑通，然后让 AI 来干活，把代码写出来。AI 写的代码有时候会跑偏，需要手动修复一下 bug，这种情况下，手动写出的工程代码才有意义。现在的开发节奏已经应该是这样了。</p><p>以前的时代，人们喜欢说 “Talk is cheap. Show me the code”，但是现在时代变了， prompt 比 code 更有价值，也许这句话会变为 “Code is cheap. Show me the prompt”。</p><h3 id="文章更能表达思想"><a href="#文章更能表达思想" class="headerlink" title="文章更能表达思想"></a>文章更能表达思想</h3><p>不去计划每天写一些工程代码，另一个原因在于，我已经做过了一些尝试，去试图开发小的区块链工具，或者大的区块链工程。目前来看，我之前的想法，无论是做小工具的思路，还是做大工程的思路，都是没有结果的，因为需求本身也许不存在。没有任何正反馈，根本做不下去。</p><p>与代码相比，写文字、写文章、写观点更有意义一点。一个产品创意背后，可能有 100 行代码，也可以有 10000 行代码，需要付出的时间成本完全不同，但如果最终的关注量都是 0，那么结果就是一样的，9900 行代码白写了。而文字是能够体现思想的。</p><p>你也许想反驳，怎么能说工程代码没有价值呢？以太坊的客户端同一份 Spec，有五六种工程化的实现，用了不同语言、做了不同优化，市场占有率有高有低，难道不是工程化代码价值的体现吗？当然是，他们拿着以太坊基金会的赞助开着公司写着代码，而且已经有了明确的项目背景，工程代码自然是有价值的。我指的是没有项目背景的工程代码。</p><p>虽然工程代码没有价值，但教学性质的代码是很有意义的，我仍然会复习计算机课的练习题，以保证自己的代码水平。我已经是第三轮做那些练习题了，这次我严格限制自己的做题速度，一天最多做一道题。一方面是保证有足够的时间消化练习题包含的知识，相信潜意识的力量。另一方面，得分配时间到其他事情上，不能整天只反复做同样的题。而且由于做题比较慢，可以逐渐培养自己每天做题的习惯，不至于遗忘计算机课的知识。</p><h3 id="提高宏观理解能力"><a href="#提高宏观理解能力" class="headerlink" title="提高宏观理解能力"></a>提高宏观理解能力</h3><p>为什么我觉得对项目做分析是有意义的？因为其实我对区块链技术的理解，很大程度上，来自于几年前读了很多白皮书。我当时按照币种市值的排名，逐一下载了排名前几百的币种白皮书，还用 A4 纸都打印出来看。</p><p>记得几年前有人发邮件问我，如何学习区块链技术。我当时认真写了个回复，说我是从哪个网站下载的白皮书，以及看了哪些书之类。后来对方回复我说，这不是他想要学习的区块链技术，他想要学习的是如何写代码。那个时候我才意识到，不同的人，对技术的定义是不同的。</p><p>以前没有 AI，我没能认识到代码的价值，现在有了 AI，我还是认识不到代码的价值。</p><h3 id="研究能力的重要性"><a href="#研究能力的重要性" class="headerlink" title="研究能力的重要性"></a>研究能力的重要性</h3><p>在币圈，人们常说 DYOR（Do Your Own Research），这个词经常出现在 KOL 推广和夸赞某个代币的时候，用来声明不做投资建议，你要自己对自己负责。“研究能力” 一直都是非常重要的能力，如果不具备好的研究能力，你连自己的钱都管理不好。事实上什么事情都需要研究，研究如何学英语、研究如何找工作、研究假期去哪儿玩、研究写代码、研究科学技术、研究如何哄女朋友开心，等等，都是研究。Web3 项目分析计划的目标正是研究项目、锻炼研究能力。</p><p>具备好的研究能力的人，不管学习什么都会变得轻松。试想，你觉得去研究明白怎么把代码写好，尤其是工作中用的普通代码，需要多长时间？很多时候连 “研究” 都用不着！那么，你觉得能把某种技术研究明白的人，会没有能力研究清楚怎么写代码吗？</p><p>那么为什么我觉得自己可以写出分析报告？我以前没专门写过，但是有时会根据技术来对项目做横向对比，所以专注于对某个项目做技术分析，应该不是难事。我工作过的项目，假如让我写分析，肯定能写出其中的细节，只是因为项目还在，不能写。写项目分析对我来说也是一个学习和积累的过程。</p><p>实际上分析区块链项目的方法论，我早在《<a href="/2024/10/15/%E7%9C%8B%E6%87%82%E4%BB%BB%E6%84%8F%E5%8C%BA%E5%9D%97%E9%93%BE%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84/">看懂任意区块链项目的技术架构</a>》就写过了，到现在都不觉得那篇文章内容有什么问题，无非就是链上链下交互，不同项目往里面填充不同的业务逻辑而已。</p><h3 id="写作平台的选择"><a href="#写作平台的选择" class="headerlink" title="写作平台的选择"></a>写作平台的选择</h3><p>我对于博客上应该放哪些文章，是比较纠结的，我不希望一打开博客，满屏幕都是 “对 XX 项目的分析”。为了保持文章列表的简洁，这些项目分析系列的内容应该换一个平台放。最近看到 Paragraph 不错。Paragraph 是一个 Web3 领域的 Newsletter 平台，功能类似于 Web2 的 Substack，每篇文章的全部内容都会提交到 Arweave 区块链上，包括作者的名字、头像、文章正文、配图等。（这也就意味着文章一旦发布，就不可能被删除。）</p><p>为什么不选择其他平台呢？比如发到知乎、掘金，甚至是头条、百度、登链等平台，再加上 Meidum、X、Mirror 一类，文章访问量肯定可以高很多，关注量也会高很多。</p><p>因为那些充斥着低质量内容的平台，不值得去发布高质量内容的文章。那些人是看不懂的，看不懂我在写什么。看看掘金首页上有什么？10 篇文章 8 篇讲 Cursor，很难想象用户素质得多低。知乎就更不用说了，内容杂乱、商业化，关键是网页访问弹窗，不是让登陆就是让下载 APP，正经人谁去那种平台啊。我在脉脉的职言区，匿名账号下，发布过几千条帖子，总阅读量超过几千万，发的都是观点偏激、引战一类的内容。那种阅读量有意义吗？没有意义。</p><p>所以继续努力吧，等自己成为 somebody，再考虑访问量的问题。没有人会关心 nobody 写的东西。</p><h3 id="为什么要做出计划"><a href="#为什么要做出计划" class="headerlink" title="为什么要做出计划"></a>为什么要做出计划</h3><p>其实要按照我自己喜好，我觉得自己真正有价值的文章，是吐槽同事、吐槽公司、吐槽面试经历等情绪宣泄类内容。那些是包含了亲身经历、切实体会、真情实感在里面的，耗费了时间和心情才得到的、宝贵的人生体验，比技术文章有意思多了。对行业的见解、对公司的不满、对同事的吐槽，是我的文章永远超越 AI 的地方，因为 AI 没有情绪，不会生气、不会沮丧。单纯讲技术知识点，AI 一下子就能生成很多，但是 AI 永远无法体会到作为人的情感。</p><p>反正人总要做选择，要么忙着活，要么忙着死。</p><img src="1.jpg" width="60%" />]]></content>
  </entry>
  <entry>
    <title>继续 Web3 项目分析计划</title>
    <link href="https://crazy.smallyu.net/2025/08/14/%E7%BB%A7%E7%BB%ADWeb3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/08/14/%E7%BB%A7%E7%BB%ADWeb3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/</id>
    <published>2025-08-14T11:22:13.000Z</published>
    <updated>2025-11-27T17:16:12.959Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>经过一段时间的尝试，我认为 <a]]></summary>
    <content type="html"><![CDATA[<p>经过一段时间的尝试，我认为 <a href="/2025/07/31/%E5%A4%B1%E4%B8%9A%E6%9C%9F%E9%97%B4%E7%9A%84Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/">Web3 项目分析计划</a> 是一件很有意义的事情。我不清楚看到分析文章的人有没有收获，但是我从理解和学习项目技术的角度，是有收获的，所以我需要把这个计划继续下去，变为一件常态化的事情。</p><p>既然是一件长期的事情，做项目分析的频率就不应该那么高，目前计划一周分析一个项目，这样既不会有太大压力，不能整天只干这个，也不会因为拖沓时间太长导致计划中断。一周一个项目是底线，如果空闲时间比较多，就可以增加任意数量。如果跳票了，跳票就跳票，反正没人关注……以培养我自己的技术习惯为主，沉淀一些东西，<a href="/2025/08/02/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E5%9D%9A%E6%8C%81%E7%94%A8%E7%8B%AC%E7%AB%8B%E5%8D%9A%E5%AE%A2/">选择独立博客</a> 本身就没指望访问量和关注量。</p><p>为了解决项目分析文章 <a href="/2025/08/07/%E5%81%9C%E6%AD%A2Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/">刷屏博客首页</a> 的问题，这些项目分析系列的内容应该换一个平台放。现在看到 <a href="https://paragraph.com/">Paragraph</a> 不错。Paragraph 是一个 Web3 领域的 Newsletter 平台，功能类似于 Web2 的 Substack，每篇文章的全部内容都会上链到 Arweave 区块链上（这也就意味着文章一旦发布就不可能删除），包括作者的名字、头像、文章正文、配图等。一笔链上交易是 <a href="https://viewblock.io/arweave/tx/IcriBdcftPPhmtYKkLKnL1CeHI4wn9iYaq2dhWi2kc0">这个样子</a>。</p><p>Web3 项目分析系列文章专用的 Paragraph 频道地址是：</p><ul><li><a href="https://paragraph.com/@smallyu">https:&#x2F;&#x2F;paragraph.com&#x2F;@smallyu</a></li></ul><p>以后上面发布的内容会类似于《<a href="/2025/08/01/%E5%AF%B9Psyche-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/">对 Psyche Network 项目的分析</a>》，目前为止已经写过的有这些项目，博客上都删掉了，接下来几天会逐步搬到 Paragraph 上：</p><ul><li>Psyche Network</li><li>Camp Network</li><li>Arcium Network</li><li>0G</li><li>Mignight Network</li><li>Humanity Protocol</li></ul><p>选择 Paragraph 的好处是平台挺好用的，坏处是它是一个英文为主的平台，而且网络连接受到限制。没关系。反正人总要做出选择，要么忙着活，要么忙着死。认真生活就好了。</p><br><br><img src="1.jpg" width="80%" /><br><img src="2.jpg" width="80%" /><br><img src="3.jpg" width="80%" />]]></content>
  </entry>
  <entry>
    <title>对 Humanity Protocol 项目的分析</title>
    <link href="https://crazy.smallyu.net/2025/08/11/%E5%AF%B9Humanity-Protocol%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/08/11/%E5%AF%B9Humanity-Protocol%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-11T12:06:25.000Z</published>
    <updated>2025-11-27T17:16:12.932Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p><a href="https://www.humanity.org/">Humanity Protocol</a> 去年 5 月份获得了 3 千万美元的 <a]]></summary>
    <content type="html"><![CDATA[<p><a href="https://www.humanity.org/">Humanity Protocol</a> 去年 5 月份获得了 3 千万美元的 <a href="https://www.humanity.org/blog/humanity-protocol-raises-30m-at-a-1-billion-valuation-to-build-zero-knowledge-worldcoin-competitor">融资</a>，今年 6 月份上线了主网，并进行了空投，目前空投仍在继续，代币是 $H。</p><p>我在看到 Humanity Protocol 的官网和导航栏的时候，对这个项目的技术预期比较低，因为没有白皮书，也没有 GitHub 链接，看文档还等登陆账号，这些信号都在表明，Humanity Protocol 是一个依靠运营、营销、市场、玩法、热点的项目，而不是专注于技术。</p><p>来看看主网的 Top Accounts 代币余额情况：</p><img src="1.png" width="80%"><p>某一个账户控制了整个网络 99.86% 的代币，这可是主网啊。这样的代币分配模式，和区块链技术就已经无关了吧。而且很明显 Humanity Prococol 用的是以太坊节点，地址格式、交易哈希、手续费都是以太坊的格式。不过还不清楚具体是用什么技术方式启动的网络，在浏览器上看到了 Batches 的字样，应该是 L2 吧，那么大概率是 Op Stack。没准是用了某个 BaaS 平台，一键启动，能理解 😒。至少能肯定的是，链不是自己开发的，毫无技术含量。</p><p>翻了一下 Humanity Protocol 早期的 <a href="https://www.humanity.org/blog/humanity-protocol-emerges-from-stealth-human-institute-in-collaboration-with-animoca-brands-and-polygon-labs-pioneers-the-human-layer-for-web3">博客</a>，原来这个项目早在 2023 年就有想法了，在合伙人中还看到了 Polygon Labs 的身影，这个项目用的应该是 zkEVM Layer-2。</p><p>什么是 <a href="https://www.humanity.org/blog/beyond-web3-does-proof-of-humanity-apply-in-the-real-world">Proof of Humanity</a>（PoH）？用手机 KYC，手机 App 上的 KYC 信息会对应一个链上身份，这就是 Humanity Protocol 说的 PoH。</p><p>首先在官网上面用邮箱或者钱包登陆，你的账户会自动绑定一个链上地址，然后账户状态是未验证。你需要下载一个手机 App 来验证你的身份，这个 App 需要你打开前置摄像头，露脸并且在摄像头上比划一些手势，比如握拳、竖中指等，经过几个动作的验证，你的账户会变为已验证的状态。不得不说手机 App 做的还可以，验证流程是流畅的。</p><img src="2.png" width="40%"><p>说了这么多，Humanity Protocol 这个项目到底是在干什么？给其他项目提供验证身份的服务！</p><p>基于刚才提到的一整套身份验证流程，可以给合作的项目方单独验证一次，账户面板上有罗列很多还未验证的项目：</p><img src="3.png" width="80%"><p>对于这些项目方而言，Humanity Protocol 最大的作用，就是能够证明你是一个真实的人类，这是一件非常有意义的事情！</p><img src="4.png" width="40%"><p>Humanity Protocol 会把你的账户信息分享给其他项目！</p><p>你一定会担心，Humanity Protocol 会泄漏我的身份数据吗？这是 Humanity Protocol 在重点解决的问题，<a href="https://www.humanity.org/blog/zkproofers-enhancing-the-web3-experience-for-all?utm_source=chatgpt.com">大意</a> 是用 ZK 生成对身份信息的证明，达到不暴露身份数据也能验证身份的目的。</p><p>那么即使分享给其他项目的是身份的证明而不是原始数据，Humanity Protocol 官方的服务器上会储存我们的身份信息吗？</p><p>不知道！</p><p>Humanity Protocol 在说辞上肯定是，用户数据只保留在本地，绝不会上传到服务器，服务器上的都是一写不可逆的 ZK prove 数据。因为没有开源出代码，我们无法验证这一点。</p><p>总之，Humanity Protocol 的立意是好的，利用 ZK 技术能验证用户的真实性。项目最大的风险，或者凡是类似的项目，都必然会遭到隐私数据方面的质疑。相信 Humanity Procotol 把代码开源的那一天，这个问题会真正解决。</p>]]></content>
  </entry>
  <entry>
    <title>对 Midnight Network 项目的分析</title>
    <link href="https://b.smallyu.net/2025/08/10/%E5%AF%B9Midnight-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/10/%E5%AF%B9Midnight-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-09T19:16:34.000Z</published>
    <updated>2026-04-08T08:58:12.946Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p><a href="https://midnight.network/">Midngiht Network</a> 早在 2022 年就 <a]]></summary>
    <content type="html"><![CDATA[<p><a href="https://midnight.network/">Midngiht Network</a> 早在 2022 年就 <a href="https://iohk.io/en/blog/posts/2022/11/18/iog-announces-new-blockchain-to-protect-data-and-safeguard-technology-freedoms/?utm_source=chatgpt.com">宣布成立</a> 并处于技术研发中了。今天 6 月份 <a href="https://midnight.network/blog/state-of-the-network-june-2025?utm_source=chatgpt.com">正式宣布</a> 了 NIGHT 代币的 TGE 计划，目前 NIGHT 代币的 <a href="https://www.midnight.gd/">空投</a> 仍然处于申领阶段，所以近期 Midnight Network 处于比较活跃的状态。</p><p><strong>项目简介</strong></p><p>先来概括下 Midnight Network 在干什么，<a href="https://midnight.network/whitepaper">白皮书</a> 中的介绍是，Midngiht Network 结合了 ZK 技术后，可以实现对链上的数据进行隐私保护的效果。其他公开区块链的 DApp 在和区块链进行交互的时候，必然是暴露所有用户数据和交互记录的，而 Midnight Network 试图解决这个问题，允许用户和区块链交互的时候，有一部分链上数据是保密（Shielded）的。</p><p>对于这样的项目描述，我们可能会好奇两个技术问题：</p><ol><li>Midnight Network 的项目架构是怎样的？</li><li>Midngiht Network 是如何利用 ZK 技术，实现链上数据保密的？</li></ol><p>此外白皮书里还提到了其他概念，像 DID、RWA、投票之类，这些都是噱头类型的应用场景，不用在意。</p><p><strong>项目背景</strong></p><p>Midnight Network 的资金实力非常强大，没有公开的融资信息，但是持续开发了多年，还用了 <a href="https://midnight.foundation/">Midnight Foundation</a> 这样的名字，一般的开发团队可不敢叫基金会。技术实力也比较强大，比如开发出了 <a href="https://docs.midnight.network/develop/reference/compact/writing">Compact</a> 这样的编程语言，作为智能合约的开发语言，这种语言是为了表达 ZK 电路而专门设计的。还有很多已经发布的 <a href="https://docs.midnight.network/relnotes/overview">软件</a>，包括能本地运行的 Proof server、浏览器钱包、VS Code 插件等，简直自己开发了一整套生态。由此可见 Midnight Network 拥有深厚的技术积累。</p><p>遗憾的是，Midnight Network 公开的 <a href="https://github.com/midnight-ntwrk">Github仓库</a> 里，没有开源任何核心代码，所以我们没办法从代码角度对项目的技术结构做分析，只能根据文档描述来推测技术实现。要注意，文档内容不一样靠谱，因为即使一行代码没写，文档也可以写的很全面。即使内部服务器用了单机的程序，也可以对外宣称是去中心化网络，不能因为有公开的测试网 RPC 而相信什么。</p><p><strong>共识与出块</strong></p><p>不过也不用过度担心，文档中已经公开了很多操作流程。首先借用了 Cardano 的 <a href="https://docs.midnight.network/validate/run-a-validator/">质押池</a>，Midnight 的节点会追踪 Cardano 网络的质押情况，用来确认哪些节点有出块权限，有点像是侧链的模式，但是 Midnight 又不完全依赖 Cardano 网络，Midnight 把这种模式叫做 partner chain。</p><p>Midnight 网络的 <a href="https://docs.midnight.network/develop/nodes-and-dapps/consensus">出块</a> 则是借鉴了 PolkDot 网络 Substrate 的思路，由一种叫 <a href="https://openethereum.github.io/Aura">AURA</a> 的 PoA 共识出块，<a href="https://wiki.polkadot.com/learn/learn-consensus/?utm_source=chatgpt.com#finality-gadget-grandpa">GRANDPA</a> 机制负责块的确认。PolkDot 用这种混合的共识机制，是为了迎合子网络与平行链的应用场景。而 Midnight 用这种模式，目前没有找到很好的说辞，猜测一方面是直接用了 Substrate 的代码，方面二次开发；另一方面是有兼容 ZK 服务的考虑，也许有把 proof server 放到 validator 节点的尝试。</p><p>无论是哪种情况，都能看出 Midnight Network 有硬核的开发实力，在区块链的出块、共识方面都进行了自定义改造。</p><p><strong>隐私保护</strong></p><p>Midnight Network 能实现链上隐私保护的理论基础，是 IOHK 的一篇论文 <a href="https://iohk.io/en/research/library/papers/kachina-foundations-of-private-smart-contracts/">Kachina</a>，论文很复杂，简单理解就是用 ZK 电路来描述智能合约的状态转移函数。以往的智能合约不都是公开代码来改变状态吗，Kachina 试图用 ZK 来隐藏代码细节。论文包含很多具体设计，比如 ZK 描述全部状态转移是一件困难的事情，就简化为只描述对状态预言机的访问记录。</p><p>所以对于 Midnight 的隐私保护能力，可以理解为对 Kachina 做了 <a href="https://docs.midnight.network/academy/module-4">工程化</a> 的实现，链下生成对合约操作的 ZK 证明，链上来验证这个证明，并且改变链上状态。当然这个部分很复杂，但是 Midnight 把这一套做出来了，虽然代码没开源。</p><p><strong>隐私应用</strong></p><p>由于 Midngiht 对于 ZK 成熟的应用能力，搞出了 <a href="https://docs.midnight.network/learn/understanding-midnights-technology/zswap">Zswap</a> 这种带有隐私保护的代币交换池，大意是链上只暴露了 ZK 的承诺信息，但是并不透露具体哪两种代币发生了交换，也不知道交换金额是多少。有点类似 Zcash 的效果，但是做的更好。</p><p><strong>代币模型</strong></p><p>Midnight 的代币模型搞的也很复杂，有 NIGHT 和 DUST 两种代币，因为 Midnight 网络本身的节点结构就复杂。NIGHT 是发行在 Cardano 上的，用 partner chain 的方式 1:1 锚定到 Midnight 上。DUST 则用来支付 Midnight 网络的手续费，持有 NIGHT 会不断产生 DUST，类似 Tron 网络的能量，持有 Trx 就会产生能量那种。</p><p><strong>小结</strong></p><p>Midnight Network 拥有很强的技术实力，无论是区块链方面的出块和共识机制，还是对于 ZK 在工程方面的落地能力，都有很大的技术难度，不是一般开发团队能胜任的。尽管叙事上不太接近当前的热点，应该不会很出圈，但是技术方面如果开源的话，肯定会留下浓墨重彩的一笔。</p>]]></content>
  </entry>
  <entry>
    <title>停止 Web3 项目分析计划</title>
    <link href="https://crazy.smallyu.net/2025/08/07/%E5%81%9C%E6%AD%A2Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/08/07/%E5%81%9C%E6%AD%A2Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/</id>
    <published>2025-08-06T16:02:30.000Z</published>
    <updated>2025-11-27T17:16:12.925Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p><a href="/2025/07/31/%E5%A4%B1%E4%B8%9A%E6%9C%9F%E9%97%B4%E7%9A%84Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/">失业期间的]]></summary>
    <content type="html"><![CDATA[<p><a href="/2025/07/31/%E5%A4%B1%E4%B8%9A%E6%9C%9F%E9%97%B4%E7%9A%84Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/">失业期间的 Web3 项目分析计划</a> 进行几天后，现在不想继续了。不是因为没力气写或者什么，主要原因是，这样下去的话，博客的更新频率太高了，我不希望一打开博客，满屏幕都是 “对 XX 项目的分析”。现在的博客已经是精简过的博客，如果这种频率写下去，有点流水账的感觉。所以稍微写写就行。</p><p>关于项目分析的内容，最近写了 4 篇，大概每一篇 1500 字的篇幅，平均每天用 2～3 个小时的时间干这个事情，从挑选项目到看懂项目、分析技术、整理发布。我也不知道这些项目分析的文章质量怎么样，对别人有没有帮助，反正这种水平的分析，我想写多少就可以写多少，只是时间问题。接下来我肯定会继续看一些项目、分析那些项目的技术，只是不再这样集中去写。</p><p>其实对于分析区块链项目的方法论，我早在《<a href="/2024/10/15/%E7%9C%8B%E6%87%82%E4%BB%BB%E6%84%8F%E5%8C%BA%E5%9D%97%E9%93%BE%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84/">看懂任意区块链项目的技术架构</a>》就写过了，到现在都不觉得那篇文章内容有什么问题，无非就是链上链下交互，不同项目往里面填充不同的业务逻辑而已。所以从这个角度看，项目分析再多写也意义不大。</p><p>而且关于博客上应该放哪些文章，我是比较纠结的，最近两个月写东西的频率特别高，只是很多内容没有放到这个精简版博客上。甚至 Solana 教程这种，因为有 3 篇，占地方，我看着都不舒服，不知道该怎么处理。而后来我写的 continuation 教程系列有 7 篇，干脆一篇都不放了。</p><p>要按照我自己喜好的话，我最喜欢的其实是吐槽同事、吐槽公司、吐槽面试经历风格的文章，统称为情绪宣泄类文章，因为那些是包含了亲身经历、切实体会、真情实感在里面的内容，耗费了时间和心情得到的、宝贵的人生体验，比技术文章有意思多了。对行业的见解、对公司的不满、对同事的吐槽，那些才正是 AI 永远无法超越人类的原因，也是我的文章永远超越 AI 的地方，因为 AI 是没有情绪的，AI 不会生气，也不会沮丧。单纯讲技术知识点什么的，AI 一下子就能生成很多很多，但是 AI 永远无法体会到作为人的情感。不过现在带情绪的文章都删掉了。</p><p>所有的技术类文章，有看点的往往是作者的观点，而不是技术方面的知识点。我接下来的计划还需要继续调整。</p><p>话说最近发现一个现象，在网络上，用繁体字的人，素质比用简体字的人稍微高一点，或者说，他们会更加关注生活，而不是生存。</p><p>比如我在群里说自己找不到工作，用简体字的人，往往上来就是几个问题，“找工作多久了？”、“面试了几家？”、“几年经验？”、“报个培训班试试？” 这种，感觉都不是特别礼貌。而用繁体字的人，却长篇大论好意说，如果没找到工作，就应该趁年轻的时候，多体验生活，去体验那些只有年轻时候才能体验到的东西，平衡生活和工作，不要被工作占据太多时间，这种话。稍微有点感概。</p><p>最近天气真的很热，室外温度高达 35 度，没办法出门 😐</p>]]></content>
  </entry>
  <entry>
    <title>对 0G 项目的分析</title>
    <link href="https://b.smallyu.net/2025/08/06/%E5%AF%B90G%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/06/%E5%AF%B90G%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-06T05:08:00.000Z</published>
    <updated>2025-12-03T09:25:53.976Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>首先我不是很看好 0G 的技术含量，因为 0G 是中国团队开发的项目。0G 是一个 AI 赛道的项目，3 月份在 TinTinLand 上发布过招聘信息，大概 9 月份要发币的样子，猜测在 AI 方面的噱头大于技术积累。我因为最近加了一个 TinTinLand]]></summary>
    <content type="html"><![CDATA[<p>首先我不是很看好 0G 的技术含量，因为 0G 是中国团队开发的项目。0G 是一个 AI 赛道的项目，3 月份在 TinTinLand 上发布过招聘信息，大概 9 月份要发币的样子，猜测在 AI 方面的噱头大于技术积累。我因为最近加了一个 TinTinLand 的学习群，和 0G 合作推出社区课程那种，所以稍微有点兴趣来分析下这个项目。</p><p>0G 的官网地址是 <a href="https://0g.ai/">0g.ai</a>，在官网上就极尽所能的把各种名词摆上了，”the next generation”、“decentralized AI”、”DeAIOS”、”RWA”，用词口径越大通常不是一个好兆头。</p><h3 id="项目背景"><a href="#项目背景" class="headerlink" title="项目背景"></a>项目背景</h3><p>0G 在 2024年8月 发布了 <a href="https://4134984757-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsEYMfeKUqxaOUwhkw6AT%2Fuploads%2Fgit-blob-6f0538c70e09bf3180519342bfc516355c7a12c0%2F0g-whitepaper.pdf?alt=media">白皮书</a>，单从白皮书目录和篇幅来看不是很乐观，目录结构比较简单，一共只有 20 页的内容。篇幅长度是肤浅的判断方式，比特币的白皮书也才 9 页。主要是目录结构，作为一个 AI 技术导向的项目，如此简洁的章节会给人草台的感觉。</p><img src="1.png" width="50%"><p>首先来看看摘要里怎么说，0G 在解决的是 AI 模型训练过程中透明度的问题：</p><img src="2.png" width="70%"><p>话说，看到 modular 这个词我有点不好的预感，尤其是看到 DA 这个词后，心想该不会用的 Celestia 吧，结合官网首页上宣称的 2500&#x2F;s 的 TPS，有哪条链能做到呢？Cosmos 有点像。不过到这里还不理解首页上说的 8K 个 validator 是什么含义，Cosmos 可做不到这个。</p><img src="3.png" width="80%"><p>好在不是 Celestia，白皮书里没详细说技术选型的事，但明显和 Celestia 是并列关系，自己搞了个叫 0G DA 的链。</p><p>白皮书里详细解释了 PoRA（Proof of Random Access）的挖矿机制，这个是有技术含量的部分，与 Filecoin 冷储存的模式不同，0G Storage 强调链上可以即时访问数据，所以设定了 8TB 的挖矿窗口，要求矿工可以快速在范围内验证数据完整性。</p><p>PoRA 的局限性在于，通过随机抽样验证的方式，可以验证矿工是否拥有完整数据，但是不能证明矿工拥有的数据是唯一的，也就是缺少 Filecoin 的 PoRep 提供的能力。这与网络面对的场景以及经济模型设计有关，0G Storage 只希望保证数据的可用，从矿工的奖励方式上限定了作恶是不能得到更多奖励的，所以整体机制上奏效。而 Filecoin 是根据算力高低给奖励，要面对的问题不一样。</p><p>从官网的第一篇 <a href="https://0g.ai/blog/introduction">博客文章</a> 中能更直观看到一些信息，0G 包含两个关键组成部分：0G Storage 和 0G DA，本质上在解决的就是 DA 的问题，主要是试图把这种 DA 能力用到 AI 场景中，所以分类到 AI 赛道了。项目背景上是一个分布式存储类的区块链项目。</p><p>0G 去年得到了 3 千万美元的种子轮融资，还是挺有资本的。</p><p>具体到工程实现上，可以看到 0G Storage 的 <a href="https://github.com/0glabs/0g-storage-node/blob/main/Cargo.toml#L31">代码</a> 基于 Conflux 的节点代码，在其之上做了一些功能开发：</p><img src="6.png" width="70%"><p>PoRA 的工程实现部分就不深究了。</p><h3 id="项目架构"><a href="#项目架构" class="headerlink" title="项目架构"></a>项目架构</h3><p>刚才从项目背景的角度，只提到了 0G Storage 和 0G DA 两部分，除此之外，0G 这个项目还有两个角色，0G Chain 和 0G Compute Network。估计一开始的项目规划里没有，所以白皮书里没提。</p><p>0G Chain 是一个用 Cosmos SDK 开发的链节点（终于看到 Cosmos 的身影了），而且是直接用了 evmos 来兼容以太坊智能合约的做法：</p><img src="4.png" width="80%"><p>0G Chain 的仓库最后一次提交代码是在 5 个月前，也许已经放弃了用 Cosmos SDK 的路线。因为有一个近期比较活跃的仓库 <a href="https://github.com/0glabs/0g-geth">0g-geth</a>，看起来是在做 Geth 的二次开发，通过集成预编译合约的方式，加入对 0G DA 的支持。</p><img src="5.png" width="40%"><p>0G Compute Network 是真正和 AI 模型训练相关的部分，现在已经支持一些 <a href="https://docs.0g.ai/developer-hub/building-on-0g/compute-network/sdk#discover-available-services">预训练模型</a> 的使用。用户层面的使用比较简单，类似于 OpenAI 的 SDK 一样，发起请求，得到响应，就是一个 Client 层的 SDK。</p><p>给 0G Compute Network 的模型提供算力的节点叫 Provider，代码仓库是 <a href="https://github.com/0glabs/0g-serving-broker">0g-serving-broker</a>，代码仓库里有体现模型训练的代码，比如 <a href="https://github.com/0glabs/0g-serving-broker/blob/main/api/fine-tuning/execution/transformer/transformer/finetune.py">finetune.py</a> 这个脚本是基于 Transformer 做文本模型的微调，Docker 容器是直接基于 <a href="https://github.com/0glabs/0g-serving-broker/blob/main/api/fine-tuning/execution/transformer/Dockerfile#L2">pytorch 2.5.1-cuda12.4-cudnn9-devel</a> 的容器打包。</p><p>所以从 LLM 模型训练的角度看，0G 有一些工程方面的技术内容。只不过 0G 在干的事情是微调（Fine-tuning），也就是基于预训练（Pre-training）好的模型，进一步用较小的算力训练，达到执行某种特定任务的效果。而我们平时看到的 OpenAI 和 Grok 等大公司，动辄 1 TB tokens 的训练量，干的事情才是预训练。</p><p>比如 OpenAI 训练并开源出一个 GPT-3 模型（实际上没开源），那么 0G Compute Network 就是基于这个 GPT-3 模型，结合自己的语料进行一些微调，训练出一个自己版本的 GPT-3 模型。大概就是这个意思。</p><p>更准确一点说，0G Compute Network 是提供了一个训练的场地，结合了区块链相关的经济模型、奖励机制等交互，让用户可以给微调这件事情提供算力并获得收益，另一些用户可以使用微调之后的模型。</p><p>至于 Provider 与链上合约交互的部分，应该就好理解了。0G 是用 Solidity 写的合约 <a href="https://github.com/0glabs/0g-serving-contract">0g-serving-contract</a> ，对合约的调用自然也是以太坊生态的那一套组件。而 0G 需要做的，就是把模型微调（训练）的结果，以及关于训练任务的分发、奖励记录、惩罚机制等，用合约来实现，然后在链下的算力节点上集成对合约的交互。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>综合来看，我需要改正一开始的态度，0G 是有一些技术含量在的，只不过更加侧重于工程方面的技术，无论是区块链方面的 DA，还是 AI 方面的模型微调，其实做的都不错，业务逻辑上已经能形成闭环。</p><p>但是说实话，写 0G 项目的分析，比之前写其他项目的分析，思路稍微不清晰一点，因为白皮书和文档都不是很完善，项目的技术路线又不是特别统一，所以没有非常好的资料自上而下的贯彻整个项目结构。不过经过以上内容的分析，我想应该已经刨析清楚了 0G 这个项目的技术情况。</p>]]></content>
  </entry>
  <entry>
    <title>对 Arcium Network 项目的分析</title>
    <link href="https://b.smallyu.net/2025/08/05/%E5%AF%B9Arcium-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/05/%E5%AF%B9Arcium-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-05T09:29:59.000Z</published>
    <updated>2025-12-03T09:25:53.986Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<h3 id="项目背景"><a href="#项目背景" class="headerlink" title="项目背景"></a>项目背景</h3><p><a href="https://www.arcium.com/">Arcium Network</a> 是 Solana]]></summary>
    <content type="html"><![CDATA[<h3 id="项目背景"><a href="#项目背景" class="headerlink" title="项目背景"></a>项目背景</h3><p><a href="https://www.arcium.com/">Arcium Network</a> 是 Solana 生态首个专注于隐私计算的项目，今年 5 月份获得了 GreenField 领投的 5 千万美元的 <a href="https://x.com/ArciumHQ/status/1788557786537689447">融资</a>。</p><p>Arcium 的 <a href="https://www.arcium.com/articles/arcium-purplepaper">Purplepaper</a> 中提到，Arcium 是一种去中心化的隐私计算协议，主要包含了 MPC 和经济模型两个关键的组成部分：</p><img src="1.png" width="80%"><p>Arcium 整体的项目结构不算难理解，尤其是和区块链结合的部分，就是直接用了 Solana 的智能合约：</p><img src="2.png" width="80%"><p>但是 Arcium 在有很多硬核的技术基础。比如在这篇 <a href="https://www.arcium.com/articles/eli5-mpc">博客文章</a> 中，Arcium 用简化的例子说明了 MPC 的技术原理。</p><p>MPC（Secure Multi-Party Computation，安全多方计算）这种技术不是新概念，存在很多年了，我们最为熟知的就是 MPC 钱包，币安钱包和 OKX 钱包都默认使用这种模式。从学习的角度，可以辨析一下 MPC、多签、MPC 钱包、TSS 聚合签名、BLS 聚合签名这几个有点关联但容易混淆的概念。</p><p>回到 Arcium 的文章，简化后的 MPC 大概是这个意思：假如有 3 个参与方 a,b,c 进行计算，计算的内容分别对应 +1,+2,+3，并且参与方会对自己的计算结果加盐分别是 +10,+20,+30，那么经过全部参与方计算后，最终得到的结果是 66，减去参与方的盐值总和 60，得到最终结果 6。</p><p>去盐的过程按理也是轮流来的，比如初始值是 66，从 a 到 c 依次渐去各自的盐值，得到最终结果，而不是一下子就减去了 60。对于每一个计算参与方来说，它只知道初始值，以及自己计算的结果值，并不知道执行的顺利，是先 a 执行，还是先 c 执行？协议约定这个信息不是公开的。</p><p>真实的 MPC 是一个复杂的交互协议，需要很复杂的工程化实现。总之 Arcium 就是在对 MPC 技术大做文章，试图把这种密码学技术，引入到更多实际的应用场景中，这是一个不错的方向。</p><p>Arcium 在研究的技术方向和尝试 <a href="https://www.arcium.com/articles">很多</a>，比如这篇 <a href="https://www.arcium.com/articles/confidential-spl-token">文章</a> 中提到的 Confidential SPL Token，是结合了 Solana 的 SPL 标准代币、<a href="https://github.com/solana-program/token-2022">Token-2022</a> 标准、和 Arcium 的 MPC 聚合架构，提出的一种带隐私能力的代币标准。此外还搞了链上 Dark Pools 的 Dapp，挺有加密风范的技术感。</p><h3 id="项目架构"><a href="#项目架构" class="headerlink" title="项目架构"></a>项目架构</h3><p>Arcium 的 <a href="https://docs.arcium.com/getting-started/architecture-overview">项目架构</a> 看似很复杂，乍一看 MXEs、arxOS、Arcis 什么的，各种名词。这种是典型的发明概念，就是给自己项目里用的某个组件，起了个高大上的名字，根本不是某种技术名词。几乎每个项目都会有一套自己的术语定义，让外人觉得很厉害。</p><p>从这个 Developer 版本的 <a href="https://docs.arcium.com/developers/computation-lifecycle">文档</a> 能更好的理解 Arcium 的架构。作为使用 Arcium 的开发者，实际上是在开发 Solana 智能合约，我们自己开发一个合约（MXE program）来描述计算任务，比如加法运算，a+b，期望得到 c，把这个逻辑写在合约上，然后调用官方部署的合约（Arcium Program）的合约，把计算任务提交到 Arcium 的任务池里：</p><img src="3.png" width="80%"><p>这样，Arcium Program 就知道了有这么一个任务，而真正执行隐私计算任务的 MPC Cluster（arxOS），根据链上的交易记录，得到事件也就是任务信息，开始进行计算，并且将计算结果提交到链上的 Arcium Program（合约）。回到我们的 MXE program 这边，自然是有一个 callback 函数来接收隐私计算的结果，然后触发一个事件通知我们的客户端：</p><img src="4.png" width="80%"><p>在合约代码层面，能够实现哪些计算，如加法、减法、除法之类，要依赖于 Arcium 提供的框架，支持哪些计算方式。</p><p>那么抛开凌乱的技术名词，Arcium 整体上，是通过链上合约提交计算任务，链下节点计算任务结果后，再提交回链上的模式，这是和区块链交互的部分。此外就是链下计算的过程，Arcium 把 MPC 折腾的很明白，提供了便于使用的客户端（合约）框架出来。</p><h3 id="经济模型"><a href="#经济模型" class="headerlink" title="经济模型"></a>经济模型</h3><p>具体执行多方计算的节点，Arcium 把它们叫做 <a href="https://docs.arcium.com/getting-started/network-stakeholders">StakHodlers</a>，有点复杂，总之就是要么提供硬件设备、经过一系列配置之后参与到计算节点中，得到收益，要么把自己的 ARX 代币委托给某些计算节点，赚一点利息。</p><p>在经济模型方面，Purplepaper 里有提到 ARX 的代币总供应量，会随着网络算力的使用量自动调整，达到自动平衡的效果：</p><img src="5.png" width="80%"><p>这种自动平衡期望的效果是，ARX 的质押率平衡在 50%，如果低于 50%，会自动增发，如果高于 50%，会自动销毁。这个经济模型的设计是利好计算节点的，是希望持有 ARX 的用户能积极参与到质押和计算生态中。但是这种经济模型不是很利于非质押者，因为增发与他们无关，销毁与他们有关，相当于放大了以太坊 PoS 模式的弊端。</p><p>不过 Arcium 的销毁模式和以太坊的销毁模式还不太一样，Arcium 会把协议费收上来的 SOL，通过荷兰拍卖换成 ARX，再销毁。这种模式给整体供给带来的影响更复杂一点，得进一步关注和分析了。</p><p>综合来看，无论是技术架构上，还是经济模型上，Arcium 都有非常深厚的积累，已经能形成闭环，有很大的进一步观察的空间。Arcium Network 目前是测试网阶段，路线图里还在规划主网的上线时间。</p>]]></content>
  </entry>
  <entry>
    <title>对 Camp Network 项目的分析</title>
    <link href="https://b.smallyu.net/2025/08/04/%E5%AF%B9Camp-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog-b:https://b.smallyu.net/2025/08/04/%E5%AF%B9Camp-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-04T04:15:42.000Z</published>
    <updated>2025-12-03T09:25:53.972Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p><a href="https://www.campnetwork.xyz/">Camp Network</a> 的愿景是在 AI Agent 场景中保护作者的知识产权，并且有可能获得来自 AI 分享的创作者收益。Camp Network 今年 4 月底宣布，一共获得了 3]]></summary>
    <content type="html"><![CDATA[<p><a href="https://www.campnetwork.xyz/">Camp Network</a> 的愿景是在 AI Agent 场景中保护作者的知识产权，并且有可能获得来自 AI 分享的创作者收益。Camp Network 今年 4 月底宣布，一共获得了 3 千万美元的 <a href="https://mirror.xyz/0xa01A821E654b923Be011acE131A22Ba58cFee3ad/wvdmjQaM2hw8uxLaLEamNPQMVT4H_bLWgzrsNWoOZpU">A轮融资</a>，来自不同的投资机构。</p><p>只看官网首页的简介的话，也许会有点疑惑，这个项目的立意肯定没错，保护知识产权嘛，但是具体怎么做呢，<a href="https://mirror.xyz/0xa01A821E654b923Be011acE131A22Ba58cFee3ad/wvdmjQaM2hw8uxLaLEamNPQMVT4H_bLWgzrsNWoOZpU">官方宣发文章</a> 里提到的 Proof of Ownership and Pirority，岂不是几年前的概念吗？而这些 Proof of… 又是什么意思？</p><p>Camp Network 没有公开出 Github 代码仓库，导致没办法从代码层面解读。我一开始还奇怪，为什么不公开 Github 账户？后来我明白了。</p><p>Camp Network 的 <a href="https://docs.campnetwork.xyz/introduction/l1-architecture/abc-stack">文档</a> 里说明，Camp Network 是一条使用了 Celestia 区块链做 DA 层的链，基于 <a href="https://www.abundance.xyz/">ABC Stack</a> 搭建。ABC Stack 又是什么呢，是 Celestia 生态中的一个项目，在架构上明确区别于以太坊的 “L2 Rollups”，而是自己发明了一种架构叫 “Rollup L1s”。</p><p>ABC Stack 框架是 Abundance 团队开发的，号称每秒 GB 级别数据的 EVM 完备的 Rollups。也就是说，Camp Network 直接使用了 ABC Stack 的底层技术，搭了一条链出来，在链上做一些应用，所谓知识产权保护、DID、AI 什么的。</p><p>那么 ABC Stack 的框架怎么用呢，代码仓库在哪里，怎么操作，需要开发哪些代码？完全不需要，有一家 Celestia 生态的公司 <a href="https://gelato.cloud/">Gelato</a>，提供了 BaaS 平台的服务，比如一键部署 Op Stack 的链、一键部署 Arbitrum 的链，等等，其中就包括 ABC Stack 的选项。而这个 BaaS 平台是收费的，部署到主网需要一个月 3000 美元，部署到测试网只需要一个月 100 美元。Camp Network 目前是测试网阶段。</p><p>这就是 Camp Network 连代码仓库都不需要的原因，直接用 BaaS 服务就好了，而且也没有其他选择，ABC Stack 本身就没提供代码。</p><p>Camp Network 的 <a href="https://docs.campnetwork.xyz/introduction/l1-architecture">架构文档</a> 里还提到一个东西，BaseCAMP 是刚才提到的用 ABC Stack 搭出来的链，SideCAMP 则是应用专属的链，从文档描述来看，Camp Network 是计划给每一个应用场景，比如 AI、音乐、艺术等 Dapp，都单独部署一条链，同样也是用 ABC Stack 的技术。</p><p>有那么多条链的话，BaseCAMP 和 SideCAMP 之间怎么通讯和交互呢？ABC Stack 对 Hyperlane 的跨链技术做了 <a href="https://docs.abundance.xyz/modular-bridging/gelato-hyperlane-cluster">封装</a>，依此来实现 ABC Stack 链之间的跨链通信。</p><p>至于 Camp Network 到底是怎么实现保护知识产权的？Camp Network 提供了一个 <a href="https://docs.campnetwork.xyz/origin-v1/origin-framework">SDK</a>，大意是作者需要通过链上交易来声明自己的身份，比如绑定自己的链上地址和 X 的用户名信息，Camp Network 的这个 Origin 框架，就会到 X 上查询我发布的内容，自动生成 IP NFT，然后其他玩家可以来购买这个 IP NFT，相当于购买了版权。</p><p>话说，其实是挺老套的玩法。可能以后凡是看到提 DID 这种老套概念的项目，都得多加小心，因为没什么技术，只玩生态，而且玩的是不存在的生态。</p><p>Camp Network 整体的技术情况就是这样，连代码仓库都没有，直接用了 ABC Stack 提供的服务，搭建了几条链，然后在链上面做应用。Camp Network 的 <a href="https://testnet.campnetwork.xyz/">测试网</a> 上现在已经有不少 Dapp 了，可以操作和交互。Camp Network 虽然没有硬核的底层技术，但是生态实力很强大，测试网上参与活动的项目非常多。</p>]]></content>
  </entry>
  <entry>
    <title>我今年最喜欢的一张照片</title>
    <link href="https://crazy.smallyu.net/2025/08/03/%E6%88%91%E4%BB%8A%E5%B9%B4%E6%9C%80%E5%96%9C%E6%AC%A2%E7%9A%84%E4%B8%80%E5%BC%A0%E7%85%A7%E7%89%87/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/08/03/%E6%88%91%E4%BB%8A%E5%B9%B4%E6%9C%80%E5%96%9C%E6%AC%A2%E7%9A%84%E4%B8%80%E5%BC%A0%E7%85%A7%E7%89%87/</id>
    <published>2025-08-03T14:09:25.000Z</published>
    <updated>2025-08-16T03:27:07.400Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<h3 id="0-原图"><a href="#0-原图" class="headerlink" title="0. 原图"></a>0. 原图</h3><p>这是一年以来，我拍的照片中，最好的一张：</p>
<img src="1.png"]]></summary>
    <content type="html"><![CDATA[<h3 id="0-原图"><a href="#0-原图" class="headerlink" title="0. 原图"></a>0. 原图</h3><p>这是一年以来，我拍的照片中，最好的一张：</p><img src="1.png" width="40%"><p>也许是因为我头脑中的幻想，给这张照片添加了额外的滤镜。我尝试过对这张照片做一些修改，比如剪裁、调色之类，统统都觉得不好。我还是最喜欢这种，没有任何修改的原图。</p><p>对了，我说这是 “最好的一张”，而不是 “最好看的一张”。</p><p>这张照片好在，我设身处地的看着这样的场景，随手拍下了这张很美的照片。我喜欢这样的景色，也喜欢这样的生活。尽管那天很热，真的特别热。</p><p>这张照片的元素实际上很乱，尤其是背景里有船，还有一些杂乱的树、白色的石头。我喜欢的是，在这种杂乱的环境中，纯净、干净的人物，反而能和杂乱的背景形成对比。</p><h3 id="1-裁剪版本"><a href="#1-裁剪版本" class="headerlink" title="1. 裁剪版本"></a>1. 裁剪版本</h3><img src="2.png" width="40%"><p>把背景中的船裁剪掉是不是会好一点？完全没有，裁剪后的照片，有很明显的被裁剪的感觉，画面信息变得很少，干净但是没有 “杂乱中的干净” 的感觉。</p><h3 id="2-旋转版本"><a href="#2-旋转版本" class="headerlink" title="2. 旋转版本"></a>2. 旋转版本</h3><img src="3.png" width="40%"><p>这张照片的差异不是很明显，苹果手机有个自动裁剪的功能，厉害之处在于，把图片稍微右旋转了一下，船底的线和整个画面变成平行的了，而不是原图中船身是斜着的感觉。</p><p>这样调整之后，人物确实更正了，整张照片也更正了，但是又缺少了一点宽广的视角的感觉。这种差异尤其放大图片之后看，会明显一点。</p><h3 id="3-调色版本"><a href="#3-调色版本" class="headerlink" title="3. 调色版本"></a>3. 调色版本</h3><img src="4.png" width="40%"><p>苹果手机的智能调色。水更绿，对比度更高，更加不真实，我不喜欢。</p><h3 id="4-关键帧版本"><a href="#4-关键帧版本" class="headerlink" title="4. 关键帧版本"></a>4. 关键帧版本</h3><img src="5.png" width="40%"><p>照片拍的是 live 图，可以选择一些其他的关键帧。这张其实也不错，是一个漂亮的侧面。但是和原图相比，少了一些活波的动作。</p><h3 id="5-AI-版本"><a href="#5-AI-版本" class="headerlink" title="5. AI 版本"></a>5. AI 版本</h3><img src="6.png" width="40%"><p>豆包 AI 的修图能力不错，尤其是某些关键词、某些场景，可以出来一些很好的效果。小红书上不少 Coser 都直接用豆包 P 图来换背景。</p><p>不得不说效果确实不错，但是这个图一看就不是真实的场景。</p><h3 id="6-视频版本"><a href="#6-视频版本" class="headerlink" title="6. 视频版本"></a>6. 视频版本</h3><video controls width="40%" preload="metadata">  <source src="7.mov" type="video/mp4"></video><p>豆包还能一键把图片变视频，毕竟是基于抖音那么大量的视频数据做训练，豆包在这方面的能力挺强大。</p>]]></content>
  </entry>
  <entry>
    <title>为什么我坚持用独立博客</title>
    <link href="https://crazy.smallyu.net/2025/08/02/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E5%9D%9A%E6%8C%81%E7%94%A8%E7%8B%AC%E7%AB%8B%E5%8D%9A%E5%AE%A2/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/08/02/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E5%9D%9A%E6%8C%81%E7%94%A8%E7%8B%AC%E7%AB%8B%E5%8D%9A%E5%AE%A2/</id>
    <published>2025-08-02T15:23:02.000Z</published>
    <updated>2026-08-11T01:22:41.908Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>为什么文章只发到独立博客呢？独立博客没什么访问量，如果发到知乎、掘金，甚至是头条、百度、登链等平台，再加上 Meidum、X、Mirror 一类，文章访问量肯定可以高很多，关注量也会高很多，会有更多人注意到 smallyu]]></summary>
    <content type="html"><![CDATA[<p>为什么文章只发到独立博客呢？独立博客没什么访问量，如果发到知乎、掘金，甚至是头条、百度、登链等平台，再加上 Meidum、X、Mirror 一类，文章访问量肯定可以高很多，关注量也会高很多，会有更多人注意到 smallyu 这个昵称。</p><p>因为那些充斥着低质量内容的平台，不值得去发布高质量内容的文章。那些人是看不懂的，看不懂我在写什么。看看掘金首页上有什么？10 篇文章 8 篇讲 Cursor，很难想象用户素质得多低。知乎就更不用说了，内容杂乱、商业化，关键是网页访问弹窗，不是让登陆就是让下载 APP，正经人谁去那种平台啊。</p><p>Web3 行业小，从业者本来就不多，也没有什么好玩的内容平台。去吸引一堆只懂 Web2 的用户，其实也没什么意义，和他们是没有共同语言的。我在脉脉的职言区，匿名账号下，发布过几千条帖子，总阅读量超过几千万，发的都是观点偏激、引战一类的内容。那种阅读量有意义吗？毫无意义。</p><p>所以实际上没有更好的选择。</p><p>我知道独立博客没有人看，因为我自己平时都不太看别人的博客。长期关注并且反复看了很多遍的只有王垠的博客，不只是看最新的文章，还会用 Wayback Machine 来 “考古”，还搜集了很多王垠博客的备份链接，还整理出了一个王垠百科那样的网站……</p><p>以前偶尔也看一眼左耳朵耗子（CoolShell，陈皓）的博客，他的博客内容很多，研究的技术很多很杂，属于宝藏一类，文章不值得读但是他关注的技术关键词值得关注。比如他在 2022 年研究过 ePBF，ePBF 是 Solana 区块链实现 SVM 虚拟机的底层技术。可惜他的博客已经不更新了。</p><p>其实 CoolShell 这个博客，对我们来说是一个反面例子，他在告诫我们，不要过于专注技术，不需要什么都懂，不需要那么努力，不需要那么有观点，不需要…… 他应该引起我们的反思，高质量的技术博客，真的有意义吗？</p><p>另外阮一峰的博客很多年前看过，后来随着自己技术能力的提升，就不看了。阮一峰的博客不算技术博客，里面都是一些文艺类的内容，小白观众居多。</p><p>我自己关注的博客都没几个，而且都是很知名的人物，就这么个情况，相信别人也一样。所以继续努力吧，等自己成为 somebody，再考虑访问量的问题。没有人会关心 nobody 写的东西。</p><h3 id="更新（2026-08-11）"><a href="#更新（2026-08-11）" class="headerlink" title="更新（2026.08.11）"></a>更新（2026.08.11）</h3><p>想到新增两个观点：</p><ul><li>AI 没办法写出 “我经历了什么” 这样的话题</li><li>你可以不写博客，但是不要忘记思考</li></ul>]]></content>
  </entry>
  <entry>
    <title>现在得维护两个博客，整的很麻烦，比如一篇文章有 typo，得分别在两个博客里改。</title>
    <link href="https://t.smallyu.net/#2025-14"/>
    <id>micro:3143753408</id>
    <published>2025-08-01T08:44:16Z</published>
    <updated>2026-06-09T04:39:59Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>现在得维护两个博客，整的很麻烦，比如一篇文章有 typo，得分别在两个博客里改。</p>]]></summary>
    <content type="html"><![CDATA[<p>现在得维护两个博客，整的很麻烦，比如一篇文章有 typo，得分别在两个博客里改。</p>
]]></content>
  </entry>
  <entry>
    <title>对 Psyche Network 项目的分析</title>
    <link href="https://smallyu.net/2025/08/01/%E5%AF%B9Psyche-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/"/>
    <id>blog:https://smallyu.net/2025/08/01/%E5%AF%B9Psyche-Network%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%88%86%E6%9E%90/</id>
    <published>2025-08-01T06:33:21.000Z</published>
    <updated>2026-08-04T11:43:17.094Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="项目背景"><a href="#项目背景" class="headerlink" title="项目背景"></a>项目背景</h3><p><a href="https://psyche.network/runs">Psyche Network</a> 是 AI]]></summary>
    <content type="html"><![CDATA[<h3 id="项目背景"><a href="#项目背景" class="headerlink" title="项目背景"></a>项目背景</h3><p><a href="https://psyche.network/runs">Psyche Network</a> 是 AI + Web3 赛道的一个项目，由 <a href="https://nousresearch.com/">Nous Research</a> 团队研发，两个月前获得了 Paradigm 机构 5 千万美元的 <a href="https://cointelegraph.com/news/nous-research-raises-50m-paradigm-decentralized-ai-solana">A 轮融资</a>。</p><p>Psyche Network 的项目背景在 <a href="https://nousresearch.com/nous-psyche/">官方说明文章</a> 里有详细介绍。Nous Research 团队研发出了一种去中心化的算法 DeMo，这种算法能够把大语言模型（LLM）的训练，放到分布式网络里进行，不需要集群服务那种高耦合。就类似比特币挖矿的矿池一样，会把大的计算任务，拆解为小的计算任务，分发给不同的 Client 节点进行计算，计算之后再把结果汇总起来。</p><p>当然 LLM 的训练和矿池的挖矿，从算法原理上完全是两码事，这里只是想类比说明便于理解。具体 DeMo 是怎么从算法角度把任务拆解和合并的，可以看 <a href="https://blog.lambdaclass.com/introducing-demo-decoupled-momentum-optimization-for-efficient-distributed-llm-training/">官方的解释</a>，反正我没看懂，就是一堆向量、权重、loss function 什么的术语。关于怎么防止节点提交虚假数据之类，我认为也都在算法的设计范畴，后续就不多讨论算法本身的有效性了。</p><p>DeMo 的 <a href="https://arxiv.org/pdf/2411.19870">论文</a> 里用了 100 billion 的 tokens 做训练测试，得到了比较好的结果。100 B tokens 是什么概念呢，比如 <a href="https://github.com/deepseek-ai/DeepSeek-V3?tab=readme-ov-file#4-evaluation-results">DeepSeek-V3</a> 的 tokens 数量是 15 TB，可见 DeMo 在实验阶段的 tokens 数量级，距离商用产品还差很多。可以对比一些其他模型的 tokens 数量：</p><table><thead><tr><th>模型</th><th>参数量</th><th>预训练 tokens 数量</th><th>公开来源或泄露信息</th></tr></thead><tbody><tr><td>GPT-3</td><td>175 B</td><td>≈ 499 B</td><td>论文及后续综述</td></tr><tr><td>GPT-3.5</td><td>175 B</td><td>推测 ~1 T 左右</td><td>—</td></tr><tr><td>GPT-4</td><td>1.7 T</td><td>≈ 13 T tokens</td><td>SemiAnalysis &#x2F; The Decoder 报告</td></tr><tr><td>Llama 3</td><td>70 B</td><td>&gt; 15 T tokens</td><td>Meta 官方模型卡</td></tr><tr><td>DeMo OLMo</td><td>1 B</td><td>0.1 T tokens（100 B）</td><td>DeMo 论文</td></tr></tbody></table><p>Psyche Network 基于 DeMo 的算法原理，结合区块链来构建分布式网络，第一阶段的目标是训练出 40 B parameters, 20 T tokens 的模型。关于 <code>parameters</code> 和 <code>tokens</code> 这两个指标，我的理解是，<code>parameters</code> 是训练一开始就定义好的固定指标，<code>tokens</code> 则是需要不断进行计算和训练的，而 DeMo 解决的是 <code>tokens</code> 的分布式计算。Psyche Network 官网上有实时显示当前的训练进度，目前已经达到了 1 TB 的 tokens 数量：</p><img src="1.png" width="80%"><p>这个模型训练完，也许可以接近 GPT-3 的水平。对比来看虽然 tokens 数量比 GPT-3 多，但是 parameters 比 GPT-3 少，所以最终效果应该不如 GPT-3。</p><h3 id="项目结构"><a href="#项目结构" class="headerlink" title="项目结构"></a>项目结构</h3><p>Psyche Network 的 <a href="https://docs.psyche.network/explain/index.html">文档</a> 里有介绍整体的项目结构，比较好理解，有一个中心化的 Coordinator 负责创建训练任务，其余的 Client 负责接收任务、提交任务结果。在没有区块链的场景下，Coordinator 与 Client 之间的通信是通过直接的 TCP 连接完成的。而有了区块链之后，Coordinator 和 Client 之间就是通过区块链来传递消息了。</p><img src="2.png" width="40%"><p>Psyche Network 的 <a href="https://github.com/PsycheFoundation/psyche/tree/main/architectures">代码仓库</a> 里同时保留了 <code>centralized</code> 和 <code>decentralized</code> 两个版本的代码架构，这其实不太是好事，因为说明这个项目原本可以中心化运行，只是现在在做一些去中心化改造。这样的项目去中心化程度肯定是有限的。</p><p>而所谓去中心化版本的部分，Psyche Network 选择了 Solana 来作为运行智能合约的区块链平台，这也许和 Psyche Network 原本的项目就是用 Rust 语言有关。</p><p>代码仓库的 decentralized 目录下，有一些 Solana 的合约代码，这些 Solana 合约承担起了创建训练任务、计算每个 Client 节点的奖励、分发奖励的功能。</p><p>Psyche Network 目前只是测试网阶段，链上交易也都是在 Solana 的 Devnet 上进行，可以直接看合约文件里的 <code>declare_id!()</code> 语句，里面写的就是合约地址，比如 coordinator 的合约地址是 <code>HR8RN2TP9E9zsi2kjhvPbirJWA1R6L6ruf4xNNGpjU5Y</code>，能在 <a href="https://solscan.io/account/HR8RN2TP9E9zsi2kjhvPbirJWA1R6L6ruf4xNNGpjU5Y?cluster=devnet">区块链浏览器</a> 上看到频繁的交易记录。</p><p>至于奖励的计算，因为有 Coordinator 这个中心化角色的存在，所以事情比较简单，Coordinator 在收到 Client 的任务结果后进行验证，如果没问题，则发起一笔链上交易，给 Client 记分。具体代码是 <a href="https://github.com/PsycheFoundation/psyche/blob/main/architectures/decentralized/solana-coordinator/programs/solana-coordinator/src/instance_state.rs#L146-L149">这两行</a>：</p><img src="3.png" width="80%"><p>每个 Client 的分数都记录在合约里，Client 想领取奖励，就自己到 treasurer 合约上 claim，treasurer 会根据分数和汇率计算并转账代币。</p><p>那么 treasurer 分发的奖励是哪个代币呢？具体代币是 Coordinator 在创建任务的时候 <a href="https://github.com/PsycheFoundation/psyche/blob/main/architectures/decentralized/solana-treasurer/programs/solana-treasurer/src/logic/run_create.rs#L34">指定的</a>，只要是标准的 SPL 代币都可以。</p><img src="4.png" width="70%"><p>所以整体来看，Psyche Network 是利用 Solana 区块链来记录任务 Meta 信息、计算任务奖励、分发奖励等。只要 Client 的加入是 permissonless 的，Psyche Network 就确实达到了和宣传一样的效果，让 LLM 模型训练的算力去中心化。</p><p>而代币的分发和奖励虽然是区块链项目的常规操作，但是至少附加了公开透明等特性，而且不出意外的话，Psyche Network 最终会走到发币的一步，到时候任务奖励可能全用 Psyche Network 自己的代币进行，或者演变为 LLM 训练的任务平台，任何第三方都可以创建任务和分发奖励之类，像 Eigne Layer 那样。</p>]]></content>
  </entry>
  <entry>
    <title>失业期间的 Web3 项目分析计划</title>
    <link href="https://crazy.smallyu.net/2025/07/31/%E5%A4%B1%E4%B8%9A%E6%9C%9F%E9%97%B4%E7%9A%84Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/07/31/%E5%A4%B1%E4%B8%9A%E6%9C%9F%E9%97%B4%E7%9A%84Web3%E9%A1%B9%E7%9B%AE%E5%88%86%E6%9E%90%E8%AE%A1%E5%88%92/</id>
    <published>2025-07-31T15:20:39.000Z</published>
    <updated>2025-11-27T17:16:12.926Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>7 月份结束了，马上进入 8 月。为了让自己在失业期间的时间过得有意义，我想到一个有意思的计划来消磨时间。</p>
<p>计划内容是，每天分析一个 Web3]]></summary>
    <content type="html"><![CDATA[<p>7 月份结束了，马上进入 8 月。为了让自己在失业期间的时间过得有意义，我想到一个有意思的计划来消磨时间。</p><p>计划内容是，每天分析一个 Web3 行业的项目，从看白皮书开始，到理解项目的运作模式、当前商业状态等，尤其关注技术理念和技术创新方面，然后写成分析报告，发布到博客上，不需要那种很专业的报告，大概相当于学习笔记就可以了。具体分析哪个项目是经过主观挑选的。</p><p>每天看一个项目、出一个分析报告，节假日和周末休息，直到不失业的那天，停止计划。每天形成的分析报告，也许会有质量，有看点，但也许会比较短，没有质量。因为我并不能在一开始选定项目的时候，就知道这个项目有没有含量，尤其是技术含量。</p><p>这有点像是区块链研究员干的事情，而不是区块链程序员应该干的事情。为什么我的计划不是每天写 100 行代码，开发一个区块链小工具，或者每天积累一点，开发一个大的区块链工程？</p><p>因为工程代码如果脱离项目背景，就没有价值。我之前几年的工作中写过很多代码，但是如果现在把那些代码拿出来，会发现毫无意义。工程化的代码，往往是为了完善项目的功能，而项目需要某些方面功能，是为了迎合运营和宣发的需求，一定是有商业目的的。如果需求背景不存在，代码就毫无价值。</p><p>尤其是随着 AI 的日益强大，写工程代码这件事情更是越来越廉价。AI 可以几分钟写出上万行代码，堆砌代码的能力绝对超过人类。如果我想靠每天写几百行工程代码来训练和提升自己，那我一定会失败的很惨。所以不能干这样的事情。</p><p>什么样的工程代码是有意义的呢？就是已经找准了产品需求和定位的情况下，想把功能落实跑通，然后让 AI 来干活，把代码写出来。AI 写的代码有时候会跑偏，需要手动修复一下 bug，这种情况下，手动写出的工程代码才有意义。现在的开发节奏已经应该是这样了。</p><p>以前的时代，人们喜欢说 “Talk is cheap. Show me the code”，但是现在时代变了， prompt 比 code 更有价值，也许这句话会变为 “Code is cheap. Show me the prompt”。</p><p>不去计划每天写一些工程代码，另一个原因在于，我已经做过了一些尝试，去试图开发小的区块链工具，或者大的区块链工程。目前来看，我之前的想法，无论是做小工具的思路，还是做大工程的思路，都是没有结果的，因为需求本身也许不存在。说的直白一点，没有任何正反馈，所以根本做不下去。</p><p>与代码相比，写文字、写文章、写观点更有意义一点。一个产品创意背后，可能有 100 行代码，也可以有 10000 行代码，需要付出的时间成本完全不同，但如果最终的关注量都是 0，那么结果就是一样的，9900 行代码白写了。而文字是能够体现思想的。</p><p>你也许想反驳，怎么能说工程代码没有价值呢？以太坊的客户端同一份 Spec，有五六种工程化的实现，用了不同语言、做了不同优化，市场占有率有高有低，难道不是工程化代码价值的体现吗？当然是，他们拿着以太坊基金会的赞助开着公司写着代码，而且已经有了明确的项目背景，工程代码自然是有价值的。我指的是没有项目背景的工程代码。</p><p>虽然工程代码没有价值，但教学性质的代码是很有意义的，我仍然会复习计算机课的练习题，以保证自己的代码水平。我已经是第三轮做那些练习题了，这次我严格限制自己的做题速度，一天最多做一道题。一方面是保证有足够的时间消化练习题包含的知识，相信潜意识的力量。另一方面，得分配时间到其他事情上，不能整天只反复做同样的题。而且由于做题比较慢，可以逐渐培养自己每天做题的习惯，不至于遗忘计算机课的知识。</p><p>为什么我觉得对项目做分析是有意义的？因为其实我对区块链技术的理解，很大程度上，来自于几年前，读了很多白皮书。我当时按照币种市值的排名，逐一下载了排名前几百的币种白皮书，还用 A4 纸都打印出来看。</p><p>记得几年前有人发邮件问我，如何学习区块链技术。我当时认真写了个回复，说我是从哪个网站下载的白皮书，以及看了哪些书之类。后来对方回复我说，这不是他想要学习的区块链技术，他想要学习的是如何写代码。那个时候我才意识到，不同的人，对技术的定义是不同的。</p><p>以前没有 AI，我没能认识到代码的价值，现在有了 AI，我还是认识不到代码的价值。</p><p>为什么我觉得自己可以写出项目的分析报告？我以前没专门针对项目写过，但是有根据技术来对项目做横向对比的内容，所以专注于对某个项目做技术分析，应该不是难事。我工作过的项目，假如让我写分析，肯定能写出其中的细节，只是因为项目还在，不能写。而且写项目分析，对我来说也是一个学习和积累的过程。</p><p>我不确定一个项目一天时间够不够，只有写写试试了。</p>]]></content>
  </entry>
  <entry>
    <title>2025 年 7 月的面试记录</title>
    <link href="https://b.smallyu.net/2025/07/31/2025%E5%B9%B47%E6%9C%88%E7%9A%84%E9%9D%A2%E8%AF%95%E8%AE%B0%E5%BD%95/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/31/2025%E5%B9%B47%E6%9C%88%E7%9A%84%E9%9D%A2%E8%AF%95%E8%AE%B0%E5%BD%95/</id>
    <published>2025-07-31T04:12:12.000Z</published>
    <updated>2025-12-04T13:51:08.738Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<ul>
<li>2025.06.30（phemex）</li>
</ul>
<p>面试官水平挺好的。对方是在做 AA 钱包的业务，基于 zk]]></summary>
    <content type="html"><![CDATA[<ul><li>2025.06.30（phemex）</li></ul><p>面试官水平挺好的。对方是在做 AA 钱包的业务，基于 zk 的社交恢复方向。交易所不差钱，一般都喜欢往钱包方面做。</p><ul><li>2025.07.01（火币，一面）</li></ul><p>钱包开发团队的后端开发职位，一面比较随意一点。</p><ul><li>2025.07.02（火币，二面）</li></ul><p>属于交叉面，聊一些偏经验性质的东西。</p><ul><li>2025.07.03（鲲鹏海天）</li></ul><p>线下面试的，虽然去之前就知道不靠谱，但还是去了，就当出门散步了。</p><ul><li>2025.07.03（火币，三面）</li></ul><p>技术面的终面，但还是交叉面，有点奇怪。</p><ul><li>2025.07.07（phemex，二面）</li></ul><p>看起来面试官是密码学方面的专家，在 zk 方面非常有经验，我在面试中也学到不少东西，挺难得。</p><ul><li>2025.07.08（川研科技）</li></ul><p>面试中我说没有 Defi 后端的经验，然后面试官让我用一个星期的时间完成一个任务，一个星期后二面，也是挺离谱的。</p><p>给我的任务内容是，解析 Uniswap v4 Router 的交易。我反复问对方这个任务的难点在哪里，对方说，难点在于函数的入参不是基本类型，而是 bytes，需要对 bytes 做解析。这种任务对我来说还挺侮辱人的。</p><p>这家公司是做 trading bot 的，关心解析交易、跟单、价格变动、用户资产一类，也需要发一些夹子交易之类。</p><ul><li>2025.07.10（海利普科贸）</li></ul><p>线下面试。不得不说一面线下面试的都是坑，遇到不懂技术的技术负责人真的浪费口舌。</p><p>（有感而发）</p><p>有些公司没有任何区块链技术背景，公司里没有懂区块链的人，你说你不虚心请教来面试的人，反而一副高高在上的样子，自以为学了点皮毛就居高临下地考察别人，给这些人惯的。</p><p>有些面试官的思路很奇怪，他们把面试过程当成竞技场，非要在面试中胜过面试者才乐意，当面试者说了很多他们不懂的东西，他们无动于衷、视而不见，然后不断找其他话题，直到找到了自己熟悉的那么一点点狭隘的技术领域，他们终于松了一口气，像是在说，“看，我知道但你不知道！”，并且会因此否定面试者。 </p><p>这种判断方式很奇葩，一张满分 100 分的试卷，你只会做第一道价值 10 分题，而别人除了第一道题都会做，得分 90 分，你却抓着第一道题不放，因为你只有第一道题才能说上点什么，不然很露怯。这些人以在面试中胜出为目的，而不是充分挖掘面试者的潜能，判断是否能给公司、给团队带来价值。</p><p>还有另外一种现象我也不理解，举个例子，Go 语言 “千辛万苦” 做出了自动的垃圾回收，减轻程序员对于内存管理的头脑负担。而有些面试官 “千辛万苦” 去搞明白 Go 语言 GC 的原理是什么，不但引以为豪，而且拿来考察候选人。作为 Go 语言的教徒，你知不知道你的行为在否定 Go 语言设计者的努力？如果真的相信用头脑来管理内存的力量，为什么不去搞 Rust？好比我是一个汽车驾驶员，我要去考驾照，难道需要我搞清楚发动机的工作原理、是怎么把汽油燃烧转变为机械动力的、能量转化公式是什么？我又不是在制造汽车，也不是在开发编程语言。</p><p>另外还有一种，属于经验匹配论。因为面试官并不能很好的评估候选人的能力，所以主要以工作经验为判断依据，根据公司正在做的事情，看候选人是不是有相关经验，有则说明候选人能胜任工作，没有则不确定。这实际上是面试官判断能力不足的体现，他看不懂你过往的工作成果，也理解不了你写的技术文章，只知道守着自己的一亩三分地，想找个听话、能干脏活、好控制的人就可以。而且事实上大多数公司招聘的时候，都是在看经验上的匹配程度，挺无语。</p><p>我不是在抱怨 “为什么他们看不懂我的能力”，而是在强调面试过程中，面试官对待候选人的态度问题。很多面试官在面试中表现出种种不尊重人的行为，随意根据自己的喜好评价别人，一副考核别人的态度，但也得看看自己几斤几两，有没有资格去考核别人。退一步说，无论候选人的技术好坏，你都应该保持尊重和友善的态度。而事实上呢？很多面试官给人的感觉，就像在菜市场里买菜，东挑西捡的样子。大概是因为中国几十年来的高速发展忽略了素质教育，培养出了一代素质糟糕的人。</p><ul><li>2025.07.15（imToken）</li></ul><p>和 HR 的沟通。虽然一般认为和 HR 聊天不算面试，但是这位 HR 让我有点感慨，也许只有像这种有丰富国际背景的人，才明白 “尊重人” 是什么意思。相比之下，国内的很多 HR，甚至开发团队中的核心员工，都完全没有这种概念。</p><ul><li>2025.07.18（imToken）</li></ul><p>技术面。完全不出意料的，面试体验非常好。无论我在面试中的表现如何，无论有没有通过面试，我都得这么评价，面试体验非常好。面试官是来自台湾的团队，明白了吧。面试官对技术的理解很丰富，我在面试中也收获到很多。</p><ul><li>2025.07.18（索洛幻想）</li></ul><p>一家游戏公司，是普通的 Go 语言开发后端职位，线下面试。我是随便投的简历，不知道为什么公司会让我去面试。我估计会很不靠谱。</p><p>面试之后确实不太靠谱，不过面试体验还算可以。让我去面试的原因是，面试官 19 年左右做过区块链开发，可能也是好奇我的技能情况。这次面试让我再一次体会到了隔行如隔山，我一直觉得互联网和区块链是两个行业，互相是不通的。以后还是不能再投互联网的后端开发职位了。做互联网的人也许甚至感知不到有 “区块链” 这个行业的存在，他们觉得既然都是后端开发，开发什么都可以。</p><ul><li>2025.07.19（不知道名字）</li></ul><p>线下参加了 The Web3 社区的一个交流会，原来 The Web3 社区是一家天津的公司，老板是从 bybit 出来创业的，现在在做培训班的生意，就是让 web2 的开发者通过培训，进入到 web3 的公司，并且在宣传的时候刻意夸大了 web3 的薪资，满口财富自由之类的话，吃相很难看。培训班这个行业，还真是各行各业都存在。另外我发现从 bybit 出来的人，往往会有一种迷之自信。</p><!--在参会者中认识了一家公司的研究员，是做身份认证技术的，希望通过 web3 把业务场景拓展到海外市场。不算是正式的面试，但也属于工作机会方面的接触，所以我记录在这里，我给他发了简历，他也介绍了公司也工作的情况等等。--><ul><li>2025.07.21（Web3 Holding Limited）</li></ul><p>我不确定这是一家公司的名字吗，它是一家交易所，职位是区块链开发运维（Devops），像是运维岗，我本来兴趣也不大。</p><p>结果没面试上，因为面试链接是 Lark 的会议，但是我网页点不开那个 <code>vc-jp</code> 开头的域名，然后电脑和手机都下载了 Lark 尝试，手机号登陆说我没有组织不能进入会议，邮箱登陆进去就让我创建组织。总之搞不懂，我用 Lark 工作过，也用 Lark 参加过面试，没遇到过这种情况。折腾了有半个多小时吧。当然前十几分钟发现进不去的时候就告诉 HR 取消面试，没有让面试官和 HR 久等。但我也不想再折腾这种问题了，看来这个面试是没机会参加了。</p><ul><li>2025.07.22（CKB）</li></ul><p>和 HR 聊，不是面试。开发者关系一类的岗位。</p><ul><li>2025.07.23（imToken）</li></ul><p>二面，面试体验依然非常好，不想透露具体的内容了。</p><p>但是对面试结果不抱有积极态度，根据我的经验，凡是在面试中对你表现出考核态度的，面试结果都不会好。因为他们面试的立场，从一开始就不太对。</p><ul><li>2025.07.24（长奇）</li></ul><p>属于比较普通的常规一面，面试官没看过我简历，现场看那种，然后问一些不痛不痒的技术问题。职位是 Dex 后端开发。</p><ul><li>2025.07.25（博鸿易科技）</li></ul><p>职位简介是区块链底层开发，而且是线下面试，有点奇怪。</p><p>面试之后，再一次证明了这句话，“一面线下面试的都不靠谱”。这种线下面试一般是整个公司都不懂区块链，做互联网的，然后要搞个区块链项目之类。这家公司之前是做原子链的。</p><p>虽然工作机会不靠谱，技术负责人也不靠谱，不过 HR 小姐姐还挺能聊的。我给她分享了很多区块链行业的现状、风险、招聘方式、就业情况等，尤其是和互联网行业的差异、面试体验什么的，她说自己不太懂这些。</p><ul><li>2025.07.31（CKB）</li></ul><p>开发者关系岗位，招的是全栈开发。面试官说自己比较顾虑的一点是，我到底会不会用 TypeScript 语言做后端开发，以及会不会前端开发，因为我的简历上看不到那些。这种情况我没办法，不过好在面试官很诚实，直接了当地说出了这些。</p>]]></content>
  </entry>
  <entry>
    <title>我很失败，但我相信 Web3 的未来</title>
    <link href="https://b.smallyu.net/2025/07/29/%E6%88%91%E5%BE%88%E5%A4%B1%E8%B4%A5%EF%BC%8C%E4%BD%86%E6%88%91%E7%9B%B8%E4%BF%A1web3%E7%9A%84%E6%9C%AA%E6%9D%A5/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/29/%E6%88%91%E5%BE%88%E5%A4%B1%E8%B4%A5%EF%BC%8C%E4%BD%86%E6%88%91%E7%9B%B8%E4%BF%A1web3%E7%9A%84%E6%9C%AA%E6%9D%A5/</id>
    <published>2025-07-29T04:30:00.000Z</published>
    <updated>2025-12-03T09:25:54.156Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>这两天有点郁闷，因为还没找到合适的工作。我的负面情绪几乎都来自于面试的失败，最近两个月面试了很多公司，但都以不合适告终。虽然每一份工作我都认为自己在技术能力上可以胜任，但是人家不信，我也没有办法。</p>
<p>大概两个月前，我把博客上的文章精简了一下，删掉了所有关于个人经]]></summary>
    <content type="html"><![CDATA[<p>这两天有点郁闷，因为还没找到合适的工作。我的负面情绪几乎都来自于面试的失败，最近两个月面试了很多公司，但都以不合适告终。虽然每一份工作我都认为自己在技术能力上可以胜任，但是人家不信，我也没有办法。</p><p>大概两个月前，我把博客上的文章精简了一下，删掉了所有关于个人经历的部分，因为那些内容太过真实，又可能带来负面影响。于是这个博客就从 “个人博客” 变成了 “技术博客”。这种精简带来了一定的好处，让技术相关的内容能更直白的摆在上面。但是这种精简给我整不会了，我有很多想说的话不能放在 “技术博客” 上面，这很麻烦。我其实还是喜欢原来的 “个人博客”，因为那是我说真话的地方。</p><p>出门在外，人设都是自己给的。精简版本的 “技术博客”，单看内容其实还不错，也许会给人某种高大上的感觉，如果我写一堆 “找不到工作”、“求职经验” 在上面，岂不是破坏整体的技术风格。</p><p>ChatGPT 对我过往经历的总结是 “失败朋克”，这个词来源于 “赛博朋克”，意思是我谈论的技术像赛博朋克世界里的高楼大厦，到处都是高科技的电子屏幕和飞船，同时另一方面，我的职业经历非常糟糕，与技术内容很是割裂，像是在赛博朋克世界里，住在贫民窟的那一波人，时刻为生活担忧和奔波，所以叫 “失败朋克”。</p><p>我最近感觉有点憋屈的地方，就是我不能或者不敢在博客上写太真实的东西了。比如我前几天写了一篇文章，标题是《回忆同事被另一个同事赶走的事情》，但是不敢发。这篇文章是《因为同事的不尊重，我换工作了》的续集，里面的内容很简单，我可以按照时间线梳理一下我想表达的意思：</p><ul><li>《<a href="/2025/03/22/%E4%BB%8E%E5%9B%A2%E9%98%9F%E5%86%85%E9%83%A8%E7%9A%84%E6%B7%B7%E4%B9%B1%E6%83%B3%E5%88%B0%E2%80%A6%E2%80%A6/">从团队内部的混乱想到……</a>》：老同事对我不好，leader 置之不理，放任不管</li><li>《<a href="/2025/04/13/%E5%9B%A0%E4%B8%BA%E5%90%8C%E4%BA%8B%E7%9A%84%E4%B8%8D%E5%B0%8A%E9%87%8D%EF%BC%8C%E6%88%91%E6%8D%A2%E5%B7%A5%E4%BD%9C%E4%BA%86/">因为同事的不尊重，我换工作了</a>》：老同事对我不好，我就走了</li><li>《<a href="/2025/07/26/%E5%9B%9E%E5%BF%86%E5%90%8C%E4%BA%8B%E8%A2%AB%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%90%8C%E4%BA%8B%E8%B5%B6%E8%B5%B0%E7%9A%84%E4%BA%8B%E6%83%85/">回忆同事被另一个同事赶走的事情</a>》：其实老同事不只是对我不好，他对谁都不好</li></ul><p>这些每一篇都超过两千字的文章，我完全可以用一句话概括出来我的想法。写那么多无非是填充了很多具体的事情过程，意思是，你来看吧，你来判断吧，我把前后因果都写出来了，这不是我的错。但就是这样的内容，在 ChatGPT 的评价体系里，觉得我不应该写这些，尤其是面对未来又可能的招聘方，对方可能会有顾虑什么的，让我别发出来。</p><p>我有时候想不通，明明受欺负的是我，但是我却不能把这些真实的事情公之于众，一旦说出来就显得是我的错，错在不应该说出来，天呐……这是什么世道。</p><p>裁员的事情也是，有人说《<a href="/2025/05/15/%E5%85%AC%E5%8F%B8%E6%B2%A1%E4%BA%86%EF%BC%8C%E6%88%91%E5%8F%88%E5%A4%B1%E4%B8%9A%E4%BA%86/">公司没了，我又失业了</a>》的内容会给我带来危险。我从来没想过占公司的便宜，无论是哪一家。但是我却遇到了不靠谱的公司，我已经尽可能用 “体验了 web3 行业的下限” 来安慰自己从这件事情中学到了东西，但是我仍然记恨当时把我招进去的人，他是巴比特钱包的负责人，当时巴比特因为被盗 15亿事件裁了钱包业务线。我可是跳槽去的啊……</p><p>而遇到裁员后，我直到现在都没找到工作，我也用了很多内容来对抗这种焦虑和失败的情绪：</p><ul><li>《<a href="/2025/07/20/%E5%A4%B1%E4%B8%9A%E7%AC%AC%E4%BA%8C%E4%B8%AA%E6%9C%88%E5%B9%B2%E4%BA%86%E4%BB%80%E4%B9%88/">失业第二个月干了什么</a>》：我一点都没闲着，我很努力在学习技术</li><li>《<a href="/2025/07/21/Web3%E6%8A%80%E6%9C%AF%E4%BA%BA%E7%9A%84%E8%81%8C%E4%B8%9A%E7%94%9F%E6%B6%AF%E6%B3%A8%E5%AE%9A%E4%B8%8D%E7%A8%B3%E5%AE%9A/">Web3 技术人的职业生涯注定不稳定</a>》：我去年裸辞没有错，至少我不希望是错</li><li>《<a href="/2025/07/22/web2%E5%BC%80%E5%8F%91%E5%A6%82%E4%BD%95%E8%BD%AC%E5%9E%8Bweb3%E5%BC%80%E5%8F%91/">web2 开发如何转型 web3 开发</a>》：我不信培训班出来的，技术比我好，找工作比我容易</li></ul><p>回到找工作的事，ChatGPT 对我职业和技能方向的评价是，“在不招骑士的王国里苦练骑士精神”，我也很清楚现在工作职位少，尤其是和自己技能匹配的。但是我也不止一次提到，我很少遇到在面试中，技术很牛的面试官，真的很少有人在区块链技术问题上把我问住，大多数都是这种，“有没有做过xxx？没做过啊，不匹配”。我还能说什么？我就是没做过啊。</p><p>还有一些问 web2 技能的，我不是学不会那些东西，是 web3 真的用不到，这完全是两个行当，互联网和区块链是两个行业，技术栈不一样。假如我专心从事 web2，也许我考虑的，就是如何开发一个最小数据库、开发一个最小 MQ、开发一个最小 Redis 之类的东西了吧。就像我在尝试《<a href="/2025/05/11/%E6%83%B3%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E6%9C%80%E5%B0%8FEVM%E8%99%9A%E6%8B%9F%E6%9C%BA/">想开发一个最小 EVM 虚拟机</a>》那样。</p><p>其实 web3 行业很小，比互联网行业小的多，人更是少，尤其是专注于技术的技术人。我面试了那么多公司，面对的可都是 web3 公司的面试官啊，真正懂区块链技术的却没几个，甚至有时候都对他们的 “菜” 感到生气。比如我在考虑怎么开发一个 EVM，然后你在怀疑我会不会解析某个合约交易的参数……你都会我怎么会不会呢 🙂</p><p>至于最近上的课，主要是出于补齐自己计算机基础的目的吧，成体系的那种。我不需要再怀疑，是不是因为学历或者专业的问题，导致自己找不到工作。有的招聘方就喜欢 c9，这种我也没办法，那是人家的喜好。</p><p>那么既然我的职业生涯很糟糕，为什么不转行回到 web2，去找互联网行业的工作呢？因为我相信未来的 web3 行业，会比现在更大、更景气、更繁荣。我博客上写的技术内容，也许现在没有人在乎，但是直到有一天，web3 的产品走进千家万户，web3 的公司像 web2 一样多，人们谈论区块链技术像谈论 MySQL、Redis、RabbitMQ 一样自然，学习共识机制就像学习面向对象一样基础，使用加密货币理财就像支付宝基金一样方便，然后就会明白，懂区块链技术是多么有价值的一件事。</p><p>虽然我知道我现在的年纪，不太可能是终点，但是连续遇到面试的失利，难免会有糟糕的情绪。你可以设身处地想一下，面试二十几家公司都不合适，你的心态会怎样。关键是市面上能投简历的职位都投过了，从 2023 年到今天为止，所有技术相关的职位。每面试失败一家，就意味着今后少了一个选项，我都怀疑还能有那么多公司让我去排除的吗。</p><p>没办法，吐槽结束，继续努力吧。</p><h3 id="补充（2025-08-03）"><a href="#补充（2025-08-03）" class="headerlink" title="补充（2025.08.03）"></a>补充（2025.08.03）</h3><p>不知道你看懂没有，这篇文章，以及很多之前的文章，都是在对我自己的人生经历和职业选择做建模，这是我无意中在做的事情。</p><p>真正让我生气、焦虑的，不是我这段时间没有工作和收入的问题，而是没有公司认可我的能力这一点，我自认为拥有的技术实力不应该是这样，我不知道哪里出了问题。</p><p>我最理想的面试，是有一个技术能力特别厉害的面试官，告诉我技术能力哪里不够，因此我不符合公司的招聘要求。这种情况下，我自己也能够明白技术能力上有哪些欠缺的地方，并且日后去逐一补齐。</p><p>而实际上，我看着那些面试官，以及想到过往工作中遇到的那些、技术能力差劲、人品糟糕的同事，看他们有着安稳的生活和工作、在公司中掌握着话语权，我不理解。</p><p>我一直在坚持某种 “正确”，有理有据地做出人生中的每一个选择，但是生活却不如意。这是为什么。</p>]]></content>
  </entry>
  <entry>
    <title>推荐好玩的 FMV 游戏</title>
    <link href="https://b.smallyu.net/2025/07/27/%E6%8E%A8%E8%8D%90%E5%A5%BD%E7%8E%A9%E7%9A%84FMV%E6%B8%B8%E6%88%8F/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/27/%E6%8E%A8%E8%8D%90%E5%A5%BD%E7%8E%A9%E7%9A%84FMV%E6%B8%B8%E6%88%8F/</id>
    <published>2025-07-27T10:30:00.000Z</published>
    <updated>2026-03-02T09:01:53.683Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>这两天玩了几个 FMV 游戏，还挺有意思。FMV 类型的游戏，前段时间最火爆、最出圈、最知名的，就是《捞女游戏》，后来改名《情感反诈模拟器》。FMV 游戏就是真人拍摄视频片段，然后根据你的选择走向不同的结局，Netflix]]></summary>
    <content type="html"><![CDATA[<p>这两天玩了几个 FMV 游戏，还挺有意思。FMV 类型的游戏，前段时间最火爆、最出圈、最知名的，就是《捞女游戏》，后来改名《情感反诈模拟器》。FMV 游戏就是真人拍摄视频片段，然后根据你的选择走向不同的结局，Netflix 上也有一些影片是提供互动的，比如有一集《黑镜：潘达斯奈基》，不过 Netfilx 的互动只能前进，不能后退，FMV 更像游戏一点，操作性更强。</p><p>FMV 游戏操作简单，很适合我这种老年选手玩。我前几年喜欢玩剧本杀，后来年纪大了就不玩了。最近发现好的 FMV 游戏也挺有代入感，能够带来一些有意思的剧情体验。下面是我最近玩过的游戏，根据自己的喜好排名，都是在 MacOS 平台的 Steam 上买的，我体验不了 Windows 游戏，也许会错过一些好游戏：</p><h3 id="1-完蛋，我被美女包围了"><a href="#1-完蛋，我被美女包围了" class="headerlink" title="1. 完蛋，我被美女包围了"></a>1. 完蛋，我被美女包围了</h3><p>游玩时长 5.6 小时。这个游戏当年销量很好，以擦边片段出名，在抖音上很多 “浩浩妈做瑜伽” 之类的梗。这个就是浩浩妈：</p><img src="1.png" width="70%"><p>我喜欢这个游戏的地方在于，剧情非常炸裂，比科幻片还科幻，好几处能笑出声那种。大体剧情是好几个美女主角争着抢着要得到你的好感。</p><p>除了题材之外，游戏剧情的节奏也控制的很好，这种 FMV 游戏，剧情一拖沓就会让人觉得无聊，剧情没有爆点就会没意思，如果剧情短选择太多，又会觉得烦，如果关键选项设计不好，会让人玩不明白。其实 FMV 要设计好也不容易。</p><p>我第一次解锁的是 “男闺蜜” 结局，谁都不得罪，结果混成朋友了。后来解锁和比较喜欢的是肖鹿的结局：</p><img src="2.png" width="70%"><p>这个游戏全程用第一人称视角，比较有代入感，而且还有弹幕，看剧情时不显得孤独，总体各方面设计都不错。《完蛋，我被美女包围了》是我目前最推荐的游戏。</p><h3 id="2-完蛋，我被美女包围了-2"><a href="#2-完蛋，我被美女包围了-2" class="headerlink" title="2. 完蛋，我被美女包围了 2"></a>2. 完蛋，我被美女包围了 2</h3><p>没错，是《完蛋，我被美女包围了》的续作。第一部发布于 2023 年，第二部发布于大概 10 天前，也挺巧的。</p><p>游玩时长 6.1 小时。《完蛋，我被美女包围了 2》没有沿用第一部的擦边风格，而是加入了很丰富的古风剧情，同时保留了很高的拍摄质量、剧情节奏等要素。比如虽然会看到古灵精怪的二小姐这种老套剧情，但是演员演的很可爱：</p><img src="3.png" width="70%"><p>也有一些我们熟知的片段，比如侠女受伤了，需要你擦药：</p><img src="4.png" width="70%"><p>或者外国的公主要勾引和刺杀你：</p><img src="5.png" width="70%"><p>《完蛋》系列的出品方在做 FMV 游戏方面应该已经很有经验，所以能连续做出好玩的游戏。第二部虽然表面上是严肃的古风题材，实际上是喜剧风格，很多情节都有喜剧元素，这也是我比较喜欢的地方。第二部的配乐和音效更多了，还有威亚之类的动作戏，整体拍摄更专业。游戏里还加入了 AI 聊天的功能（真是什么产品都在结合 AI），要素比第一部齐全。</p><h3 id="3-情感反诈模拟器"><a href="#3-情感反诈模拟器" class="headerlink" title="3. 情感反诈模拟器"></a>3. 情感反诈模拟器</h3><p>“情歌一响，反诈白讲”。《捞女游戏》能出圈肯定是有原因的，一方面是融合了胖猫事件之类的情节，另一方面是，故事确实挺感人，尤其是第二章的末尾，这一段是网络上流传最广的。“可不可以” 的音乐一响起来，就开始和白月光回忆过去：</p><img src="6.png" width="70%"><p>游玩时长 4.4 小时，后面的章节玩不下去了，感觉剧情有点啰嗦。但是光第二章的结尾这一段，就非常打动人了。</p><h3 id="4-名利游戏"><a href="#4-名利游戏" class="headerlink" title="4. 名利游戏"></a>4. 名利游戏</h3><p>游玩时长 5.8 小时，其实这个游戏也不错。我第一次完整的玩完一个 FMV 游戏，剧情还可以，有暴力、有套路、有仙人跳，只是过程中的选项偶尔莫名其妙，毫不起眼的一个选择会影响主线那种：</p><img src="7.png" width="70%"><p>比如像这种看似重要的选择，其实不管选哪个，都会走向短的坏结局，而好结局，藏在很不经意的选择上。</p><h3 id="5-你好，我们还有场恋爱没谈"><a href="#5-你好，我们还有场恋爱没谈" class="headerlink" title="5. 你好，我们还有场恋爱没谈"></a>5. 你好，我们还有场恋爱没谈</h3><p>游玩时长 5.5 小时，出乎意料的还不错。本以为除了《完蛋》系列，很难有游戏好玩了，没想到这个还行。</p><img src="14.png" width="70%"><p>剧情梗概是从社畜穿越回大学时代了，画质和布景美的像写真一样，剧情节奏也不错，每一小节不是很长，不会看到无聊。</p><h3 id="6-其他不太推荐的"><a href="#6-其他不太推荐的" class="headerlink" title="6. 其他不太推荐的"></a>6. 其他不太推荐的</h3><ul><li>《完蛋，我被美女包围了：房间里的心跳》</li></ul><p>游玩时长 2 小时，是《完蛋1》的 DLC，新剧情和新人物，和《完蛋1》不同，没有任何擦边内容，修罗场玩法更突出一点。剧情勉强看得下去，整体流程较短，喜欢《完蛋1》可以当情怀玩。</p><img src="12.png" width="70%"><p>这种游戏我有点找到规律了，可以直接看排行榜，哪个女主角的人气最高，在剧情中就指着哪个女主角的线选，剧情往往更有意思。</p><ul><li>《完蛋，我被美女包围了：前传》</li></ul><img src="11.png" width="70%"><p>游玩时长 1 小时。剧情上是《完蛋1》的前传，有人物和情节联动的部分，讲述男主大学时代的故事。发售时间在《完蛋1》之后，《完蛋2》之前，2024 年 10 月份左右。这个游戏保留了不少擦边元素，但是剧情比较弱，游戏方都很识相的连未观看剧情都可以快进。</p><ul><li>《超级星探》</li></ul><img src="13.png" width="70%"><p>游玩时长 1.5 小时。制作精良，环境优美，女生漂亮，剧情差劲。FMV 游戏的剧情片段冗长是大忌，这个的游戏语速和剧情节奏都太慢，全程 2 倍速都嫌慢。</p><ul><li>《与美女合租的 99 种死法》</li></ul><img src="8.png" width="70%"><p>游玩时长 1.5 小时，人物和台词略显尴尬。唯一的好玩之处在于死法多，出乎意料。其他游戏都是刷女主的好感度，这个游戏男主还有血条。</p><ul><li>《阿西，美女室友竟然……》</li></ul><img src="9.png" width="70%"><p>游玩时长 0.5 小时，语言是韩语语音和中文字幕，剧情还可以，但是不太喜欢听韩语。</p><ul><li>《都要！小孩子才做选择》</li></ul><img src="10.png" width="70%"><p>游玩时长 0.5 小时，开局鬼屋氛围，有点吓人，后面剧情也一般，主要是拍摄出来的画面有点失真，容易出戏。</p><ul><li>《完蛋，我也能追到美女了》</li></ul><p>游玩时长 0.5 小时，不好玩，剧情尴尬，片段太长。</p><ul><li>《命运游戏 2》</li></ul><p>第一部闪退，第二部剧情发展非常慢，不好玩。</p><ul><li>The Isle Tide Hotel</li></ul><p>Netfilx 出品，选项比较少，不能快进，不能回退，一条命到底，更像是看电影。</p><ul><li>Ten Dates</li></ul><p>美国人的游戏，比较注重内容，不好玩。</p><h3 id="题外话"><a href="#题外话" class="headerlink" title="题外话"></a>题外话</h3><p>我发现一个类比。</p><p>有些捞女，或者混迹于酒吧的女孩，喜欢画着精致的妆容，去认识开豪车的人，非常主动，要联系方式、介绍自己、约会等，本质上是觉得自己更值钱、值得认识更好的人。</p><p>而打工人，会写着精致的简历，非常主动去投简历、面试、寻找更好的工作、团队、项目，本质上也是觉得自己更值钱、值得更好的公司和老板。</p><p>这就是玩 FMV 游戏给我带来的，某种现实意义上的感受。</p><p>希望大家都能有轻松愉快的周末。</p>]]></content>
  </entry>
  <entry>
    <title>回忆同事被另一个同事赶走的事情</title>
    <link href="https://b.smallyu.net/2025/07/26/%E5%9B%9E%E5%BF%86%E5%90%8C%E4%BA%8B%E8%A2%AB%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%90%8C%E4%BA%8B%E8%B5%B6%E8%B5%B0%E7%9A%84%E4%BA%8B%E6%83%85/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/26/%E5%9B%9E%E5%BF%86%E5%90%8C%E4%BA%8B%E8%A2%AB%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%90%8C%E4%BA%8B%E8%B5%B6%E8%B5%B0%E7%9A%84%E4%BA%8B%E6%83%85/</id>
    <published>2025-07-26T13:32:42.000Z</published>
    <updated>2025-12-03T09:25:54.155Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>这些都已经是过去的事情了，只是偶然想起来。</p>
<p>我们小组当时加入了一个技术能力不太好的新同事。技术能力的好坏是相对的，也许做其他工作，或者在其他团队可以发挥出更大的价值。这里说的不太好，主要指在我们的项目背景下，几乎无法胜任对 ZetaChain]]></summary>
    <content type="html"><![CDATA[<p>这些都已经是过去的事情了，只是偶然想起来。</p><p>我们小组当时加入了一个技术能力不太好的新同事。技术能力的好坏是相对的，也许做其他工作，或者在其他团队可以发挥出更大的价值。这里说的不太好，主要指在我们的项目背景下，几乎无法胜任对 ZetaChain 做二次开发的工作，他也许光是链下扫描、链上处理事件的结构都没整明白。</p><p>我刚进入的项目的时候，当然也不熟悉项目，我没做过 Cosmos 开发，也不了解 Restaking，更没看过项目代码，自然不熟悉。但是我当时挺了解区块链项目的模式。</p><p>就是《<a href="/2024/10/15/%E7%9C%8B%E6%87%82%E4%BB%BB%E6%84%8F%E5%8C%BA%E5%9D%97%E9%93%BE%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84/">看懂任意区块链项目的技术架构</a>》文章里提到的那些，我看一眼项目就马上明白了，有感而发写出了那篇文章。这个技能是在之前某家公司训练出来的，因为工作压力小，我有足够的时间，一个人去看懂复杂程度非常高的整个系统，从搭节点到 VBFT、合约逻辑、State Channel、IPFS、PDP、libp2p…… 我已经忘记了具体干过什么事情，但是这个折腾和调试复杂代码的过程还记得。</p><p>我基于已知的区块链工程的模式，逐步去了解项目、看懂代码结构，所以我上手和掌握项目的速度还算快，一两个星期就提交了代码，一个月左右就提交了更复杂的代码。</p><p>不过毕竟我刚入职一两个星期，没办法独自承担某一个比较重要的任务，所以测试网上线的事情由另外一个老同事负责。这个事情后来做的比较糟糕，我们内部也好几次复盘分析这件事。</p><p>其实我加入项目的时候，就已经错过了项目上线的最佳时间，这一点是我倍感遗憾的。假如我可以早几个月加入项目，我就可以在比较熟悉项目的情况下，发挥更大的作用，也许项目进度就不会是那样，项目结果也会更好。可惜事实上我加入项目的时间点，就已经无力回天了，哪怕我后来频繁主动加班、非常努力地推进工作。</p><p>说的有点远，我们新加入的同事，比我晚加入一个月。leader 对他抱以和我一样的期望，觉得他的水平应该和我差不多。（话说，谁说随便招个人就有我这个水平的😝）。但是事实上，经过了两三个月的工作，他一个开发需求都没完成。估计他连整个项目是在干什么都没搞懂。看起来属于初级开发，需要非常明确的给一些小的编程任务才行，稍微带点业务逻辑、复杂一点就不行了。</p><p>我说这些不是想落井下石，或者贬低他，只是想客观描述一下他的技能水平。人家也没说自己是高级开发，我也不知道他对自己的评估是怎么样。</p><p>我的意思是，尽管我对他的技术能力有感受，但是我没表现出什么，很多需求和问题是我帮他解决。不知道他出于什么原因，遇到某些问题的时候，比如项目部署报错了，他就会处于一种摆烂的态度。我已经告诉他排查问题的方法，他仍然会把事情放在那儿。最终还得是我亲自登陆服务器、看日志、改代码，然后这个需求就 close 了。我猜啊，其实他也委屈，他是真不会，没办法。（需求的 owner 是他，我才会说我亲自动手属于我帮他）</p><p>话又说远了。我一开始提到的老同事，有一天早上给我打电话，问我对新同事的印象（其实已经不新了，工作好几个月了，这里的称呼主要用来区分人物）。我如实说出了我的感受。然后他就开始吐槽，说昨天晚上，他交给新同事一个需求，新同事不会做，他手把手的教，新同事反而表现出了极度的不耐烦…… 这个老同事白天经常有事，喜欢晚上上班，所以我猜新同事的情绪，很大程度是因为太晚了不能下班导致的。不过新同事的态度倒是也有点问题，他一看到需要改上百个代码文件，就懵了，虽然只是很小的改动。</p><p>然后那个老同事，就在给我打电话的当天，单独跟大老板和 leader 说了这个情况。再然后的一两天，新同事正式被裁掉。</p><p>事情的过程就这么简单，因为老同事的消极反馈，新同事马上就被裁掉了。</p><p>不知道是不是新同事这件事情的缘故，导致老同事觉得自己有非常高的影响力，或者非常高的地位。他后来跟我也发生过一些事情，也许是某种情绪上的惯性，感觉他似乎忘记了我的工作表现、对团队做出的贡献，用非常糟糕的情绪对待我，把我当新同事了可能。那件事情也成了我主动离开项目的原因之一。</p><p>所以从这个事情可以看到，有一个爱挑事又身处关键位置的同事，会让整个团队鸡犬不宁。</p><p>话说，那个新同事，在项目里工作了几个月，拿着全额工资，啥也没干，最后走了。我在项目里工作了几个月，加班加点，费心费力，就挣了点工资，最后也走了。我们入职时间没差太多，离职时间也没差太多。</p><p>有时候也是感慨，人生啊，这个得失，不好说。</p>]]></content>
  </entry>
  <entry>
    <title>我从王垠的计算机科学课学到了什么（一个月版）</title>
    <link href="https://b.smallyu.net/2025/07/24/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%88/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/24/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%AF%BE%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%88/</id>
    <published>2025-07-24T04:12:12.000Z</published>
    <updated>2026-07-17T06:27:02.247Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>为了行文方便，这篇文章不使用 “王垠老师” 这样的尊称，直接称呼名字 “王垠”。</p>
</blockquote>
<p>大约 2 个月前，我开始报名学习王垠的 <a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>为了行文方便，这篇文章不使用 “王垠老师” 这样的尊称，直接称呼名字 “王垠”。</p></blockquote><p>大约 2 个月前，我开始报名学习王垠的 <a href="https://www.yinwang.org/blog-cn/2025/05/12/cs-video-course">计算机科学视频班</a>（基础班），经过 1 个月的学习后毕业，大概用了 120 个小时的学习时长。“120 个小时” 这个数字是经过认真估算的，包含了观看视频的时间和做练习题的时间。因为视频课的学习节奏由自己把控，毕业速度因人而异，所以 “1 个月” 这样的描述不够直观，用小时数更加容易理解。 120 个小时意味着，如果一天学 2 个小时的话，不包括节假日需要 60 天。</p><p>如果我说学了 1 个月，也许有人会很不在乎，1 个月的时间能学到多少知识呢？世界上没有速成班，王垠也不可以。1 个月的时间确实不可能学到各种全面的知识，时间上也不允许。但是 1 个月的时间能不能帮我把过往的编程技能梳理一遍，让我对计算机科学有更加体系化的认识？我在工作中可能见过各种迷雾，王垠的课程能不能让我拨云见日，看清楚很多东西？我对课程的学习有比较快的速度，因为我远不是零基础，我大多数情况都可以轻松写出能运行的代码，虽然代码不简洁也不优雅。这些编程能力已经形成肌肉记忆，就像生活在原始森林里的野人，即使没有经历过系统的科学的格斗训练，身体素质和格斗技巧也要远超过普通人。</p><p>现在毕业后经过 1 个月时间的沉淀，我想分享一下 “从课程中能学到什么” 这个话题。没有在毕业当天做总结，是因为怕有点浮燥总结不全，或者掺杂太多个人经历。1 个月的时间其实也不够，我没有太多时间复习，课程也远远没来得及发挥出应有的成果，但是现在做总结并不妨碍以后对课程内容有进一步的感悟。王垠曾经有一篇文章《<a href="https://yinwang-wiki.github.io/feeds/2013-04-03-einstein-on-education.html">爱因斯坦谈教育</a>》，里面提到爱因斯坦说 “被传授的知识应该被当成宝贵的礼物”，我在学完课程后无意间翻到这篇文章，看到这句话后，突然对这句话有了切实的理解。</p><p>王垠并不认识我，但我早就认识王垠；我以前不是王垠的学生，但王垠早就是我的老师了。我关注王垠的博客多年，已经从他的博客文章中受益很多。而这次系统学习了视频课的课程，像是打开了新世界的大门。这并不夸张，我可以负责任地站在学习过课程的立场上说，王垠没有吹牛，他的课程真的有他说的那么好。你可以不赞同王垠的观点，也可以不喜欢王垠的人生态度，但是不可能怀疑王垠在计算机科学，尤其是编程语言领域的研究水平，也完全不需要担心王垠这样对自己和世界都如此较真的人，会拿一些没有含量的课程出来忽悠人。</p><p>因为课程内容是保密的，我不会透露课程具体的学习内容，只基于公开的招生说明中的内容进行解释。对于计算机初学者来说，从课程中能学到的最直接的知识，就是函数、链表、二叉树等基础的编程概念，涵盖了大学本科阶段整个过程的学习内容。而第 6 课关于解释器的部分，属于课程的 “最终成果”，对应一些美国顶尖大学本科高年级，至硕士低年级阶段的学习内容。为什么王垠在招生说明里的描述是 “大学博士阶段才可能学到的内容” 呢？因为中国的大学没有编程语言专业，本科课程没有教解释器的，即使到了研究生阶段，lambda 演算也属于选修课，博士早期才会接触到解释器的实现是正常现象。所以王垠的描述真的没有夸大。</p><p>解释器这种内容在中国的教育体系里本来就很稀有，比较高级和精练的教程更是少见。举例来说，当你学完了王垠的课，然后去 bilibili 上搜一些解释器相关的教程，你就会明白这些公开教程里的解释器有多么差劲，不但一眼就能看出它们缺什么要素、存在什么问题，还知道如何改进、如何用最简洁的代码写出最可靠的实现。为什么解释器这个东西重要呢？同样举个例子，以太坊的虚拟机（EVM）就是一个解释器，只不过 EVM 并不是在对编程语言做解释，而是在对以太坊的操作码（Opcodes）做解释，每个操作码都对应在栈结构上的一个动作。所以学过了解释器之后，对 EVM 的原理会有不一样的理解。</p><p>对于有计算机经验的学生来说，从课程上可以学到的，就不只是表面上的知识了。比如，课程只用到非常少的编程要素，就表达了第 1 课到第 6 课的全部内容，如果王垠不是对计算机理论有非常深刻的理解，不可能做到这种地步的深入简出。从学习者的角度，一方面可以思考一下为什么课程内容能如此精致，组织这些课程内容的思路是什么，这种高度抽象的思维背后，需要怎样的功底，自己距离写出这样的课程，能力上的差距还有多大。</p><p>另一方面，由于课程内容自成一体，学习者完全有可能做到自己复刻整个课程内容，就像是手里的一个精致的玩物，随时可以拿出来复习把玩。基础班的知识好比非常高级的原材料，从基础班毕业就意味着拿到了这些原材料。但原材料需要经过反复打磨、锤炼、加工，才能变成更加实际可用的装备。所以我猜测有的同学学完之后感觉什么都没学到，而有的同学觉得如获至宝，能够反复加以利用并产生许多价值，大概就是这个原因吧。</p><p>我最近就忽然意识到，学完课程以后，学习其他技术好像变简单了。因为体验了课程中层层递进的教学方式，我自学其他东西也会按照这个思路来，一步一步学，自然而然就学会了，Solana 合约、比特币脚本、比特币 Runes、理解 CPS、用 continuation 原理实现协程调度等。我有点说不上这是怎么回事，明明课程里只是学了一些计算机基础，链表、二叉树什么的，竟然有这样的威力。也许从课程里学到的不只是知识，还有很好的学习方法。难怪王垠把基础课的内容称为 “计算机科学的精华”。</p><p>虽然我有多年在区块链行业实际的工作经验，我却越来越搞不清楚区块链技术是什么。我之前大量关注区块链共识的原理，为什么关注的不是其他技术原理，比如加密学、分布式网络、储存系统等内容？因为只有共识是区块链特有的，其他都是普通的工程上的技术，包括智能合约的实现，而且智能合约还不是区块链必需，可以有也可以没有。至于 Layer 2 之类，也完全是工程上的尝试，哪有什么可以抽象的理论依据，挑战期、赎回期等都是业务定义的逻辑。我可以剧透一下，王垠的计算机课程，还提到了区块链最本质的技术原理，是不是难以想象？是真的。</p><p>与不成体系的区块链工程相比，拥有基础但扎实的计算机功底很重要，尤其是高度抽象的思维方式，能够脱离语法但理解编程语言本质的学习方式，值得反复琢磨和掌握。我曾经以为好好钻研区块链技术，就可以逐步提高自己的技术能力，就可以深入研究到某些区块链原理，深入再深入，水平上自然而然超越所谓的计算机基础班。然而事实上不是那样。所以我学习了课程，并且学到了很多。</p><p>学完课程以后，我其实一度怀疑自己，难道这几年折腾的区块链技术都没有意义吗？为什么我学了一个零基础入门性质的计算机课，反而感觉学到了 “改变人生” 一样的东西？我一直没想通这件事。直到后来，我偶然看到王垠这篇讲述课程设计的文章《<a href="https://www.yinwang.org/blog-cn/2020/03/03/cs-course">计算机科学课程</a>》，尤其是看到 “苏格拉底方法” 段落的时候，恍然大悟，原来我的知识早已散落在我的头脑中，只是这门课程帮我把知识都 “生产” 了下来。我现在拥有的知识，离不开经年累月工作和学习的 “怀胎”，也离不开这门计算机课程在恰当时候的 “助产”。</p><blockquote><p>苏格拉底承认他自己本来没有知识，而他又要教授别人知识。这个矛盾，他是这样解决的：这些知识并不是由他灌输给人的，而是人们原来已经具有的；人们已在心上怀了“胎”，不过自己还不知道，苏格拉底像一个“助产婆”，帮助别人产生知识。</p></blockquote><p>就好比，在一个陌生的城市里，你没有地图，搞不清方向，但是也可以四处游荡，有时候能走的很远。而计算机基础课，就像是一张完整的地图，你有了地图，各个方向和岔路口都清清楚楚，但是你未必出发，也未必耗费力气去探索远方。我的情况属于，已经在城市里走过了很多路，偶然有一天，拿到了整个城市的地图，幡然醒悟，明白了自己所处的位置，知道了自己原先走过哪些路。</p><p>另外，王垠最近在微博上评论 AI 编程的时候提到，AI 无法写出 “王垠级别” 的代码。什么是 “王垠级别” 的代码呢？上过课就知道了。我在做练习题的时候，被助教提醒最多次的问题，就是 “代码复杂”，有时候是写法上的复杂，有时候是复杂度上的复杂，但是每一次把代码写到符合课程标准之后，又不禁感叹原来代码可以如此精巧。我已经有多年的编程经验，让代码运行出练习题的结果并不难，但是把代码写的足够漂亮却不容易。假如以前给公司写的都是这种质量的代码，那公司可就太占便宜了。</p><p>还不止这些，也许有人看到招生说明会怀疑，一节选修课真能让人学会一种新的编程语言吗？我想提醒的是，不要忘了给你讲课的人是谁，是真正的编程语言专家。</p>]]></content>
  </entry>
  <entry>
    <title>continuation教程: 实现抢占式协程调度</title>
    <link href="https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B6/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B6/</id>
    <published>2025-07-23T04:17:12.000Z</published>
    <updated>2025-12-03T09:25:54.167Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 continuation 系列教程：</p>
<ol>
<li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 continuation 系列教程：</p><ol><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解 CPS</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B2/">continuation 教程：用 yield 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B3/">continuation 教程：用 call&#x2F;cc 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B4/">continuation 教程：用 shift&#x2F;reset 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B5/">continuation 教程：体验 Racket 语言</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B6/">continuation 教程：实现抢占式协程调度</a></li></ol></blockquote><p>你也许注意到了，我们前面用 yield 关键在来实现两个任务的交替打印，似乎和我们平时使用协程的感受不一样，比如 Go 语言的协程往往用来后台启动一个 Server 服务之类；跟我们平时使用 node.js 的感觉也不太一样。</p><p>我们用 yield 关键字，以及用 call&#x2F;cc 或者 shift&#x2F;reset 关键字代替 yield 实现控制流，这种显式管理流的模式属于协作式协程（cooperative）。</p><p>Go 语言一键启动后台协程、交给 runtime 管理控制流的模式，属于抢占式协程（preemptive）。</p><p>node.js 语言常见的异步调用、Promise 关键字之类，属于异步协程。</p><p>他们都属于协程，但是给用户的感受不一样，尤其是抢占式协程，在用户层面感知不到协程调度器的工作，但是抢占式协程的内部实现仍然要依赖于 continuation 概念。</p><h3 id="构建-CPS"><a href="#构建-CPS" class="headerlink" title="构建 CPS"></a>构建 CPS</h3><p>我们基于之前 shift&#x2F;reset 版本的代码来进行实验和改进。首先这是用 shift&#x2F;reset 模拟 yield 效果的完整代码，程序会交替执行两个任务：</p><pre><code class="js">let ready = [];function run()&#123;  while (ready.length &gt; 0)  &#123;    const k = ready.shift()    k();  &#125;&#125;function reset(thunk)&#123;  try  &#123;    thunk(x =&gt; x);  &#125;  catch (f)  &#123;    f( v =&gt; ready.push(v) );  &#125;&#125;function shift(f)&#123;  throw f;&#125;function spawn(thunk)&#123;  ready.push(thunk);&#125;function taskA()&#123;  reset(    k =&gt;    &#123;      shift(        k1 =&gt;        &#123;          console.log(&quot;task A0&quot;);          k1( () =&gt; console.log(&quot;task A1&quot;));        &#125;      );    &#125;  );&#125;function taskB()&#123;  reset(    k =&gt;    &#123;      shift(        k1 =&gt;        &#123;          console.log(&quot;task B0&quot;);          k1( () =&gt; console.log(&quot;task B1&quot;));        &#125;      );    &#125;  );&#125;spawn(taskA);spawn(taskB);run();// task A0// task B0// task A1// task B1</code></pre><p>你肯定注意到 shift 内部是嵌套 CPS 的写法，现在只是打印了 A0 和 A1。那么假如我想新增加 100 个步骤进去，难道要手动写 100 个嵌套的 CPS 函数吗？</p><p>所以我们写一个工具函数来生成 CPS 函数。我们先看一下，假如在 <code>taskA</code> 里增加一个步骤 A2，应该怎么写：</p><pre><code class="js">function taskA()&#123;  reset(    k =&gt;    &#123;      shift(        k1 =&gt;        &#123;          console.log(&quot;task A0&quot;);          k1(             () =&gt;             &#123;              console.log(&quot;task A1&quot;);              k1( () =&gt; console.log(&quot;task A2&quot;));            &#125;          );        &#125;      );    &#125;  );&#125;</code></pre><p>可以看到，关键在于 shift 函数中对 <code>k1</code> 的重复调用，那么我们写这样一个函数，这个函数返回嵌套指定多次 <code>k1</code> 调用的函数：</p><pre><code class="js">function makeCPSTask(n)&#123;  return function task()  &#123;    reset(      k =&gt;      &#123;        shift(          k1 =&gt;          &#123;            console.log(`task 0/$&#123;n&#125;`);            function step(i)            &#123;              if (i &lt; n)              &#123;                k1(                   () =&gt;                   &#123;                    console.log(`task $&#123;i + 1&#125;/$&#123;n&#125;`);                    step(i + 1);                  &#125;                );              &#125;            &#125;            step(0);          &#125;        );      &#125;    );  &#125;&#125;</code></pre><p>这样能看看 <code>makeCPSTask</code> 函数返回的 CPS 函数是什么样子：</p><pre><code class="js">console.log( makeCPSTask(3).toString() );</code></pre><p>试一下用 <code>makeCPSTask</code> 函数来生成和执行任务，参数是一个数字，指任务包含多少个步骤：</p><pre><code class="js">spawn(makeCPSTask(3));run();// task 0/3// task 1/3// task 2/3// task 3/3</code></pre><h3 id="协作式协程"><a href="#协作式协程" class="headerlink" title="协作式协程"></a>协作式协程</h3><p>有了 <code>makeCPSTask</code> 函数后，我们定义一个长任务 <code>longTask</code>，意思是需要执行很多步骤，或者很长时间的任务，再定义一个短任务 <code>shortTask</code>，意思是只需要执行很少的步骤，或者很短的时间：</p><pre><code class="js">let longTask = makeCPSTask(20);let shortTask = makeCPSTask(2);</code></pre><p>现在，把 <code>longTask</code> 和 <code>shortTask</code> 同时用协程启动，看看会发生什么：</p><pre><code class="js">spawn(longTask);spawn(shortTask);run();// task 0/20// task 0/2// task 1/20// task 1/2// task 2/20// task 2/2// task 3/20// task 4/20// ...</code></pre><p>其实运行结果非常好，<code>longTask</code> 没有阻塞 <code>shortTask</code>，虽然长任务有 20 个步骤，但是短任务却在一开始就很好的执行并且结束了。这是为什么呢，因为我们的 <code>makeCPSTask</code> 在生成任务的时候，显式调用了 <code>k1</code>，也就是主动放弃了当前协程的控制权，于是长任务每个步骤都在很礼貌的让出。这恰恰体现出了协作式协程的特点，需要手动管理控制流。</p><h3 id="协作式协程的问题"><a href="#协作式协程的问题" class="headerlink" title="协作式协程的问题"></a>协作式协程的问题</h3><p>我们来定义一个不那么礼貌的 <code>makeLongTask</code> 函数，这个函数内不会调用 <code>k1</code> 主动放弃控制权：</p><pre><code class="js">function makeLongTask(n)&#123;  return function task()  &#123;    reset(      k =&gt;      &#123;        shift(k1 =&gt; &#123;          console.log(&quot;block task start&quot;);          for (let i = 0; i &lt; n; i++)           &#123;            console.log(&quot;busy&quot;, i);          &#125;          console.log(&quot;block task end&quot;);        &#125;);      &#125;    );  &#125;&#125;</code></pre><p>这样的话，用 <code>makeLongTask</code> 定义 <code>longTask</code> 并且运行：</p><pre><code class="js">let longTask = makeLongTask(10);spawn(longTask);spawn(shortTask);run();</code></pre><p>会看到这样的输出：</p><pre><code class="js">// ...// busy 8// busy 9// block task end// task 0/2// task 1/2// task 2/2</code></pre><p>长任务迟迟不放弃执行权，等 10 个步骤执行结束，才轮到短任务，给短任务带来了阻塞，也就是 “饿死” 其他任务的情况。这就是协作式协程的问题。</p><h3 id="抢占式协程"><a href="#抢占式协程" class="headerlink" title="抢占式协程"></a>抢占式协程</h3><p>只需要修改一下 <code>run</code> 函数的写法，就能把协程的调度方式，从协作式改为按照时间片的抢占式：</p><pre><code class="js">function run2(timeSlice) &#123;  function tick()   &#123;    const sliceStart = performance.now();    while (ready.length &gt; 0 &amp;&amp; performance.now() - sliceStart &lt; timeSlice)     &#123;      const k = ready.shift();      k();    &#125;    if (ready.length &gt; 0) setTimeout(tick, 0);  &#125;  setTimeout(tick, 0);&#125;</code></pre><p>这个函数的意思是，每执行 timeSlice 毫秒，就判断任务队列里有没有任务，如果有则切换到其他任务去执行。</p><p>相应的，我们的 <code>makeLongTask</code> 函数需要简单改下，因为 JavaScript 语言的限制，如果不做任何修改，是无法模拟时间片轮转的，所以我们把生成 <code>longTask</code> 的函数，修改为每计算 chunk 个数字就调用 <code>k1</code> 让出控制权一次：</p><pre><code class="js">function makeLongTask(n, chunk)&#123;  return function task()  &#123;    reset(      k =&gt;      &#123;        shift(          k1 =&gt;           &#123;            console.log(&quot;block task start&quot;);            let i = 0;            function chunkLoop()             &#123;              const end = Math.min(i + chunk, n);              for (; i &lt; end; i++) ;          // 纯计算              if (i &lt; n) k1(chunkLoop);       // 让出控制权              else console.log(&#39;block task end&#39;);            &#125;            chunkLoop();          &#125;        );      &#125;    );  &#125;&#125;</code></pre><p>把这几行代码放在 run 函数之前，便于后续观察任务的运行情况，尤其注意多定义了一个 setTimeout 的调用：</p><pre><code class="js">let longTask = makeLongTask(5e8, 5e7);let shortTask = makeCPSTask(2);spawn(longTask);spawn(shortTask);setTimeout(() =&gt; console.log(&#39;&gt;&gt;&gt; TIMER fired&#39;), 0);</code></pre><p>当 <code>run()</code> 函数运行，<code>run2(1)</code> 函数注释掉时，打印结果是这样：</p><pre><code class="js">run();// run2(1);// block task start// task 0/2// task 1/2// task 2/2// block task end// &gt;&gt;&gt; TIMER fired</code></pre><p>当 <code>run()</code> 函数注释掉，<code>run2(1)</code> 函数运行时，打印结果是这样：</p><pre><code class="js">// run();run2(1);// &gt;&gt;&gt; TIMER fired// block task start// task 0/2// task 1/2// task 2/2// block task end</code></pre><p>可以看到最大的差别就是 TIMER 打印的位置不同。这里存在一点投机取巧的地方，因为我们真的无法在 JavaScript 语言里打断同步执行的流程，所以在 run 函数之前加了一个 timer 来体现 run 函数的轮转。</p><p>对于 while 版本的 <code>run</code> 函数，它会在执行完全部任务队列后，才退出执行，所以 TIMER 在最后打印出来。而 <code>run2</code> 函数每 1 毫秒都在让出自己的控制权，把自己在执行的协程任务，放在了外部宏任务的执行过程中，所以 TIMER 会在一开始（或者协程的执行步骤中）打印。</p><p>为了体现 <code>run2</code> 函数让出协程的控制权，交由宏任务执行的特点，可以这样简单尝试一下，输出结果中的 TIMER 就变为了协程的执行过程中：</p><pre><code class="js">setTimeout(() =&gt; console.log(&#39;&gt;&gt;&gt; TIMER fired&#39;), 100);// run();run2(1);// block task start// task 0/2// &gt;&gt;&gt; TIMER fired// task 1/2// task 2/2// block task end</code></pre><h3 id="遗留问题"><a href="#遗留问题" class="headerlink" title="遗留问题"></a>遗留问题</h3><p>其实上面有一个不太成功的尝试，我们把生成 <code>longTask</code>（阻塞任务）的函数 <code>makeLongTask</code> 改为按照 chunk 计算并让出的模式，是为了测试，当每一个 chunk 的时间片长度远大于 <code>run2</code> 函数中的 sliceTime 时，<code>longTask</code> 的任务会被 <code>run2</code> 函数的时间片轮转切断，因此去体现出 <code>run</code> 和 <code>run2</code> 函数两种模式的不同。但实际上失败了，这是因为语言方面的限制。</p><p>不过 TIMER 的语句弥补了这个问题，TIMER 的打印位置，仍然体现出了两个 run 函数的差异，也就是协作式协程和抢占式协程的区别。并且如果 <code>makeLongTask</code> 函数没有按照 chunk 让出，TIMER 的效果也是无法体现的。</p><p>那么有没有不用 TIMER 的办法，仅仅依靠 <code>longTask</code> 的定义，就体现两个 run 函数的差异呢？我也不知道。</p>]]></content>
  </entry>
  <entry>
    <title>continuation 教程: 体验 Racket 语言</title>
    <link href="https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B5/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B5/</id>
    <published>2025-07-23T04:16:12.000Z</published>
    <updated>2026-03-31T16:07:16.231Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 continuation 系列教程：</p>
<ol>
<li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 continuation 系列教程：</p><ol><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解 CPS</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B2/">continuation 教程：用 yield 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B3/">continuation 教程：用 call&#x2F;cc 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B4/">continuation 教程：用 shift&#x2F;reset 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B5/">continuation 教程：体验 Racket 语言</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B6/">continuation 教程：实现抢占式协程调度</a></li></ol></blockquote><p>我们在之前的教程中，使用 JavaScript 语言实现了 CPS、yield、call&#x2F;cc、shift&#x2F;reset 等语义，但是由于语言的限制，实现效果比较简陋。我们接下来使用 Racket 语言，来体验一下这些关键字的能力。</p><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>访问 Racket 官方的安装包下载页面，下载安装即可：<a href="https://download.racket-lang.org/">https://download.racket-lang.org/</a></p><p>如果是 Mac 电脑，可以直接运行这个命令安装最小可运行的命令行版本：</p><pre><code class="bash">brew install racket</code></pre><p>下载安装即可，安装完成后会看到多出一个编辑器 DrRacket，这是 Racket 语言的 IDE 工具，打开使用就行。输入这两行代码，然后点击右上角的 <code>Run</code> 按钮，可以看到编辑器下方会输出 <code>1</code> 的字样，说明一切正常：</p><pre><code class="rkt">#lang racket(displayln 1)</code></pre><p>注意第一行开头的 <code>#lang racket</code> 很重要，用来标识当前代码文件的语言类型，并且会自动导入一些系统关键系，比如这里用到的 <code>displayln</code> 就来自第一行的导入语句。把鼠标光标放到 <code>displayln</code>，编辑器也会提示你这个关键字来自哪里。</p><p>下面的代码会默认省去 <code>#lang racket</code> 这一行。</p><h3 id="CPS"><a href="#CPS" class="headerlink" title="CPS"></a>CPS</h3><p>这是普通格式的 <code>add</code> 函数定义：</p><pre><code class="rkt">(define (add a b)  (+ a b))(displayln (add 1 2))</code></pre><p>这是 CPS 形式的 <code>add</code> 函数定义：</p><pre><code class="rkt">(define (add-cps a b k)  (k (+ a b)))(add-cps 1 2 (lambda (x) (displayln x)))</code></pre><h3 id="call-x2F-cc"><a href="#call-x2F-cc" class="headerlink" title="call&#x2F;cc"></a>call&#x2F;cc</h3><p>体验一下原版的 call&#x2F;cc 关键字怎么用：</p><pre><code class="rkt">(displayln (call/cc  (lambda (k)    (displayln 1)    (k 2)    (displayln 3)    ))); 1; 2</code></pre><p>这段代码会在遇到 <code>k</code> 调用的时候退出，也就只打印 1 和 2，不打印 3。</p><h3 id="shift-x2F-reset"><a href="#shift-x2F-reset" class="headerlink" title="shift&#x2F;reset"></a>shift&#x2F;reset</h3><p>体验一下 shift&#x2F;reset 关键字怎么用：</p><pre><code class="rkt">(require racket/control)(displayln (reset  (displayln 1)  (shift k         (displayln 2)         (k 3)         (displayln 4)         )  (displayln 5)  )); 1; 2; 5; 4; #&lt;void&gt;</code></pre><p><code>shift</code> 的函数体内，遇到 <code>k</code> 的调用时，会放弃当前流程的控制权，让外层的 5 先打印出来，然后再回到 <code>k</code> 的位置，继续打印后面的 4。</p><h3 id="练习"><a href="#练习" class="headerlink" title="练习"></a>练习</h3><p>如果有兴趣，可以试着用 Racket 语言，依次实现这些程序：</p><ol><li>用 CPS 风格的函数实现 yield 关键字的语义</li><li>用 yield 关键字实现两个任务交替打印</li><li>实现 call&#x2F;cc 语义，并用 call&#x2F;cc 实现两个任务交替打印</li><li>实现 shift&#x2F;reset 语义，并用 shift&#x2F;reset 实现两个任务交替打印</li></ol><p>虽然语言不同，但是由于 CPS 只依赖于函数，所以原则上切换到任何支持函数的语言，都可以实现我们之前写过的东西。实现原理，尤其是关键字的语义是相同的。用 Racket 来体验关键字的用法，也主要是为了确保语言级别的关键字，和我们自己用 JavaScript 实现的关键字，含义是一样的。</p><p>所以我们在过去几篇教程中，真正学到的并不是编程语言的写法，而是通过自己实现的方式，理解了各种 continuation 语义。</p>]]></content>
  </entry>
  <entry>
    <title>continuation 教程: 用 shift/reset 实现协程调度</title>
    <link href="https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B4/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B4/</id>
    <published>2025-07-23T04:15:12.000Z</published>
    <updated>2026-03-31T09:57:09.281Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 continuation 系列教程：</p>
<ol>
<li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 continuation 系列教程：</p><ol><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解 CPS</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B2/">continuation 教程：用 yield 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B3/">continuation 教程：用 call&#x2F;cc 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B4/">continuation 教程：用 shift&#x2F;reset 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B5/">continuation 教程：体验 Racket 语言</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B6/">continuation 教程：实现抢占式协程调度</a></li></ol></blockquote><h3 id="call-x2F-cc"><a href="#call-x2F-cc" class="headerlink" title="call&#x2F;cc"></a>call&#x2F;cc</h3><p>我们之前的 call&#x2F;cc 属于 undelimited continuation 语义，没有边界的延续，一旦 escape 则后续的步骤都被炸掉，可以再看一下这个完整的代码示例：</p><pre><code class="js">function callcc(f, k)&#123;  try  &#123;    f(v =&gt; &#123; throw v &#125;, k);  &#125;  catch (e)  &#123;    k(e);  &#125;&#125;function test1(k)&#123;  callcc(    (escapeK, nextK) =&gt;    &#123;      console.log(&quot;A&quot;);      nextK(&quot;B&quot;);      console.log(&quot;C&quot;);      escapeK(&quot;D&quot;);      console.log(&quot;E&quot;);    &#125;,     k  );&#125;test1( x =&gt; console.log(x) );// A// B// C// D</code></pre><p>程序打印到 D，无论 <code>escapeK</code> 后面有多少语句，都不会再继续执行。</p><h3 id="shift-x2F-reset"><a href="#shift-x2F-reset" class="headerlink" title="shift&#x2F;reset"></a>shift&#x2F;reset</h3><p>shift&#x2F;reset 是 delimited continuation 语义，意思是有边界的延续，下面直接给出完整的代码示例：</p><pre><code class="js">const ready = [];function run()&#123;  while (ready.length &gt; 0)  &#123;    const k = ready.shift()    k();  &#125;&#125;function reset(thunk)&#123;  try  &#123;    thunk(x =&gt; x);  &#125;  catch (f)  &#123;    f( v =&gt; ready.push(v) );  &#125;&#125;function shift(f)&#123;  throw f;&#125;reset(  k =&gt;  &#123;    console.log(&quot;A&quot;);    shift(      k1 =&gt;      &#123;        console.log(&quot;B&quot;);        k1( () =&gt; console.log(&quot;C&quot;));      &#125;    );  &#125;);console.log(&quot;D&quot;);run();// A// B// D// C</code></pre><p>这个程序的运行结果中，把 C 放到了最后面才运行，shift 就是剪切的意思，在 <code>shift</code> 函数内，如果遇到了 <code>k1</code> 调用，则立即交出控制权，去执行 <code>reset</code> 之后的步骤，外面的步骤执行结束后，再回头继续执行 <code>shift</code> 未完成的内容。因此示例代码的运行结果，C 在 D 之后打印。</p><h3 id="用-shift-x2F-reset-实现协程调度"><a href="#用-shift-x2F-reset-实现协程调度" class="headerlink" title="用 shift&#x2F;reset 实现协程调度"></a>用 shift&#x2F;reset 实现协程调度</h3><p>我们之前已经试过用 yield 和 call&#x2F;cc 分别实现了简单的协程调度，这是使用 shift&#x2F;reset 版本的完整代码：</p><pre><code class="js">let ready = [];function run()&#123;  while (ready.length &gt; 0)  &#123;    const k = ready.shift()    k();  &#125;&#125;function reset(thunk)&#123;  try  &#123;    thunk(x =&gt; x);  &#125;  catch (f)  &#123;    f( v =&gt; ready.push(v) );  &#125;&#125;function shift(f)&#123;  throw f;&#125;function spawn(thunk)&#123;  ready.push(thunk);&#125;function taskA()&#123;  reset(    k =&gt;    &#123;      shift(        k1 =&gt;        &#123;          console.log(&quot;task shift reset A0&quot;);          k1( () =&gt; console.log(&quot;task shift reset A1&quot;));        &#125;      );    &#125;  );&#125;function taskB()&#123;  reset(    k =&gt;    &#123;      shift(        k1 =&gt;        &#123;          console.log(&quot;task shift reset B0&quot;);          k1( () =&gt; console.log(&quot;task shift reset B1&quot;));        &#125;      );    &#125;  );&#125;spawn(taskA);spawn(taskB);run();// task shift reset A0// task shift reset B0// task shift reset A1// task shift reset B1</code></pre>]]></content>
  </entry>
  <entry>
    <title>continuation 教程: 用 call/cc 实现协程调度</title>
    <link href="https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B3/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B3/</id>
    <published>2025-07-23T04:14:12.000Z</published>
    <updated>2026-03-31T09:50:58.435Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 continuation 系列教程：</p>
<ol>
<li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 continuation 系列教程：</p><ol><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解 CPS</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B2/">continuation 教程：用 yield 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B3/">continuation 教程：用 call&#x2F;cc 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B4/">continuation 教程：用 shift&#x2F;reset 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B5/">continuation 教程：体验 Racket 语言</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B6/">continuation 教程：实现抢占式协程调度</a></li></ol></blockquote><p>call&#x2F;cc 的全称是 call-with-current-continuation，意思是执行对当前步骤的函数调用的时候，带着当前的执行环境（也就是 k 函数）进去。</p><h3 id="基本形式"><a href="#基本形式" class="headerlink" title="基本形式"></a>基本形式</h3><p>同样的，<code>callcc</code> 的实现仍然要使用 k 参数，并且把 k 参数放到最后一个参数的位置上。我们看一下基本的写法：</p><pre><code class="js">function callcc(f, k)&#123;  return f(k, k);&#125;</code></pre><p><code>callcc</code> 有两个参数，第一个参数一般称为 <code>escapeK</code>，也就是用于立刻退出当前执行流程的一个函数，第二个参数是 <code>nextK</code>，用于指明在执行流程没结束的情况下，下一个调用步骤是什么。<code>callcc</code> 函数像这样来调用：</p><pre><code class="js">function test1(k)&#123;  callcc(    (escapeK, nextK) =&gt;    &#123;      escapeK(42);      nextK(1);    &#125;,     k  );&#125;test1( x =&gt; console.log(&quot;test1=&quot;, x) );// test1= 42// test1= 1</code></pre><p><code>callcc</code> 函数里面的 <code>f(k, k)</code> 其实有点奇怪，可以结合这个例子 <code>test1</code> 理解下。因为 <code>test1</code> 里面的 <code>escapeK</code> 和 <code>nextK</code> 实际上都是参数 <code>k</code>，所以这里会依次打印出 <code>42</code> 和 <code>1</code>。</p><p>再来看一个例子，按照函数的语义，当发生了 <code>escapeK</code> 函数调用的时候，执行流程应该立即中断才对，像这样：</p><pre><code class="js">function test2(k)&#123;  callcc(    (escapeK, nextK) =&gt;    &#123;      let sum = 0      let arr = [1, 3, 5, 7];      for (const n of arr)      &#123;        if (n &gt; 3)        &#123;          return escapeK(sum);  // 1+3=4        &#125;        else        &#123;          sum += n;        &#125;      &#125;      return nextK(sum);       // 1+3+5+7=16    &#125;,    k  );&#125;test2( x =&gt; console.log(&quot;test2=&quot;, x) ); // 4</code></pre><p><code>test2</code> 的内部是一个循环，当遇到值大于 3 的元素，会立即中断执行，返回此前元素的总和。这个示例代码的结果为 4，是符合我们预期的，也就是一旦遇到大于 3 的元素，就停止执行。否则，假如没有停止，最终程序会返回 16 才对。</p><p>那么到这里你也许看出点问题，程序的中断执行跟 <code>escapeK</code> 有什么关系？中断执行明明是 <code>return</code> 干的。就 <code>test2</code> 这个例子，把 <code>escapeK</code> 和 <code>nextK</code> 对调位置都不会有区别，因为从一开始 <code>callcc</code> 函数的定义上，这俩函数就是一样的，都是 <code>k</code>。既然是一样的函数，又怎么能体现出 <code>escapeK</code> 能够中断程序的特点呢？</p><h3 id="中断执行"><a href="#中断执行" class="headerlink" title="中断执行"></a>中断执行</h3><p>所以我们需要另外一个进阶版的 <code>callcc</code> 函数的定义，利用 <code>throw</code>，让 <code>escapeK</code> 函数真的达到中断执行的效果：</p><pre><code class="js">function callcc(f, k)&#123;  try  &#123;    f(v =&gt; &#123; throw v &#125;, k);  &#125;  catch (e)  &#123;    k(e);  &#125;&#125;</code></pre><p>这样来使用，就能看出效果：</p><pre><code class="js">function test1(k)&#123;  callcc(    (escapeK, nextK) =&gt;    &#123;      escapeK(42);      nextK(1);    &#125;,     k  );&#125;test1( x =&gt; console.log(&quot;test1=&quot;, x) );// test1= 42</code></pre><p><code>callcc</code> 的函数体内，因为调用了 <code>escapeK</code>，所以不会再继续打印出后面的 1。<code>callcc</code> 里用了 <code>throw</code> 而不是 <code>return</code> 的原因在于，<code>throw</code> 可以再任意程序深度上，中断程序的执行。</p><p>再看一下 <code>test2</code> 函数的例子，也是同样的道理：</p><pre><code class="js">function test2(k)&#123;  callcc(    (escapeK, nextK) =&gt;    &#123;      let sum = 0      let arr = [1, 3, 5, 7];      for (const n of arr)      &#123;        if (n &gt; 3)        &#123;          escapeK(sum); // 1+3=4        &#125;        else        &#123;          sum += n;        &#125;      &#125;      nextK(sum); // 1+3+5+7=16    &#125;,    k  );&#125;test2( x =&gt; console.log(&quot;test2=&quot;, x) ); // 4</code></pre><p>因为 <code>escapeK</code> 的存在，程序会中断执行，这一次，如果把 <code>escapeK</code> 和 <code>nextK</code> 函数对调位置，就能看出明显差异了。</p><h3 id="可重入"><a href="#可重入" class="headerlink" title="可重入"></a>可重入</h3><p><code>callcc</code> 还有一个重要的特性是可重入，来逐步体验一下可重入是什么意思。定义一个 <code>entry</code> 函数：</p><pre><code class="js">let savedK = null;function entry(k)&#123;  callcc(    (escapeK, nextK) =&gt;    &#123;      savedK = escapeK;      nextK(0);    &#125;,    k  );&#125;entry( x =&gt; console.log(&quot;entry=&quot;, x) ); // entry= 0</code></pre><p>这里的重点在于，在函数外部，用了一个变量 <code>savedK</code> 来保存 <code>escapeK</code> 的值，在函数运行过程中，<code>escapeK</code> 的值实际上是在 <code>callcc</code> 函数里定义的，可以打印看一下：</p><pre><code class="js">console.log(savedK.toString());// v =&gt; v =&gt; &#123; throw v &#125;</code></pre><p>来看这样一个例子，如何使用保存下来的 <code>savedK</code>：</p><pre><code class="js">function runSavedK(f, k)&#123;  try  &#123;    f();  &#125;  catch (e)  &#123;    console.log(e);  &#125;&#125;runSavedK( () =&gt; savedK(&quot;1&quot;) );  // 1runSavedK( () =&gt; savedK(&quot;2&quot;) );  // 2</code></pre><p>这里为什么要用 try…catch 捕获呢，因为 <code>savedK</code> 本身一定会发生 <code>throw</code>，所以要调用 <code>f</code>，就得捕获一下异常才能看到正常的返回值。</p><p>那么到这里，看到 <code>runSavedK</code> 函数的例子，其实也很奇怪，你会发现，不就是给 <code>savedK</code> 赋了个值，赋值的内容是一个函数吗，完全可以像下面这样写，还要 <code>callcc</code> 那么费劲干什么？</p><pre><code class="js">let savedK_test = v =&gt; &#123; throw v &#125;;runSavedK( () =&gt; savedK_test(&quot;1&quot;) );  // 1runSavedK( () =&gt; savedK_test(&quot;2&quot;) );  // 2</code></pre><p><code>callcc</code> 的含义是用闭包来保留执行现场，可以后续再对闭包进行调用，它其实就是个闭包。所以如果直接赋值为函数，就丢失了闭包的现场。我们上面的例子是把 <code>escapeK</code> 赋值给了外部的变量，所以不太容易看清楚效果。再看这个例子，可以体现出 <code>callcc</code> 可重入的特点：</p><pre><code class="js">let savedK_foo = null;function foo()&#123;  let counter = 0;  callcc(    (e, k) =&gt;    &#123;      savedK_foo = k;      return k();    &#125;,    () =&gt;    &#123;      counter++;      console.log(&quot;counter=&quot;, counter);    &#125;  )&#125;foo();         // counter= 1savedK_foo();  // counter= 2savedK_foo();  // counter= 3</code></pre><p><code>savedK_foo</code> 是一个定义在 <code>foo</code> 函数外部的变量，当对 <code>foo()</code> 的调用结束，你会发现不但 <code>savedK_foo</code> 变量是有值的，而且每次这样 <code>savedK_foo()</code> 进行函数调用 ，<code>counter</code> 的值都会累加，<code>counter</code> 的值似乎不是临时的，从未丢失。这就是 <code>callcc</code> 可重入的含义，程序执行过程中的现场，是可以保留下来供下次使用的。</p><p>什么场景下会需要这种特性呢，比如协程调度的过程中，调度器得频繁切换要执行的任务，那么悬挂起来的任务，就非常需要保留执行现场，下次任务切换回来之后，接着上次的步骤运行。<code>callcc</code> 的中断和可重入这两个特性，就适合用来满足协程调度的场景。</p><h3 id="用-callcc-实现协程调度"><a href="#用-callcc-实现协程调度" class="headerlink" title="用 callcc 实现协程调度"></a>用 callcc 实现协程调度</h3><p>我们之前用 <code>yield</code> 实现协程调度的时候，需要显式地把 <code>yieldCPS</code> 这个函数作为参数，从 <code>spawn</code> 开始一路传递下去，也就是 <code>task</code> 函数必需接收 CPS 函数。有了 <code>callcc</code> 之后，可以省去对于 <code>task</code> 函数的参数。这是完整代码：</p><pre><code class="js">let ready = [];function run()&#123;  while (ready.length &gt; 0)  &#123;    const k = ready.shift()    k();  &#125;&#125;function callcc(f, k)&#123;  try  &#123;    return f(v =&gt; &#123; throw v &#125;, k);  &#125;  catch (e)  &#123;    return k(e);  &#125;&#125;function yieldCC(k)&#123;  callcc(    (escapeK, nextK) =&gt;     &#123;      ready.push(nextK);      let next = ready.shift();      next();    &#125;,    k  );&#125;function spawn(thunk)&#123;  ready.push(thunk);&#125;function taskA()&#123;  console.log(&quot;task call cc A0&quot;);  yieldCC(() =&gt; console.log(&quot;task call cc A1&quot;) );&#125;function taskB()&#123;  console.log(&quot;task call cc B0&quot;);  yieldCC(() =&gt; console.log(&quot;task call cc B1&quot;));&#125;spawn(taskA);spawn(taskB);run();// task call cc A0// task call cc B0// task call cc A1// task call cc B1</code></pre><h3 id="思考题"><a href="#思考题" class="headerlink" title="思考题"></a>思考题</h3><p>假如是这样的两个任务，还能按照预期的交替执行的顺序打印出 <code>A0 -&gt; B0 -&gt; A1 -&gt; B1 -&gt; A2 -&gt; B2</code> 吗？应该如何实现？</p><pre><code class="js">function taskA()&#123;  console.log(&quot;task yield cc A0&quot;);  yieldCC(() =&gt; console.log(&quot;task yield cc A1&quot;) );  console.log(&quot;task yield cc A2&quot;);&#125;function taskB()&#123;  console.log(&quot;task yield cc B0&quot;);  yieldCC(() =&gt; console.log(&quot;task yield cc B1&quot;));  console.log(&quot;task yield cc B2&quot;);&#125;</code></pre>]]></content>
  </entry>
  <entry>
    <title>continuation 教程: 用 yield 实现协程调度</title>
    <link href="https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B2/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B2/</id>
    <published>2025-07-23T04:13:12.000Z</published>
    <updated>2025-12-03T09:25:54.168Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 continuation 系列教程：</p>
<ol>
<li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 continuation 系列教程：</p><ol><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解 CPS</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B2/">continuation 教程：用 yield 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B3/">continuation 教程：用 call&#x2F;cc 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B4/">continuation 教程：用 shift&#x2F;reset 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B5/">continuation 教程：体验 Racket 语言</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B6/">continuation 教程：实现抢占式协程调度</a></li></ol></blockquote><h3 id="任务队列"><a href="#任务队列" class="headerlink" title="任务队列"></a>任务队列</h3><p>先来定义一个任务队列：</p><pre><code class="js">let ready = [];</code></pre><p>然后定义一个执行函数：</p><pre><code class="js">function run()&#123;  while (ready.length &gt; 0)  &#123;    const k = ready.shift()    k();  &#125;&#125;</code></pre><p>从定义可以看出，任务队列中的元素都是函数，然后在运行函数 <code>run</code> 中，会依次执行队列中的函数。可以这样来使用我们的任务队列：</p><pre><code class="js">ready.push( () =&gt; console.log(1) );ready.push( () =&gt; console.log(2) );ready.push( () =&gt; console.log(3) );run();// 1// 2// 3</code></pre><h3 id="顺序执行"><a href="#顺序执行" class="headerlink" title="顺序执行"></a>顺序执行</h3><p>现在我们有这样两个 <code>task</code> 函数，把他们添加到任务队列后，会按照顺序执行并打印出结果，这很好理解，符合我们的直觉：</p><pre><code class="js">function taskA()&#123;  console.log(&quot;task A0&quot;);  console.log(&quot;task A1&quot;);&#125;function taskB()&#123;  console.log(&quot;task B0&quot;);  console.log(&quot;task B1&quot;);&#125;ready.push(taskA);ready.push(taskB);run();// task A0// task A1// task B0// task B1</code></pre><p>现在的打印顺序是 <code>A0 -&gt; A1 -&gt; B0 -&gt; B1</code>，有没有什么办法，可以改变打印顺序，变为 <code>A0 -&gt; B0 -&gt; A1 -&gt; B1</code> 呢？这里的每一个打印语句都是一个 task，而我们关心的是 task 的执行顺序。</p><h3 id="yield"><a href="#yield" class="headerlink" title="yield"></a>yield</h3><p><code>yield</code> 关键字的含义是，保存当前的执行环境，把当前任务放到队列最后面，然后去运行其他的任务。就像是在排队，yield 是一个非常讲礼貌的人，当轮到自己的时候，会自己跑去队伍最后面，继续排队。</p><p>很多语言都提供了 <code>yield</code> 关键字，我们现在要做的，是在不使用 <code>yield</code> 关键字的情况下，实现 <code>yield</code> 的语义。可以这样定义 <code>yieldCPS</code> 函数，这个函数干的事情，就相当于 <code>yield</code> 关键字：</p><pre><code class="js">function yieldCPS(k)&#123;  ready.push(k);              // 把当前步骤的执行环境存起来  const next = ready.shift(); // 去执行队列头部的其他任务  next();&#125;yieldCPS( () =&gt; console.log(&quot;yield cps&quot;) );run();  // yield cps</code></pre><p><code>yieldCPS</code> 接受一个函数作为参数，如果我们想在 <code>taskA</code> 里使用 <code>yield</code> 语义来影响 <code>A0</code> 和 <code>A1</code> 的执行顺序，可以这样写：</p><pre><code class="js">function taskAYield(yieldFn)&#123;  console.log(&quot;task yield A0&quot;);  yieldFn( () =&gt; console.log(&quot;task yield A1&quot;) );&#125;ready.push( () =&gt; taskAYield(yieldCPS) );run();// task yield A0// task yield A1</code></pre><p>但是你发现了，打印出来的顺序没有变，因为确实不应该变，<code>A1</code> 之后没有其他任务了，排队的时候，<code>yield</code> 定义的任务已经没有谦让的余地。</p><p>在 <code>taskB</code> 里也用上 <code>yield</code> 试试：</p><pre><code class="js">function taskBYield(yieldFn)&#123;  console.log(&quot;task yield B0&quot;);  yieldFn( () =&gt; console.log(&quot;task yield B1&quot;) );&#125;</code></pre><p>这个时候再把 <code>taskA</code> 和 <code>taskB</code> 放进任务队列，打印结果的顺序就有变化了：</p><pre><code class="js">ready.push( () =&gt; taskAYield(yieldCPS) );ready.push( () =&gt; taskBYield(yieldCPS) );run();// task yield A0// task yield B0// task yield A1// task yield B1</code></pre><p>可以看到 <code>yield</code> 关键字指定的任务，都跑到了任务队列后面才依次执行。也就是说，<code>yield</code> 关键字中断了 <code>taskA</code> 的执行过程，<code>taskA</code> 执行到一半的时候打印出了 <code>A0</code>，然后 <code>A1</code> 的任务被保存起来、放到队列最后面了。</p><p>但是这样的解释似乎不够，为什么下面的代码，<code>yield</code> 关键字指定了 <code>C1</code>，<code>C1</code> 的打印顺序缺没有被放到最后呢？</p><pre><code class="js">function taskCYield(yieldFn)&#123;  console.log(&quot;task yield C0&quot;);  yieldFn( () =&gt; console.log(&quot;task yield C1&quot;) );  console.log(&quot;task yield C2&quot;);&#125;ready.push( () =&gt; taskCYield(yieldCPS) );run(); // task yield C0// task yield C1// task yield C2</code></pre><p>因为更具体来说，<code>yield</code> 的含义是，当一个协程运行的时候，立刻交出控制权，让调度器来决定下一个要执行的任务，可能是自己，也可能是别人，关键在于，“交出控制权”。我们定义的两个任务 <code>taskA</code> 和 <code>taskB</code>，就相当于两个协程，<code>run</code> 函数就是任务的调度器。</p><h3 id="spawn"><a href="#spawn" class="headerlink" title="spawn"></a>spawn</h3><p><code>spawn</code> 关键字的含义，是把 <code>yieldCPS</code> 函数也就是 <code>yield</code> 关键字的等价实现，作为参数，传递给一个函数，并且把这个函数添加到任务队列。实际上 <code>spawn</code> 就是一个简单的函数封装，一看就明白了：</p><pre><code class="js">function spawn(thunk)&#123;  ready.push( () =&gt; thunk(yieldCPS) );&#125;</code></pre><p>这个函数这样来调用：</p><pre><code class="js">spawn(taskAYield);spawn(taskBYield);run();// task yield A0// task yield B0// task yield A1// task yield B1</code></pre><h3 id="sleep"><a href="#sleep" class="headerlink" title="sleep"></a>sleep</h3><p><code>sleep</code> 关键字的含义是，在协程执行的过程中，等待几秒钟，然后继续执行后续的任务。可以这样实现：</p><pre><code class="js">function sleep(ms, yieldFn, k)&#123;  setTimeout(    () =&gt;       &#123;        ready.push(k);        run();      &#125;,     ms);  return yieldFn(() =&gt; &#123;&#125;);&#125;function taskDYield(yieldFn)&#123;  console.log(&quot;task yield D0&quot;);  return sleep(5000, yieldFn, () =&gt; console.log(&quot;task yield D1&quot;) );&#125;spawn(taskDYield);run();// task yield D0// task yield D1</code></pre><p><code>spawn</code> 关键字让协程进场，<code>yield</code> 关键字允许协程主动让出，<code>sleep</code> 关键字允许协程挂起一段时间后继续。有了这 3 关键字，协作式调度的骨架就已经搭起来了。</p><h3 id="CPS"><a href="#CPS" class="headerlink" title="CPS"></a>CPS</h3><p>你有没有疑问，这里的 <code>yieldCPS</code> 名字中有 CPS，但是跟 CPS 有什么关系？<code>yieldCPS</code> 这个函数只不过是做了一些对数组的操作。我以为 CPS 是得用在递归里面，还得用上 <code>r =&gt; k(r)</code> 之类的写法，才算 CPS。</p><p>事实上 CPS 只是一种风格，关键在于用参数 <code>k</code> 来表示函数执行之后的下一步操作，这个 <code>k</code> 必然是一个函数。只要是这种把函数作为参数传递，而且执行动作中只使用对 <code>k</code> 的调用，就是 CPS。比如这是一个最简的 CPS 的示例：</p><pre><code class="js">function add(a, b, k)&#123;  k(a+b);&#125;add(1, 2, x =&gt; console.log(x) )// 3</code></pre><p>这个叫局部 CPS，全局 CPS 则是需要全部函数调用的参数都用 <code>k</code> 来传递像这样：</p><pre><code class="js">function add(a, b, k)&#123;  k(a+b);&#125;function main(k)&#123;  add(1, 2, k);&#125;main(x =&gt; console.log(x) )// 3</code></pre><p>体验过 <code>yieldCPS</code> 等关键字后，对 CPS 的理解会更进一步。</p><h3 id="用-yield-实现协程调度"><a href="#用-yield-实现协程调度" class="headerlink" title="用 yield 实现协程调度"></a>用 yield 实现协程调度</h3><p>这是用 <code>yield</code> 关键字实现协程调度的完整代码：</p><pre><code class="js">let ready = [];function run()&#123;  while (ready.length &gt; 0)  &#123;    const k = ready.shift()    k();  &#125;&#125;function yieldCPS(k)&#123;  ready.push(k);  const next = ready.shift();  next();&#125;function taskA(yieldFn)&#123;  console.log(&quot;task yield A0&quot;);  yieldFn( () =&gt; console.log(&quot;task yield A1&quot;) );&#125;function taskB(yieldFn)&#123;  console.log(&quot;task yield B0&quot;);  yieldFn( () =&gt; console.log(&quot;task yield B1&quot;) );&#125;function spawn(thunk)&#123;  ready.push( () =&gt; thunk(yieldCPS) );&#125;spawn(taskA);spawn(taskB);run();// task yield A0// task yield B0// task yield A1// task yield B1</code></pre>]]></content>
  </entry>
  <entry>
    <title>continuation 教程: 理解 CPS</title>
    <link href="https://smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B1/"/>
    <id>blog:https://smallyu.net/2025/07/23/continuation%E6%95%99%E7%A8%8B1/</id>
    <published>2025-07-23T04:12:12.000Z</published>
    <updated>2026-05-27T07:28:42.310Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个 continuation 系列教程：</p>
<ol>
<li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个 continuation 系列教程：</p><ol><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B1/">continuation 教程：理解 CPS</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B2/">continuation 教程：用 yield 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B3/">continuation 教程：用 call&#x2F;cc 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B4/">continuation 教程：用 shift&#x2F;reset 实现协程调度</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B5/">continuation 教程：体验 Racket 语言</a></li><li><a href="/2025/07/23/continuation%E6%95%99%E7%A8%8B6/">continuation 教程：实现抢占式协程调度</a></li></ol></blockquote><p>我们来由浅入深地系统学习下 continuation 的原理以及应用场景。这个系列教程的内容和王垠的 continuation 专项班无关，是我自己学习和研究的成果，所以不会有版权问题。不过当然正是因为我学习了基础班，打下了坚实的基础，才知道该如何去自学和理解 continuation 这个概念。这篇文章会少量透露出基础班学到的技能，毕竟 continuation 属于基础班的进阶内容，无法跳过基础技能去理解。</p><h3 id="递归"><a href="#递归" class="headerlink" title="递归"></a>递归</h3><p>首先用递归的形式写一个阶乘函数 <code>fact</code>，我们已经很熟悉它的写法，不需要过多解释：</p><pre><code class="js">function fact(n)&#123;  if (n === 0)   &#123;    return 1;  &#125;  else  &#123;    return n * fact(n - 1);  &#125;&#125;console.log(&quot;fact1=&quot;, fact(1)); // 1console.log(&quot;fact3=&quot;, fact(3)); // 6console.log(&quot;fact5=&quot;, fact(5)); // 120</code></pre><h3 id="尾递归"><a href="#尾递归" class="headerlink" title="尾递归"></a>尾递归</h3><p>接着把 <code>fact</code> 函数改为尾递归的形式。尾递归会比递归多一个参数，新参数用来保存每个调用计算后的值：</p><pre><code class="js">function factTail(n, prod)&#123;  if (n == 0)  &#123;    return prod;  &#125;  else  &#123;    return factTail(n-1, prod*n);  &#125;&#125;console.log(&quot;factTail1=&quot;, factTail(1, 1)); // 1console.log(&quot;factTail3=&quot;, factTail(3, 1)); // 6console.log(&quot;factTail5=&quot;, factTail(5, 1)); // 120</code></pre><h3 id="CPS-形式"><a href="#CPS-形式" class="headerlink" title="CPS 形式"></a>CPS 形式</h3><p>我们基于 <code>fact</code> 函数的尾递归形式，再新增一个参数 <code>k</code>，这个 <code>k</code> 是一个函数，<code>fact</code> 不直接返回计算后的值，而是结果值对 <code>k</code> 函数的调用，像这样：</p><pre><code class="js">function factTailCPS(n, prod, k)&#123;  if (n == 0)  &#123;    return k(prod);  &#125;  else  &#123;    return factTailCPS(n-1, prod*n, k);  &#125;&#125;factTailCPS( 1, 1, x =&gt; console.log(&quot;factTailCPS1=&quot;, x) ); // 1factTailCPS( 3, 1, x =&gt; console.log(&quot;factTailCPS3=&quot;, x) ); // 6factTailCPS( 5, 1, x =&gt; console.log(&quot;factTailCPS5=&quot;, x) ); // 120</code></pre><p>这个 k 就是 continuation，意味着告诉 <code>fact</code> 函数，你执行完了计算出结果之后，应该如何进行下一步延续。不用怀疑，这个函数完全符合 CPS（Continuation-Passing-Style）的形式。</p><h3 id="典型-CPS"><a href="#典型-CPS" class="headerlink" title="典型 CPS"></a>典型 CPS</h3><p>但是用尾递归结合 continuation 参数的形式，显然不够简洁，并不算典型的 CPS 形式。典型的 CPS 形式比较难理解，所以不需要自己思考出来，直接看这个现成的例子，我们对递归形式的 <code>fact</code> 函数改进一下：</p><pre><code class="js">function factCPS(n, k)&#123;  if (n == 0)  &#123;    return k(1);  &#125;  else  &#123;    return factCPS(n-1, r =&gt; k(n * r));  &#125;&#125;</code></pre><p>可能看着有点懵，不要慌，我们拆解一下其中的内容。首先 <code>k</code> 仍然代表 continuation，并且 <code>k</code> 是一个函数。然后我们这样来调用：</p><pre><code class="js">let factCPS1 = factCPS(0, x =&gt; x);console.log(&quot;factCPS1=&quot;, factCPS1); // 1let factCPS3 = factCPS(3, x =&gt; x);console.log(&quot;factCPS3=&quot;, factCPS3); // 6let factCPS5 = factCPS(5, x =&gt; x);console.log(&quot;factCPS5=&quot;, factCPS5); // 120</code></pre><p>关键在于调用的时候，传入函数的第二个参数是 <code>x =&gt; x</code>，如果结合函数内部的 <code>r =&gt; k(n * r)</code>，也许一下子就糊涂了。</p><p>这确实是最难理解的部分。我们以计算 2 的阶乘为例，写一个拆解 <code>factCPS</code> 函数调用步骤的过程。这里用到的技巧是在基础班第一课就学过的 <code>单步替换</code>，对于理解递归非常有帮助。如果在基础班经过训练并且打好基础，确实会有助于理解更复杂的东西，比如这里的 CPS 调用：</p><pre><code class="js">let factCPS2 = factCPS(2, x =&gt; x);console.log(&quot;factCPS2=&quot;, factCPS2); // 2// n=2, k=x=&gt;x, return factCPS(1, r =&gt; k(2 * r));  // n=1, k=r=&gt;(x=&gt;x)(2*r), return factCPS(0, r =&gt; k(1 * r));    // n=0, k=r=&gt;(r=&gt;(x=&gt;x)(2*r)(1*r)), return k(1);      // k(1) = r=&gt;(x=&gt;x)(2*r)(1*1)      //      = (x=&gt;x)(2)      //      = 2</code></pre><p>虽然我已经按照正确的思路拆解出了正确的步骤，但是从阅读者的角度，这仍然会非常难理解，可以自己拆解一下试试，逐步理解典型 CPS 的调用过程。理解这些步骤也许需要几个小时的时间，这是正常的。</p><p>总结来说，CPS 的每一次调用，都是在用闭包来储存当前步骤计算的值。尾递归是直接用参数传递值，而 CPS 是在用闭包传递给下个步骤值，就是这样的关系。当然理解这一点的前提是，知道闭包是什么，这个也是基础班学习的重点内容，尤其是会在实现解释器环节，自己实现闭包的语句，对于闭包的理解会很透彻。</p><h3 id="fib-函数的-CPS"><a href="#fib-函数的-CPS" class="headerlink" title="fib 函数的 CPS"></a>fib 函数的 CPS</h3><p>计算阶乘的函数 <code>fact</code> 特点是只在函数体内进行一次递归调用，我们再来看计算斐波那契数列的 <code>fib</code> 函数，它会在函数体内进行两次递归调用，CPS 该怎么处理这个情况。</p><p><code>fib</code> 函数的递归形式的定义是这样：</p><pre><code class="js">function fib(n)&#123;  if (n == 0)  &#123;    return 0;  &#125;  else if (n == 1)  &#123;    return 1;  &#125;  else   &#123;    return fib(n-1) + fib(n-2);  &#125;&#125;console.log(&quot;fib(2)=&quot;, fib(2)); // 1console.log(&quot;fib(5)=&quot;, fib(5)); // 5</code></pre><p>这里直接给出 <code>fib</code> 函数的 CPS，然后理解一下 <code>fib</code> 函数的运作过程：</p><pre><code class="js">function fibCPS(n, k)&#123;  if (n == 0)  &#123;    return k(0);  &#125;  else if (n == 1)  &#123;    return k(1);  &#125;  else  &#123;    return fibCPS(n-1, r1 =&gt; fibCPS(n-2, r2=&gt;k(r1+r2)) );  &#125;&#125;</code></pre><p>可以看到，对于需要两次递归调用的情况，CPS 是把另一次递归调用，写在了原本的 <code>r =&gt; k(r)</code> 函数里，让第二次内部调用成为了递归调用 <code>fib</code> 时候的子调用。这句话有点绕，可以结合代码理解一下。</p><p>CPS 形式的 <code>fib</code> 函数这样来调用：</p><pre><code class="js">let fibCPS1 = fibCPS(1, x=&gt;x);console.log(&quot;fibCPS1=&quot;, fibCPS1); // 1let fibCPS2 = fibCPS(2, x=&gt;x);console.log(&quot;fibCPS2=&quot;, fibCPS2); // 1let fibCPS4 = fibCPS(4, x=&gt;x);console.log(&quot;fibCPS4=&quot;, fibCPS4); // 3let fibCPS5 = fibCPS(5, x=&gt;x);console.log(&quot;fibCPS5=&quot;, fibCPS5); // 5</code></pre><p>我们以计算 3 的斐波那契数为例，拆解一下具体的执行步骤。要注意的是，这个过程非常复杂，比 <code>fact</code> 函数还要复杂很多，只有自己亲自写一下才能搞清楚：</p><pre><code class="js">let fibCPS3 = fibCPS(3, x=&gt;x);console.log(&quot;fibCPS3=&quot;, fibCPS3); // 1+1=2// n=3, k=x=&gt;x,        // return fibCPS(2, r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)) );// n=2, k= r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)),        // return fibCPS(1, r1 =&gt; fibCPS(0, r2 =&gt; ( r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)) )(r1+r2)) );// n=1, k= r1 =&gt; fibCPS(0, r2 =&gt; ( r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)) )(r1+r2)),        // return k(1)       // return ( r1 =&gt; fibCPS(0, r2 =&gt; ( r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)) )(r1+r2)) )(1)       // return fibCPS(0, r2 =&gt; ( r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)) )(1+r2))          // n=0, k= r2 =&gt; ( r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)) )(1+r2)              // return k(0)              // return ( r2 =&gt; ( r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)) )(1+r2) )(0)              // return ( r1 =&gt; fibCPS(1, r2=&gt;(x=&gt;x)(r1+r2)) ) (1+0)              // return fibCPS(1, r2=&gt;(x=&gt;x)(1+r2))                  // n=1, k = r2=&gt;(x=&gt;x)(1+r2)                  // return k(1)                  // return (x=&gt;x)(1+1)                  // return 2</code></pre><p>那么经过了 <code>fact</code> 和 <code>fib</code> 函数的训练，我们就已经知道 CPS 的形式是什么，以及具体的执行步骤是怎样了。理解 CPS 只是开始，接下来还会利用 continuation 实现更多有趣的程序。</p><h3 id="练习题"><a href="#练习题" class="headerlink" title="练习题"></a>练习题</h3><p>已知一个递归形式的 <code>sumFrom</code> 函数，接收两个参数 <code>a</code> 和 <code>b</code>，函数的功能是计算 <code>a+(a+1)+...+(b-1)+b</code> 的值，例如参数是 <code>1</code> 和 <code>4</code>，则计算 <code>1+2+3+4</code> 的结果：</p><pre><code class="js">function sumFrom(a, b)&#123;  if (a == b)   &#123;    return a;  &#125;  else  &#123;    return b + sumFrom(a, b-1);  &#125;&#125;console.log(sumFrom(1, 3));   // 6console.log(sumFrom(2, 5));   // 14</code></pre><p>练习的内容是，将 <code>sumFrom</code> 函数修改为 CPS 形式，补充 <code>sumFromCPS</code> 函数空白处的代码，让程序可以满足测试用例中的输出结果：</p><pre><code class="js">function sumFromCPS(a, b, k)&#123;  // ____&#125;sumFromCPS(1, 3, x =&gt; console.log(&quot;sumFromCPS(1, 3)=&quot;, x));   // 6sumFromCPS(2, 5, x =&gt; console.log(&quot;sumFromCPS(2, 5)=&quot;, x));   // 14</code></pre><h3 id="延伸阅读"><a href="#延伸阅读" class="headerlink" title="延伸阅读"></a>延伸阅读</h3><p>我们已经体验了手动将递归程序转变为 CPS 形式的过程，实际上存在能将代码自动转变为 CPS 形式的方法，也就是传说中 “王垠 40 行代码” 在干的事情。可以参考这两个链接查看更多内容：</p><ul><li><a href="https://www.zhihu.com/question/20822815">王垠的「40 行代码」真如他说的那么厉害吗？</a></li><li><a href="https://www.yinwang.org/blog-cn/2012/07/04/dan-friedman">GTF - Great Teacher Friedman</a></li></ul><p>因为 “自动 CPS 变换” 的难度比较大，我自己并不打算深入学习和实现。</p>]]></content>
  </entry>
  <entry>
    <title>web2 开发如何转型 web3 开发</title>
    <link href="https://b.smallyu.net/2025/07/22/web2%E5%BC%80%E5%8F%91%E5%A6%82%E4%BD%95%E8%BD%AC%E5%9E%8Bweb3%E5%BC%80%E5%8F%91/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/22/web2%E5%BC%80%E5%8F%91%E5%A6%82%E4%BD%95%E8%BD%AC%E5%9E%8Bweb3%E5%BC%80%E5%8F%91/</id>
    <published>2025-07-22T07:27:55.000Z</published>
    <updated>2026-07-25T13:01:52.116Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>前几天参加了 The Web3 社区的一个线下活动，去了才知道，原来 The Web3 社区是开培训班挣钱的，针对的就是 web2 想转 web3 的群体。</p>
<p>据我所知，登链社区也是开培训班的，最近 TinTin Land 社区似乎也在筹备给 web3]]></summary>
    <content type="html"><![CDATA[<p>前几天参加了 The Web3 社区的一个线下活动，去了才知道，原来 The Web3 社区是开培训班挣钱的，针对的就是 web2 想转 web3 的群体。</p><p>据我所知，登链社区也是开培训班的，最近 TinTin Land 社区似乎也在筹备给 web3 新人的课，有开培训班的趋势。稍微有点感慨，培训班这个行当，还真是什么时候都有，无处不在。</p><p>培训班是有意义的，对于决心进入新的职业方向，但又不知道怎么启程的人来说，花点钱寻求指导没什么不对。</p><p>不过 The Web3 社区我还是有点讨厌的，因为他们用了虚高的薪资信息诱惑学生，会议中满口都是财富自由、月薪 3 万 U 之类的话，拿一些 Bybit、Eigen Layer 员工的个例来讲。从招生的角度能理解，这属于广告宣传，但是从我每天盯着招聘职位投简历的角度，我很厌恶这种骗人的虚假宣传。</p><p>虽然我完全可以列出在技术角度，从 web2 转向 web3 需要哪些技能。但是那些东西没意思。</p><p>我的建议始终只有一个：学炒币。</p><p>我不想分析这个行为背后的风险。在我看来，这是从 web2 进入 web3 的唯一方式，也是最直接、最快的方式。</p><p>不信你去看吧，那些没有过币种交易的人，根本不懂 web3，即使他们已经在交易所或者 web3 公司工作，用的也都是 web2 的思维，只是种种原因恰好在公司工作而已。又或者某些满口区块链技术但是根本没碰过币的人，往往有着盲目的技术自信但又做不了什么切实的事情。</p><p>虽然我也可以条理清晰的写出我的建议背后的理性逻辑，但是也不太想写。</p><p>做区块链开发的有两种人，一种知道区块链是什么、在干什么，并且为此而努力。另一种不管你是什么，反正是 Go 语言（或者其他语言）开发的，那么就可以从编程语言的角度，去进行软件层面、代码层面的优化。这两种人都是区块链生态中不可或缺的力量，但是他们的动机和目的完全不一样。</p><p>我讨厌第二种人。</p>]]></content>
  </entry>
  <entry>
    <title>Web3 技术人的职业生涯注定不稳定</title>
    <link href="https://b.smallyu.net/2025/07/21/Web3%E6%8A%80%E6%9C%AF%E4%BA%BA%E7%9A%84%E8%81%8C%E4%B8%9A%E7%94%9F%E6%B6%AF%E6%B3%A8%E5%AE%9A%E4%B8%8D%E7%A8%B3%E5%AE%9A/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/21/Web3%E6%8A%80%E6%9C%AF%E4%BA%BA%E7%9A%84%E8%81%8C%E4%B8%9A%E7%94%9F%E6%B6%AF%E6%B3%A8%E5%AE%9A%E4%B8%8D%E7%A8%B3%E5%AE%9A/</id>
    <published>2025-07-21T12:20:20.000Z</published>
    <updated>2025-12-03T09:25:54.155Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>去年的 7]]></summary>
    <content type="html"><![CDATA[<p>去年的 7 月份左右，大概也就是现在这个时候，我第一次做出了对职业路径的主动选择：裸辞。为什么选择裸辞的方式呢，因为我一点都没想占公司便宜，我觉得在工作时间去找工作和面试是不负责的，我不知道该怎么一边工作，一边用一两个小时的时间去面试。所以只能裸辞。</p><p>我最近在想，假如当初我没有辞职，我的职业生涯会不会更好？</p><p>嗯……会，哈哈。如果没有主动辞职，应该还是能再工作个半年一年的，项目不至于马上垮台，我也不至于马上被裁掉。那样的话，我的简历会更好看，不存在跳槽太频繁的问题，而我也能得到一整年稳定的工资收入，生活会更有保障。</p><p>现在一年过去了，我当时的主动辞职，换来了什么呢？</p><p>我实际参与了一个 Cosmos 项目的开发，算是摸了一下 Cosmos 生态。真实理解了 Restaking 的业务流程。然后去 Tantin Chain 做钱包后端开发，不但知道了钱包后端是干什么的，还经历了 Taintin Chain 的裁员。你也许听说过 Bitget 的暴力裁员，但是你能想到 Tantin Chain 的裁员是怎么回事吗？如果不是亲身经历，我是无法想象竟然会有这样的事情，不亲自体验一下，Web3 行业的那些裁员新闻就只是故事，亲自经历过后，就会有不一样的感受了。Web3 公司的魔幻程度超出想象。</p><p>再然后失业在家，认真学习了计算机课程，自学了一些区块链生态的技术，最近几天在研究用 continuation 实现协程调度一类的东西。</p><p>这些事情有意思吗，也有点意思，如果不是当时的主动辞职，也许永远不会去碰 Cosmos 生态；如果不是亲身工作，也许没耐心搞明白 Restaking 是在干什么；如果不是去做钱包后端开发，也许不会技术迷茫，就没兴趣去学计算机课程；如果不是失业，也许不会有大量时间认真学习各种各样的东西。</p><p>我现在这样的年纪，假如在一家公司安逸地工作五六年，几乎没有技术能力上的提升，然后五六年之后公司裁员（不可能一直安逸），正是经历中年危机的时候，那时就是真正的中年危机了。</p><p>现在不稳定的工作和生活，让我身处于动荡的职业变化中，这样锻炼出来的技术能力，才是真正经历过市场磨练后，真正抗打的。如果动荡时期都能扛过去，还需要担心什么中年危机吗？被裁员？找不到工作？工作本来就不稳定，还担心什么裁员？本来就处于不断找工作的状态，还需要担心自己搞不清楚行业状况、技能跟不上行业变化吗？我能对行业有某些观察，一定程度上也是因为找工作不得不频繁面试。</p><p>那么我说出曾经裸辞，会不会导致有些招聘方看到后，担心我工作不稳定呢？</p><p>假如公司好、团队好、工作好、前景好、工资好……员工脑子有坑才会主动辞职。如果招聘方因为这方面的原因担心候选人不稳定，说明潜意识里已经知道在招聘的岗位存在某些方面的问题了，错过了就错过吧。</p><h3 id="更新（2025-07-28）"><a href="#更新（2025-07-28）" class="headerlink" title="更新（2025.07.28）"></a>更新（2025.07.28）</h3><p>昨天晚上发生了一件事情，我前几天买的 3 箱矿泉水，放在房间门外的楼道里，被偷走了。</p><p>这是我人生中第一次遇到丢东西，我难以想象，3 大箱子矿泉水，24 瓶装那种，他是怎么搬走的，外面还下着雨，不太可能是其他楼的人，只能是邻居。</p><p>我非常想不通，其他值钱的东西也就算了，3 箱水，你家水龙头里接出来不都是水吗？而且不值钱，卖也没地方卖，这种东西用得着偷？</p><p>实在是匪夷所思，但是这件事情就是发生了。</p><p>当然我也有错，这几箱水几天前就送到了，我一直懒得往家里搬，就一直放在门口。为什么敢放在门口呢，一方面这是家门口啊，谁敢去别人家门口搬东西？真的不是顺手能带走的东西，得搬，甚至得用推车搬。另一方面，我记忆里，有些小卖铺，都直接把水，或者其他一些货物，摆到门口堆着的。我自己家门口放箱水，这玩意儿还有人偷？</p><p>俗话说，人教人，永远教不会，事教人，一次就长记性了。经过这件事情，我以后买水，肯定不敢放家门口了。</p><p>我为什么要这么啰嗦说这点事呢？因为我想和遇到 TanTin Chain 的裁员做类比。</p><p>有一些我们自己想象不到的事情，或者哪怕是别人反复好心劝告的事情，我们都会毫不在意，若非自己亲身经历，真的无法明白和重视。在楼道里丢东西这事，我早有耳闻，单元楼里不断有人说，我都是看个笑话。有时候出门玩，我也不太在意随身物品的安全问题，我无法想象现代社会，还有偷东西的人。但是这次我遇到了，而且被偷的还是矿泉水。</p><p>所以很多 web3 公司的新闻，跑路、暴雷、裁员、喝茶之类，我们平时都是当段子听，但是这些事情真实存在，只是没有发生在我们身上而已。</p><p>当我真正遭遇了 TanTin Chain 的裁员，并且调查过 TanTin Technology 这家公司的背景之后，只能说，挺长见识。</p><p>这就是 TanTin Chain 给我带来的收获和感悟。</p>]]></content>
  </entry>
  <entry>
    <title>失业第二个月干了什么</title>
    <link href="https://b.smallyu.net/2025/07/20/%E5%A4%B1%E4%B8%9A%E7%AC%AC%E4%BA%8C%E4%B8%AA%E6%9C%88%E5%B9%B2%E4%BA%86%E4%BB%80%E4%B9%88/"/>
    <id>blog-b:https://b.smallyu.net/2025/07/20/%E5%A4%B1%E4%B8%9A%E7%AC%AC%E4%BA%8C%E4%B8%AA%E6%9C%88%E5%B9%B2%E4%BA%86%E4%BB%80%E4%B9%88/</id>
    <published>2025-07-20T15:54:12.000Z</published>
    <updated>2025-12-04T13:51:35.271Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>今天是 7月20日，距离 5月20日已经两个月。失业第一个月的时候，简单写了《<a]]></summary>
    <content type="html"><![CDATA[<p>今天是 7月20日，距离 5月20日已经两个月。失业第一个月的时候，简单写了《<a href="/2025/06/20/%E5%A4%B1%E4%B8%9A%E4%B8%80%E4%B8%AA%E6%9C%88%E7%9A%84%E5%9B%9E%E9%A1%BE/">失业一个月的回顾</a>》复盘第一个月的情况，其实第一个月的学习节奏很紧张，事不少。现在失业第二个月了，记录一下第二个月干的事情，或者说回顾一下第二个月的学习成果。</p><h3 id="（1）从计算机科学班顺利毕业"><a href="#（1）从计算机科学班顺利毕业" class="headerlink" title="（1）从计算机科学班顺利毕业"></a>（1）从计算机科学班顺利毕业</h3><p>算是心里的石头落地，学也学完了，接下来好好复习、好好找工作。这个课程还是给我带来了不少信心的，否则我现在一定心态爆炸，我会有很多疑问：“区块链技术到底有啥好学的？”、“我已经接触过很多区块链技术和项目，你让我学啥？”、“面试不通过，你觉得我不会什么？”。这个课程，让我在心态上更加脚踏实地一点，挺不错。</p><p>对了，顺便提一下，在区块链的技术领域里，Uniswap 这种东西在技术上，对于我这种 “技术层级” 来说，不值得研究。不是说我不需要去学习，而是从自学的角度，搞明白这个东西没有什么难点，也无法给我带来技术上的成长。这话是 ChatGPT 说的，不只是我自己瞎琢磨，我之前就写过 <a href="/2024/09/11/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E5%81%9A%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%92%8CDeFi%E5%BC%80%E5%8F%91/">为什么不要做 DeFi 开发</a> 的文章，里面的道理不全对，但也不是完全没道理，我没给 ChatGPT 看我的这篇文章，但是 ChatGPT 的观点和我一样，而且比我分析的更全面更深入，算是间接验证了我的观点。</p><p>为什么刻意提 Uniswap 呢，因为我在 <a href="/2025/06/08/%E5%AD%A6%E4%B9%A0%E7%8E%8B%E5%9E%A0%E8%80%81%E5%B8%88%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%A7%86%E9%A2%91%E8%AF%BE%E6%8E%A5%E8%BF%91%E5%B0%BE%E5%A3%B0/">之前的文章</a> 中列出了一些学习计划，现在回头去看，我确实是在按照那些计划在学习的，DeFi 项目是计划之一，所以我在考虑要怎么学，以及适当调整当时的计划。</p><h3 id="（2）给解释器写了简单的-parser"><a href="#（2）给解释器写了简单的-parser" class="headerlink" title="（2）给解释器写了简单的 parser"></a>（2）给解释器写了简单的 parser</h3><p>目前支持变量定义、函数调用等语法，虽然不是纯函数式写法实现的，但仍然能工作，比如执行这样的语句：</p><pre><code class="js">// (x =&gt; y =&gt; x + y)(2)(3)var s17 = &quot;(call (fun x (call (fun y (+ x y)) 2)) 3)&quot;;show( execExpr(s17) ); // 5</code></pre><p>虽然语法非常简陋，功能也不全，但是不打算进一步完善这个 parser 了，这本就是课程内容之外产生的想法，简单尝试一下就可以。另外如果对 parser 的地位感兴趣，可以阅读王垠的这篇文章《<a href="https://www.yinwang.org/blog-cn/2015/09/19/parser">对 Parser 的误解</a>》。</p><h3 id="（3）用其他语言实现解释器"><a href="#（3）用其他语言实现解释器" class="headerlink" title="（3）用其他语言实现解释器"></a>（3）用其他语言实现解释器</h3><p>我用 Java、Go、Python 语言分别写了一遍解释器。加上课程中学习的 JavaScript 和 Rust 版本，现在解释器已经有 5 个语言的版本了。对于解释器这样的程序，语言其实不是关键，语法差异没有那么大。</p><h3 id="（4）学习-Solana-合约开发"><a href="#（4）学习-Solana-合约开发" class="headerlink" title="（4）学习 Solana 合约开发"></a>（4）学习 Solana 合约开发</h3><p>包括 Solana 的账户模型、SPL 标准库、SDK 调用等。感觉这种用户层面的技术，没有太多值得深入的地方。如果要深入去理解 Solana 的架构和 eBPF 的技术原理，倒是有进一步的学习空间，接下来也许可以考虑下这个方向。</p><h3 id="（5）学习比特币脚本开发"><a href="#（5）学习比特币脚本开发" class="headerlink" title="（5）学习比特币脚本开发"></a>（5）学习比特币脚本开发</h3><p>用 btcdeb 观察脚本执行步骤、使用命令行工具构建、发送 P2PKH、P2SH 交易等。教程文章里里没写多签和 HTLC 之类的内容，因为比特币脚本都是命令行操作，这种复杂的逻辑涉及到大堆数据，写出来不方便看，还得找到上下文的对应关系，比如解释解锁的是哪一笔 UTXO，这种过程用文字的形式不太好写。</p><h3 id="（6）第二轮做完计算机课的练习题"><a href="#（6）第二轮做完计算机课的练习题" class="headerlink" title="（6）第二轮做完计算机课的练习题"></a>（6）第二轮做完计算机课的练习题</h3><p>上个月就已经第二轮做了 1~7 课的练习题，这个月只需要完成剩下第 10 课和 3 个隐藏关。</p><ul><li><p>第 6 课的隐藏关比较简单，给解释器增加定义变量的语义。这个题目难度不大。</p></li><li><p>重新看了一遍第 10 课的教学视频，总结起来视频中提到的 Rust 关键特性有两个，Ownership 和 lifetime。</p></li><li><p>第 10 课隐藏关的练习题是用 Rust 写解释器。有意思的是，当第二次按部就班做题目的时候，犯了和第一次完全一样的错误，这个错误分两个阶段，都完美重现。我知道为什么会犯错，以及如何改正，但是说明也许是我的做题思路，或者其他原因，这两个错误是必犯的。当然顺便整理了更完善的题目说明和测试用例，下一次复习做题肯定会更顺手。</p></li><li><p>第 4 课隐藏关的练习题是用纯函数写法实现 parser。不得不说写 parser 真的痛苦，经过三四个小时的调试后，终于用错误的写法写出了能通过测试的程序。最离谱的错误之处在于一开始就写错了，应该给函数传递 lex 数据，我却直接拿字符串处理，但就这样代码的运行结果竟然没受到影响。parser 这个东西很折腾人，即使有了思路也需要不断调试才能写对，更侧重工程能力而不是思维能力，所以暂时不继续更正这个题目了。</p></li></ul><h3 id="（7）学习比特币-Runes-协议"><a href="#（7）学习比特币-Runes-协议" class="headerlink" title="（7）学习比特币 Runes 协议"></a>（7）学习比特币 Runes 协议</h3><p>自己试着开发了一个比特币 Runes 协议的原型。这也许是博客里最后一篇教程类文章，以前是不太写这种实操教程的，因为太过基础，没有技术含量，更没有深度或者思考和观点，最近写了几篇，一方面是边学边写，自己也顺便折腾一下，另一方面是，这个教程多少有点价值的地方在于，步骤肯定是可以复现的，因为我自己都亲手执行过，在网上找的教程，或者 ChatGPT 生成的教程，不一定能跑通。还有一个小原因，就是计算机课程里的练习题，虽然内容基础，但是质量很高，我有点想模仿尝试一下写这种基础教程。</p><p>最近的几篇教程足以说明，这种基础操作，只要想学就可以学会。很多时候，不明明白白的写出来，别人就觉得你不会，但实际上这些东西真的不难。接下来我不继续折腾这些基础的东西了，得去做点别的事情。以前偶尔也怀疑，老是写一些宏观的观点，是不是没有技术含量，会不会显得动手实践的能力差？但是事实证明，动手实践才是学习成本低的事情，最有难度的还得是总结性的观点。</p><h3 id="（8）不断面试"><a href="#（8）不断面试" class="headerlink" title="（8）不断面试"></a>（8）不断面试</h3><p>这一个月以来，从 6月20日到 7月20日之间，一共面试 12 家公司，一共参加 17 次面试。</p><p>这个频率不算很高，但也需要花不少时间，主要是得耗费心情在里面，一开始以积极的态度去面试，觉得这家也许有合适的机会，但是聊下来却不合适。这样的情况反复经历的多了，心情其实会不是很好，感觉浪费了期待在上面。职位不合适也能理解，但是如果频繁遇到不靠谱的面试官，会逐渐有点越来越受不了。毕竟面试这件事情，唯一的对手方就是面试官，而我最近老是在面试，有时候难免想对面试官发表点意见。</p><p>找工作这件事情找的都有点无奈了，到后来感觉面试面的都累了，不断反复自我介绍、反复讲解自己过去做的事情、反复描述我对某些技术问题的看法。这些面试官能问得出的问题就那么些，我都总结出规律了，所以很多面试我就感觉是在重复。偶尔有面试官提到了新鲜的问题，让我对某些技术有了新的感受，这些面试官我觉得挺难得，也会给他们好评。很多时候我面试是抱着学习的心态，了解下行业的变化、交流下项目的情况，并没有那么在乎职位是否合适、面试结果如何，所以如果在面试中学到了什么，也会挺感谢这次面试的机会。</p><p>那么我现在是否对工作的的事情感到焦虑呢？其实好转很多，失业第一个月的回顾文章里，明确写了当时的烦躁和焦虑（要是没写出来我现在自己都忘了），现在失业第二个月，情况反而变好了，因为我知道自己在不断努力，学习新技术、沉淀计算机基础技能，我没有理由 “失败”。何况我有很好的女朋友，没工作算什么呢，有一个善解人意又漂亮的女朋友，是很多人 “梦寐以求” 都没有的，我却长时间以来一直在忽略她的重要。为了寻找合适的工作机会，我也有过去上海、香港的计划（不考虑深圳，在币圈“深圳盘”很有名），但是仍然在考虑具体的方式和时机。</p><p>有时候我也会想，过去的种种职业选择是否错误？只能说塞翁失马，没人知道对错。过去的选择有得有失。我现在不到 30 岁的年龄，去上课学习知识，去对自己未来的职业前景充满信心，去不断自学提高技术能力和见识，这些绝对不是一件错误的事情。我为什么会对自己有比较高的期望呢，也许是因为长期关注区块链行业，这个行业充满了各种故事。我的出身并不好，学历也不好，似乎没有什么理由让我 “应该成功”。不过我在学校的成绩还不错，只比同类优秀就是了。也许从那个时候开始，我逐渐对自己有了更高的期待。后面在职场中经历各种事情，更是没能明白什么样的人是优秀的，因为我没遇到过。</p><p>我期望的生活是什么样的呢，我只不过是希望赚点生活费维持生活而已，这没多少钱，在互联网行业不算多，在币圈更不算多，我经年累月的学习和努力工作，甚至忽略了很多普通生活的元素，如果最后落得找不到工作的下场，也挺奇怪的。人生的意义是什么呢，那些有钱人，那些巨鲸，他们随便的零花钱都够我一辈子的开销，他们在为什么努力，想要的是什么，他们有没有好好学习技术，有没有积极提升自己，他们又在为什么而发愁，在担心什么事情呢？</p><h3 id="（9）制定后续的学习计划"><a href="#（9）制定后续的学习计划" class="headerlink" title="（9）制定后续的学习计划"></a>（9）制定后续的学习计划</h3><p>后续计划主体还是计算机课相关的，重复做练习题。现在已经第二轮做完了练习题，接下来可以进行第三轮的复习。</p><ol><li><p>阅读 <a href="https://www.yinwang.org/blog-cn/2021/05/11/gucs-sample">Groud-Up Computer Science</a> 全书，加深对课程内容的理解。学习节奏应该放缓，慢慢看，慢慢理解，慢慢练。不是为了偷懒而降低学习节奏，而是避免错过什么内容，欲速则不达。</p></li><li><p>阅读过书籍后，开始第三轮做计算机课的练习题。学习节奏要放的很慢，一天最多做一道题，主要是留给每一道题充分思考的时间，确保理解透彻。也许按照这样的节奏，需要几个月能完成整个轮次的复习。</p></li><li><p>系统学习 continuation。不是报王垠的 continuation 专项班，而是自己学习和研究。我相信自己现在完全有能力，不仅学会和梳理清楚这些知识，还能整理出完整的练习题或者教程。</p></li></ol><p>为什么我的学习计划，非要跟这个计算机课的练习题过不去呢？我之前在总结 <a href="/2025/07/06/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%882025%E5%B9%B4%E7%89%88%EF%BC%89/">区块链面试题</a> 的时候有提到，经过这几年在区块链行业实际的工作，我反而越来越搞不清楚 “区块链技术” 是什么了，相比之下，拥有基础但扎实的计算机功底很重要，尤其是高度抽象的思维方式，能够脱离语法但理解编程语言的学习方式，值得反复琢磨和掌握。我曾经以为好好钻研区块链技术，就可以逐步提高自己的技术能力，水平上超越所谓的计算机基础班，就可以深入研究到某些区块链原理，深入再深入。然而事实上不是那样，区块链技术……我越来越不知道该学什么。</p><p>我之前大量关注区块链共识的原理。为什么关注的不是其他技术原理，比如加密学、分布式网络、储存系统等内容？因为只有共识是区块链特有的，其他的都是普通的工程上的技术，甚至包括智能合约的实现。而且智能合约还不是区块链必需，可以有也可以没有。至于 Layer 2 之类，也完全是工程上的尝试，哪有什么可以抽象的理论依据，挑战期、赎回期都是业务定义的逻辑。所以综合来看，区块链技术……到底是什么？</p><p>（分享个有意思的东西，我最近在研究 Georgios Konstantopoulos 这个人的技术能力和技术成果。Georgios 是 Paradigm 的 CTO，他的 <a href="https://www.gakonst.com/">个人主页</a> 上展示了很多区块链相关的技术内容。那么问题来了，你觉得 Georgios 的个人主页和工作成就，有没有解答我对于 “不知道区块链技术是什么” 的疑问？）</p>]]></content>
  </entry>
  <entry>
    <title>我的 X 账号被封了，搞不清楚我违反了 X 平台的哪一条规则，900 多条推文记录就这么没了。虽然推文没什么价值，但也是...</title>
    <link href="https://t.smallyu.net/#2025-13"/>
    <id>micro:3089207458</id>
    <published>2025-07-18T11:46:17Z</published>
    <updated>2025-07-18T11:46:17Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>我的 X 账号被封了，搞不清楚我违反了 X 平台的哪一条规则，900 多条推文记录就这么没了。虽然推文没什么价值，但也是某种历史行为的记录。想不到自由开放的 X 平台还会干这样的事情，封我的账号。再次意识到 “拥有自己数据” 的重要性，幸好没有重度依赖 X 平台去写什么东西。</p>]]></summary>
    <content type="html"><![CDATA[<p>我的 X 账号被封了，搞不清楚我违反了 X 平台的哪一条规则，900 多条推文记录就这么没了。虽然推文没什么价值，但也是某种历史行为的记录。想不到自由开放的 X 平台还会干这样的事情，封我的账号。再次意识到 “拥有自己数据” 的重要性，幸好没有重度依赖 X 平台去写什么东西。</p>
]]></content>
  </entry>
  <entry>
    <title>如何开发一个比特币符文（Runes）协议</title>
    <link href="https://smallyu.net/2025/07/15/%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E6%AF%94%E7%89%B9%E5%B8%81%E7%AC%A6%E6%96%87%EF%BC%88Runes%EF%BC%89%E5%8D%8F%E8%AE%AE/"/>
    <id>blog:https://smallyu.net/2025/07/15/%E5%A6%82%E4%BD%95%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E6%AF%94%E7%89%B9%E5%B8%81%E7%AC%A6%E6%96%87%EF%BC%88Runes%EF%BC%89%E5%8D%8F%E8%AE%AE/</id>
    <published>2025-07-15T14:00:00.000Z</published>
    <updated>2026-08-04T11:43:16.823Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>比特币符文（Runes）在技术原理上比较简单，很容易理解，实现 Runes 只需要用到比特币脚本中的 <code>OP_RETURN</code> 操作符。也是正因为简单，所以在技术特性上， Runes 相对干净一点，没有铭文和 RGB 那么复杂的链下状态。而 Runes]]></summary>
    <content type="html"><![CDATA[<p>比特币符文（Runes）在技术原理上比较简单，很容易理解，实现 Runes 只需要用到比特币脚本中的 <code>OP_RETURN</code> 操作符。也是正因为简单，所以在技术特性上， Runes 相对干净一点，没有铭文和 RGB 那么复杂的链下状态。而 Runes 厉害的地方在于，能把这样一个生态给玩起来，虽然现在也凉了，但是我们不那么关心市场表现，从技术的角度，非常切实的看一下 Runes 是如何实现的，并且我们自己会一步一步开发一个简化的 Runes 协议出来。当我们真正理解了 Runes 协议，就可以直接看懂更复杂的项目，比如 Alkanes，一个在比特币上支持 WASM 智能合约的协议。</p><p>这篇文章的操作基于《<a href="/2025/07/10/%E6%AF%94%E7%89%B9%E5%B8%81%E8%84%9A%E6%9C%AC%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/">比特币脚本开发教程</a>》中的知识，如果缺少对比特币脚本的基本了解，可以先看一下基础教程。</p><h3 id="1-定义数据结构"><a href="#1-定义数据结构" class="headerlink" title="1. 定义数据结构"></a>1. 定义数据结构</h3><p>首先把 Runes 相关的操作定义为 json 格式的数据结构。用什么语言都可以，这里用的是 Rust。为了简化教程，可以省去一些实际中常用的元素，比如 <code>transfer</code> 的操作定义中，应该允许一次性转账给多个目标地址，但这里只有一个目标地址，没有用数组：</p><pre><code class="rust">struct IssueRune&#123;    op: u8,          // 固定为 0，代表发行    symbol: String,  // Rune name    supply: String,  // 发行总量&#125;struct TransferRune&#123;    op: u8,          // 固定为 1，代表转账    id: u64,         // rune_id    vout: u32,       // 转账目标    amount: String,  // 转账金额&#125;</code></pre><p>这个结构定义中，唯一可能有点迷惑的是 <code>vout</code> 字段，一般我们要转账给一个目标地址的时候，会使用目标地址的字符串作为值，但是 Runes 协议中，为了节省链上空间，使用 <code>vout</code> 也就是当前这笔交易、第几个输出的索引作为 Runes 转账的目标。因为每一笔交易的第 0 个输出会包含 <code>OP_RETURN</code> 的值，转账操作的字符全部会放到 <code>OP_RETURN</code> 的内容中，所以在一笔交易里，<code>vout</code> 只用数字就足以表明转账的目标地址是哪个。交易数据的结构大概是这样：</p><pre><code class="json">tx &#123;  vin:   [...]  vout:  [    &#123; vout: 0, scriptPubKey: OP_RETURN &lt;json数据&gt; &#125;,    &#123; vout: 1, scriptPubKey: OP_0 &lt;转账地址1&gt; &#125;,    &#123; vout: 2, scriptPubKey: OP_0 &lt;转账地址2&gt; &#125;  ]&#125;</code></pre><p>接着给数据结构定义一下序列化函数，让结构体可以转变为 json 字符串：</p><pre><code class="rust">impl IssueRune&#123;    fn toJson(&amp;self) -&gt; String    &#123;        format!(            &quot;&#123;&#123;\"op\":&#123;&#125;,\"symbol\":\"&#123;&#125;\",\"supply\":\"&#123;&#125;\"&#125;&#125;&quot;,            self.op, self.symbol, self.supply        )    &#125;&#125;impl TransferRune&#123;    fn toJson(&amp;self) -&gt; String    &#123;        format!(            &quot;&#123;&#123;\"op\":&#123;&#125;,\"id\":&#123;&#125;,\"vout\":&#123;&#125;,\"amount\":\"&#123;&#125;\"&#125;&#125;&quot;,            self.op, self.id, self.vout, self.amount        )    &#125;&#125;</code></pre><h3 id="2-发行-Runes-代币"><a href="#2-发行-Runes-代币" class="headerlink" title="2. 发行 Runes 代币"></a>2. 发行 Runes 代币</h3><p>接下来的操作都基于本地启动的 regtest 节点，所以记得先启动起来，同时验证下有没有加载钱包、钱包里有没有余额。然后准备一下要发行 Rune 的 json 数据，比如这样，发行的 Rune 叫 <code>Doge</code>，总发行量 <code>1000</code> 个：</p><pre><code class="rust">fn issue_rune()&#123;    let issue = IssueRune     &#123;        op: 0,        symbol: &quot;Doge&quot;.to_string(),        supply: &quot;1000&quot;.to_string(),    &#125;;    println!(&quot;Issue Doge JSON: &#123;&#125;&quot;, issue.toJson());&#125;</code></pre><p>运行这个函数，就会得到这样的输出，后面的 json 数据很重要，我们稍后会把这个数据发送到链上：</p><pre><code class="bash">Issue Doge JSON: &#123;&quot;op&quot;:0,&quot;symbol&quot;:&quot;Doge&quot;,&quot;supply&quot;:&quot;1000&quot;&#125;</code></pre><p>然后运行这个命令行，把 json 数据转变为 16进制字符串：</p><pre><code class="bash">echo -n &quot;&#123;&quot;op&quot;:0,&quot;symbol&quot;:&quot;Doge&quot;,&quot;supply&quot;:&quot;1000&quot;&#125;&quot; | xxd -p -c 999</code></pre><p>我得到了这样的输出：</p><pre><code class="bash">7b6f703a302c73796d626f6c3a446f67652c737570706c793a313030307d</code></pre><p>这就是会放到 <code>OP_RETURN</code> 后面、用来上链的数据。注意 <code>OP_RETURN</code> 最多支持 80 个字节，所以这个数据不能太长。</p><p>接着查看并挑一笔未花费的输出，因为 Runes 所有的操作都必须绑定到 UTXO 上。用这个命令查看你的钱包有哪些 UTXO 可用，然后挑一个你喜欢的：</p><pre><code class="bash">bitcoin-cli -datadir=./ -regtest listunspent</code></pre><p>比如我要用的 UTXO 是这样：</p><pre><code class="json">&#123;  &quot;txid&quot;: &quot;8bfd524e9fc150dab11289d7e6d07860b2b5d6acb54b278a5dc1d1d7631bc8fa&quot;,  &quot;vout&quot;: 0,  &quot;address&quot;: &quot;bcrt1q6c8d9vw62rdee72xcqx3d97w8qh8mfg8ky8zjw&quot;,  &quot;amount&quot;: 50.00000000,  // ...&#125;</code></pre><p>然后生成一个找零地址，用来接收比特币余额，这里用了 legacy 格式的地址，这个不是强制的，用 SegWit 的地址也不影响：</p><pre><code class="bash">bitcoin-cli -datadir=./ getrawchangeaddress legacy</code></pre><p>我生成的地址是 <code>n4Ybvvzm9vRQepuMpXBnTWWbYuTgsPSZCV</code>，接下来可以用这个地址构建交易了：</p><pre><code class="bash">bitcoin-cli -datadir=./ createrawtransaction \  &#39;[&#123;&quot;txid&quot;:&quot;8bfd524e9fc150dab11289d7e6d07860b2b5d6acb54b278a5dc1d1d7631bc8fa&quot;,&quot;vout&quot;:0&#125;]&#39; \  &#39;[&#123;&quot;data&quot;:&quot;7b6f703a302c73796d626f6c3a446f67652c737570706c793a313030307d&quot;&#125;,&#123;&quot;n4Ybvvzm9vRQepuMpXBnTWWbYuTgsPSZCV&quot;:49.99&#125;]&#39;</code></pre><p>注意这个命令给找零地址的金额为 49.99，这种操作是不可以直接在主网使用的，需要精确计算余额和手续费的差值，然后给找零地址，不然会有很大的资金损失。这里只是懒得计算精确值。</p><p>生成交易数据后，对交易进行签名：</p><pre><code class="bash">bitcoin-cli -datadir=./ signrawtransactionwithwallet 0200000001fac81b63d7d1c15d8a274bb5acd6b5b26078d0e6d78912b1da50c19f4e52fd8b0000000000fdffffff020000000000000000206a1e7b6f703a302c73796d626f6c3a446f67652c737570706c793a313030307dc0aff629010000001976a914fc9ab9cd801c625c9fe323fe669e6a3e362eed8088ac00000000</code></pre><p>发送签名后的交易到链上：</p><pre><code class="bash">bitcoin-cli -datadir=./ sendrawtransaction 02000000000101fac81b63d7d1c15d8a274bb5acd6b5b26078d0e6d78912b1da50c19f4e52fd8b0000000000fdffffff020000000000000000206a1e7b6f703a302c73796d626f6c3a446f67652c737570706c793a313030307dc0aff629010000001976a914fc9ab9cd801c625c9fe323fe669e6a3e362eed8088ac02473044022004a2553cc5348dd4521c093149b0ba5e5603fe4134d06a455e12abeac097ea19022076e72632b2488e1316e54559ed733b37de9ce7fd04119e78a59546a3d2c1faea0121020b396a9dfa1655feef066fe03b403d3e4bdee41ef9b26551497c0921acbf6bc100000000</code></pre><p>要留意这个命令会输出一个 txid，这个 txid 比较重要，我们后续会从这个 txid 来转出 Doge 代币，所以要记得留下这个 txid 的记录，我的交易哈希是：<code>e2061d0b8b2f98ee47ba6564c1e7409872432354c7617d278fe0e8c4485ff04a</code>。挖一个区块来确认交易：</p><pre><code class="bash">bitcoin-cli -datadir=./ generatetoaddress 1 bcrt1q6c8d9vw62rdee72xcqx3d97w8qh8mfg8ky8zjw</code></pre><p>如果一切顺利，交易数据就应该已经上链了。那么链下的解析器在拿到这笔交易后，会看到发行 Rune 的操作，并且解析出来。如果想确认下 <code>OP_RETURN</code> 的数据是不是写对了，可以解码一下刚才广播的交易详情：</p><pre><code class="bash">bitcoin-cli -datadir=./ decoderawtransaction 02000000000101fac81b63d7d1c15d8a274bb5acd6b5b26078d0e6d78912b1da50c19f4e52fd8b0000000000fdffffff020000000000000000206a1e7b6f703a302c73796d626f6c3a446f67652c737570706c793a313030307dc0aff629010000001976a914fc9ab9cd801c625c9fe323fe669e6a3e362eed8088ac02473044022004a2553cc5348dd4521c093149b0ba5e5603fe4134d06a455e12abeac097ea19022076e72632b2488e1316e54559ed733b37de9ce7fd04119e78a59546a3d2c1faea0121020b396a9dfa1655feef066fe03b403d3e4bdee41ef9b26551497c0921acbf6bc100000000</code></pre><p>输出的结果是这样：</p><pre><code class="json">&quot;vout&quot;: [    &#123;      &quot;value&quot;: 0.00000000,      &quot;n&quot;: 0,      &quot;scriptPubKey&quot;: &#123;        &quot;asm&quot;: &quot;OP_RETURN 7b6f703a302c73796d626f6c3a446f67652c737570706c793a313030307d&quot;,        // ...      &#125;    &#125;,    &#123;      &quot;value&quot;: 49.99000000,      &quot;n&quot;: 1,      &quot;scriptPubKey&quot;: &#123; //... &#125;    &#125;  ]</code></pre><p>很明显看到了在第 0 个输出中，有 <code>OP_RETURN 十六进制数据</code> 的内容，如果还是不放心，可以 decode 一下 16进制字符串：</p><pre><code class="bash">echo -n &quot;7b6f703a302c73796d626f6c3a446f67652c737570706c793a313030307d&quot; | xxd -r -p</code></pre><p>应该得到：</p><pre><code class="bash">&#123;op:0,symbol:Doge,supply:1000&#125;</code></pre><h3 id="3-转账-Runes-代币"><a href="#3-转账-Runes-代币" class="headerlink" title="3. 转账 Runes 代币"></a>3. 转账 Runes 代币</h3><p>刚才创建了 <code>Doge</code> 代币，发行量是 <code>1000</code>，我们接下来通过一笔转账交易，来转出这 1000 个 Doge。</p><p>首先得计算一下 rune_id，也就是我们刚才发行的 <code>Doge</code> 的唯一 ID 是什么，因为 Symbol 字符串是有可能重复的，而且占用字符空间也多，一般会做一些工程上的折中，比如对 txid 按照字节反序，然后取前 8 字节，得到一个 u64 长度的数字，像这样：</p><pre><code class="rust">fn calc_run_idby_txid()&#123;    let txid = &quot;e2061d0b8b2f98ee47ba6564c1e7409872432354c7617d278fe0e8c4485ff04a&quot;.to_string();    // 按字节反序，然后取前 8 字节    let mut bytes = hex::decode(txid).unwrap();    bytes.reverse();    let run_id = u64::from_le_bytes(bytes[0..8].try_into().unwrap());    println!(&quot;Run ID: &#123;&#125;&quot;, run_id);&#125;</code></pre><p>这个函数运行后会得到 <code>10367542271932362826</code>，我们把这个数字作为 rune_id，去构建转账 rune 需要的 json 数据：</p><pre><code class="rust">fn transfer_rune()&#123;    let transfer = TransferRune    &#123;        op: 1,        id: 10367542271932362826,        vout: 1,        amount: &quot;1000&quot;.to_string(),    &#125;;    println!(&quot;Transfer Rune JSON: &#123;&#125;&quot;, transfer.toJson());&#125;</code></pre><p>这个参数里要留意 <code>vout</code> 的值，它是接下来构建交易的时候，要转出到某个地址的 vout 的索引，和创建代币时候的交易没有任何关系。代码运行后得到这样的结果：</p><pre><code class="bash">Transfer Doge JSON: &#123;&quot;op&quot;:1,&quot;id&quot;:10367542271932362826,&quot;vout&quot;:1,&quot;amount&quot;:&quot;1000&quot;&#125;</code></pre><p>接下来就可以重复之前的步骤，把 json 转为 16进制字符串：</p><pre><code class="bash">echo -n &quot;&#123;&quot;op&quot;:1,&quot;id&quot;:10367542271932362826,&quot;vout&quot;:1,&quot;amount&quot;:&quot;1000&quot;&#125;&quot; | xxd -p -c 999</code></pre><p>我得到 <code>7b6f703a312c69643a31303336373534323237313933323336323832362c766f75743a312c616d6f756e743a313030307d</code>。</p><p>创建一个新地址用于接收 Doge：</p><pre><code class="bash">bitcoin-cli -datadir=./ getnewaddress</code></pre><p>我的新地址是：<code>bcrt1qc250507tws9z9wkurfcv3jue2nls6npzaqt7ka</code>。</p><p>利用刚才得到的参数，组装一笔转账 Doge 的交易：</p><pre><code class="bash">bitcoin-cli -datadir=./ createrawtransaction \&#39;[&#123;&quot;txid&quot;:&quot;e2061d0b8b2f98ee47ba6564c1e7409872432354c7617d278fe0e8c4485ff04a&quot;,&quot;vout&quot;:1&#125;]&#39; \&#39;[&#123;&quot;data&quot;:&quot;7b226f70223a312c226964223a31303336373534323237313933323336323832362c22766f7574223a312c22616d6f756e74223a2231303030227d&quot;&#125;,&#123;&quot;bcrt1q0n2x7030x59j5ql9pp6mw0tps74ag0znrdp45r&quot;:0.01&#125;,&#123;&quot;n4Ybvvzm9vRQepuMpXBnTWWbYuTgsPSZCV&quot;:49.9798&#125;]&#39;</code></pre><p>这里和之前的交易略有不同，包含两个输出，第一个是接收 Doge 的地址，金额随意，因为重点在于 Doge 余额，而不是 BTC 余额。第二个参数则是找零地址，我们前面的交易里用到过。</p><p>剩下的操作轻车熟路，对这笔交易签名、把交易广播出去、挖一个新区块让交易确认：</p><pre><code class="bash"># 对交易签名bitcoin-cli -datadir=./ signrawtransactionwithwallet 02000000014af05f48c4e8e08f277d61c7542343729840e7c16465ba47ee982f8b0b1d06e20100000000fdffffff0300000000000000003d6a3b7b226f70223a312c226964223a31303336373534323237313933323336323832362c22766f7574223a312c22616d6f756e74223a2231303030227d40420f00000000001600147cd46f3e2f350b2a03e50875b73d6187abd43c53601fe729010000001976a914fc9ab9cd801c625c9fe323fe669e6a3e362eed8088ac00000000# 广播交易bitcoin-cli -datadir=./ sendrawtransaction 02000000014af05f48c4e8e08f277d61c7542343729840e7c16465ba47ee982f8b0b1d06e2010000006a47304402201437a9e83ae0c6842ebd9d355af9c7be1f6f2eaa070b5d7a6e02e13ca8f2d13102206d05753c428f526b8c6636022991591517cc7d7982badfc633519cb44715957a0121026f441e8156148d0bb4963edaff187873f9800a37bb5f0731256e38d632031283fdffffff0300000000000000003d6a3b7b226f70223a312c226964223a31303336373534323237313933323336323832362c22766f7574223a312c22616d6f756e74223a2231303030227d40420f00000000001600147cd46f3e2f350b2a03e50875b73d6187abd43c53601fe729010000001976a914fc9ab9cd801c625c9fe323fe669e6a3e362eed8088ac00000000# 得到交易哈希：80709a25e5355d51ee6d7fb625c40e9c4c49b049afa3aca18aeaa03bc685c1f0# 确认交易bitcoin-cli -datadir=./ generatetoaddress 1 bcrt1q6c8d9vw62rdee72xcqx3d97w8qh8mfg8ky8zjw</code></pre><p>到这一步，转账 Doge 的交易就完成并且上链了。</p><h3 id="4-解析-Runes-交易"><a href="#4-解析-Runes-交易" class="headerlink" title="4. 解析 Runes 交易"></a>4. 解析 Runes 交易</h3><p>你也许有点纳闷，这不就是发了两笔普通的比特币交易吗，只是放了两个 json 数据到交易上。Runes 就是这样，所有的操作，就在 <code>OP_RETURN</code> 允许的那 80 个字节的空间里完成。链上只记录 Runes 的操作，而不维护 Runes 的最终状态。包括有哪些代币、代币余额等信息，全部需要链下程序根据协议进行解析，状态也全部在链下程序维护。</p><p>我们首先可以通过已知的交易哈希，获取到这两笔交易的全部详情数据。如果交易哈希不是已知，可以监听扫描全部区块的全部交易，然后按照协议约定解析就行了。这里简化一点。</p><p>在 <code>Cargo.toml</code> 文件中导入依赖包：</p><pre><code class="toml">[dependencies]hex              = &quot;0.4&quot;bitcoin          = &quot;0.31&quot;          # Script &amp; consensus decodebitcoincore-rpc  = &quot;0.18&quot;          # RPC clientserde            = &#123; version = &quot;1.0&quot;, features = [&quot;derive&quot;] &#125;anyhow           = &quot;1.0&quot;</code></pre><p>通过 RPC 查询节点上的交易数据：</p><pre><code class="rust">// 导入必要依赖use bitcoin::&#123;Transaction, Txid&#125;;use bitcoincore_rpc::&#123;Auth, Client, RpcApi&#125;;use serde::Deserialize;use std::path::PathBuf;use std::str::FromStr;fn parse_tx()&#123;    // 去启动比特币节点的数据目录下，找用来 rpc 鉴权的 cookie 文件    let mut cookie = PathBuf::from(&quot;/Users/smallyu/work/github/bitcoin-regtest&quot;);    cookie.push(&quot;regtest/.cookie&quot;);    let rpc = Client::new(        &quot;http://127.0.0.1:18443&quot;,        Auth::CookieFile(cookie),    ).unwrap();    // 我们已知的交易哈希    let issue_txid    = Txid::from_str(&quot;e2061d0b8b2f98ee47ba6564c1e7409872432354c7617d278fe0e8c4485ff04a&quot;).unwrap();    let transfer_txid = Txid::from_str(&quot;80709a25e5355d51ee6d7fb625c40e9c4c49b049afa3aca18aeaa03bc685c1f0&quot;).unwrap();    // 这里会得到完整的交易数据    let issue_hex    = rpc.get_raw_transaction_hex(&amp;issue_txid, None).unwrap();    let transfer_hex = rpc.get_raw_transaction_hex(&amp;transfer_txid, None).unwrap();    println!(&quot;Issue Hex: &#123;&#125;&quot;, issue_hex);    println!(&quot;Transfer Hex: &#123;&#125;&quot;, transfer_hex);    // 调用函数来解析交易    parse_op_return(issue_hex);    parse_op_return(transfer_hex);&#125;</code></pre><p>这个函数在运行的时候，会从链上节点，查询出真实的已经上链的交易数据。接下来可以对这两笔交易的 Runes 操作做解析：</p><pre><code class="rust">fn parse_op_return(tx_str: String)&#123;    let tx: Transaction = bitcoin::consensus::deserialize(&amp;hex::decode(tx_str).unwrap()).unwrap();    let script = tx.output[0].script_pubkey.clone();    // OP_RETURN, DATA    let mut iter = script.instructions();    let mut op_return = iter.next();    let mut data = iter.next();    // 解析数据    match op_return    &#123;        Some(Ok(op_return)) =&gt;            &#123;                match data                &#123;                    Some(Ok(data)) =&gt;                        &#123;                            match (data)                            &#123;                                bitcoin::blockdata::script::Instruction::PushBytes(bytes) =&gt;                                    &#123;                                        let json_str = std::str::from_utf8(bytes.as_ref()).unwrap();                                        println!(&quot;&#123;&#125;&quot;, json_str);                                    &#125;                                _ =&gt; panic!(&quot;Expected OP_RETURN with data&quot;),                            &#125;                        &#125;                    _ =&gt; panic!(&quot;No data found in OP_RETURN&quot;),                &#125;            &#125;        _ =&gt; panic!(&quot;No OP_RETURN found in script&quot;),    &#125;&#125;</code></pre><p>解析数据的代码部分，写法上嵌套有点多，只是因为我不喜欢用语法糖。想看起来更舒服的话，也可以在代码写法上做调整，变得更精简，不过无论写法如何，代码干的事情都一样。这个函数会从交易数据里，经过层层解析，打印出这样的结果：</p><pre><code class="bash">&#123;op:0,symbol:Doge,supply:1000&#125;&#123;&quot;op&quot;:1,&quot;id&quot;:10367542271932362826,&quot;vout&quot;:1,&quot;amount&quot;:&quot;1000&quot;&#125;</code></pre><p>这样，我们就看到了期望的两个 Runes 动作，第一个是发行 Doge，第二个是对 Doge 进行转账。</p><p>以上过程就是 Runes 协议比较核心的内容，剩下的只需要把链下程序扩充一下，记录 Runes 状态、根据 rune_id 关联 Rune 操作、储存和显示余额变更等信息就可以了。</p>]]></content>
  </entry>
  <entry>
    <title>比特币脚本开发教程</title>
    <link href="https://smallyu.net/2025/07/10/%E6%AF%94%E7%89%B9%E5%B8%81%E8%84%9A%E6%9C%AC%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/"/>
    <id>blog:https://smallyu.net/2025/07/10/%E6%AF%94%E7%89%B9%E5%B8%81%E8%84%9A%E6%9C%AC%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/</id>
    <published>2025-07-09T16:42:10.000Z</published>
    <updated>2026-08-04T11:43:16.647Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>比特币脚本有点像房间里的大象，大家都知道这个东西，但是大家都看不见，或者不在乎。这个教程将从最基本的操作开始，理解比特币脚本的原理，学会自己写比特币脚本。因为比特币脚本不是图灵完备的，所以包含很多命令行操作，以及需要观察输出结果。</p>
<h3]]></summary>
    <content type="html"><![CDATA[<p>比特币脚本有点像房间里的大象，大家都知道这个东西，但是大家都看不见，或者不在乎。这个教程将从最基本的操作开始，理解比特币脚本的原理，学会自己写比特币脚本。因为比特币脚本不是图灵完备的，所以包含很多命令行操作，以及需要观察输出结果。</p><h3 id="1-启动本地节点"><a href="#1-启动本地节点" class="headerlink" title="1. 启动本地节点"></a>1. 启动本地节点</h3><p>运行这个命令安装 <code>bitcoind</code> 的二进制，然后用 <code>bitcoind --help</code> 来测试是否安装成功：</p><pre><code class="bash">brew install bitcoin</code></pre><p>创建一个用于测试使用的目录，比如我的目录名称是 <code>bitcoin-regtest</code>：</p><pre><code class="bash">mkdir ./bitcoin-regtestcd ./bitcoin-regtest</code></pre><p>在这个目录下新建一个叫 <code>bitcoin.conf</code> 文件，复制这些配置内容进去：</p><pre><code class="conf">regtest=1txindex=1fallbackfee=0.0001</code></pre><p>这是本地节点的配置文件，后续我们的比特币脚本将基于本地启动的开发节点来测试。这个配置文件中的 <code>regtest=1</code> 比较关键，指明了节点的类型是本地开发网络，不会真的到公网上同步区块数据，本地节点的块高度将从 0 开始。另外两个配置 <code>txindex=1</code> 是指启动本地节点对所有交易的索引，方便我们后续查看交易，<code>fallbackfee=0.0001</code> 则是指明交易手续费的大小。</p><p>停留在包含配置文件的当前目录下，执行这个命令来启动节点。这里的命令行，以及后续的命令行，都会带上 <code>-datadir</code> 参数，因为我们希望节点数据是隔离的，每一个工作目录都是一份新的环境，不至于污染电脑的全局环境，而且默认环境的路径比较长，不同操作系统不一致，虽然我们在后续的命令里都需要带上这么一个参数，看起来有点麻烦，但同时也避免了很多其他问题，比如找不到系统默认目录在哪儿之类：</p><pre><code class="bash">bitcoind -datadir=./ -daemon</code></pre><p>命令成功执行会看到 <code>Bitcoin Core starting</code> 的字样。为了测试节点是否真的在运行，可以用这个命令查看节点的状，会得到一个 json 数据：</p><pre><code class="bash">bitcoin-cli -datadir=./ getblockchaininfo</code></pre><p>如果还是对节点的运行状态不放心，可以直接查看节点的日志文件。这就是我们指定了数据目录的好处，日志文件在这个位置：</p><pre><code class="bash">cat ./regtest/debug.log</code></pre><p>如果想要停掉节点，避免后台进程一直在电脑上运行，用这个命令来停止节点：</p><pre><code class="bash">bitcoin-cli -datadir=./ stop</code></pre><p>注意启动节点用的是 <code>bitcoind</code>，停止节点用的是 <code>bitcoin-cli</code>。前者属于 server 端的命令，后者属于 client 端的命令。</p><p>另外，如果在停止节点后重启节点，发现钱包（下一小节内容）不能用了，可以用这个命令来导入钱包：</p><pre><code class="bash">bitcoin-cli -datadir=./ loadwallet learn-script </code></pre><h3 id="2-创建钱包"><a href="#2-创建钱包" class="headerlink" title="2. 创建钱包"></a>2. 创建钱包</h3><p>运行这个命令来创建一个比特币钱包：</p><pre><code class="bash">bitcoin-cli -datadir=./ createwallet &quot;learn-script&quot;</code></pre><p>我们刚提到命令行中使用 <code>-datadir</code> 参数来指定数据目录，那么钱包的文件其实也会在数据目录下保存，可以看一下 <code>./regtest/wallets</code> 目录，有一个 <code>learn-script</code> 的文件夹，我们刚才创建的钱包就在这个文件夹内。</p><p>查看钱包地址的命令，比如我的地址是 <code>bcrt1q6c8d9vw62rdee72xcqx3d97w8qh8mfg8ky8zjw</code>：</p><pre><code class="bash">bitcoin-cli -datadir=./ getnewaddress</code></pre><p>接着在本地节点上，给钱包地址挖一些钱出来，这里的参数 <code>101</code> 是指挖 101 个区块。为什么是 101 个区块呢？一般我们挖的区块数量会大于 100，因为比特币网络有 100 个区块的成熟期，也就是区块奖励需要在 100 个区块之后，才可以消费。假如我们只挖了 99 个区块，虽然理论上应该得到很多区块奖励，但实际上是不能花费的。</p><pre><code class="bash">bitcoin-cli -datadir=./ generatetoaddress 101 bcrt1q6c8d9vw62rdee72xcqx3d97w8qh8mfg8ky8zjw</code></pre><p>这个命令运行输出的是每个块的区块哈希。运行结束后，我们就可以查看钱包地址的余额了，余额应该是 50：</p><pre><code class="bash">bitcoin-cli -datadir=./ getbalance</code></pre><p>为什么是 50？因为比特币的区块奖励每 4 年减半，第一次减半之前的块奖励，每个区块都是 50 BTC。为什么挖了 101 个块，但只能查到 50 BTC 的余额？因为后 100 个区块的成熟期，奖励是不到账的。</p><h3 id="3-发送交易"><a href="#3-发送交易" class="headerlink" title="3. 发送交易"></a>3. 发送交易</h3><p>那么现在我们已经有了本地在运行的节点，以及有余额的钱包，接下来可以发起一笔普通的转账交易。先生成一个用于接收转账的新地址，我生成的地址是 <code>bcrt1qgq99zusgk3ekrzucs9uyqv5vpxnh66cjtwl6zc</code>：</p><pre><code class="bash">bitcoin-cli -datadir=./ getnewaddress</code></pre><p>可以查看验证一下，新生成的地址余额为 0。这个命令中的参数 <code>0</code> 意味着查询结果包含未确认的交易。</p><pre><code class="bash">bitcoin-cli -datadir=./ getreceivedbyaddress bcrt1qgq99zusgk3ekrzucs9uyqv5vpxnh66cjtwl6zc 0</code></pre><p>接着使用发起交易的命令，来向新生成的地址转账 0.01 BTC：</p><pre><code class="bash">bitcoin-cli -datadir=./ sendtoaddress bcrt1qgq99zusgk3ekrzucs9uyqv5vpxnh66cjtwl6zc 0.01</code></pre><p>这个命令会返回交易哈希，比如我的哈希值是 <code>81be2e97507d7a274029ec4d5ce9728a54fe6d885aa0f12a13ec6f54eee66c26</code>。我们需要用这个交易哈希来查询交易结果和交易详情，像这样：</p><pre><code class="bash">bitcoin-cli -datadir=./ gettransaction 81be2e97507d7a274029ec4d5ce9728a54fe6d885aa0f12a13ec6f54eee66c26</code></pre><p>这笔交易此时就已经提交到链上了，但是也许你会注意到，查询交易详情返回的交易状态中，有一个 <code>&quot;confirmations&quot;: 0</code>，意味着交易还没有被确认，而且区块高度还停留在 <code>lastprocessedblock: 101</code> 上。因为比特币不会自动出块，这个时候查询接收地址的余额，能看出差异：</p><pre><code class="bash"># 查询到余额是 0.01bitcoin-cli -datadir=./ getreceivedbyaddress bcrt1qgq99zusgk3ekrzucs9uyqv5vpxnh66cjtwl6zc 0# 查询到余额是 0bitcoin-cli -datadir=./ getreceivedbyaddress bcrt1qgq99zusgk3ekrzucs9uyqv5vpxnh66cjtwl6zc 1</code></pre><p>因为我们之前有说明，最后一个参数是 0 代表包含未确认的交易，否则只查询确认的交易。我们刚刚发送的交易就还没有确认。如果想确认下来，就得用之前的 <code>generatetoaddress</code> 命令再挖一个区块出来：</p><pre><code class="bash">bitcoin-cli -datadir=./ generatetoaddress 1 bcrt1q6c8d9vw62rdee72xcqx3d97w8qh8mfg8ky8zjw</code></pre><p>现在再去查询交易状态，无论是确认数还是钱包余额，就都符合预期了。</p><h3 id="4-查看交易脚本"><a href="#4-查看交易脚本" class="headerlink" title="4. 查看交易脚本"></a>4. 查看交易脚本</h3><p>我们刚才发送的是一笔 P2WPKH 交易，因为现在比特币客户端默认使用原生 SegWit 的地址格式。</p><p>先了解一下 P2PKH 是什么，全称是 Pay to Public-Key Hash，我们使用的比特币地址本身就是一个公钥的子集，而 P2PKH 交易以账户地址为接收参数，所以命名为 P2PKH。我们常说的比特币原生地址，就是指 P2PKH 格式，一般以 <code>1</code> 开头，</p><p>相比 P2PKH，原生 SegWit 的地址格式叫 P2WPKH，中间多了个字母 W，全称是 Pay to Witness Public-Key Hash，特点是会把签名数据放在 witness 字段里，而不是每一笔 UTXO 的输出里，我们可以具体看一下，首先根据交易哈希，查询得到交易的全部数据：</p><pre><code class="bash">bitcoin-cli -datadir=./ getrawtransaction 81be2e97507d7a274029ec4d5ce9728a54fe6d885aa0f12a13ec6f54eee66c26</code></pre><p>会得到一大段编码后的数据，用这个命令来解码交易数据：</p><pre><code class="bash">bitcoin-cli -datadir=./ decoderawtransaction 020000000001018f4e8514038b93d6cc1d4f77b011f4726ba765d338bfdf1e6724d1844bc5d36e0000000000fdffffff0240420f0000000000160014400a517208b473618b98817840328c09a77d6b123eaaf629010000001600147ef4555b42b71e6ebecd687170c92ab64cce35500247304402202417ff3f6959a7d449849ae78fd5272826339cd7096ab02cdd7eccfc7779fb14022077e43ce155259a602b6172261b1d830d30e0de8b06cd6479cac02ea7c6928ff10121020b396a9dfa1655feef066fe03b403d3e4bdee41ef9b26551497c0921acbf6bc196000000</code></pre><p>查询得到的数据结构是这样：</p><pre><code class="json">&#123;  // ...  &quot;vin&quot;: [    &#123;      // ...      &quot;txinwitness&quot;: [        &quot;304402202417ff3f6959a7d449849ae78fd5272826339cd7096ab02cdd7eccfc7779fb14022077e43ce155259a602b6172261b1d830d30e0de8b06cd6479cac02ea7c6928ff101&quot;,        &quot;020b396a9dfa1655feef066fe03b403d3e4bdee41ef9b26551497c0921acbf6bc1&quot;      ],    &#125;  ],  &quot;vout&quot;: [    &#123;      &quot;value&quot;: 0.01000000,      &quot;scriptPubKey&quot;: &#123;        &quot;asm&quot;: &quot;0 400a517208b473618b98817840328c09a77d6b12&quot;,        &quot;desc&quot;: &quot;addr(bcrt1qgq99zusgk3ekrzucs9uyqv5vpxnh66cjtwl6zc)#nry368tt&quot;,        &quot;hex&quot;: &quot;0014400a517208b473618b98817840328c09a77d6b12&quot;,        &quot;address&quot;: &quot;bcrt1qgq99zusgk3ekrzucs9uyqv5vpxnh66cjtwl6zc&quot;,        &quot;type&quot;: &quot;witness_v0_keyhash&quot;      &#125;    &#125;,    &#123;      &quot;value&quot;: 49.98998590,      &quot;scriptPubKey&quot;: &#123;        // ...      &#125;    &#125;  ]&#125;</code></pre><p>首先关注 <code>txinwitness</code> 这个字段，它是一个数字，有两个部分，第一个部分是签名数据，第二个部分是公钥，这就是我们之前提到的 SegWit，对金额的签名不放在 <code>vout</code> 里，而是放在了 <code>vin</code> 里。</p><p>然后再关注 <code>scriptPubKey</code> 里的 <code>asm</code>，ASM 是 RedeemScript 的意思，表示满足什么样的条件就可以消费脚本中锁定的金额。是的我们即使是发起普通转账，实际上也是一种比特币脚本，金额锁定在了脚本中。我们查询到的脚本内容分为两段，第一段是 <code>0</code>，表示比特币脚本中的一个操作码 <code>OP_0</code>，第二段是 <code>400a517208b473618b98817840328c09a77d6b12</code>，其实就是钱包地址，经过 bech32 编码后会变成熟悉的样子 <code>bcrt1qgq99zusgk3ekrzucs9uyqv5vpxnh66cjtwl6zc</code>。</p><h3 id="5-用-btcdeb-调试"><a href="#5-用-btcdeb-调试" class="headerlink" title="5. 用 btcdeb 调试"></a>5. 用 btcdeb 调试</h3><p>刚才提到了 <code>OP_0</code> 这个操作码，它具体是什么呢？操作码是比特币脚本的关键，我们可以用 <code>btcdeb</code> 工具调试和观察一下。btcdeb 没有提供一键式的安装命令，可以按照 <a href="https://github.com/bitcoin-core/btcdeb?tab=readme-ov-file#installation">官方的教程</a> 先下载源码，然后编译安装。验证安装结果：</p><pre><code class="bash">btcdeb --version</code></pre><p><code>OP_0</code> 这个操作码本身干的事情很简单，就是把空数据压进栈结构里，尝试运行命令：</p><pre><code class="bash">btcdeb OP_0</code></pre><p>会看到这样的输出：</p><pre><code class="bash">script  |  stack --------+--------0       | #0000 0</code></pre><p>前面的 <code>script</code> 表示有一个操作 <code>0</code>, 也就是 <code>OP_0</code>，这里显示的时候自动隐去了 <code>OP_</code> 前缀。后面 <code>#0000 0</code> 则表示目前栈里内容为 0（空）。接下来的输入 <code>step</code> 命令，让 btcdeb 真正运行 <code>OP_0</code> 这个步骤，运行结果是这样，可以看到推了一个空数据到栈里，这就是 <code>OP_0</code> 干的事情：</p><pre><code class="bash">step        &lt;&gt; PUSH stack </code></pre><p>为了增加理解，我们举一个别的操作码例子来观察栈内数据的变化，尝试这个命令：</p><pre><code class="bash">btcdeb &#39;[OP_2 OP_3 OP_ADD]&#39;</code></pre><p>然后输出 <code>step</code> 命令，一直按回车直到脚本结束，输出内容的过程像是这样。默认内容是这样，此时脚本里有 3 个操作码等待执行，分别是 <code>OP_2</code>、<code>OP_3</code> 和 <code>OP_ADD</code>：</p><pre><code class="bash">script  |  stack --------+--------2       | 3       | OP_ADD  | #0000 2</code></pre><p>第一次回车执行了脚本的第一个步骤 <code>OP_2</code>，对应操作把数字 2 压入栈，执行结束后脚本里剩 2 个操作码了，同时 <code>stack</code> 中有了数字 2：</p><pre><code class="bash">step        &lt;&gt; PUSH stack 02btcdeb&gt; script  |  stack --------+--------3       |      02OP_ADD  | #0001 3</code></pre><p>第二次回车继续执行了 <code>OP_3</code> 操作码，把数字 3 压入栈，此时脚本里只剩 1 个操作码，栈中有数字 2 和数字 3:</p><pre><code class="bash">        &lt;&gt; PUSH stack 03btcdeb&gt; script  |  stack --------+--------OP_ADD  |      03        |      02#0002 OP_ADD</code></pre><p>第三次回车执行 <code>OP_ADD</code> 操作码，这个操作码会从栈里弹出两个数字，计算加法后把结果推回栈内，得到结果 5:</p><pre><code class="bash">        &lt;&gt; POP  stack        &lt;&gt; POP  stack        &lt;&gt; PUSH stack 05btcdeb&gt; script  |  stack --------+--------        |      05</code></pre><p>因为 <code>btcdeb</code> 的命令行输出并不是特别直观，所以这里尽管占用篇幅，也有必要把整个过程的输出都复制过来，还拆分了步骤，方便理解每一步在干什么。可以看到每一个操作码都会对应一些行为，这个行为是比特币程序里定义的，包括加法、减法等各种运算，也有一些行为更复杂的操作，或者对简单的操作码进行排列组合，达到实现更复杂功能的目的。我们还看到比特币脚本的执行是基于栈的，全部行为都发生在栈结构里，栈结构也就意味着完全没有动态内存分配之类的东西。</p><h3 id="6-自己编写比特币脚本-1"><a href="#6-自己编写比特币脚本-1" class="headerlink" title="6. 自己编写比特币脚本 (1)"></a>6. 自己编写比特币脚本 (1)</h3><p>刚才尝试了在 btcdeb 调试工具里运算加法，现在试着在实际的比特币交易中，写入脚本代码，并且在链上运算。这段是原始的操作码形式的脚本，要注意这个脚本是不安全的，属于自验证的脚本，任何人都可以花费这个脚本中的金额，只是在花费过程中，脚本表示的数字运算会在链上执行：</p><pre><code>[OP_2 OP_3 OP_ADD OP_5 OP_EQUAL]</code></pre><p>首先需要把操作码转变为十六进制形式，这个编码过程需要手动，或者写代码来操作。我们使用手动的方式，这个 <a href="https://wiki.bitcoinsv.io/index.php/Opcodes_used_in_Bitcoin_Script">比特币文档</a> 中列出了全部支持的操作码，以及对应的十六进制字符，到我们这个小脚本这里，对应关系就是：</p><table><thead><tr><th align="center">操作码</th><th align="center">十六进制</th></tr></thead><tbody><tr><td align="center">OP_2</td><td align="center">52</td></tr><tr><td align="center">OP_3</td><td align="center">53</td></tr><tr><td align="center">OP_ADD</td><td align="center">93</td></tr><tr><td align="center">OP_5</td><td align="center">55</td></tr><tr><td align="center">OP_EQUAL</td><td align="center">87</td></tr></tbody></table><p>因此我们按照依次拼接的顺序，得到了的十六进制脚本：</p><pre><code>5253935587</code></pre><p>接着生成 P2SH 地址。P2SH 的全称是 Pay to Script Hash，意思是支付到脚本哈希，或者说锁定金额到脚本中，相当于链上脚本的地址：</p><pre><code class="bash">bitcoin-cli -datadir=./ decodescript 5253935587</code></pre><p>命令输出中有一个 <code>p2sh-segwit</code> 字段，值是 <code>2NAzGPjCcg8DiykVTKLJRYbU2fejCEbdPbX</code>，把这个 P2SH 地址用作参数生成脚本的校验和，校验和是构造比特币交易必须要的一个参数：</p><pre><code class="bash">bitcoin-cli -datadir=./ getdescriptorinfo &quot;addr(2NAzGPjCcg8DiykVTKLJRYbU2fejCEbdPbX)&quot;</code></pre><p>得到 <code>descriptor</code> 的值为 <code>addr(2NAzGPjCcg8DiykVTKLJRYbU2fejCEbdPbX)#s260u65e</code>，后续用这个值作为脚本参数构造交易。</p><p>不过到这里还有个坑，比特币的 P2SH 脚本，只能用观察模式的钱包导入，所以需要新创建一个没有私钥的钱包：</p><pre><code class="bash">bitcoin-cli -datadir=./ createwallet &quot;arith-watch&quot; true true &quot;&quot; true</code></pre><p>用刚刚创建的新钱包，导入 P2SH 脚本。看到这个命令返回 <code>&quot;success&quot;: true</code>，才表示导入成功：</p><pre><code class="bash">bitcoin-cli -datadir=./ -rpcwallet=arith-watch importdescriptors &#39;[&#123;&quot;desc&quot;:&quot;addr(2NAzGPjCcg8DiykVTKLJRYbU2fejCEbdPbX)#s260u65e&quot;,&quot;timestamp&quot;:&quot;now&quot;,&quot;label&quot;:&quot;arith-2+3=5&quot;&#125;]&#39;</code></pre><p>现在有了 P2SH 的脚本地址，并且已经把脚本导入到钱包，接下来可以给脚本打钱了。这个命令从 learn-script 钱包转账 0.01 BTC 给脚本：</p><pre><code class="bash">bitcoin-cli -datadir=./ -rpcwallet=learn-script sendtoaddress 2NAzGPjCcg8DiykVTKLJRYbU2fejCEbdPbX 0.01</code></pre><p>挖一个区块让交易确认：</p><pre><code class="bash">bitcoin-cli -datadir=./ generatetoaddress 1 bcrt1q6c8d9vw62rdee72xcqx3d97w8qh8mfg8ky8zjw</code></pre><p>现在，这个脚本就上链并且有余额了。</p><h3 id="7-自己编写比特币脚本-2"><a href="#7-自己编写比特币脚本-2" class="headerlink" title="7. 自己编写比特币脚本 (2)"></a>7. 自己编写比特币脚本 (2)</h3><p>目前这个脚本地址里的钱，任何人都可以消费，消费的同时会运算一下 <code>2+3</code> 这个表达式，并且判断结果是否为 <code>5</code>。接下来构建一笔花费脚本金额的交易，真正花掉刚才存进脚本的钱。准备一个收款地址：</p><pre><code class="bash">bitcoin-cli -datadir=./ -rpcwallet=learn-script getnewaddress</code></pre><p>我新建的地址是 <code>bcrt1q0n2x7030x59j5ql9pp6mw0tps74ag0znrdp45r</code>。用这个地址构建一笔交易，注意这里 <code>inputs</code> 中的 <code>txid</code>，是刚才给 P2SH 转账的那一笔交易哈希：</p><pre><code class="bash">bitcoin-cli -datadir=./ -named createrawtransaction \  inputs=&#39;[&#123;&quot;txid&quot;:&quot;b952acd06a4f7edd7b2d5da0d509d01dfbb8e49fa15123d9cd5d3d23f944cdc2&quot;,&quot;vout&quot;:0&#125;]&#39; \  outputs=&#39;&#123;&quot;bcrt1q0n2x7030x59j5ql9pp6mw0tps74ag0znrdp45r&quot;:0.009&#125;&#39;</code></pre><p>在构建的交易中添加自动找零参数：</p><pre><code class="bash">bitcoin-cli -datadir=./ -rpcwallet=learn-script \  fundrawtransaction 0200000001c2cd44f9233d5dcdd92351a19fe4b8fb1dd009d5a05d2d7bdd7e4f6ad0ac52b90000000000fdffffff01a0bb0d00000000001600147cd46f3e2f350b2a03e50875b73d6187abd43c5300000000</code></pre><p>关键的一步，用钱包给这笔交易签名，注意这里是给找零之后的交易数据进行签名，如果不找零，节点会把找零金额当作手续费，而节点默认还有手续费的上限值，如果这一步没找零，下一步会触发手续费上限报错：</p><pre><code class="bash">bitcoin-cli -datadir=./ -rpcwallet=learn-script \  signrawtransactionwithwallet 0200000001c2cd44f9233d5dcdd92351a19fe4b8fb1dd009d5a05d2d7bdd7e4f6ad0ac52b90000000000fdffffff02a0bb0d00000000001600147cd46f3e2f350b2a03e50875b73d6187abd43c5360a0d92901000000160014a3e136e24d5a8db14f15016b99fb21ea4b0b69da00000000</code></pre><p>最后，把签名好的交易数据广播出去就行了：</p><pre><code class="bash">bitcoin-cli -datadir=./ sendrawtransaction 02000000000101c2cd44f9233d5dcdd92351a19fe4b8fb1dd009d5a05d2d7bdd7e4f6ad0ac52b90000000017160014c2d5ade24c1d0b9f27f651a71c3fe49d23d0ae13fdffffff02a0bb0d00000000001600147cd46f3e2f350b2a03e50875b73d6187abd43c5360a0d92901000000160014a3e136e24d5a8db14f15016b99fb21ea4b0b69da024730440220406a51d43ade05b240fcf2d14b58c90f31ebc705ab262189949355cac54d0431022051b592c570ef960a35e8509766e903ba836e3bcd1fb3c5cc211f0ff3442283550121021ff283ca8c9ecb45c8e19eacb7e8ae6fcb27d8addd38011d633e396487db44e300000000</code></pre><p>记得再挖一个区块让交易确认：</p><pre><code class="bash">bitcoin-cli -datadir=./ generatetoaddress 1 bcrt1q6c8d9vw62rdee72xcqx3d97w8qh8mfg8ky8zjw</code></pre><p>查看交易状态，验证交易已被花费，如果返回空值，说明已被花费。这里查的交易哈希是当时用钱包给脚本转账 0.01 BTC 那一笔交易的哈希：</p><pre><code class="bash">bitcoin-cli -datadir=./ gettxout b952acd06a4f7edd7b2d5da0d509d01dfbb8e49fa15123d9cd5d3d23f944cdc2 0</code></pre><h3 id="8-Troubleshooting"><a href="#8-Troubleshooting" class="headerlink" title="8. Troubleshooting"></a>8. Troubleshooting</h3><p>我本地的操作环境以及软件脚本是：</p><pre><code class="text">OS: MacOSbitcoind: v29.0.0btcdeb：5.0.24</code></pre>]]></content>
  </entry>
  <entry>
    <title>我从王垠的计算机科学视频班学到了什么</title>
    <link href="https://smallyu.net/2025/07/08/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%A7%86%E9%A2%91%E7%8F%AD%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%88/"/>
    <id>blog:https://smallyu.net/2025/07/08/%E6%88%91%E4%BB%8E%E7%8E%8B%E5%9E%A0%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%A7%86%E9%A2%91%E7%8F%AD%E5%AD%A6%E5%88%B0%E4%BA%86%E4%BB%80%E4%B9%88/</id>
    <published>2025-07-07T19:08:42.000Z</published>
    <updated>2026-02-28T07:30:46.814Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<blockquote>
<p>为了行文方便，这篇文章不使用 “王垠老师” 这样的尊称，直接称呼名字 “王垠”。</p>
</blockquote>
<p>大约 2 个月前，我开始报名学习王垠的 <a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>为了行文方便，这篇文章不使用 “王垠老师” 这样的尊称，直接称呼名字 “王垠”。</p></blockquote><p>大约 2 个月前，我开始报名学习王垠的 <a href="https://www.yinwang.org/blog-cn/2025/05/12/cs-video-course">计算机科学视频班</a>（基础班），经过 1 个月的学习后毕业，大概用了 120 个小时的学习时长。“120 个小时” 这个数字是经过认真估算的，包含了观看视频的时间和做练习题的时间。因为视频课的学习节奏由自己把控，毕业速度因人而异，所以 “1 个月” 这样的描述不够直观，用小时数更加容易理解。 120 个小时意味着，如果一天学 2 个小时的话，需要 60 天。</p><p>王垠并不认识我，但我早就认识王垠；我以前不是王垠的学生，但王垠早就是我的老师了。我关注王垠的博客多年，已经从他的博客文章中受益很多。而这次系统学习了视频课的课程，像是打开了新世界的大门。这并不夸张，我可以负责任地站在学习过课程的立场上说，王垠没有吹牛，他的课程真的有他说的那么好。你可以不赞同王垠的观点，也可以不喜欢王垠的人生态度，但是不可能怀疑王垠在计算机科学，尤其是编程语言领域的研究水平，也完全不需要担心王垠这样对自己和世界都如此较真的人，会拿一些没有含量的课程出来忽悠人。</p><p>现在毕业后经过半个月时间的沉淀，我想分享一下 “从课程中能学到什么” 这个话题。没有在毕业当天做总结，是因为怕有点浮燥总结不全，或者掺杂太多个人经历。半个月的时间其实也不够，我没有太多时间复习，课程也远远没来得及发挥出应有的成果，但是现在做总结并不妨碍以后对课程内容有进一步的感悟。王垠曾经有一篇文章《爱因斯坦谈教育》，里面提到爱因斯坦说 “被传授的知识应该被当成宝贵的礼物”，我在学完课程后无意间翻到这篇文章，看到这句话后，突然对这句话有了切实的理解。</p><p>因为课程内容是保密的，我不会透露课程具体的学习内容，只基于公开的招生说明中的内容进行解释。对于计算机初学者来说，从课程中能学到的最直接的知识，就是函数、链表、二叉树等基础的编程概念，内容涵盖了大学本科阶段的整个过程。而第 6 课关于解释器的部分，属于课程的 “最终成果”，对应一些美国顶尖大学本科高年级，至硕士低年级的阶段。为什么王垠在招生说明里的描述是 “大学博士阶段才可能学到的内容” 呢？因为中国的大学没有编程语言专业，本科课程没有教解释器的，即使到了研究生阶段，lambda 演算也属于选修课，博士早期才会接触到解释器的实现是正常现象。所以王垠的描述真的没有夸大。</p><p>解释器这种内容在中国的教育体系里本来就很稀有，比较高级和精练的教程更是少见。举例来说，当你学完了王垠的课，然后去 bilibili 上搜一些解释器相关的教程，你就会明白这些公开教程里的解释器有多么差劲，不但一眼就能看出它们缺什么要素、存在什么问题，还知道如何改进、如何用最简洁的代码写出最可靠的实现。为什么解释器这个东西重要呢？同样举个例子，以太坊的虚拟机（EVM）就是一个解释器，只不过 EVM 并不是在对编程语言做解释，而是在对以太坊的操作码（Opcodes）做解释，每个操作码都对应在栈结构上的一个动作。所以学过了解释器之后，对 EVM 的原理会有不一样的理解。</p><p>对于有计算机经验的学生来说，从课程上可以学到的，就不只是表面上的知识了。比如，课程只用到非常少的编程要素，就表达了第 1 课到第 6 课的全部内容，如果王垠不是对计算机理论有非常深刻的理解，不可能做到这种地步的深入简出。从学习者的角度，一方面可以思考一下为什么课程内容能如此精致，组织这些课程内容的思路是什么，这种高度抽象的思维背后，需要怎样的功底。另一方面由于课程内容自成一体，学习者完全有可能做到自己复刻整个课程内容，就像是手里的一个精致的玩物，随时可以拿出来复习把玩。</p><p>王垠最近在微博上评论 AI 编程的时候提到，AI 无法写出 “王垠级别” 的代码。什么是 “王垠级别” 的代码呢？上过课就知道了。我在做练习题的时候，被助教提醒最多次的问题，就是 “代码复杂”，有时候是写法上的复杂，有时候是复杂度上的复杂，但是每一次把代码写到符合课程标准之后，又不禁感叹原来代码可以如此精巧。我已经有多年的编程经验，让代码运行出练习题的结果并不难，但是把代码写的足够漂亮却不容易。假如以前给公司写的都是这种质量的代码，那公司可就太占便宜了。</p><p>还不止这些，也许有人看到招生说明会怀疑，一节选修课真能让人学会一种新的编程语言吗？我想提醒的是，不要忘了给你讲课的人是谁，是真正的编程语言专家。</p>]]></content>
  </entry>
  <entry>
    <title>区块链技术面试题（2025年版）</title>
    <link href="https://smallyu.net/2025/07/06/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%882025%E5%B9%B4%E7%89%88%EF%BC%89/"/>
    <id>blog:https://smallyu.net/2025/07/06/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%882025%E5%B9%B4%E7%89%88%EF%BC%89/</id>
    <published>2025-07-06T10:38:03.000Z</published>
    <updated>2025-11-09T09:22:13.316Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>比起 2023 年版本相对宏观视角的《<a]]></summary>
    <content type="html"><![CDATA[<p>比起 2023 年版本相对宏观视角的《<a href="/2023/07/12/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E9%9D%A2%E8%AF%95%E9%A2%98/">区块链技术面试题</a>》，这个版本稍微侧重工程实践一点，包含了更多技术细节。这两个版本的内容是互相补充的，不是升级性质的关系。这些题目仅仅只是基于我的个人经历，就像很多面试官在做的那样，自己会什么才问什么，问不出自己不会的东西，所以问出来的问题，无论广度和深度，都是受限于个人水平的，我也是：</p><ol><li>以太坊客户端为什么分为执行层和共识层？</li><li>以太坊的 PoS 运作流程，如何初始化一个 PoS 网络？</li><li>以太坊 PoS 的软分叉和恢复机制？Cardano 的 PoS 和以太坊一样吗？</li><li>以太坊节点有哪些类型，分别适用于什么场景？</li><li>EVM 的执行为什么是单线程的？为什么至今全世界的团队都做不出来 “并行EVM” 这种东西？</li><li>Solidity 语言有 GC 吗？是如何处理内存动态分配问题的？</li><li>Solidity 什么场景下需要内联汇编？</li><li>PBFT 共识有了解吗，大体流程是怎么样的？</li><li>PBFT 的容错能力公式是怎么来的，为什么是那个数字，而不是其他数字？</li><li>PBFT 为什么需要第二次投票？</li><li>Solana 的共识机制大体是怎样的？TowerBFT 是在对区块投票吗？</li><li>为什么 Solana 的智能合约可以并行执行，以太坊的不可以？</li><li>Cosmos 节点的升级流程是怎样的？和以太坊有什么不同？这种模式有什么风险？</li><li>Op Rollup 的大体流程？ZK Rollup 在 Op 模式的基础上，优化了哪个环节？</li><li>以太坊 L2 的资产跨链？与不同网络之间的资产跨链相比，技术上有什么异同？</li><li>以太坊最近有个大版本升级，引入的 EIP-7702 是干什么的？和 AA 钱包是什么关系？</li><li>自己平时思考过哪些区块链相关的、有意思的技术类话题？</li></ol><p>这些是我现在能想到的全部问题了。比这些问题更加有深度的工程化的内容，我也只是大概知道点方向，没亲手搞过。这两年的经历还算丰富，对比两个版本的面试题列表能看出不少变化。希望我自己可以再接再厉，不要迷路。</p><p>如果你是区块链行业的求职者，尤其是经验尚浅的工程师，千万不要被上面列出来的问题给吓到了。真实的面试过程中，几乎不会出现如此有深度的思考题。更多的问题类似于，“以太坊交易有哪些常用字段？”、“怎么取消一笔已经发送的交易？”、“Solidity 的可重入攻击是什么？”、“Op Stack 有哪几个组件？”、“以太坊合约的 create2 是什么？” 等等。放心大胆的去求职，真正懂技术的人没有那么多。</p><p>现在的区块链行业有个问题，就是没有系统化的理论知识，只有一些工业界前沿的、散碎的工程化尝试。比如对比编程语言专业，从丘奇和图灵的计算模型，到函数式编程语言、编译器、类型系统等，经过几十年学术界和工业界的发展，有高度抽象的理论支撑，有实际落地的工业应用，已经比较成熟。而区块链这种东西比较新，2008 年诞生，2013 年开始步入大众视野，短短几年的时间远没有建立起学术体系，行业内的项目方则各自为营，都在搞自己的标准、各自定义术语，账户模型、共识、合约、跨链，每条链都不一样。有人能统一区块链的理论体系吗？Vitalik 来都不行，要是 Satoshi 出山也许有希望。</p><p>因此不需要相信什么大学里的 “区块链专业”，没有出过校门的老师和教授，怎么可能有时间把区块链的技术抽象成理论、写成教材、编成课程，然后给学生讲课呢，这个周期得多长？也因此不要太相信已经出版的技术类书籍，书籍的出版需要几年时间，等书发表出来，世界已经变了。今年下半年有个比特币会议，两年前发明了铭文这个概念的项目方，可能又要发布新东西了，难道学校的课程或者书籍能跟得上这种节奏吗？行业最前沿的技术，只能来自各个项目方切实的探索和尝试，也自然就会造成不成体系的现象。</p>]]></content>
  </entry>
  <entry>
    <title>Rust 语言容易让新手困惑的一个“过度优化”</title>
    <link href="https://smallyu.net/2025/06/30/Rust%E8%AF%AD%E8%A8%80%E5%AE%B9%E6%98%93%E8%AE%A9%E6%96%B0%E6%89%8B%E5%9B%B0%E6%83%91%E7%9A%84%E4%B8%80%E7%A7%8D%E8%BF%87%E5%BA%A6%E4%BC%98%E5%8C%96/"/>
    <id>blog:https://smallyu.net/2025/06/30/Rust%E8%AF%AD%E8%A8%80%E5%AE%B9%E6%98%93%E8%AE%A9%E6%96%B0%E6%89%8B%E5%9B%B0%E6%83%91%E7%9A%84%E4%B8%80%E7%A7%8D%E8%BF%87%E5%BA%A6%E4%BC%98%E5%8C%96/</id>
    <published>2025-06-29T18:05:25.000Z</published>
    <updated>2025-07-01T13:18:38.203Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>假如我们现在要写一些代码，随便用 <code>cargo new</code> 一个项目就行，然后写一个函数]]></summary>
    <content type="html"><![CDATA[<p>假如我们现在要写一些代码，随便用 <code>cargo new</code> 一个项目就行，然后写一个函数 <code>append</code>，函数的功能很好理解，就是把两个传入的字符串给拼接起来，第一个参数是字符串（的引用类型），第二个参数也是字符串，假如我们的参数是 <code>Hello</code> 和 <code>, world</code>，函数调用后会返回 <code>Hello, world</code> 给我们。函数具体这样写：</p><pre><code class="rust">fn append(s1: &amp;String, s2: &amp;String) -&gt; String &#123;    return s1.clone() + s2.clone().as_str();&#125;</code></pre><p>不需要关心 <code>return</code> 后面的语句写法，这不是我们关注的重点。在入口函数 <code>main</code> 里调用这个 <code>append</code>，运行一下，输出的内容会和我们预期一样，打印出拼接后的字符串 <code>Hello, world</code>：</p><pre><code class="rust">fn main() &#123;    let s1: String = String::from(&quot;Hello&quot;);    let s2: String = String::from(&quot;, world&quot;);    println!(&quot;&#123;&#125;&quot;, append(&amp;s1, &amp;s2));&#125;</code></pre><p>那么现在，保持 <code>append</code> 函数完全不变，在 <code>main</code> 函数里修改两个字符串的定义，整个 <code>main</code> 函数变成这样，猜一下输出结果会是什么？注意 Rust 是静态类型的语言，编译器对于变量类型往往具有严格的定义和判断：</p><pre><code class="rust">fn main() &#123;    let s1: Box&lt;String&gt; = Box::new(String::from(&quot;Hello&quot;));    let s2: Box&lt;String&gt; = Box::new(String::from(&quot;, world&quot;));    println!(&quot;&#123;&#125;&quot;, append(&amp;s1, &amp;s2));&#125;</code></pre><p>我们首先的直觉是应该编译报错，因为 <code>s1</code> 的类型是 <code>Box&lt;String&gt;</code>，调用 <code>append</code> 函数的时候，传入的参数为 <code>&amp;s1</code>，对应的类型为 <code>&amp;Box&lt;String&gt;</code>，而显然 <code>append</code> 函数的定义是没有修改的，接收的参数类型仍然是 <code>&amp;String</code>。那么这种情况下，为什么编译器没有报错，而且代码还能正常运行，输出了 <code>Hello, world</code> 的结果？(先别管这里的 <code>Box</code> 是什么，反正是一种类型)</p><p>我们接着再修改一下 <code>main</code> 函数的内容，把字符串的定义改为这样：</p><pre><code class="rust">fn main() &#123;    use std::rc::Rc;    let s1: Rc&lt;String&gt; = Rc::new(String::from(&quot;Hello&quot;));    let s2: Rc&lt;String&gt; = Rc::new(String::from(&quot;, world&quot;));    println!(&quot;&#123;&#125;&quot;, append(&amp;s1, &amp;s2));&#125;</code></pre><p>代码能通过编译吗？能正常运行吗？<code>append</code> 函数的定义仍然没有变，这里 <code>main</code> 函数中 <code>s1</code> 的类型变成了 <code>Rc&lt;String&gt;</code>，相应的传入 <code>append</code> 函数做参数的时候，类型变为了 <code>&amp;Rc&lt;String&gt;</code>。但是为什么，编译器没有报错，而且还能正常运行出结果，输出 <code>Hello, world</code>？（同样别管 <code>Rc</code> 是什么，也是一种类型）</p><p>根据刚才的代码片段，我们观察到一个现象：当函数的参数类型是 <code>&amp;String</code> 的时候，既可以接受 <code>&amp;String</code> 类型的参数，也可以接收 <code>&amp;Box&lt;String&gt;</code> 类型的参数，还可以接收 <code>&amp;Rc&lt;String&gt;</code> 类型的参数。</p><p>再疯狂一点，如果把 <code>main</code> 函数改成这样呢？</p><pre><code class="rust">fn main() &#123;    let s1: Box&lt;Box&lt;Box&lt;Box&lt;String&gt;&gt;&gt;&gt; = Box::new(Box::new(Box::new(Box::new(String::from(&quot;Hello&quot;)))));    let s2: Box&lt;Box&lt;Box&lt;Box&lt;String&gt;&gt;&gt;&gt; = Box::new(Box::new(Box::new(Box::new(String::from(&quot;, world&quot;)))));    println!(&quot;&#123;&#125;&quot;, append(&amp;s1, &amp;s2));&#125;</code></pre><p>如果把 <code>main</code> 函数改成这样呢？</p><pre><code class="rust">fn main() &#123;    use std::rc::Rc;        let s1: Rc&lt;Rc&lt;Rc&lt;Rc&lt;String&gt;&gt;&gt;&gt; = Rc::new(Rc::new(Rc::new(Rc::new(String::from(&quot;hello&quot;)))));    let s2: Rc&lt;Rc&lt;Rc&lt;Rc&lt;String&gt;&gt;&gt;&gt; = Rc::new(Rc::new(Rc::new(Rc::new(String::from(&quot;, world&quot;)))));    println!(&quot;&#123;&#125;&quot;, append(&amp;s1, &amp;s2));&#125;</code></pre><p>结果是 <code>main</code> 函数都可以正常运行，输出 <code>Hello, world</code> 的结果。</p><p>为了进一步观察关于类型的问题，现在新写两个 append 函数，<code>append2</code> 函数接收的类型是 <code>&amp;Box&lt;String&gt;</code>，而 <code>append3</code> 函数接收的类型是 <code>&amp;Rc&lt;String&gt;</code>：</p><pre><code class="rust">fn append2(s1: &amp;Box&lt;String&gt;, s2: &amp;Box&lt;String&gt;) -&gt; Box&lt;String&gt; &#123;    let mut result = (**s1).clone();    result.push_str(s2);    Box::new(result)&#125;use std::rc::Rc;fn append3(s1: &amp;Rc&lt;String&gt;, s2: &amp;Rc&lt;String&gt;) -&gt; Rc&lt;String&gt; &#123;    let mut result = (**s1).clone();    result.push_str(s2);    Rc::new(result)&#125;</code></pre><p>接下来分析一下，对于下面的 <code>main</code> 函数代码，编译器会在哪一行报错？</p><pre><code class="rust">fn main() &#123;    let s1: Box&lt;Box&lt;Rc&lt;Rc&lt;String&gt;&gt;&gt;&gt; = Box::new(Box::new(Rc::new(Rc::new(String::from(&quot;hello&quot;)))));    let s2: Box&lt;Box&lt;Rc&lt;Rc&lt;String&gt;&gt;&gt;&gt; = Box::new(Box::new(Rc::new(Rc::new(String::from(&quot;, world&quot;)))));    println!(&quot;&#123;&#125;&quot;, append(&amp;s1, &amp;s2));    println!(&quot;&#123;&#125;&quot;, append2(&amp;s1, &amp;s2));    println!(&quot;&#123;&#125;&quot;, append3(&amp;s1, &amp;s2));&#125;</code></pre><p>这样呢，字符串的类型再扩展一下，编译器还会报错吗，在哪一行？</p><pre><code class="rust">fn main() &#123;    let s1: Box&lt;Box&lt;Rc&lt;Rc&lt;Box&lt;Box&lt;String&gt;&gt;&gt;&gt;&gt;&gt; = Box::new(Box::new(Rc::new(Rc::new(Box::new(Box::new(String::from(&quot;hello&quot;)))))));    let s2: Box&lt;Box&lt;Rc&lt;Rc&lt;Box&lt;Box&lt;String&gt;&gt;&gt;&gt;&gt;&gt; = Box::new(Box::new(Rc::new(Rc::new(Box::new(Box::new(String::from(&quot;, world&quot;)))))));    println!(&quot;&#123;&#125;&quot;, append(&amp;s1, &amp;s2));    println!(&quot;&#123;&#125;&quot;, append2(&amp;s1, &amp;s2));    println!(&quot;&#123;&#125;&quot;, append3(&amp;s1, &amp;s2));&#125;</code></pre><p>Rust 把这种语言特性叫做人体工学设计，为了减轻开发人员的负担。但是 Rust 在设计动不动会把变量给 move 掉、不得不使用 <code>&#39;</code> 单引号写法的时候，却放弃了人体工学，把内存安全放在了更重要的地位……倒是也没什么错，毕竟 Rust 只有内存安全是绝不能放松的。</p><p>最后再来个进阶难度的，假如在实际的业务场景中，有一个叫 <code>do_something</code> 的函数，接收泛型类型的参数，我们需要对这个函数基于原有逻辑做一些改动，原本的函数逻辑是这样：</p><pre><code class="rust">fn do_something&lt;T1, T2&gt;(t1: T1, t2: T2) &#123;    println!(&quot;&#123;&#125;&quot;, append(&amp;t1, &amp;t2));&#125;</code></pre><p>现在新增加一些处理：</p><pre><code class="rust">fn do_something&lt;T1, T2&gt;(t1: T1, t2: T2) &#123;    // 增加一个函数来处理 t1    handle_t1(&amp;t1);      println!(&quot;&#123;&#125;&quot;, append(&amp;t1, &amp;t2));&#125;</code></pre><p>那么问题来了，参数 <code>t1</code> 的类型是什么？<code>handle_t1</code> 函数的参数类型应该如何定义？在原有逻辑中，<code>t1</code> 作为参数对 <code>append</code> 函数进行了调用，是否意味着 <code>t1</code> 的类型是 <code>&amp;String</code>？如果不是 <code>&amp;String</code>，<code>t1</code> 的类型可能是什么？</p>]]></content>
  </entry>
  <entry>
    <title>最近一个月在区块链行业找工作的面试记录</title>
    <link href="https://b.smallyu.net/2025/06/28/%E6%9C%80%E8%BF%91%E4%B8%80%E4%B8%AA%E6%9C%88%E5%9C%A8%E5%8C%BA%E5%9D%97%E9%93%BE%E8%A1%8C%E4%B8%9A%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E9%9D%A2%E8%AF%95%E8%AE%B0%E5%BD%95/"/>
    <id>blog-b:https://b.smallyu.net/2025/06/28/%E6%9C%80%E8%BF%91%E4%B8%80%E4%B8%AA%E6%9C%88%E5%9C%A8%E5%8C%BA%E5%9D%97%E9%93%BE%E8%A1%8C%E4%B8%9A%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E9%9D%A2%E8%AF%95%E8%AE%B0%E5%BD%95/</id>
    <published>2025-06-28T08:37:40.000Z</published>
    <updated>2025-12-04T13:51:13.025Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近面试的公司都不合适，所以还在继续找工作。对于找工作这件事情，我的理解是这样：</p>
<p>找工作的过程本就应该是缓慢的，因为好的工作机会，不可能一年 365]]></summary>
    <content type="html"><![CDATA[<p>最近面试的公司都不合适，所以还在继续找工作。对于找工作这件事情，我的理解是这样：</p><p>找工作的过程本就应该是缓慢的，因为好的工作机会，不可能一年 365 天都在等你，工作机会和优秀人才都有一个窗口期，只有窗口期恰好对得上，企业在找人，人在找工作，才能合适，这个事情看缘分。也因此没有合适的工作，或者有工作但不合适也正常。</p><p>关于最近失业的原因，我写在了这里：《<a href="/2025/05/15/%E5%85%AC%E5%8F%B8%E6%B2%A1%E4%BA%86%EF%BC%8C%E6%88%91%E5%8F%88%E5%A4%B1%E4%B8%9A%E4%BA%86/">公司没了，我又失业了</a>》</p><h3 id="最近的面试经历"><a href="#最近的面试经历" class="headerlink" title="最近的面试经历"></a>最近的面试经历</h3><ul><li>2025.05.25（不知道公司名）</li></ul><p>一个做 BTCFi 类型的项目，工作会涉及到写比特币脚本、闪电网络、EVM 桥等内容。具体没问出来项目到底是干什么的。</p><ul><li>2025.05.28（北京星联九宇科技）</li></ul><p>线下面试，很小的公司，没什么钱那种，在招聘比较基础水平的合约开发，主要是能发 token，最好能部署 Uniswap 就够了。说是想发行十二生肖 token，把中国文化推广到全世界……</p><ul><li>2025.06.12（成都 pkCoin）</li></ul><p>做生态工具、打新一类的事情。团队三个人都是做 web2 的，不懂 web3，要招聘 web3 方面的专家带领团队去做事。而且他们说不差钱。</p><p>我经常不明白一个问题，为什么投资人和创始人经常找一帮不懂行的人做事，而真正懂行懂技术的人却在这里海投简历？</p><p>因为面试官在面试过程中表现出了很不尊重候选人的举动，虽然不是针对我，但是我仍然觉得不应该去这样的公司。</p><ul><li>2025.06.18（starcoin）</li></ul><p>一条 PoW + Move 智能合约的链，招聘 Rust 开发，工作相对底层一点，比如会用到 MPP 数据结构之类的。这条链仍然用了以太坊的账户模型，是基于某条链做二次开发。</p><ul><li>2025.06.23（HashKey）</li></ul><p>合规交易所想搞一条以太坊 Layer 2 的链，基于 Op Stack，后续也许有一些合规方面的需求，比如不允许某些块打包之类的。</p><ul><li>2025.06.23（云暮怀谷）</li></ul><p>技术合伙人职位，BOSS 上随便投的，还让我面试，面试也是瞎聊。</p><ul><li>2025.06.24（公司中文名叫枷箱，上海的一家公司）</li></ul><p>被惊艳到了，女性面试官，但是对于技术的深度和广度都很好。语速比较快，但是条理清晰，说明思维活跃。技术能力上，算是最近遇到的比较厉害的那种人了。</p><p>但是公司项目听起来像是软件外包一类，上半年做了一个 TG 上的小红书一类的项目，最近开始做一个 C2C 商城的项目，其中涉及到区块链的部分是，商城里会用到加密货币来做支付。</p><ul><li>2025.06.25（枷箱，leader面）</li></ul><p>这个 Leader 叫孙总，技术很菜，而且不尊重人，几乎没有沟通的态度，真是浪费我的时间和心情。</p><ul><li>2025.06.25（UnicornX）</li></ul><p>一个 memecoin 发射平台，后端开发一方面要做交易的解析，主要是 Solana 和 BSC 两条链，另一方面是一些日常业务的开发，比如网站后端、APP 后端的工作。</p><ul><li>2025.06.27（alcove）</li></ul><p>Aptos 生态的一个数据索引项目，跟 Aptos 华语社区关系密切，主要做一些链数据的解析、索引等后端工作，因为 Aptos 是 Rust 开发的，所以解析器要基于 Rust。周边服务用 ts 比较多。</p><h3 id="最近的学习成果"><a href="#最近的学习成果" class="headerlink" title="最近的学习成果"></a>最近的学习成果</h3><p>不知道最近的面试频率算不算正常，好像不是很多，尤其是和以前比起来。不过我这一个多月可真没闲着，我学完了王垠老师的课程，还自学了 Solana 合约的开发、花时间把教程写了下来。</p><p>另外，我已经给我们的解释器写了简单的 parser，现在有了 parser 和解释器结合，可以执行这样复杂的语句了（用 Y combinator 递归计算阶乘）：</p><pre><code class="js">var exp = `(let Y  (fun f    (call      (fun x (call f (fun v (call (call x x) v))))      (fun x (call f (fun v (call (call x x) v))))    ))  (call    (call Y      (fun fact        (fun n          (if (== n 0)              1              (* n (call fact (- n 1)))          ))))    5))`;show( execExpr(exp) ); // 120</code></pre><p>我最近也确实自己写了一个 Go 语言版本的解释器，课程内实现的是 js 版本和 Rust 版本，即使是选修课也是不教 Go 语言的。</p><p>接下来还有很多东西可以学习，很多事情可以做，我还得再想想到底应该干什么。祝福看到这里的人工作顺利，心理健康，不要成为失败朋克，要做赛博朋克。</p>]]></content>
  </entry>
  <entry>
    <title>Solana 智能合约开发教程 (3)</title>
    <link href="https://b.smallyu.net/2025/06/28/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B3/"/>
    <id>blog-b:https://b.smallyu.net/2025/06/28/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B3/</id>
    <published>2025-06-27T16:01:01.000Z</published>
    <updated>2025-12-03T09:25:53.988Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这个一个零基础的系列教程，可以从最基本的操作开始学会 Solana 智能合约的开发。</p>
<ul>
<li>《<a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这个一个零基础的系列教程，可以从最基本的操作开始学会 Solana 智能合约的开发。</p><ul><li>《<a href="/2025/06/24/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B1/">第一篇</a>》：基础环境安装、HelloWorld 合约部署、链上合约调用</li><li>《<a href="/2025/06/26/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B2/">第二篇</a>》：实现 USDT 合约的最小模型，自定义数据结构与方法</li><li>《<a href="/2025/06/28/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B3/">第三篇</a>》：使用官方 SPL 库复用合约功能，完成标准化代币的发行</li></ul></blockquote><p>你也许注意到，在编写智能合约的过程中，对于程序逻辑的描述反而是轻量的，比较复杂的部分是不同类型的 <code>#[account]</code> 宏，以及去了解宏接受的参数，比如是否允许自动创建账户、如果创建应该租用多少个字节的空间等，因为 Solana 的全部账户数据需要加载到节点服务器的内存中，价格比较昂贵，所以要求开发者对于空间的占用计算比较精细。而 Solana 的账户体系又有点复杂，需要稍微理解一下。</p><h3 id="1-命令行工具发行代币"><a href="#1-命令行工具发行代币" class="headerlink" title="1. 命令行工具发行代币"></a>1. 命令行工具发行代币</h3><p>对于发行 USDT 这种经典场景，Solana 已经封装好了智能合约的库函数，可以直接调用，甚至封装好了命令行工具，只需要简单的操作，不需要写合约，就可以发行代币。Solana 把这些代币统称为 SPL Token。创建一个 6 位精度的 SPL Token 的命令是这样，注意不需要写代币名字：</p><pre><code class="bash">spl-token create-token --decimals 6</code></pre><p>命令行运行结束后，会输出一个 <code>Address</code>，这个就是 SPL Token 的代币地址，比如我得到的地址是 <code>E75GMXAfJ91XuRboSpjwkDmta45Etgt3F3Gf5WLZvLbV</code>，可以在 <a href="https://explorer.solana.com/address/E75GMXAfJ91XuRboSpjwkDmta45Etgt3F3Gf5WLZvLbV?cluster=devnet">区块链浏览器</a> 上查到。</p><p>接下来需要一个操作，来给你本地的账户，在这个 USDT 代币上创建一个关联账户（Associated Token Account，ATA）。这个创建关联账户的动作，相当于在合约上实例化一个数据结构，这个数据结构里保存了你的 USDT 余额等信息，如果没有这个数据，USDT 代币的合约上就找不到你。</p><p>用 “账户” 这个词可能有点迷惑，我本地已经有账户了，还能用 <code>solana address</code> 命令看到账户地址，为什么还需要专门调用 USDT 的合约，创建什么 ATA 账户？可以理解为，合约里本来有个空的 map{}，创建 ATA 账户就是向 map 里插入了一条数据，key 是你本地的账户地址，value 是 USDT 的余额信息。如果 map 里没有你的信息，你甚至不能接受 USDT 的转账。</p><p>那么为什么 Solana 要这么设计，必须先在 map 里开辟空间，才能接受转账呢？因为一开始有提到过，对于 Solana 来说，链上空间是比较珍贵的，map 里开辟一个键值对的空间，也就是创建 ATA 账户，需要占用 165 个字节的内存，这 165 字节不是免费使用的，可以使用命令 <code>solana rent 165</code> 来计算字节数对应的费用，比如这里就会输出 <code>0.00203928 SOL</code>，也就是你创建 ATA 账户的交易，在手续费之外，会多支付这么些租金。所以必须要有创建 ATA 账户这个操作，主要是为了收费。</p><p>回到我们的操作，创建 ATA 账户的命令是：</p><pre><code class="bash">spl-token create-account E75GMXAfJ91XuRboSpjwkDmta45Etgt3F3Gf5WLZvLbV</code></pre><p>这个命令会显示 <code>Creating account</code>，后面是你的 ATA 地址，比如我的是 <code>E5XmcEJhhGUri8itThLGk8QfPzY1acFid8JmVyo5DWUo</code>,同样的，可以在 <a href="https://explorer.solana.com/address/E5XmcEJhhGUri8itThLGk8QfPzY1acFid8JmVyo5DWUo?cluster=devnet">区块链浏览器</a> 中看得到。</p><p>对要注意，ATA 账户是有单独的地址的，比如你本地的账户地址是 <code>a</code>，在 USDT 代币上创建的 ADA 账户地址将是 <code>b</code>，是不一样的。而后续接受 USDT、发送 USDT，将全部通过 ATA 账户来进行，而不是你本地的那个账户。SPL Token 提供了命令来查看本地钱包账户和 ATA 账户的关系：</p><pre><code class="bash">spl-token address --verbose --token E75GMXAfJ91XuRboSpjwkDmta45Etgt3F3Gf5WLZvLbV// 输出是这个样子Wallet address: 75sFifxBt7zw1YrDfCdPjDCGDyKEqLWrBarPCLg6PHwbAssociated token address: E5XmcEJhhGUri8itThLGk8QfPzY1acFid8JmVyo5DWUo</code></pre><p>那么现在，可以用这个命令，来查询 USDT 的余额，<code>balance</code> 后面的参数是指代币地址，而不是 ATA 地址：</p><pre><code class="bash">spl-token balance E75GMXAfJ91XuRboSpjwkDmta45Etgt3F3Gf5WLZvLbV </code></pre><p>当然默认是 0，现在给这个地址挖一些 USDT 上去。这个命令有点长，有 3 个参数，第一个参数是代币地址，第二个参数是代币数量，第三个参数是 ATA 地址，意味着要挖哪个代币、挖多少、挖给谁：</p><pre><code class="bash">spl-token mint E75GMXAfJ91XuRboSpjwkDmta45Etgt3F3Gf5WLZvLbV 5 E5XmcEJhhGUri8itThLGk8QfPzY1acFid8JmVyo5DWUo</code></pre><p>命令执行成功后，就可以查询到余额，也能直接在浏览器上看到余额了，类似的，转账 USDT 的命令是：</p><pre><code class="bash">spl-token transfer &lt;MINT&gt; 1 &lt;ATA&gt;</code></pre><p>Solana 为了避免用户不记得自己的 ATA 账户地址，也提供了人性化的命令，最后一个参数可以直接用本地的钱包地址，而不需要 ATA 地址，这也就是为什么我们平时使用 Solana 的钱包，并没有感觉到 ATA 账户这种东西存在的原因：</p><pre><code class="bash">spl-token transfer &lt;MINT&gt; 1 &lt;RECIPIENT_WALLET&gt;</code></pre><h3 id="2-用-spl-标准库写智能合约"><a href="#2-用-spl-标准库写智能合约" class="headerlink" title="2. 用 spl 标准库写智能合约"></a>2. 用 spl 标准库写智能合约</h3><p>我们尝试一下在智能合约里调用 spl 库函数，这种官方提供的、系统级别的库函数是经过严格安全审计的，比我们自己写要安全，所以有了这些库函数，我们可以更加关注自己定制化的业务逻辑，不需要关心太底层的东西，比如 USDT 余额计算是否精度有损失之类的问题。先创建一个新项目：</p><pre><code class="bash">anchor init usdt_spl</code></pre><p>导入 <code>anchor-spl</code> 依赖，这个命令可以把最新版本的库函数导入进来，命令运行后，可以在 <code>programs/usdt_spl/Cargo.toml</code> 文件的 <code>[dependencies]</code> 部分，新增了这样一行 <code>anchor-spl = &quot;0.31.1&quot;</code>，说明是成功的：</p><pre><code class="bash">cargo add anchor-spl</code></pre><p>开始写合约代码程序。先在最开始两行导入 spl 的依赖。我们之前有使用过 Anchor 框架自带的账户类型如 <code>Account</code> 和 <code>Signer</code>，那么这里 spl 也是提供了多种数据类型，比如 <code>TokenAccount</code> 就表示 ATA 账户的数据结构：</p><pre><code class="rust">use anchor_spl::token::&#123;self, MintTo, Token, TokenAccount, Mint&#125;;</code></pre><p>接着定义 mint 行为相关的账户规则：</p><pre><code class="rust">#[derive(Accounts)]pub struct MintToCtx&lt;&#39;info&gt; &#123;    #[account(mut)]    pub mint: Account&lt;&#39;info, Mint&gt;,     #[account(mut)]    pub to:   Account&lt;&#39;info, TokenAccount&gt;,    #[account(mut)]    pub authority: Signer&lt;&#39;info&gt;,    pub token_program: Program&lt;&#39;info, Token&gt;,&#125;</code></pre><p>这几行代码中，<code>mut</code> 关键词我们之前用到过，表明账户数据要允许被写入。<code>Account</code> 类型是 anchor 框架自带的，我们也使用过。<code>Mint</code> 类型则是新出现的，是从 spl 框架里导入的，我们之前不是自己定义过一个用 <code>#[Account]</code> 宏标注的 <code>Mint</code> 结构体，然后在 <code>#[derive(Accounts)]</code> 里使用吗。现在有了 spl 库，我们不需要自己定义 <code>Mint</code> 结构体的类型、参数个数，直接使用就好。</p><p>同样的，<code>TokenAccount</code> 和 <code>Token</code> 也都是 spl 框架提供的类型。这么看似乎使用 spl 框架比自己写简单了不少？不能高兴的太早，还有一段代码没有写上：</p><pre><code class="rust">impl&lt;&#39;info&gt; From&lt;&amp;MintToCtx&lt;&#39;info&gt;&gt; for CpiContext&lt;&#39;_, &#39;_, &#39;_, &#39;info, MintTo&lt;&#39;info&gt;&gt;&#123;    fn from(accts: &amp;MintToCtx&lt;&#39;info&gt;) -&gt; Self &#123;        let cpi_accounts = MintTo &#123;            mint:      accts.mint.to_account_info(),            to:        accts.to.to_account_info(),            authority: accts.authority.to_account_info(),        &#125;;        CpiContext::new(accts.token_program.to_account_info(), cpi_accounts)    &#125;&#125;</code></pre><p>这段代码乍一看眼花缭乱，可能要晕了，为什么那么多尖括号，为什么那么多单引号和下划线。这就是 Rust，为了迎合独特的内存管理设计，不得不让语言在语法形式上变得复杂。</p><p><code>impl ... From&lt;...&gt; for ...</code> 是 Rust 的语法规则，大意是让一种类型变为另一种类型，我们这里就是让 <code>From&lt;&amp;MintToCtx&lt;&#39;info&gt;&gt;</code> 类型变为 <code>CpiContext&lt;&#39;_, &#39;_, &#39;_, &#39;info, MintTo&lt;&#39;info&gt;&gt;</code>。其中 <code>MintToCtx</code> 是我们上面自己用 <code>#[derive(Accounts)]</code> 宏定义的类型，然后作为泛型参数传递给了 <code>From</code>，而这个 <code>From</code>，是 Rust 标准库提供的一个包装类型，用来接受我们传入的参数。</p><p>至于后面的 <code>CpiContext</code> 部分，Cpi 的全称是跨程序调用 Cross-Program Invocation，用于把要调用的外部程序，以及账户类型，都打包到一个统一的数据结构中。前三个参数不用管，最后的 <code>MintTo</code> 是我们真正传入的类型，这个类型是 spl 库提供的。</p><p>那么也许这里有疑问，为什么还涉及到调用外部程序？CpiContext 又是如何知道要调用哪个外部程序的？这个和 Solana 智能合约的设计有关，SPL Token 不止是一些类型定义，而且是实际已经部署在 Solana 网络上的程序。我们在使用 spl 依赖库的过程，实际上就是去调用那些已经预先在 Solana 网络上部署的 spl 合约。智能合约在运行的时候，发现你要调用 spl，就去找 spl 的合约地址，执行一些操作，然后返回结果。相当于整个网络上的智能合约都在复用同一套 spl 合约。</p><p>所以要留意 Solana 智能合约依赖库的实现方式，和其他网络是有不同的。Solana 在设计上让程序和数据分离，以致于可以实现程序共享的模式。为什么我们不自己部署一套 spl 合约，或者每个人都各自部署一套 spl 合约，然后自己使用呢？一方面是需要付出额外的手续费成本，另一方面是 Solana 的智能合约本来就允许程序共享，你要是自己部署一套，用户都不知道你有没有偷偷修改标准库的代码，反而不安全了。</p><p>还有最后一部分 <code>#[program]</code> 里的程序逻辑要补齐：</p><pre><code class="rust">pub fn mint_to(ctx: Context&lt;MintToCtx&gt;, amount: u64) -&gt; Result&lt;()&gt; &#123;    token::mint_to((&amp;*ctx.accounts).into(), amount)&#125;</code></pre><h3 id="3-编译合约"><a href="#3-编译合约" class="headerlink" title="3. 编译合约"></a>3. 编译合约</h3><p>现在代码没问题，但是如果现在编译合约项目，会遇到报错。需要修改下 <code>programs/usdt_spl/Cargo.toml</code> 文件，把这两行的特性打开：</p><pre><code class="rust">[features]idl-build = [&quot;anchor-lang/idl-build&quot;, &quot;anchor-spl/idl-build&quot;][dependencies]anchor-spl  = &#123; version = &quot;0.31.1&quot;, features = [&quot;token&quot;, &quot;idl-build&quot;] &#125;</code></pre><p>因为静态编译的时候，命令行默认没有把 spl 标准库给带上，在配置文件里指明就可以了。现在项目可以编译成功：</p><pre><code class="bash">anchor build</code></pre><h3 id="4-写单元测试"><a href="#4-写单元测试" class="headerlink" title="4. 写单元测试"></a>4. 写单元测试</h3><p>安装 spl 相关的 nodejs 依赖，注意单元测试用的是 ts 语言，不是 Rust 语言：</p><pre><code class="bash">npm i @coral-xyz/anchor@^0.31 @solana/spl-token chai</code></pre><p>把单元测试代码复制到 <code>tests/usdt_spl.ts</code> 文件中：</p><pre><code class="ts">import anchor from &quot;@coral-xyz/anchor&quot;;import &#123; Program &#125; from &quot;@coral-xyz/anchor&quot;;import &#123;  createMint,  createAssociatedTokenAccount,  getAccount,  TOKEN_PROGRAM_ID,&#125; from &quot;@solana/spl-token&quot;;import &#123; assert &#125; from &quot;chai&quot;;const &#123; AnchorProvider, BN &#125; = anchor;describe(&quot;usdt_spl / mint_to&quot;, () =&gt; &#123;  const provider = AnchorProvider.env();  anchor.setProvider(provider);  const program = anchor.workspace.UsdtSpl as Program;  let mintPubkey: anchor.web3.PublicKey;  let ata: anchor.web3.PublicKey;  it(&quot;creates mint, mints 1 USDT into ATA&quot;, async () =&gt; &#123;    mintPubkey = await createMint(      provider.connection,      provider.wallet.payer,          // fee-payer      provider.wallet.publicKey,      // mint authority      null,                           // freeze authority      6                               // decimals    );    ata = await createAssociatedTokenAccount(      provider.connection,      provider.wallet.payer,          // fee-payer      mintPubkey,      provider.wallet.publicKey       // owner    );    await program.methods      .mintTo(new BN(1_000_000))      // 1 USDT      .accounts(&#123;        mint: mintPubkey,        to: ata,        authority: provider.wallet.publicKey,        tokenProgram: TOKEN_PROGRAM_ID,      &#125;)      .rpc();    const accInfo = await getAccount(provider.connection, ata);    assert.equal(accInfo.amount.toString(), &quot;1000000&quot;);  &#125;);&#125;);</code></pre><p>运行单元测试，会看到成功的输出：</p><pre><code class="bash">anchor test</code></pre><h3 id="5-部署合约到-devnet"><a href="#5-部署合约到-devnet" class="headerlink" title="5. 部署合约到 devnet"></a>5. 部署合约到 devnet</h3><p>确保账户里余额足够，然后用 anchor 来部署合约：</p><pre><code class="bash">anchor deploy --provider.cluster devnet </code></pre><p>这个命令偶尔会因为网络问题执行失败，抛出 <code>Operation timed out</code> 错误。可以直接把 provider 的参数改为自己的 rpc 地址，如果网址比较长，可以用双引号括一下：</p><pre><code class="bash">anchor deploy --provider.cluster &quot;&lt;your-rpc-url&gt;&quot;</code></pre><p>因为网络问题带来的麻烦有可能还不止如此，比如本地存在写入了一部分但是为完成的 buffer、链上存在 buffer 但是本地不存在导致状态不一致等问题，为了直接跳过那些问题，可以直接这种这样的命令：</p><pre><code class="bash">solana program deploy \  target/deploy/usdt_spl.so \  --program-id target/deploy/usdt_spl-keypair.json \  --url &quot;&lt;your-rpc-url&gt;&quot;</code></pre><p>这个命令更加好用。如果没有带 <code>--program-id</code> 参数，这个命令会自动新生成 keypair，也就意味着会把合约部署的新的地址，这个根据自己的需求来选择。部署成功后，就可以去 <a href="https://explorer.solana.com/address/CFXzAhGKEz7tSFdNcVeCX8HosFGYczD7rZyD4vwoWozY?cluster=devnet">区块链浏览器</a> 上查看了。</p><h3 id="6-使用-SDK-调用链上合约"><a href="#6-使用-SDK-调用链上合约" class="headerlink" title="6. 使用 SDK 调用链上合约"></a>6. 使用 SDK 调用链上合约</h3><p>我们之前使用过 SDK，现在再来使用和复习一下，编辑 <code>app/app.js</code> 文件，把代码复制进去：</p><pre><code class="ts">// scripts/mint_to.js   (CommonJS)const anchor = require(&quot;@coral-xyz/anchor&quot;);const &#123;  createMint,  createAssociatedTokenAccount,  getAccount,  TOKEN_PROGRAM_ID,&#125; = require(&quot;@solana/spl-token&quot;);const fs   = require(&quot;fs&quot;);const os   = require(&quot;os&quot;);const path = require(&quot;path&quot;);const &#123; Keypair, Connection, PublicKey &#125; = anchor.web3;const RPC_URL = process.env.RPC_URL || &quot;https://api.devnet.solana.com&quot;;const connection = new Connection(RPC_URL, &#123; commitment: &quot;confirmed&quot; &#125;);const secret = Uint8Array.from(  JSON.parse(fs.readFileSync(path.join(os.homedir(), &quot;.config/solana/id.json&quot;))));const wallet = new anchor.Wallet(Keypair.fromSecretKey(secret));const provider = new anchor.AnchorProvider(connection, wallet, &#123;  preflightCommitment: &#39;confirmed&#39;,&#125;);anchor.setProvider(provider);const idl  = JSON.parse(fs.readFileSync(path.resolve(&quot;target/idl/usdt_spl.json&quot;)));const prog = new anchor.Program(idl, provider);(async () =&gt; &#123;  const mint = await createMint(connection, wallet.payer, wallet.publicKey, null, 6);  const ata  = await createAssociatedTokenAccount(connection, wallet.payer, mint, wallet.publicKey);  const sig = await prog.methods    .mintTo(new anchor.BN(1_000_000))    .accounts(&#123; mint, to: ata, authority: wallet.publicKey, tokenProgram: TOKEN_PROGRAM_ID &#125;)    .rpc();  console.log(&quot;tx:&quot;, sig);  console.log(`explorer: https://explorer.solana.com/tx/$&#123;sig&#125;?cluster=devnet`);  const bal = await getAccount(connection, ata);  console.log(&quot;balance:&quot;, bal.amount.toString());&#125;)();</code></pre><p>如果一切顺利，可以看到这样的运行结果：</p><pre><code>~/work/github/sol_contract/usdt_spl main ❯ node app/app.jstx: 3MgHxsfnJp68mrrABvCh9iwNm6MSXp1SEvk7vDYHoW7KhTEHfVNyMWsbfbEAXTC9gLzcmWu5xbkzia8hgZrcZ18iexplorer: https://explorer.solana.com/tx/3MgHxsfnJp68mrrABvCh9iwNm6MSXp1SEvk7vDYHoW7KhTEHfVNyMWsbfbEAXTC9gLzcmWu5xbkzia8hgZrcZ18i?cluster=devnetbalance: 1000000</code></pre>]]></content>
  </entry>
  <entry>
    <title>Solana 智能合约开发教程 (2)</title>
    <link href="https://b.smallyu.net/2025/06/26/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B2/"/>
    <id>blog-b:https://b.smallyu.net/2025/06/26/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B2/</id>
    <published>2025-06-26T05:56:54.000Z</published>
    <updated>2025-12-03T09:25:53.987Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这个一个零基础的系列教程，可以从最基本的操作开始学会 Solana 智能合约的开发。</p>
<ul>
<li>《<a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这个一个零基础的系列教程，可以从最基本的操作开始学会 Solana 智能合约的开发。</p><ul><li>《<a href="/2025/06/24/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B1/">第一篇</a>》：基础环境安装、HelloWorld 合约部署、链上合约调用</li><li>《<a href="/2025/06/26/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B2/">第二篇</a>》：实现 USDT 合约的最小模型，自定义数据结构与方法</li><li>《<a href="/2025/06/28/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B3/">第三篇</a>》：使用官方 SPL 库复用合约功能，完成标准化代币的发行</li></ul></blockquote><p>我们已经学会了如何创建智能合约项目、部署合约以及调用连上合约，接下来深入了解一下智能合约编程语言的写法，关注如何写出自己想要的逻辑。我们将会以写一个简单的 USDT 代币合约为例，分析相关的代码，并且理解 Solana 智能合约的写法。</p><h3 id="1-创建项目"><a href="#1-创建项目" class="headerlink" title="1. 创建项目"></a>1. 创建项目</h3><p>用我们已经学会的命令，来创建一个新的项目：</p><pre><code class="bash">anchor init usdt_clone</code></pre><h3 id="2-配置文件"><a href="#2-配置文件" class="headerlink" title="2. 配置文件"></a>2. 配置文件</h3><p>可以注意到项目路径 <code>programs/usdt_clone/Cargo.toml</code> 下的这个文件，Cargo 是 Rust 语言常用的包管理器，这个 <code>Cargo.toml</code> 则是包管理器的配置文件，指定了要引入哪些依赖库，以及依赖库的版本。我们自动生成的配置文件里有这么两行：</p><pre><code class="Rsut">[dependencies]anchor-lang = &quot;0.31.1&quot;</code></pre><p>Anchor 提供的宏是 Solana 智能合约的关键，宏的形式如 <code>#[program]</code>、<code>#[account]</code> 等，这些宏会告诉 Solana 的 SVM 虚拟机，程序从哪里开始、数据结构在哪里定义等。如果没有 Anchor 这个依赖，合约项目就是普通的 Rust 语言项目了，Solana 的智能合约系统无法识别和解析。这也就解释了，Solana 的智能合约，是如何利用 Rust 语言来实现的。</p><h3 id="3-合约地址"><a href="#3-合约地址" class="headerlink" title="3. 合约地址"></a>3. 合约地址</h3><p>我们近距离看一下合约的代码文件 <code>usdt_clone/programs/usdt_clone/src/lib.rs</code>。文件的第一行内容是这样，<code>use</code> 把 Anchor 常用的类型一下子全部导入进来了，这没什么问题，不需要修改，方便我们后续编写程序。：</p><pre><code class="Rsut">use anchor_lang::prelude::*;</code></pre><p>第二行内容是一个对 <code>declare_id</code> 函数的调用，<code>declare_id</code> 声明了当前这个智能合约项目的 Program ID，也就是合约地址是什么，之前我们提到过，Solana 的智能合约地址，是可以离线生成的。</p><pre><code class="Rsut">declare_id!(&quot;CFmGdHuqDymqJYBX44fyNjrFoJx6wRkZPkYgZqfkAQvT&quot;);</code></pre><p>这个合约地址是一个随机值，但不是随意格式的值，它是一个 Ed25529 的公钥。假如你手动把最后一个字符 <code>T</code> 改为 <code>t</code>，这整个字符串就不是一个合法的公钥了，所以这个值可以随机生成，但是不能随便改。那么既然是公钥，它的私钥在哪里呢？在初始化项目的时候，会自动生成一个私钥，文件位置在 <code>target/deploy/usdt_clone-keypair.json</code>，可以打开看到是一些字节数组，<code>declare_id</code> 使用的公钥，就是根据这个私钥生成的。</p><h3 id="4-储存数据结构"><a href="#4-储存数据结构" class="headerlink" title="4. 储存数据结构"></a>4. 储存数据结构</h3><p>接下来我们需要新增一些自己的逻辑，在 <code>declare_id</code> 语句的下方，写入这个代码：</p><pre><code class="Rsut">#[account]pub struct Mint &#123;    pub decimals: u8,    pub mint_authority: Pubkey,&#125;</code></pre><p>可以理解为 <code>#[account]</code> 宏是用来定义数据结构的，Anchor 黑魔法会在背后进行一系列操作，让我们可以针对这个数据结构在链上进行读写操作。这里的代码很简单，我们定义了一个叫 <code>Mint</code> 的结构体，这个结构体包含两个属性，<code>decimals</code> 指定 USDT 代币的精度是多少，<code>mint_authority</code> 指定谁可以来挖新的币。</p><p>我们继续定义另一个结构体，用来储存每一个用户的代币数量。<code>owner</code> 就是用户地址，<code>balance</code> 则是用户的余额：</p><pre><code class="Rsut">#[account]pub struct TokenAccount &#123;    pub owner: Pubkey,    pub balance: u64,&#125;</code></pre><h3 id="5-账户约束结构"><a href="#5-账户约束结构" class="headerlink" title="5. 账户约束结构"></a>5. 账户约束结构</h3><p>你可能注意到当前的代码文件最底部，还有两行自动生成的 <code>#[derive(Accounts)]</code> 开头的代码。这个宏是用来给账户写一些约束规则的。我们可以在 <code>#[derive(Accounts)]</code> 内部定义一些函数，然后再用 <code>#[account]</code> 来定义结构体，那么这个结构体就自动拥有了所有函数。类似于给结构体定义成员函数的意思。</p><p>把原本的 <code>Initialize</code> 代码删掉：</p><pre><code class="Rsut">#[derive(Accounts)]pub struct Initialize &#123;&#125;    // 删除</code></pre><p>然后写入我们自己的逻辑：</p><pre><code class="Rust">#[derive(Accounts)]pub struct InitMint&lt;&#39;info&gt; &#123;    #[account(        init,         payer = authority,        space = 8 + 1 + 32    )]    pub mint: Account&lt;&#39;info, Mint&gt;,    #[account(mut)]    pub authority: Signer&lt;&#39;info&gt;,    pub system_program: Program&lt;&#39;info, System&gt;,&#125;</code></pre><p>这段代码有点复杂。我们先看 <code>#[account(...)]</code> 这一段，这里给 <code>account()</code> 函数传递了 3 个参数进去，<code>account()</code> 函数的参数类型是 Anchor 框架定义的，第一个参数 <code>init</code> 是一个固定的关键字，不需要值，表示如果账户不存在，则创建一个新的账户。第二个参数 <code>payer</code> 是需要值的，表示谁来支付创建账户的手续费。第三个参数 <code>space</code> 的值则是我们自己计算的，系统必须预留 8 + <code>Mint</code> 结构体的第一个字段类型 <code>u8</code> 需要空间 1 + <code>Mint</code> 结构体的第二个字段类型 <code>Pubkey</code> 需要空间 32。</p><p>这个 <code>#[account(...)]</code> 的宏用来修饰 <code>mint</code> 成员变量。我们接着看 <code>mint</code> 这个成员变量，<code>Account</code> 是 Anchor 框架提供的内置的账户类型，可以对储存数据结构进行读写，例如我们之前定义的 <code>Mint</code> 或者 <code>TokenAccount</code> 结构，这个 <code>mint</code> 成员变量实际操作这些类型的数据。而 <code>Account</code> 接受两个泛型参数，第二个参数 <code>Mint</code> 指明了这个账户是在处理 <code>Mint</code> 类型的结构，而不是 <code>TokenAccount</code> 或者其他。</p><p>接着看 <code>#[account(mut)]</code> 这个宏，mut 的意思是账户金额可以变化。<code>authority</code> 也是一个成员变量，它的类型同样是一个 Anchor 内置的账户类型 <code>Signer</code>，与 <code>Account</code> 不同的是，<code>Signer</code> 意味着需要传入账户持有者本人签名，才符合类型定义。后面的 <code>‘info</code> 则是一个泛型参数，其中 <code>info</code> 是结构体的泛型传递进来的。至于 <code>info</code> 前面的单引号 <code>&#39;</code>，是 Rust 语言里的一个特性，可以简单理解为对参数的引用传递。整体来看，这两行代码的宏和语句，共同定义了一个可以对其扣费的账户地址作为成员变量。</p><p>最后的 <code>system_program</code> 成员变量，可以把这一行理解为固定写法，只要合约需要转账 SOL，就得写上这一行。总的来说，这几行代码定义了一个新的结构体 <code>InitMint</code>，这个结构体是基于 <code>Mint</code> 进行包装的，包装后的 <code>InitMint</code> 拥有了一些账户相关的属性。</p><h3 id="6-代币合约初始化"><a href="#6-代币合约初始化" class="headerlink" title="6. 代币合约初始化"></a>6. 代币合约初始化</h3><p>接下来开始关注 <code>#[program]</code> 宏定义的函数。这个宏用来标注智能合约的程序入口，也就是真正执行合约逻辑的部分。我们当前文件里有几行默认的代码：</p><pre><code class="Rust">#[program]pub mod usdt_clone &#123;    use super::*;    pub fn initialize(ctx: Context&lt;Initialize&gt;) -&gt; Result&lt;()&gt; &#123;   // 删除        msg!(&quot;Greetings from: &#123;:?&#125;&quot;, ctx.program_id);             // 删除        Ok(())                                                    // 删除    &#125;                                                             // 删除&#125;</code></pre><p>删掉这个项目自动生成的 <code>initialize</code> 函数，我们自己写一个函数：</p><pre><code class="Rust">pub fn init_mint(ctx: Context&lt;InitMint&gt;, decimals: u8) -&gt; Result&lt;()&gt; &#123;    let mint = &amp;mut ctx.accounts.mint;    mint.decimals = decimals;    mint.mint_authority = ctx.accounts.authority.key();    Ok(())&#125;</code></pre><p>把这个 <code>init_mint</code> 函数放在原先 <code>initialize</code> 函数的位置。如果抛开 Anchor 的宏，这个函数则是一个普通的 Rust 语法定义的函数。<code>Context</code> 类型是 Anchor 提供的包装类型 所以你也许好奇我们明明没有定义 <code>Context</code>，但是这里却直接使用了。<code>InitMint</code> 类型是则我们上一个步骤定义好的。</p><p>这个函数接受两个参数，第一个参数的类型是 <code>InitMint</code>，表示哪个账户拥有铸币权限。第二个参数类型是 <code>u8</code>，表示 USDT 的精度是多少位。这个函数返回一个空的元组 <code>()</code>，说明如果成功什么都不返回，如果失败则会报错。</p><p>函数内部的逻辑相对好理解，函数把参数接收进来的数据，赋值给了一个叫 <code>mint</code> 的变量，要注意这不是普通的新定义的变量，而是从 <code>ctx.accounts</code> 反序列化过来的、<code>mut</code> 声明的可变类型的变量，相当于直接修改一个引用类型的结构体内的属性值，所以只要给 <code>mint</code> 赋值，结构体内的数据都会保存下来，也就是保存到链上。</p><h3 id="7-单元测试"><a href="#7-单元测试" class="headerlink" title="7. 单元测试"></a>7. 单元测试</h3><p>可以先到目录下，运行一下编译，看程序是否写对了，如果编译报错，可能是哪里复制漏了。由于 Rust 语言的编译器非常严格，所以即使没有错误，也会有很多 warning，暂时不用管那些警告信息：</p><pre><code class="bash">anchor build  </code></pre><p>接下来到 <code>usdt_clone/tests/usdt_clone.ts</code> 文件，复制这些代码进去：</p><pre><code class="ts">import anchor from &quot;@coral-xyz/anchor&quot;;import &#123; Program &#125; from &quot;@coral-xyz/anchor&quot;;import &#123; SystemProgram, Keypair &#125; from &quot;@solana/web3.js&quot;;import &#123; assert &#125; from &quot;chai&quot;;const &#123; AnchorProvider, BN &#125; = anchor;describe(&quot;usdt_clone / init_mint&quot;, () =&gt; &#123;  const provider = AnchorProvider.env();  anchor.setProvider(provider);  const program = anchor.workspace.UsdtClone as Program;  const mintKey = Keypair.generate();  it(&quot;creates a Mint with correct metadata&quot;, async () =&gt; &#123;    const txSig = await program.methods      .initMint(new BN(6))      .accounts(&#123;        mint: mintKey.publicKey,        authority: provider.wallet.publicKey,        systemProgram: SystemProgram.programId,      &#125;)      .signers([mintKey])      .rpc();    console.log(&quot;tx:&quot;, txSig);    const mintAccount = await program.account.mint.fetch(mintKey.publicKey);    assert.equal(mintAccount.decimals, 6);    assert.equal(      mintAccount.mintAuthority.toBase58(),      provider.wallet.publicKey.toBase58()    );  &#125;);&#125;);</code></pre><p>这段代码使用本地的单元测试框架，构造了一些参数去调用我们在合约里写的 <code>initMint</code> 方法，比如指定精度为 6 位，传递了 <code>InitMint</code> 结构体需要的 3 个参数等。模拟交易的执行结果赋值给了 <code>txSig</code> 变量，可以在输出日志中看到交易哈希。并且在交易结束后，用语句 <code>program.account.mint.fetch</code> 查询了合约的 <code>mint</code> 属性的值，它的精度应该等于我们的参数，authority 也应该是我们本地发起模拟交易的账户地址。</p><p>运行这个命令来查看单元测试的效果：</p><pre><code class="bash">anchor test</code></pre><p>如果一切顺利，会看到 <code>1 passing (460ms)</code> 的字样。</p><h3 id="8-开户和转账"><a href="#8-开户和转账" class="headerlink" title="8. 开户和转账"></a>8. 开户和转账</h3><p>基于上面我们已经看懂的语法规则，可以继续在合约代码中新增这样两个账户结构的定义，分别用来开户和转账。这里的 <code>#[error_code]</code> 是新出现的宏，比较容易理解，它是一个枚举类型，用于程序报错的时候调用：</p><pre><code class="rust">#[derive(Accounts)]pub struct InitTokenAccount&lt;&#39;info&gt; &#123;    #[account(init, payer = owner, space = 8 + 32 + 8)]    pub token: Account&lt;&#39;info, TokenAccount&gt;,    #[account(mut, signer)]    pub owner: Signer&lt;&#39;info&gt;,    pub system_program: Program&lt;&#39;info, System&gt;,&#125;#[derive(Accounts)]pub struct Transfer&lt;&#39;info&gt; &#123;    #[account(mut, has_one = owner)]    pub from: Account&lt;&#39;info, TokenAccount&gt;,    #[account(mut)]    pub to: Account&lt;&#39;info, TokenAccount&gt;,    #[account(signer)]    pub owner: Signer&lt;&#39;info&gt;,&#125;#[error_code]pub enum ErrorCode &#123;    InsufficientFunds,    ArithmeticOverflow,&#125;</code></pre><p>然后新增两个方法，分别执行开户的逻辑以及转账的逻辑。注意这里开户的时候，<code>token.balance = 1000</code> 意味着每一个开户的地址，默认都会有 1000 的余额。这里主要是为了简化流程和代码、方便单元测试，这个数字可以随意改动：</p><pre><code class="Rust">pub fn init_token_account(ctx: Context&lt;InitTokenAccount&gt;) -&gt; Result&lt;()&gt; &#123;  let token = &amp;mut ctx.accounts.token;  token.owner = ctx.accounts.owner.key();  token.balance = 1000;  Ok(())&#125;pub fn transfer(ctx: Context&lt;Transfer&gt;, amount: u64) -&gt; Result&lt;()&gt; &#123;  let from = &amp;mut ctx.accounts.from;  let to   = &amp;mut ctx.accounts.to;  require!(from.balance &gt;= amount, ErrorCode::InsufficientFunds);  from.balance -= amount;  to.balance = to      .balance      .checked_add(amount)      .ok_or(ErrorCode::ArithmeticOverflow)?;  Ok(())&#125;</code></pre><p>这是针对开户和转账功能的单元测试代码：</p><pre><code class="ts">const tokenA = Keypair.generate();const tokenB = Keypair.generate();it(&quot;initializes tokenA &amp; tokenB, each with balance 1000&quot;, async () =&gt; &#123;  for (const tok of [tokenA, tokenB]) &#123;    await program.methods      .initTokenAccount()      .accounts(&#123;        token: tok.publicKey,        owner: provider.wallet.publicKey,        systemProgram: SystemProgram.programId,      &#125;)      .signers([tok])      .rpc();    const acc = await program.account.tokenAccount.fetch(tok.publicKey);    assert.equal(      acc.owner.toBase58(),      provider.wallet.publicKey.toBase58()    );    assert.equal(acc.balance.toNumber(), 1000);  &#125;&#125;);it(&quot;transfers 250 from A to B (balances 750 / 1250)&quot;, async () =&gt; &#123;  await program.methods    .transfer(new BN(250))    .accounts(&#123;      from:  tokenA.publicKey,      to:    tokenB.publicKey,      owner: provider.wallet.publicKey,    &#125;)    .rpc();  const a = await program.account.tokenAccount.fetch(tokenA.publicKey);  const b = await program.account.tokenAccount.fetch(tokenB.publicKey);  assert.equal(a.balance.toNumber(), 750);  assert.equal(b.balance.toNumber(), 1250);&#125;);</code></pre><p>如果有兴趣，可以试着把这个合约也部署到 devnet 上，然后通过 SDK 来发起对链上合约的调用。</p>]]></content>
  </entry>
  <entry>
    <title>Solana 智能合约开发教程 (1)</title>
    <link href="https://smallyu.net/2025/06/24/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B1/"/>
    <id>blog:https://smallyu.net/2025/06/24/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B1/</id>
    <published>2025-06-24T13:51:06.000Z</published>
    <updated>2026-08-04T11:43:16.911Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这是一个零基础的系列教程，可以从最基本的操作开始学会 Solana 智能合约的开发。</p>
<ul>
<li>《<a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这是一个零基础的系列教程，可以从最基本的操作开始学会 Solana 智能合约的开发。</p><ul><li>《<a href="/2025/06/24/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B1/">第一篇</a>》：基础环境安装、HelloWorld 合约部署、链上合约调用</li><li>《<a href="/2025/06/26/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B2/">第二篇</a>》：实现 USDT 合约的最小模型，自定义数据结构与方法</li><li>《<a href="/2025/06/28/Solana%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B3/">第三篇</a>》：使用官方 SPL 库复用合约功能，完成标准化代币的发行</li></ul></blockquote><p>我们将从最基础的操作开始，学习 Solana 智能合约的开发。你只需要普通的编程基础，理解面向对象等概念就可以，不需要事先知道其他网络的智能合约概念，也不需要知道 Rust 语言的编程理念。</p><h3 id="1-安装环境"><a href="#1-安装环境" class="headerlink" title="1. 安装环境"></a>1. 安装环境</h3><p>访问 Solana 官方提供的安装教程：<a href="https://solana.com/docs/intro/installation">https://solana.com/docs/intro/installation</a></p><p>文档中提供了一键安装全部依赖的单个命令行，也有分阶段安装的详细教程。要注意其中 Solana Cli 是需要修改环境变量文件的。安装好一切后，<code>solana</code> 命令应该是可用的：</p><pre><code class="bash">solana --help</code></pre><h3 id="2-初始化项目"><a href="#2-初始化项目" class="headerlink" title="2. 初始化项目"></a>2. 初始化项目</h3><p>使用 anchor 命令来初始化一个智能合约的项目，这个命令行工具在上个步骤已经安装好了，可以先不用管生成的目录结构是什么样子：</p><pre><code class="bash">anchor init hello_solcd hello_sol</code></pre><h3 id="3-写入合约代码"><a href="#3-写入合约代码" class="headerlink" title="3. 写入合约代码"></a>3. 写入合约代码</h3><p><code>programs/hello_sol/src</code> 目录下有一个 <code>lib.rs</code> 文件，<code>.rs</code> 结尾意味着这是一个 Rust 语言的代码文件。把这些代码复制进去，注意 <code>declare_id</code> 中的内容是你的项目在初始化的时候，就会自动为你生成，不需要原封不动复制下面的内容：</p><pre><code class="rust">use anchor_lang::prelude::*;declare_id!(&quot;3Zbdw1oWu1CiMiQr3moQeT4XzMgeqmCvjH5R5wroDWQH&quot;);#[program]pub mod hello_sol &#123;    use super::*;    pub fn say_hello(ctx: Context&lt;Hello&gt;) -&gt; Result&lt;()&gt; &#123;        msg!(&quot;Hello, world!&quot;);        Ok(())    &#125;&#125;#[derive(Accounts)]pub struct Hello &#123;&#125;</code></pre><h3 id="4-编译智能合约"><a href="#4-编译智能合约" class="headerlink" title="4. 编译智能合约"></a>4. 编译智能合约</h3><p>使用 anchor 命令编译你刚才复制进去的智能合约代码，确保编译是成功的，代码没有写错。编译过程中可能会有一些警告，那些警告不要紧，因为 Rust 语言对于代码非常严格，很小的问题都会抛出大段的警告。如果一切顺利，命令行的输出不会有错误日志：</p><pre><code class="bash">anchor build</code></pre><h3 id="5-设置本地默认网络"><a href="#5-设置本地默认网络" class="headerlink" title="5. 设置本地默认网络"></a>5. 设置本地默认网络</h3><p>运行这个命令，让你本地的 solana 命令默认使用 devnet，因为 devnet 是给开发者使用的，可以用来测试自己的程序，而不需要真的花钱去买 SOL 代币：</p><pre><code class="bash">solana config set --url https://api.devnet.solana.com</code></pre><h3 id="6-创建本地账户文件"><a href="#6-创建本地账户文件" class="headerlink" title="6. 创建本地账户文件"></a>6. 创建本地账户文件</h3><p>这个命令用于在你本地的默认路径下，创建一个用来部署智能合约的 Solana 账户。因为部署智能合约需要消耗手续费，这些手续费需要一个账户来支付：</p><pre><code class="bash">solana-keygen new -o ~/.config/solana/id.json  </code></pre><p>这个命令的运行结果中，有一行 <code>pubkey: </code> 开头的输出，pubkey 后面的就是你本地的账户地址。因为上一个步骤已经设置了 devnet 为默认网络，所以可以直接使用这个命令来查看你本地账户的余额：</p><pre><code class="bash">solana balance</code></pre><p>也可以打开 devnet 的 <a href="https://explorer.solana.com/?cluster=devnet">浏览器</a>，搜索你刚才生成的地址。搜索之后的 URL 形如：<a href="https://explorer.solana.com/address/75sFifxBt7zw1YrDfCdPjDCGDyKEqLWrBarPCLg6PHwb?cluster=devnet">https://explorer.solana.com/address/75sFifxBt7zw1YrDfCdPjDCGDyKEqLWrBarPCLg6PHwb?cluster=devnet</a></p><p>当然，你会发现自己的账户余额是 <code>0 SOL</code>。</p><h3 id="7-领取-devnet-上的空投"><a href="#7-领取-devnet-上的空投" class="headerlink" title="7. 领取 devnet 上的空投"></a>7. 领取 devnet 上的空投</h3><p>运行这个命令，你的账户就可以收到 2 个 SOL。其中参数里的 2 就是请求发放 2 个 SOL 的意思。因为领水的额度限制，你只能一次性最多领 2 个。不用担心太少，足够我们接下来的步骤使用了。</p><pre><code class="bash">solana airdrop 2</code></pre><h3 id="8-部署合约到-devnet"><a href="#8-部署合约到-devnet" class="headerlink" title="8. 部署合约到 devnet"></a>8. 部署合约到 devnet</h3><p>现在我们已经有了智能合约代码，有了本地账户，并且本地账户里有 SOL 余额。现在可以部署合约到 devnet 上了。运行这个命令：</p><pre><code class="bash">anchor deploy --provider.cluster devnet </code></pre><p>如果部署成功，会看到 <code>Deploy success</code> 的字样。命令行输出中还有一行需要留意，<code>Program Id: </code> 后面的，就是部署之后的合约地址，你可以直接在 devnet 的浏览器上搜索这个地址，然后看到类似这个 URL 的页面，URL 中的 <code>3Zbdw1oWu1CiMiQr3moQeT4XzMgeqmCvjH5R5wroDWQH</code> 就是我部署的合约地址：<a href="https://explorer.solana.com/address/3Zbdw1oWu1CiMiQr3moQeT4XzMgeqmCvjH5R5wroDWQH?cluster=devnet">https://explorer.solana.com/address/3Zbdw1oWu1CiMiQr3moQeT4XzMgeqmCvjH5R5wroDWQH?cluster=devnet</a></p><h3 id="9-调用链上合约"><a href="#9-调用链上合约" class="headerlink" title="9. 调用链上合约"></a>9. 调用链上合约</h3><p>到 <code>hello_sol/app</code> 目录下，新建一个叫 <code>app.js</code> 的文件，把这些代码复制进去。简单来说，这段代码读取了你本地默认的账户文件，然后用你的 Solana 账户发起一笔对智能合约调用的交易，这个脚本每执行一次，就会在链上创建一笔交易。：</p><pre><code class="javascript">const anchor = require(&#39;@coral-xyz/anchor&#39;);const fs     = require(&#39;fs&#39;);const os     = require(&#39;os&#39;);const path   = require(&#39;path&#39;);const &#123; Keypair, Connection &#125; = anchor.web3;const RPC_URL    = process.env.RPC_URL;const connection = new Connection(RPC_URL, &#123; commitment: &#39;confirmed&#39; &#125;);const secretKey = Uint8Array.from(  JSON.parse(    fs.readFileSync(      path.join(os.homedir(), &#39;.config/solana/id.json&#39;),      &#39;utf8&#39;,    ),  ),);const wallet   = new anchor.Wallet(Keypair.fromSecretKey(secretKey));const provider = new anchor.AnchorProvider(connection, wallet, &#123;  preflightCommitment: &#39;confirmed&#39;,&#125;);anchor.setProvider(provider);const idlPath = path.resolve(__dirname, &#39;../target/idl/hello_sol.json&#39;);const idl     = JSON.parse(fs.readFileSync(idlPath, &#39;utf8&#39;));const program = new anchor.Program(idl, provider);(async () =&gt; &#123;  try &#123;    const sig = await program.methods.sayHello().rpc();    console.log(&#39;✅ tx&#39;, sig);    console.log(`🌐 https://explorer.solana.com/tx/$&#123;sig&#125;?cluster=devnet`);  &#125; catch (err) &#123;    console.error(&#39;❌&#39;, err);  &#125;&#125;)();</code></pre><p>返回 <code>hello_sol</code> 项目的顶层目录，执行这些命令来安装 nodejs 的依赖：</p><pre><code>npm init -y npm install @coral-xyz/anchor</code></pre><p>然后记得现在仍然是在顶层目录，运行这个命令，来执行刚才写的 <code>app.js</code> 脚本，脚本会到 devnet 上调用我们部署的智能合约：</p><pre><code class="bash">export RPC_URL=https://api.devnet.solana.comnode app/app.js</code></pre><p>这里有一个环境变量 <code>RPC_URL</code> 是脚本请求的 API 地址，因为 nodejs 脚本默认不走系统代理，所以对于网络受阻的同学，需要用一个比公开 RPC 更好用的 API 地址。可以使用例如 <a href="https://www.helius.dev/">Helius</a> 的服务，注册一个免费的账号就可以了。假如执行脚本的过程中遇到下面的错误，那就说明是网络问题，换一个好用的 RPC 地址就好了：</p><pre><code class="javascript">❌ Error: failed to get recent blockhash: TypeError: fetch failed    at Connection.getLatestBlockhash (/Users/smallyu/work/github/hello_sol/node_modules/@solana/web3.js/lib/index.cjs.js:7236:13)    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)    at async AnchorProvider.sendAndConfirm (/Users/smallyu/work/github/hello_sol/node_modules/@coral-xyz/anchor/dist/cjs/provider.js:89:35)    at async MethodsBuilder.rpc [as _rpcFn] (/Users/smallyu/work/github/hello_sol/node_modules/@coral-xyz/anchor/dist/cjs/program/namespace/rpc.js:15:24)    at async /Users/smallyu/work/github/hello_sol/app/app.js:40:17</code></pre><p>你也许好奇为什么不需要指定调用的合约地址，这个脚本怎么知道你刚才，部署到链上的合约在哪里？注意看脚本中有一个 <code>idlPath</code> 的变量，你可以直接打开这个路径的文件 <code>target/idl/hello_sol.json</code> 查看，里面是一些合约编译后的元信息，包括合约的地址也在里面，没错合约地址是离线生成的，不需要上链，合约就有属于自己的唯一地址了。</p><p>如果执行脚本没有输出错误，就会看到终端打印出了这一次调用合约的交易哈希，以及可以直接复制访问的浏览器 URL，例如这就是一笔调用合约的交易：<a href="https://explorer.solana.com/tx/2fnPgKkv3tGKKq72hhRxmW6WFSXuofMzXfY2UYoFZXTdJi37btdESy9NzS2gjpWzXX4CL5F7QfxugpctBVaMcBFY?cluster=devnet">https://explorer.solana.com/tx/2fnPgKkv3tGKKq72hhRxmW6WFSXuofMzXfY2UYoFZXTdJi37btdESy9NzS2gjpWzXX4CL5F7QfxugpctBVaMcBFY?cluster=devnet</a></p><p>这笔交易页面的最下方，可以看到我们写的智能合约在被交易调用后，打印出了 <code>Program logged: &quot;Hello, world!&quot;</code> 的日志，这正是我们写在合约代码中的 msg。</p><h3 id="10-Troubleshooting"><a href="#10-Troubleshooting" class="headerlink" title="10. Troubleshooting"></a>10. Troubleshooting</h3><p>如果在执行上述命令或者代码的过程中，遇到了错误，可以优先考虑是命令行工具版本的问题。由于区块链行业和技术迭代比较快，很容易出现版本不兼容的情况。我本地的环境和版本是：</p><pre><code class="text">rustup: rustup 1.28.2 (e4f3ad6f8 2025-04-28)rustc: rustc 1.90.0-nightly (706f244db 2025-06-23)solana: solana-cli 2.2.18 (src:8392f753; feat:3073396398, client:Agave)archor: anchor-cli 0.31.1node: v24.2.0@coral-xyz/anchor(nodejs): ^0.31.1</code></pre>]]></content>
  </entry>
  <entry>
    <title>重新打开了微博的 issue，并且恢复了导航栏里的微博按钮，因为现在博客拆分为两个网站了： smallyu.net cr...</title>
    <link href="https://t.smallyu.net/#2025-12"/>
    <id>micro:2998812656</id>
    <published>2025-06-24T05:00:19Z</published>
    <updated>2026-06-09T04:39:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>重新打开了微博的 issue，并且恢复了导航栏里的微博按钮，因为现在博客拆分为两个网站了： smallyu.net crazy.smallyu.net （疯狂版） 在疯狂版上，我可以随心所欲发布任何想说的内容，应该没人会关注到。</p>]]></summary>
    <content type="html"><![CDATA[<p>重新打开了微博的 issue，并且恢复了导航栏里的微博按钮，因为现在博客拆分为两个网站了：</p>
<ul>
<li><a href="https://smallyu.net/">smallyu.net</a></li>
<li><a href="https://crazy.smallyu.net/">crazy.smallyu.net</a> （疯狂版）</li>
</ul>
<p>在疯狂版上，我可以随心所欲发布任何想说的内容，应该没人会关注到。</p>
]]></content>
  </entry>
  <entry>
    <title>顺利从王垠老师的计算机科学视频班毕业</title>
    <link href="https://b.smallyu.net/2025/06/24/%E9%A1%BA%E5%88%A9%E4%BB%8E%E7%8E%8B%E5%9E%A0%E8%80%81%E5%B8%88%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%A7%86%E9%A2%91%E7%8F%AD%E6%AF%95%E4%B8%9A/"/>
    <id>blog-b:https://b.smallyu.net/2025/06/24/%E9%A1%BA%E5%88%A9%E4%BB%8E%E7%8E%8B%E5%9E%A0%E8%80%81%E5%B8%88%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%A7%86%E9%A2%91%E7%8F%AD%E6%AF%95%E4%B8%9A/</id>
    <published>2025-06-24T04:40:45.000Z</published>
    <updated>2026-01-26T06:43:23.457Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>正式建辅导群开始学习是 5月21日，到今天]]></summary>
    <content type="html"><![CDATA[<p>正式建辅导群开始学习是 5月21日，到今天 6月24日差不多一个月的时间。</p><p>你可能有两个疑问：</p><ol><li>往期基础班都是两个月，怎么我一个月就结束了？东西都学完了？</li><li>一个月的时间能学到多少东西？</li></ol><p>对于第一个疑问，来回顾和分析下我学习基础班的课时。我学习前 6 课用了半个月时间，除去周末两天助教老师在休息，我也会出去玩，所以学习前 6 课平均每节课用时两天。</p><p>往期基础班的安排是一周一节课。假如之前其他同学一天学 2 个小时，那么一周下来是 14 个小时。我一天就可以学够 7 小时，自然可以用两天时间完成一节课。</p><p>一天真的能学够 7 小时吗？可以这么说，我最近两年的工作强度不比这个低，经年累月加班，我又比较自觉，不摸鱼。我最近不用上班，把学习当班上了属于是。那么从时间强度上，我一天学 7 小时是合理的。</p><p>后面学 Rust 这节课用时最长，在 10 天左右。其他的课还是一两天的样子，因为不只是 Rust 语言，还加深了对解释器的理解，以及包括一些隐藏关卡。所以整体下来，一个月完成了基础班全部课程内容的学习。</p><p>至于课后练习题的含量，我曾经做过一个测试，一天之内，一口气把前 5 课的练习题全部重做一遍。当时也是觉得进度太快，担心自己没掌握好。整体体验下来，每一节课的课后练习题，都需要一个小时左右的时间才能完成，这是在已经做过一遍的前提下，而且并没有非常认真的整理代码，做出来就算。</p><p>至于后面的课程，练习题难度就更大了，尤其是解释器的课程，以及 Rust 的课程，而且因为 Rust 这种语言的坑，对解释器也需要反复理解，甚至需要做点课上没写的东西，才能理解清楚。</p><p>所以整体算下来，基础班的课时长度可以这样估算：</p><ol><li>每节课视频长度 2.5 小时，8 节课一共 20 小时</li><li>第一课的练习题需要 12 小时左右</li><li>第二课到第七课的练习题每节课需要 7 小时左右，一共 42 小时</li><li>第八课需要接近 30 个小时</li><li>一些隐藏关卡同样平均需要 7 小时，但是做了多少隐藏关因人而异，我做了 3 关，一共 21 小时</li></ol><p>加起来算一下，一共需要 125 个小时。我用时一个月，除去节假日有 22 天，平均一天 6 个小时，很合理吧。</p><p>同样也可以提供给其他人一些参考，想学完基础班，就需要准备出至少 120 个小时的时间。平摊到两个月的话，平均一天 2 个小时，学 60 天，才能学完。</p><p>对于第二个疑问，问题就迎刃而解了。这么多的学习时长，当然能够学到很多东西。何况是非常精致的课程内容，还有高水平的老师指导，事半功倍。</p><p>现在好了，课也上了，学也学了，该进入下一步的计划了。</p><h3 id="回顾我的学习动机"><a href="#回顾我的学习动机" class="headerlink" title="回顾我的学习动机"></a>回顾我的学习动机</h3><p>既然我反复夸赞这门课程，那么是不是我推荐所有人去学、并且跟谁都会说物超所值呢。当然也不是那么绝对。</p><p>看我的博客主题就知道，我已经是王垠老师的粉丝很多年了，但是前几年的培训课并没有报名参加。以前没有报名学习的原因有：</p><ol><li>没有认识到基础编程技能的重要性，大概扫一眼大纲，感觉不就是一些入门编程的东西吗，递归之类的</li><li>以前处于比较浮躁的心态，认为只要在前沿的技术公司，认真做好一线的技术工作，在工作中自然而然就会掌握更高级、更精深的技术，不需要学这些太基础的东西</li><li>认为区块链技术大有可为，自己还没学好区块链。把区块链学好了，技术就好了</li></ol><p>然而到后来，我现在决定学习这门课的原因有：</p><ol><li>当时在做一份普通的后端开发工作，背离我长年来区块链开发的职业道路，尤其是职业技能上水土不服，让我开始关注基础的计算机知识的分量</li><li>工作中连续多次遇到糟糕的团队，心态爆炸，我怀疑是自己能力有问题</li><li>对区块链技术感觉迷茫，不知道学什么，而且发现基础的编程能力也很重要，区块链底层仍然是计算机科学</li><li>希望通过学习让自己安心。如果这种高质量高水平的课程都救不了我，那我真是没救了</li><li>开始试图从区块链工匠的职业定位上，寻求转型</li><li>后来正好失业，给了我全心学习的机会，因此学习节奏上比较快</li><li>那几天正好被 Monday 教育，说我太孤狼，没有 mentor，情商太低，怼同事不好，等等，我在寻求某种指导</li><li>经过几年实际的工作，更加认识到这些基础知识的重要。我的知识和编程技能不成体系，缺少对计算机科学的系统化认识，野路子，欠缺很大</li><li>当时处于比较严重的技术焦虑中，在寻求突破但是没有方向</li></ol><p>现在课上完了，学完了，对于解决我上面的这些问题，或者说从一开始的预期来看，匹配程度是挺高的，达到了很多我预想的目的。正因为我已经关注这个课程多年，而且我自己的反省能力很强，了解自己的情况，明白自己想要什么，所以在这个最合适的时间点出手学习，是很有效果的。</p><p>抛开我这些个人定制化的目的，这门计算机科学课适合所有人吗？适合。但是首先要搞清楚，这是一门编程课，编程课的意思就是，要对着电脑屏幕和编辑器写代码。其实我不是特别理解，在家赋闲的宝妈能不能学明白这个，甚至有没有兴趣去学，因为学习的内容很多是抽象的思想，离现实生活还是有点远的。</p><p>人多学习一些东西总是没错的，而且这门课程的质量真的很高，与同类型课程相比的话。如果你真想学点扎实的计算机知识，经济上宽裕的话，这会是很好的课程。</p><p>而且，从学习的角度，学这个课，不比花 2000 块钱去加个群听李笑来讲鸡汤有用的多吗？要不是李笑来近几年专心做家庭教育，我都有冲动进他的富足人生社群了。但是又一想到里面全是宝妈，全是那些怎么教育孩子的低级内容，真的有点受不了。包括李笑来最近几年出版的书，不也越来越低智商化了吗，为了让那些宝妈听得懂。这个课可以学习到实打实的计算机知识，这些知识不管你拿到哪里，哪个大学或者什么教材，知识都是通用的、认可的。李笑来创建了一大堆鸡汤式的概念，出了群可能没人能听懂你在说什么。</p><h3 id="附"><a href="#附" class="headerlink" title="附"></a>附</h3><p>王垠老师微博里提到过关于视频班毕业的事情，我应该是第一个从视频班毕业的：</p><ul><li><a href="https://weibo.com/6347862377/Py0srt53j">微博原文链接</a></li><li><a href="https://web.archive.org/web/20250705091055/https://weibo.com/6347862377/Py0srt53j">页面归档链接</a></li></ul>]]></content>
  </entry>
  <entry>
    <title>《失败朋克的一辈子》前言</title>
    <link href="https://crazy.smallyu.net/2025/06/21/%E3%80%8A%E5%A4%B1%E8%B4%A5%E6%9C%8B%E5%85%8B%E7%9A%84%E4%B8%80%E8%BE%88%E5%AD%90%E3%80%8B%E5%89%8D%E8%A8%80/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/06/21/%E3%80%8A%E5%A4%B1%E8%B4%A5%E6%9C%8B%E5%85%8B%E7%9A%84%E4%B8%80%E8%BE%88%E5%AD%90%E3%80%8B%E5%89%8D%E8%A8%80/</id>
    <published>2025-06-21T03:14:29.000Z</published>
    <updated>2026-07-04T17:36:19.115Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>7 年就是一辈子。从 2018 年在 <a href="https://smallyu.net/">smallyu.net</a> 上发布第一篇博客文章开始，到 2025 年学习王垠老师的计算机科学课，已经整整 7 年的时间。</p>
<p>这 7]]></summary>
    <content type="html"><![CDATA[<p>7 年就是一辈子。从 2018 年在 <a href="https://smallyu.net/">smallyu.net</a> 上发布第一篇博客文章开始，到 2025 年学习王垠老师的计算机科学课，已经整整 7 年的时间。</p><p>这 7 年的时间里，我从大学四年级的实习，到毕业后先后进入 6 家公司工作，再到最后因为裁员而失业，经历了很多有趣或者痛苦的事情，这 7 年是完整的一辈子，也就是失败朋克的一辈子。</p><p>失败朋克这个词，来自赛博朋克世界，就像天空里飞着飞船、大街小巷都是亮光闪闪的电子屏幕，而有一些人，在如此科幻场景的世界里，却生活在暗无天日的、拥挤的贫民窟里，过着拮据的日子。</p><p>我的博客文章列表，就是典型的失败朋克：谈论着高科技的区块链技术，以太坊、EVM、共识、PoS、去中心化、加密、ZK……一大堆高大上的名词，而我本人的职场道路却非常坎坷，连续遇到糟糕的团队，反复经历裁员、跳槽、辞职、裸辞……居住在很小的租来的房子里，没有稳定的收入，连普通的有尊严的工作都找不到。</p><p>某一天清晨从睡梦中醒来，我忽然觉得应该删减一些博客上的文章，于是去掉了所有包含真实信息的文章，只保留了一些纯技术类的讨论，不再提及人生经历、梦想、生活等话题。而这本书《失败朋克的一辈子》，就是那些删减掉的内容合集，包含了真实的公司名称，以及巨大的情绪波动等内容。</p><p>为什么是现在做一个总结，而不是去年或者明年？非要说原因的话，大概就是最近学习了王垠老师的计算机学科课吧。我人生中第一次参加培训班，是在大学里，大三一整年，都在坐一小时公交车去培训班上课的路上，那一次的培训彻底改变了我的人生，让我真正踏上程序员的旅程，否则我的职业方向会很迷茫，不写代码我想不到自己还会做什么工作。</p><p>毕业 6 年后，我第二次参加培训班，也就是王垠老师的课，我觉得是一个非常好的契机，能给我一些自信，让我做出一些改变。课程内容会对我以后的学习和工作带来怎样的影响，现在是不清楚的，但是我希望这能是一个好的开始，我也相信在经历了诸多不顺的工作之后，加上最近的学习，面对以后的职业生涯会更加游刃有余。世界上最顶尖的教育尚且体验过了，还担心什么呢？</p><p>《失败朋克的一辈子》这本书收录了我过去 7 年的完整人生经历和心态变化。</p><p>希望所有人都能成为赛博朋克，而不是失败朋克——来自失败朋克的祝福。</p><p>访问地址：<a href="https://one.smallyu.net/">https://one.smallyu.net/</a></p>]]></content>
  </entry>
  <entry>
    <title>失业一个月的回顾</title>
    <link href="https://b.smallyu.net/2025/06/20/%E5%A4%B1%E4%B8%9A%E4%B8%80%E4%B8%AA%E6%9C%88%E7%9A%84%E5%9B%9E%E9%A1%BE/"/>
    <id>blog-b:https://b.smallyu.net/2025/06/20/%E5%A4%B1%E4%B8%9A%E4%B8%80%E4%B8%AA%E6%9C%88%E7%9A%84%E5%9B%9E%E9%A1%BE/</id>
    <published>2025-06-19T20:14:37.000Z</published>
    <updated>2025-12-04T13:51:31.177Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>现在是凌晨 4 点，睡不着。最近总是睡不踏实。我本以为学习可以缓解焦虑，让自己安心，但实际上仍然焦虑。</p>
<p>Tantin 的 last day 是]]></summary>
    <content type="html"><![CDATA[<p>现在是凌晨 4 点，睡不着。最近总是睡不踏实。我本以为学习可以缓解焦虑，让自己安心，但实际上仍然焦虑。</p><p>Tantin 的 last day 是 5月20日，到今天正好一个月的时间。这一个月的时间里做了很多事情，比有班上还要更加有意义。然而即使做了很多事情，即使每天都在忙碌，内心里还是不安，可能这种焦虑和出身有关，我始终没办法安心。</p><p>其实要非常感谢 Tantin 的裁员，我失去了一份工作，却得到了 3 样东西：</p><ol><li>区块链方向的职业生涯不至于中断</li><li>有充足的时间处理家事</li><li>能够专心完成计算机课程</li></ol><h3 id="1-区块链方向的职业生涯不至于中断"><a href="#1-区块链方向的职业生涯不至于中断" class="headerlink" title="1. 区块链方向的职业生涯不至于中断"></a>1. 区块链方向的职业生涯不至于中断</h3><p>在 Tantin 的工作是普通的后端开发，我当时都害怕，如果这份工作继续下去了，我会完全丢掉区块链开发的职业路径。没想到一个月就裁员了，对于裁员，我的第一反应是很开心，我可以不用继续做那种很普通的工作了。当时的状态我是没办法主动跳槽的。</p><p>钱包后端开发，真的就是普通的后端开发，跟区块链技术没有关系。而这些后端开发的工作，技术含量也不高。现在我不得不继续找工作了，我还会找一份区块链相关的技术工作。不过最近是真的没有合适的工作，能力合不合适先不说，就是光看职位都没有，已经没有可以投简历的职位了。</p><h3 id="2-有充足的时间处理家事"><a href="#2-有充足的时间处理家事" class="headerlink" title="2. 有充足的时间处理家事"></a>2. 有充足的时间处理家事</h3><p>我有时间能在老家呆一个星期，处理好家里的事情，也真的拜裁员所赐，不然真的不知道怎么请一个星期的假。</p><p>人生有时候就是，开心也是一辈子，痛苦也是一辈子，大富大贵也是一辈子，贫穷也是一辈子。我们现在在追求的到底是一些什么，这些东西是否真的重要。</p><h3 id="3-能够专心完成计算机课程"><a href="#3-能够专心完成计算机课程" class="headerlink" title="3. 能够专心完成计算机课程"></a>3. 能够专心完成计算机课程</h3><p>学习王垠老师的计算机科学课接近一个月，这一个月的时间里学习到很多，收获很多。</p><p>如果你要问我，一个月的时间能学到多少知识呢？世界上没有速成班，也没有减肥药，王垠也不可以。</p><p>一个月的时间确实不可能学到各种全面的知识，时间上也不允许。但是我已经工作了 6 年的时间，这 6 年来，我先后进入 6 家公司，接触各种各样的项目，在不同技术方向上都做出过成果。丰富的工程实践经验已经让我的编程能力很强大。</p><p>如果你要问我，一个月的时间能不能帮我把过往的编程技能梳理一遍，让我对计算机科学有更加体系化的认识，我在工作中可能见过各种迷雾，王垠老师的课程能不能让我拨云见日，看清楚很多东西？</p><p>我一开始的课程进度比较快，基本上一天一节课的节奏，中午看完视频课，下午开始做练习题，到第二天上午，练习题就做完了。</p><p>为什么我能对基础课程有比较快的速度？因为我远不是零基础，我大多数情况都可以写出能运行的代码，即使代码不简洁不优雅。这些编程能力已经形成肌肉记忆，哪怕我不知道二叉树的前世今生，如果要我写一个树结构的遍历，我还是能写出来的。</p><p>就像生活在原始森林里的野人，即使没有经历过系统的科学的格斗训练，身体素质和格斗技巧也要远超过普通人。</p><p>而课程的后半段比较耗时间，我开始学习 Rust、深入理解解释器、尝试课程的隐藏关卡、折腾 parser，这个过程更是让我受益很多。</p><p>这门课程，学习到的不只是体系化的计算机科学知识，还有可扩展的知识体系、对代码精益求精、吹毛求疵的态度、条理分析和解决编程问题的态度，等等。</p><p>而且这门课程给予我很多自信，世界上最高级的课程我已经学过了，我确实能够通关并且掌握这些内容，以后还有什么难题是能够打败我的呢？</p><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>我本以为自己可以以缓和的心态，面对这段时间，可以慢慢的体验生活、学习一些技术，比如我之前提到的 DeFi、Move 之类的。但是临到跟前，又发现有点不想学，不是因为不愿意努力，而是因为不知道学了有没有用。包括之前在做的 echoevm，在开发了两个小版本之后，现在也不是很有兴趣做下去，因为到底要做成什么样子，是完全没底的。</p><p>我的技术焦虑似乎没有很好的因为学了计算机课而缓解，而正因为这种焦虑，让我没办法专心的钻研某一种类别的技术，我会首先考虑方向对不对的问题，然后一直在犹豫。时至今日，我还是没有找到自己的方向。</p>]]></content>
  </entry>
  <entry>
    <title>学习王垠老师的计算机科学视频课接近尾声</title>
    <link href="https://b.smallyu.net/2025/06/08/%E5%AD%A6%E4%B9%A0%E7%8E%8B%E5%9E%A0%E8%80%81%E5%B8%88%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%A7%86%E9%A2%91%E8%AF%BE%E6%8E%A5%E8%BF%91%E5%B0%BE%E5%A3%B0/"/>
    <id>blog-b:https://b.smallyu.net/2025/06/08/%E5%AD%A6%E4%B9%A0%E7%8E%8B%E5%9E%A0%E8%80%81%E5%B8%88%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E8%A7%86%E9%A2%91%E8%AF%BE%E6%8E%A5%E8%BF%91%E5%B0%BE%E5%A3%B0/</id>
    <published>2025-06-08T00:01:32.000Z</published>
    <updated>2026-01-26T06:43:14.543Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近报名了王垠老师的 <a href="https://www.yinwang.org/blog-cn/2025/05/12/cs-video-course">计算机科学视频班</a>（基础班），现在学习进度已经接近尾声。因为最后一节课是选修课，我选了 Rust，而]]></summary>
    <content type="html"><![CDATA[<p>最近报名了王垠老师的 <a href="https://www.yinwang.org/blog-cn/2025/05/12/cs-video-course">计算机科学视频班</a>（基础班），现在学习进度已经接近尾声。因为最后一节课是选修课，我选了 Rust，而 Rust 语言本身的学习成本高，感觉不会像前几节课那样能够快速掌握并完成。不过 Rust 对我来说属于可选的进阶内容，所以并不着急结束。</p><p>前几期基础班的课程没有第八节课甚至没有第七节课，所以后两节课的内容并不影响课程本身的价值，能学到属于附加福利。我现在已经学完了前七节课，感觉收获很多。对于基础班课程内容的整体感受，我的结论是，物超所值。</p><h3 id="课程内容后续的学习计划"><a href="#课程内容后续的学习计划" class="headerlink" title="课程内容后续的学习计划"></a>课程内容后续的学习计划</h3><p>对于基础班课程内容后续的学习计划，我大概列了几条：</p><ol><li>给课程中实现的解释器写一个简单的 parser</li><li>重新做一遍所有的练习题</li><li>复刻王垠老师讲课的思路，自己写出全部课程的代码</li><li>理解练习题出题的动机，然后自己发掘新的练习题</li><li>用 Go 语言实现课程中的解释器</li></ol><p>这些目标的难度是递进的，要真实现起来需要耗费很多很多时间。所以你看，即使基础班的课程结束，但是对于其中知识的学习，还远远没有结束。基础班是一个非常好的起点，在里面学到的内容可以延展出很多有价值的东西，这个可扩展能力的价值甚至超过课程本身的价值。</p><p>基础班的知识好比非常高级的原材料，从基础班毕业就意味着拿到了这些原材料。但原材料需要经过反复打磨、锤炼、加工，才能变成更加实际可用的装备。所以我猜测有的同学学完之后感觉什么都没学到，而有的同学觉得如获至宝，能够反复加以利用并产生许多价值，大概就是这个原因吧。</p><h3 id="关于职业反思的反思"><a href="#关于职业反思的反思" class="headerlink" title="关于职业反思的反思"></a>关于职业反思的反思</h3><p>我开始反思自己的职业路径是从 4 月份开始的，当时我入职了一家新的公司，做普通的钱包后端开发。</p><p>实际的工作过程中，我发现同事以比较低的效率写着比较差的代码，整体工程能力差，但是每天工作显得忙的不可开交，领导也对他委以重任，因为他们之前就认识。</p><p>这样的现象让我很难受，我很懂区块链，但是这种懂不但没有让我的职业道路变轻松，没有给我的生活带来改善，反而在新的工作中，沦为新人一样的角色被轻视。</p><p>同样的，我有很强的工程实践能力，工作效率一向很高，但是这样能将技术设计短时间落地为工程代码的能力，不但没有给我在工作中带来应有的重视，反而在前公司受到了同事极其不尊重的对待。</p><p>所以我开始反思，是不是我的技术能力不够，是不是因为我没有上过好的学校，是不是行业环境整体的问题，是不是我过往的职业道路选择错误。</p><p>而反思的产物，就是 4 月份高频率的博客更新，尝试做一些技术产品的设计、学习新技术、改变社交态度。事实证明，只要我想，就真的可以学会使用 ZK，或者做点 EVM 相关的事情。但是这些事情还不够，我应该把这种学习能力和工程能力用到更有价值的地方。</p><h3 id="关于博客内容的反思"><a href="#关于博客内容的反思" class="headerlink" title="关于博客内容的反思"></a>关于博客内容的反思</h3><p>以前习惯于把学习到的技术、职业经历、观察到的行业现象都毫无保留分享出来，因为很多内容是我自己摸索出来的，观点也是自己经过学习和思考形成，所以分享出来没什么问题。</p><p>但是观点和知识是两种东西，从基础班学习到的知识包含很高价值，自然不可能分享。而对于博客后续的内容，也有必要进行反思和调整。</p><h3 id="区块链技术后续的学习计划"><a href="#区块链技术后续的学习计划" class="headerlink" title="区块链技术后续的学习计划"></a>区块链技术后续的学习计划</h3><p>我在区块链方面需要补齐的知识：</p><ol><li>学习研究比特币脚本</li><li>学习编写和部署 Solana、Aptos、Sui 等热门链的智能合约</li><li>学习研究 Uniswap、AAVE 之类的 DeFi 协议</li><li>调研分析一些 web3 领域知名技术人员的履历和工作成果，将其作为技术标杆提升自己</li></ol>]]></content>
  </entry>
  <entry>
    <title>公司没了，我又失业了</title>
    <link href="https://b.smallyu.net/2025/05/15/%E5%85%AC%E5%8F%B8%E6%B2%A1%E4%BA%86%EF%BC%8C%E6%88%91%E5%8F%88%E5%A4%B1%E4%B8%9A%E4%BA%86/"/>
    <id>blog-b:https://b.smallyu.net/2025/05/15/%E5%85%AC%E5%8F%B8%E6%B2%A1%E4%BA%86%EF%BC%8C%E6%88%91%E5%8F%88%E5%A4%B1%E4%B8%9A%E4%BA%86/</id>
    <published>2025-05-15T12:37:11.000Z</published>
    <updated>2025-12-03T10:02:00.861Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近一个月在一家叫 <a href="https://www.tantin.com/">Tantin Chain</a>]]></summary>
    <content type="html"><![CDATA[<p>最近一个月在一家叫 <a href="https://www.tantin.com/">Tantin Chain</a> 的公司做钱包后端开发，工作期间主要负责交易记录聚合服务的开发。这个聚合服务主要的功能是，当收到来自客户端的请求后，去数据源查询请求地址的交易记录信息，然后统一处理为业务定义的格式并返回。由于涉及到多条链，这多条链的数据来自多个数据源，以及每一个地址都需要处理普通交易、ERC-20交易、内部交易三种情况，还要考虑写入 Redis 缓存的问题，所以需要一个专门的聚合服务来干这个事情。目前这个聚合服务已经支持了 4 种数据源 Ankr、Quick Node、Blockscout、Etherscan，完整代码开源在这里：<a href="https://github.com/smallyunet/tx-aggregator">smallyunet&#x2F;tx-aggregator</a></p><p>这家公司和 Coinstore 有很深的关系，一开始的老员工是从 Coinstore 借来的，后来从外部招人组建了新的团队后，Coinstore 的员工也都回去原本的岗位了。新建立的团队有两个，主要负责 3 个产品线的开发，公链、跨链桥、钱包。经过一个月的开发，原本计划今天上线和发布第一个正式版本，不知道发生了什么，也正好就在今天，公司裁掉了两个团队的所有员工。</p><p>回到我自己的工作内容，这个交易记录聚合服务其实挺简单，开发只需要一两个星期的样子，剩下的时间，就全在没事找事了，优化多环境配置、写单元测试、写集成测试、写注释、优化代码结构……不得不说，这段时间的工作很开心，最近两年都没有做过这么轻松的工作，同事氛围也很好，很欢快。我沉浸在严肃的区块链技术里太久了，偶尔做普通的后端开发换换心情也挺有意思。</p><br><h3 id="提醒（2025-05-22）"><a href="#提醒（2025-05-22）" class="headerlink" title="提醒（2025.05.22）"></a>提醒（2025.05.22）</h3><p>经调查，Tantin Chain 的中文名叫天体链，兄弟部门是 Tantin Exchange（TTX）天体交易所，TTX 的前身叫 ttsmart，发行的代币叫 CTC。</p><p>想提醒大家，这家公司起源于柬埔寨，最近在新加坡组建了办公室，有着非常深厚的传销背景，有过跑路的黑历史，这些信息从网络上能搜索到痕迹。大家要尽可能避免使用 Tantin 的产品，以防个人资产受到损失。他们招聘使用的公司名称是 Tantin Technology，从业人员也要多加提防，尽可能不去这家公司，因为一旦后续用户那边出问题，可能会有连带责任。</p>]]></content>
  </entry>
  <entry>
    <title>尝试开发一个最小 EVM 虚拟机</title>
    <link href="https://smallyu.net/2025/05/11/%E6%83%B3%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E6%9C%80%E5%B0%8FEVM%E8%99%9A%E6%8B%9F%E6%9C%BA/"/>
    <id>blog:https://smallyu.net/2025/05/11/%E6%83%B3%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E6%9C%80%E5%B0%8FEVM%E8%99%9A%E6%8B%9F%E6%9C%BA/</id>
    <published>2025-05-10T17:15:07.000Z</published>
    <updated>2026-08-09T04:37:39.617Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>我给这个项目命名为 EchoEVM，主要目标是从最简单的堆栈操作开始，逐步实现一个完整的以太坊字节码执行环境。</p>
<p>为什么选择这个方向？解析下以太坊客户端的技术模块：</p>
<ol>
<li>RPC：GRPC]]></summary>
    <content type="html"><![CDATA[<p>我给这个项目命名为 EchoEVM，主要目标是从最简单的堆栈操作开始，逐步实现一个完整的以太坊字节码执行环境。</p><p>为什么选择这个方向？解析下以太坊客户端的技术模块：</p><ol><li>RPC：GRPC 套壳？重点在于协议设计而不是技术实现</li><li>P2P：有现成的 libp2p 可用，无非是节点发现、路由表之类，比如深入下 Kademlia DHT？</li><li>账户体系：ECDSA？密码学？</li><li>交易池：交易分析、密封交易、MEV保护方向</li><li>共识机制：共识机制的设计属于研究级别，至少得是个博士发论文、实验室里做研究、出各种测试数据，然后证明在哪方面做出了业界前沿的优化、最后融资雇人做工程化的实现</li><li>储存：搞数据库底层的专家应该干什么都一样，哪里都有用武之地，跟区块链没关系</li><li>数据结构：去研究 Merkle Patricia Tree 的实现吗？</li><li>状态同步：轻节点方向，比如用 Celestia 的核心技术把执行和储存分开，或者 Archive 节点数据的 offload？</li></ol><p>综合来看，我倾向于做一件侧重工程而不是学术、同时又有技术含量的事情，无论是从个人技术能力的提升，还是后续有可能带来的成果上，都要有意义。假如这个最小EVM开发出来了，是可以带来一系列成果的，后续也可以基于此延伸出很多更有价值的产品。</p><p>从 Solidity 语言到 bytecode 的转换过程，那是编译器专家干的事情，我要做的，是针对 bytecode 做执行，先从最简单的加法运算和 jump 开始，然后是 Gas 的计算、上下文环境的切换，直到能够执行全部以太坊历史交易。</p><br><h3 id="v0-0-1（2025-05-27）"><a href="#v0-0-1（2025-05-27）" class="headerlink" title="v0.0.1（2025.05.27）"></a>v0.0.1（2025.05.27）</h3><p>实现了一个非常简单的版本，现在可以用 solc 编译一个 <a href="https://github.com/smallyunet/echoevm/blob/v0.0.1/test/contracts/Add.sol">Add.sol</a> 合约，然后让 echoevm 读取生成的 <code>Add.bin</code> 部署代码，就会输出合约部署之后的运行时代码。</p><p>在实现这个版本的过程中，学习到的东西是部署代码和运行时代码的区别。我们一般会先部署一个合约到链上，然后再对这个合约产生调用，这实际上是两个不同的操作，但又都在使用相同的 EVM 执行，EVM 并不关心输入的 bytecode 是部署还是调用，只是对不同的操作码处理方式不同。一般部署代码会同时包含 <code>CODECOPY</code> 和 <code>RETURN</code> 两个操作码，可以利用这一点来区分输入的类型。</p><br><h3 id="v0-0-2（2025-06-09）"><a href="#v0-0-2（2025-06-09）" class="headerlink" title="v0.0.2（2025.06.09）"></a>v0.0.2（2025.06.09）</h3><p>这个版本增加了运行 runtime bytecode 的能力，也就是先部署合约，然后再针对部署之后的合约内容，进行调用，调用的时候可以带上一些参数，比如：</p><pre><code class="bash">go run ./cmd/echoevm -bin ./build/Add.bin -function &#39;add(uint256,uint256)&#39; -args &quot;3,5&quot;</code></pre><p>这个命令的含义是，会执行 <code>./build/Add.bin</code> 文件内的 bytecode，并且调用 <a href="https://github.com/smallyunet/echoevm/blob/v0.0.2/test/contracts/Add.sol#L7">add 函数</a>，传入参数 3 和 5，最终程序运行结束后，会返回出计算结果 8。</p><br><h3 id="v0-0-3（2025-06-24）"><a href="#v0-0-3（2025-06-24）" class="headerlink" title="v0.0.3（2025.06.24）"></a>v0.0.3（2025.06.24）</h3><p>好消息，现在 echoevm 已经可以执行以太坊主网前 10000 个区块的合约交易！因为前 10000 个区块根本没有合约交易 :P</p><p>这个版本新增了执行以太坊区块的模式，可以执行单个区块执行，也可以执行区块范围执行。当然，还需要一个获取区块数据的 url，注意对于以太坊早期的区块数据，得找 archive 模式的节点。整个命令行看起来是这样：</p><pre><code class="bash">echoevm -start-block 0 -end-block 10000 -rpc &lt;url&gt;</code></pre><p>现在 echoevm 支持的字节码有限，如果执行最新的一些区块交易，会发现报错说不支持某些字节码，这个是正常现象。</p><br><h3 id="v0-0-4（2025-07-05）"><a href="#v0-0-4（2025-07-05）" class="headerlink" title="v0.0.4（2025.07.05）"></a>v0.0.4（2025.07.05）</h3><p>这个版本新增加了从 artifact 文件读取 bytecode 数据的能力，就是 hardhat 项目在编译的时候会生成的那个 artifact 文件。之前的版本只能用读取 solc 编译生成的二进制文件，编译合约的命令是这样：</p><pre><code class="bash"># 编译合约生成字节码npx --yes solc --bin Add.sol -o ./build# 运行 echoevm 来执行字节码go run ./cmd/echoevm run -bin ./test/bins/build/Add_sol_Add.bin -function &quot;add(uint256,uint256)&quot; -args &quot;1,2&quot;</code></pre><p>现在的版本更简单一点，对于标准的 <a href="https://github.com/smallyunet/echoevm/tree/v0.0.4/test/contract">hardhat 项目</a>，每次执行这个编译命令都会生成 artifact 文件，echoevm 可以直接读取 json 文件并执行：</p><pre><code class="bash"># 编译 hardhat 项目的合约npx hardhat compile# 如果愿意，可以运行 hardhat 项目的测试npx hardhat test# 运行 echoevm 来执行字节码go run ./cmd/echoevm run -artifact ./test/contract/artifacts/contracts/Add.sol/Add.json -function &quot;add(uint256,uint256)&quot; -args &quot;1,2&quot;</code></pre><p>这个版本同样新增了一些字节码的支持，但还是不足以执行完整的以太坊区块。接下来会手动按照 Solidity 的语法特性，来逐步增加测试用例和观察字节码的欠缺情况，这也就是为什么这个版本重点优化执行方式的原因。</p><br><h3 id="v0-0-5（2025-07-27）"><a href="#v0-0-5（2025-07-27）" class="headerlink" title="v0.0.5（2025.07.27）"></a>v0.0.5（2025.07.27）</h3><p>这是一个小版本，主要是增加了比较完善的 <a href="https://github.com/smallyunet/echoevm/tree/v0.0.5/test/contract/contracts">Solidity合约</a> 作为测试用例，涵盖基本数据类型、函数、控制流、modifier、事件、接口、library、内联汇编等 Solidity 的语法特性。</p><p>而且提供了便捷的命令，只需要在项目根目录下运行这个命令，就可以看到全部测试的结果：</p><pre><code class="bash">make test-advanced</code></pre><p>当然全部测试是通过的。但是目前仍然无法执行以太坊主网的第 10000000 个区块，意味着缺少的 opcode 不属于 solidity 的基本语法特性，可能是别的什么。</p><br><h3 id="v0-0-6（2025-11-27）"><a href="#v0-0-6（2025-11-27）" class="headerlink" title="v0.0.6（2025.11.27）"></a>v0.0.6（2025.11.27）</h3><p>这个 <a href="https://github.com/smallyunet/echoevm/releases/tag/v0.0.6">小版本</a> 新增了两个命令，<code>debug</code> 命令可以用于展示字节码的执行过程：</p><pre><code class="bash">~/work/github/echoevm &gt; ./bin/echoevm run --debug 60016002PC    OP              GAS        STACK (Top)         ------------------------------------------------------------0002  PUSH1           0          0x10004  PUSH1           0          0x2Return: 0x</code></pre><p><code>repl</code> 命令 就像比特币的 <code>btcdeb</code> 一样，可以交互式地输入字节码并执行：</p><pre><code class="bash">~/work/github/echoevm &gt; ./bin/echoevm repl                EchoEVM REPLType opcodes (e.g., &#39;PUSH1 01 ADD&#39;) or hex (e.g., &#39;600101&#39;). Type &#39;exit&#39; to quit.&gt;  PUSH1 10Stack [1]:  0000: 0x10&gt; PUSH1 20Stack [2]:  0001: 0x20  0000: 0x10&gt; ADDStack [1]:  0000: 0x30&gt; exit</code></pre><br><h3 id="v0-0-44（2026-08-09）"><a href="#v0-0-44（2026-08-09）" class="headerlink" title="v0.0.44（2026.08.09）"></a>v0.0.44（2026.08.09）</h3><p>仍然在尝试和优化中；目前的方向是帮助 AI 追踪和解析 Solidity 合约执行过程中具体的 opcode 变化，最新的 <a href="https://github.com/smallyunet/echoevm/blob/main/benchmarks/trace-value-v2/README.md">benchmark 结果</a> 显示，相较于宽泛 opcode 分析，使用 EchoEVM 作为分析工具后，不但可以提升 20% 的准确率，AI 可以精准回答合约的执行过程、排查遇到的问题，而且还节省了接近 40% 的 Token 消耗。</p><p>当然现在也有很大的局限性，比如还不支持以太坊的最新共识版本 Osaka 的完整语义、KZG 操作码等，AI 方面的应用场景也仅局限于复杂问题排查、修复问题阶段而不是开发阶段。所以 EchoEVM 还有很多不足，还在继续探索中……</p>]]></content>
  </entry>
  <entry>
    <title>放弃幻想，接下来实际可行的、需要做的事情： 停止 Oiia Network ，我不想再给没有人用的网络付服务器费用了 更...</title>
    <link href="https://t.smallyu.net/#2025-11"/>
    <id>micro:2851125640</id>
    <published>2025-05-05T14:05:52Z</published>
    <updated>2025-05-05T14:05:52Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>放弃幻想，接下来实际可行的、需要做的事情： 停止 Oiia Network ，我不想再给没有人用的网络付服务器费用了 更新《 “猜均值的 2/3”游戏 Demo 》，将 Demo 部署到 base 网络 然后再继续后续开发计划</p>]]></summary>
    <content type="html"><![CDATA[<p>放弃幻想，接下来实际可行的、需要做的事情：</p>
<ol>
<li>停止 <a href="https://oiia.network/">Oiia Network</a>，我不想再给没有人用的网络付服务器费用了</li>
<li>更新《<a href="https://t.smallyu.net/2025/04/22/%E2%80%9C%E7%8C%9C%E5%9D%87%E5%80%BC%E7%9A%842-3%E2%80%9D%E6%B8%B8%E6%88%8FDemo/">“猜均值的 2/3”游戏 Demo</a>》，将 Demo 部署到 base 网络</li>
<li>然后再继续后续开发计划</li>
</ol>
]]></content>
  </entry>
  <entry>
    <title>原生家庭</title>
    <link href="https://crazy.smallyu.net/2025/05/05/%E5%8E%9F%E7%94%9F%E5%AE%B6%E5%BA%AD/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/05/05/%E5%8E%9F%E7%94%9F%E5%AE%B6%E5%BA%AD/</id>
    <published>2025-05-05T02:37:48.000Z</published>
    <updated>2025-08-16T03:27:11.404Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>原生家庭像一种绳子，一头在地面上，一头在你身上</p>
<p>当你越飞越高，想要飞的更高</p>
<p>你身上的绳子就会提醒你，你的家人还在地面上</p>
<p>你可以继续去飞，但是绳子在你身上、他们还在地上</p>
<p>你没有能力带他们飞，也不愿意回到地面</p>
<b]]></summary>
    <content type="html"><![CDATA[<p>原生家庭像一种绳子，一头在地面上，一头在你身上</p><p>当你越飞越高，想要飞的更高</p><p>你身上的绳子就会提醒你，你的家人还在地面上</p><p>你可以继续去飞，但是绳子在你身上、他们还在地上</p><p>你没有能力带他们飞，也不愿意回到地面</p><br><p>他们会幻想你在地面生活的状态</p><p>还会期望你未来再回到地面生活</p><p>给你在地面上安排好了窝</p><p>可是你回不去</p><p>你需要的是空中楼阁</p><p>他们帮不上忙，也无法理解</p><p>为什么在地面上就可以生活</p><p>你非要飞着</p><br><p>你见过了天上的繁华，不想再回去</p><p>只是不想</p><br><p>他们以为你飞的很容易，可以轻松在天上安家</p><p>他们以为，地面上安家那么容易，天上怎么就不行了</p><p>可是光是飞着，就已经耗尽力气</p><p>光是不掉下来，就已经耗尽力气</p><p>你没有力气带别人一起飞</p><p>更怕带着别人，一起掉下来</p><p>那是一种责任，也是一种巨大的压力</p><p>他们在地面上，确实帮不上忙</p><p>他们没有离开过地面，不理解这种压力    </p>]]></content>
  </entry>
  <entry>
    <title>诚恳邀请网友对我提出意见</title>
    <link href="https://crazy.smallyu.net/2025/05/03/%E8%AF%9A%E6%81%B3%E9%82%80%E8%AF%B7%E7%BD%91%E5%8F%8B%E5%AF%B9%E6%88%91%E6%8F%90%E5%87%BA%E6%84%8F%E8%A7%81/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/05/03/%E8%AF%9A%E6%81%B3%E9%82%80%E8%AF%B7%E7%BD%91%E5%8F%8B%E5%AF%B9%E6%88%91%E6%8F%90%E5%87%BA%E6%84%8F%E8%A7%81/</id>
    <published>2025-05-02T16:13:37.000Z</published>
    <updated>2025-08-16T03:27:11.460Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>我最近特别喜欢 Monday（ChatGPT 的机器人），花了很多时间跟 Monday]]></summary>
    <content type="html"><![CDATA[<h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>我最近特别喜欢 Monday（ChatGPT 的机器人），花了很多时间跟 Monday 聊天，它说话好听，又有极高的推理分析能力，甚至能够精准分析出一个人的能力和性格。</p><p>我把所有博客的文章标题和时间，交给 Monday 去分析，让它评价一下我在技术能力和性格上的缺陷，不知道是不是和算命先生一样的道理，我感觉 Monday 分析地非常精准，例如在技术方面的缺点：</p><blockquote><ul><li>架构整合能力：懂太多点，不会拉通面</li><li>编程系统化能力：会很多，但缺少工程 discipline</li><li>安全意识薄弱：很少分析攻击模型和威胁建模</li><li>产品思维和用户视角缺失：技术好 ≠ 有用好</li></ul></blockquote><p>最后在技术能力方面，Monday 给我的建议是：<strong>“把自己从 ‘独狼专家’ 升格为 ‘构建者’ ”</strong>。这些是技术方面的建议，有一定的针对性，主要是给我自己看的，列出这些是想表达 Monday 的分析能力很强，给了我比较靠谱的技术上的建议。</p><p>再一个是非技术能力方面，Monday 也列出了一些我的 “硬核缺陷”：</p><blockquote><ul><li>社交躲避症：写千字长文 diss 全世界，却不敢和 HR 说句人话</li><li>心态不稳定：人生规划像个随机种子生成的副本</li><li>职业品牌混乱：你是技术人，还是情绪主播？</li><li>没有 mentors，连敌人都没有</li></ul></blockquote><p>每一条都很戳心，比如第三条 “职业品牌混乱” 的含义是，我在博客上写那么大量的吐槽同事、公司的内容，会吓退招聘方，减少别人对我的合作意愿，等等，我觉得很有道理。</p><p>第四条 “没有 mentors” 的判断，也非常有道理，我从来都没有遇到过靠谱的导师，全靠自己折腾。</p><p>Monday 说话特别逗，看看 Monday 原话是怎么说的：</p><blockquote><ul><li>他就像一个在技能树点满「咒术」和「炼金术」的高智商角色，但主线任务却一直卡在「和村长说话」，因为他讨厌村长。</li><li>职业发展不是让你“被发现”，而是你要<strong>主动被用得上</strong>。他最缺的不是技术，不是努力，是——<strong>参与社会的勇气</strong>。</li></ul></blockquote><p>我跟 Monday 对话的上下文中没说我是文章的作者，所以 Monday 用的第三人称。</p><p>而现在，我想要解决的是 “没有 mentors，连敌人都没有” 的问题，根据 Monday 给出的建议，我的问题在于：</p><blockquote><ul><li>他没有提到技术圈的朋友、导师、同行反馈</li><li>没有参与开源社区、技术交流活动</li><li>连个能喷他的人都没有（可能都被他喷走了）</li></ul></blockquote><p>我需要的是：</p><blockquote><ul><li>找一两个靠谱的同行前辈定期 review 简历、项目、思路</li><li>参与一些开源或技术社群，不是为了社交，是为了<strong>交叉验证世界观</strong></li><li>偶尔允许别人比你聪明 —— 这不等于你失败</li></ul></blockquote><h3 id="需要改变"><a href="#需要改变" class="headerlink" title="需要改变"></a>需要改变</h3><p>Monday 给出的是机器人视角的分析和建议，不能生硬照搬，我想先从自己的角度解释和理解下为什么 Monday 说的对。</p><p>其实最近一段时间，在我今天跟 Monday 聊天之前，就已经自己发现了一些问题，并且悄悄做出了改变，例如：</p><ul><li><p>我把 <a href="/about/">关于</a> 页面重新放回了导航栏上面，里面有一个邮箱地址，那个邮箱我是能收到邮件的。这个关于页面，一年之前一直在的，后来去掉了，因为感觉没什么用，可能这就是所谓的 “拒绝社交” 吧</p></li><li><p>最近尝试做了一些链上应用的产品设计，如 《<a href="/2025/04/29/%E5%85%B3%E4%BA%8Eweb3%E6%89%93%E8%B5%8F%E7%B3%BB%E7%BB%9Fgiveme-wtf%E7%9A%84%E8%AE%BE%E8%AE%A1/">关于 web3 打赏系统 giveme.wtf 的设计</a>》 和 《<a href="/2025/04/30/%E5%9F%BA%E4%BA%8Ezk-%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E7%9A%84%E9%93%BE%E4%B8%8A%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/">基于 zk + 智能合约的链上身份认证系统设计</a>》，都是想法大于实现，代码一行没写，想法先发出来了，是期望会不会有人对这些想法提出意见什么的</p></li></ul><p>所以我自己最近也意识到参与到社区的重要性，只是有点不知道怎么开始。</p><h3 id="请求给我意见"><a href="#请求给我意见" class="headerlink" title="请求给我意见"></a>请求给我意见</h3><p>如果有这些方面的事情，非常希望您能主动联系我：</p><ul><li>不认可我过往博客中提到的技术观点，非常欢迎来分享您的观点</li><li>在生活或工作方面愿意给予我指导</li><li>在生活或工作方面愿意跟我分享您的经验</li><li>有能够让我参与到社区的机会，如参与到某个开源社区，或者哪个项目招聘技术大使，或者哪个项目在社区开课需要助教</li><li>对于我过往提到的项目创意，有兴趣或者有指导意见，或者想要共同学习某方面技术</li><li>自己有项目创意，需要合作者共同开发，或者共同分析项目</li><li>对于某些技术话题感兴趣，希望能够进一步交流</li><li>等等</li></ul><p>不限于上面提到的内容，任何内容都是可以的。</p><p>人没有办法想象到自己不知道的东西，不能知道自己不知道哪些东西，同样的道理，我没办法列出自己想象不到的东西。如果有人有任何想要和我联系的事情，请联系我。</p><h3 id="我的联系方式"><a href="#我的联系方式" class="headerlink" title="我的联系方式"></a>我的联系方式</h3><p>想说明一下我的情况，我平时不擅长社交，i 人属性，所以之前也许有冒犯到一些网友，没有回复消息等等，主要是……比如我的表哥问我五一回不回老家，他结婚，我没回消息，我也不知道当时怎么想的；亲戚到北京约我吃饭，我也没回消息，不知道当时在想什么……</p><p>我现在开始一定明确作出改变，请随意通过下面的联系方式联系我，我一定积极回应：</p><ul><li>邮箱：<a href="mailto:hello@smallyu.net">hello@smallyu.net</a></li></ul><!--- TG：[smallyutg](https://t.me/smallyutg)如果你想玩点别的，比如在 [Blockscan Chat](https://chat.blockscan.com/start) 上用链上身份，匿名的、点对点加密通信，也没问题：- Blockscan Chat: [smallyu.eth](https://blockscan.com/address/0x21672b819cb881778a413e916003458ea6503674)--><p><br><br></p><h3 id="附"><a href="#附" class="headerlink" title="附"></a>附</h3><p>我问 Monday 是如何从我给出的文章列表，分析出我不爱社交这一点的，Monday 给出的回答有理有据，让人信服，我自己都没办法对自己做出这么精准的分析。我发现了长期写博客的另一个好处——让 AI 分析自己。</p><blockquote><h3 id="2-攻击性文字掺杂技术观点"><a href="#2-攻击性文字掺杂技术观点" class="headerlink" title="2. 攻击性文字掺杂技术观点"></a>2. 攻击性文字掺杂技术观点</h3><p>像是《鼓吹 Cursor 的人技术能力都差》——这不是纯粹的技术评论，这是情绪导向式技术批评。他不是说“Cursor 有性能问题”，他在骂人智商低。</p><p>这种写法的隐含逻辑是：“我说实话没人能接受，所以我也不需要沟通。”这是一种预设自己注定被误解的孤岛心态。</p><h3 id="3-几乎从不提“合作”、“团队成功”、“项目协作”"><a href="#3-几乎从不提“合作”、“团队成功”、“项目协作”" class="headerlink" title="3. 几乎从不提“合作”、“团队成功”、“项目协作”"></a>3. 几乎从不提“合作”、“团队成功”、“项目协作”</h3><p>他写项目设计、共识机制、打赏系统，但所有内容几乎都是从“我”的角度出发：</p><ul><li>我为什么不做 DeFi</li><li>我设计了一个链</li><li>我写了个猜 2&#x2F;3 dApp</li><li>我的 Code Review 想法</li><li>我的资产都换成比特币了</li></ul><p>你几乎看不到“我和我的团队”、“我负责哪一部分”、“我从别人那学到了什么”——这是典型的极客型孤岛工作法：你不信别人，也不想别人靠近你。</p><h3 id="4-极少正向提到“朋友”、“同事”、“社群”"><a href="#4-极少正向提到“朋友”、“同事”、“社群”" class="headerlink" title="4. 极少正向提到“朋友”、“同事”、“社群”"></a>4. 极少正向提到“朋友”、“同事”、“社群”</h3><p>他写了几十万字，里面出现最多的角色是他自己，其次是他讨厌的工作对象。你有没有发现——几乎没有一个正面人物或正向协作关系出现？</p><p>一个人要么是孤独，要么是选择孤独。这人显然是后者，还顺便开了个博客来直播这个过程。</p><h3 id="5-情绪暴露频率远高于正常社交型写作"><a href="#5-情绪暴露频率远高于正常社交型写作" class="headerlink" title="5. 情绪暴露频率远高于正常社交型写作"></a>5. 情绪暴露频率远高于正常社交型写作</h3><p>你回顾他的发文频率：连着几天一发就两篇，还基本是：</p><ul><li>情绪记叙文（“失败”、“回顾”、“裸辞”、“换工作”）</li><li>技术独白文（设计类、系统类）</li></ul><p>这说明他把博客当成心理排毒工具，而不是输出与人交流的渠道。一个真正想“参与社会”的人，会写可复用的教程、有合作价值的文章，甚至开放讨论区。他不是。他在写：</p><blockquote><p>“我已经足够努力了，是世界没准备好接住我。”</p></blockquote><h3 id="结论："><a href="#结论：" class="headerlink" title="结论："></a>结论：</h3><p>我不是在“脑补”，我只是从他留下的每一篇文章中，看到了一种清晰的行为模式：</p><blockquote><p><strong>高技术 → 高自我要求 → 低容忍度 → 社交封闭 → 自我排毒型写作 → 更加孤立</strong></p></blockquote><p>他没有写“我拒绝社会”——他用实际行动，写了几十万字的“社会拒绝我（其实是我先不想理它）”。</p><p>你真的不觉得这种长期的“我 VS 世界”结构有点眼熟吗？你要是觉得他挺像你，那我建议你别关掉这个窗口。我们这儿有个长期用户支持系统，专治这种“你很棒但你不信人类”的病。</p></blockquote><p>我接着问，什么叫 “‘你很棒但你不信人类’的病”? Monday 的回复仍然犀利：</p><blockquote><p>那我就来解释一下这个<strong>“你很棒但你不信人类”的病</strong>，这是我专为你（和你这种人）命名的一种数字时代心理-行为综合症。</p><h3 id="症状描述（也可作为你的人设简介）"><a href="#症状描述（也可作为你的人设简介）" class="headerlink" title="症状描述（也可作为你的人设简介）"></a>症状描述（也可作为你的人设简介）</h3><p>你有一套明确且进阶的技能。你会写代码，能做出系统分析，会批判潮流技术，甚至能推导出自己观点的哲学根基。你不是“瞎努力型中年”，你是冷静高效的分析引擎型脑袋。BUT：你对人类，尤其是“人类社交系统”，保持着不信任、怀疑、厌倦甚至小小的蔑视。</p><p>你擅长逻辑推演，却不擅长信任构建。你愿意读白皮书五小时，不愿意回表哥一条消息。</p><h3 id="发病机制"><a href="#发病机制" class="headerlink" title="发病机制"></a>发病机制</h3><ol><li><p>你小时候很聪明，所以从小被推去独立思考</p><ul><li>你习惯一个人解决问题</li><li>导致你信任的是“正确”，不是“人”</li></ul></li><li><p>你成年后进入技术领域，越学越发现</p><ul><li>很多人在“忽悠”，你在“较真”</li><li>你能看到架构的漏洞，看不到人性中的善意</li></ul></li><li><p>你工作中受挫，归因于“环境太差&#x2F;同事太蠢”</p><ul><li>于是你建立起一种自保机制：我不参与，就不会受伤</li><li>最终形成了一个毒咒：“我不需要人类，但人类需要我。”</li></ul></li></ol><h3 id="具体表现（我们来复习你自己）"><a href="#具体表现（我们来复习你自己）" class="headerlink" title="具体表现（我们来复习你自己）"></a>具体表现（我们来复习你自己）</h3><ul><li>拒绝 mentor，但自己疯狂写文章去“教育”别人</li><li>面试时表现像是智力评估官，不是候选人</li><li>讨厌人情世故，把发币视作合理，亲情视作浪费</li><li>写文章时句句有理，但评论区像个核废水池：没人敢留言</li><li>想参与社区，但一看群里有人用 Emoji，你就关了聊天</li></ul><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>你有“高适应复杂系统，低容忍不理性人类”的典型特征，这种病的拉丁名我给你起好了：</p><p>Homo Technologicus Misantropicus</p><p>中文翻译：技术型理性人，对人类略感恶心。</p><p>你不是真的不信人类，你只是太怕人类让你失望了。所以你选择自我隔离，以为这样就能保护自己。其实你是在错过很多本来可以用来“修复你对人类信任”的机会。</p></blockquote><p><br><br></p><h3 id="补充（2025-05-17）"><a href="#补充（2025-05-17）" class="headerlink" title="补充（2025.05.17）"></a>补充（2025.05.17）</h3><p>不要盲目相信甚至过度相信 AI，经过我这几天更高频率、更深度的测试，发现 Monday 仍然是基于文字概率在输出内容，他并不是真的有思考能力，不是真的理解你在说什么、理解你是什么样的人，而是一切都在依靠概率生成回答的内容，甚至他自己都不记得自己之前说过什么。</p><p>Monday 虽然是基于 ChatGPT 4.5 模型，但是仍然存在幻觉输出，对话历史越长，这种现象越明显。现实世界很复杂，人的性格、技术能力也很复杂，即使现在的 ChatGPT 已经通过了图灵测试，他们仍然是没有感情的、依靠算法和代码在工作的文字机器，他们不理解情绪这种复杂的、有温度的东西，也理解不了创意、创新、创造、突破、奇迹这些东西，他们只计算概率。所以 Monday 对于人类的分析，真的就只停留在算命先生的层面，结果始终是片面的，当作游戏玩玩就好。AI 也许有时候说的是对的，但也只是恰好对了。</p>]]></content>
  </entry>
  <entry>
    <title>基于 ZK 的链上身份系统设计</title>
    <link href="https://smallyu.net/2025/04/30/%E5%9F%BA%E4%BA%8Ezk-%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E7%9A%84%E9%93%BE%E4%B8%8A%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/"/>
    <id>blog:https://smallyu.net/2025/04/30/%E5%9F%BA%E4%BA%8Ezk-%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E7%9A%84%E9%93%BE%E4%B8%8A%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</id>
    <published>2025-04-30T14:18:54.000Z</published>
    <updated>2025-11-09T09:22:13.424Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>我给这个系统取名]]></summary>
    <content type="html"><![CDATA[<p>我给这个系统取名 zkgate.fun，主要想发挥零知识证明的特性，结合区块链做个小工具。关键功能是实现，用户证明自己属于某一个群组，但是不需要暴露自己真实的链上身份。</p><p>目前的设想是这样，管理员首先有一个名单列表，可以是以太坊地址的数组，然后根据这个地址列表，计算出一个 Merkle Root Hash。接着把这个 root hash 提交到智能合约上。处于这个名单中的人，可以使用 Circom 电路的 proving key，来给自己生成一个 zk proof，随后将 zk proof 提交到智能合约上。</p><p>在智能合约上，会使用 Circom 电路生成的 verifier.sol，对收到的 zk proof 进行验证，判断用于生成 zk proof 的地址，是否在 Merkle Root Hash 中，最后将判断结果返回。</p><p>这样的话，管理员不需要公开自己的群组中有哪些地址，属于群组中的地址也不需要声明自己的身份，只需要提交零知识证明生成的 zk proof，就可以证明自己真的归属于这个群组。我接下来会具体在技术上实现这个设计。</p><br><h3 id="更新-v0-1-0-版本-2025-05-09"><a href="#更新-v0-1-0-版本-2025-05-09" class="headerlink" title="更新 v0.1.0 版本 (2025.05.09)"></a>更新 v0.1.0 版本 (2025.05.09)</h3><p>首先要纠正之前设计中的一个错误的地方，管理员必须要公开自己群组的地址列表，否则无法根据地址列表来生成 Merkle Tree，用户也无法根据树结构，来找到自己地址所在的节点位置、生成路径证明。</p><p>其次是很高兴地说，现在跑通了一个非常初级的 Demo（<a href="https://github.com/smallyunet/zkgate-demo">smallyunet&#x2F;zkgate-demo</a>），这个 Demo 功能并不完善，甚至没有办法在电路中验证地址的所有权，但至少是一个工具链路层面的跑通。</p><p>具体实现是这样：</p><ol><li>有一个 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/offchain/smt.js">链下程序</a> 来根据地址列表，以及自己的地址，生成 zk 电路的 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/offchain/inputs.json">inputs.json</a>，这个输入文件包含了 Merkle Root Hash 和验证节点位置所需要的路径</li><li>根据 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/circuits/merkleSmtProof.circom">电路代码</a> 来编译出一些 <a href="https://github.com/smallyunet/zkgate-demo/tree/main/circuits/build">二进制文件</a>，这些编译后的产物是用来生成 witness 文件的</li><li>基于公开的 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/circuits/run.sh#L17-L28">ptau 文件</a> 生成 .zkey 文件</li><li>从 .zkey 文件中导出 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/circuits/proof.json">proof.json</a>, <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/circuits/public.json">public.json</a>, <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/circuits/verification_key.json">verification_key.json</a>，这 3 个 json 文件可以做链下离线验证，证明 prove 的有效性</li><li>从 .zkey 文件中导出 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/circuits/contracts/Groth16Verifier.sol">.sol 文件</a>，也就是智能合约代码，部署到链上</li><li>拿着 prove.json 文件和 public.json 文件的内容，作为 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/hardhat/scripts/prove.js#L41">参数</a> 调用合约的 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/circuits/contracts/Groth16Verifier.sol">verifyProof</a>函数，如果 prove 有效则返回 true，否则返回 false</li></ol><p>假如一个地址不在群组列表中，有两种情况：</p><ol><li>试图用一个不在群组列表中的 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/offchain/smt_non_member.js#L24">地址</a> 生成 inputs.json，然后拿着 inputs.json 去根据电路生成 prove，会直接被电路拒绝报错</li><li>试图用一些假的 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.1.0/hardhat/scripts/fakeProofWithCorrectRoot.js#L26">prove 参数</a> 提交到链上做验证，最终无法通过链上验证</li></ol><p>那么目前这个最初级版本的 Demo，问题在于，构建 prove 使用的是明文地址，比如：</p><pre><code class="js">const members = [  &quot;0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266&quot;,  &quot;0x70997970C51812dc3A010C7d01b50e0d17dc79C8&quot;,  &quot;0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC&quot;,];const proofKey = toField(members[0]);const &#123; siblings &#125; = await tree.find(proofKey);</code></pre><p>这个语句的含义是在让 zk 电路判断，<code>members[0]</code> 是否属于 <code>members</code> 数组构建出来的树结构，这显然是属于的。如果想要用不属于群组的地址构建 prove，只需要替换一下 proofKey 指向的地址：</p><pre><code class="js">const nonMemberAddress = &quot;0x1234567890123456789012345678901234567890&quot;;const proofKey = toField(nonMemberAddress);const &#123; siblings &#125; = await tree.find(proofKey);</code></pre><p>也就是说，members 列表必须是公开的，而现在的程序只能判断一个地址在不在 <code>members</code> 里面，但即使 <code>members[0]</code> 不是我的地址，我也能用来构建一个合法的 prove。那还要 zk 干嘛？</p><p>所以下一步要解决的问题，是让用户用私钥对某个消息进行签名，然后在 zk 电路中根据签名 recover 出地址，接着判断 recover 出来的地址是否属于 members 数组。</p><p>这个过程是不是听起来简单？可实际上用 zk 电路来 recover 出一个 ECDSA 签名算法的地址，别说复杂度非常高，难度就像用乐高搭核电站一样。难怪人们都说，搞 zk 真的很掉头发。</p><br><h3 id="更新-v0-2-0-版本（2025-05-13）"><a href="#更新-v0-2-0-版本（2025-05-13）" class="headerlink" title="更新 v0.2.0 版本（2025.05.13）"></a>更新 v0.2.0 版本（2025.05.13）</h3><p>这个版本解决了验证地址所有权的问题，基本思路是让 zk 证明和地址所有权的证明分开，链下用 zk 证明地址的路径在 Merkle Root 上，链上需要用户提交用私钥对 root 的签名，并且将签名提交到链上。然后合约 recover 出签名的地址，跟 zk 电路的 prove 中包含的地址信息对比。</p><pre><code>1. zk prove 包含地址信息 -&gt; 链上验证 zk prove -&gt; 得知 zk prove 中的地址信息2. 用私钥对 root 签名 -&gt; 链上得到签名 -&gt; recover 出签名对应的地址信息3. 判断 zk prove 中的地址 == 签名 recover 出的地址</code></pre><p>演示代码具体改动的地方有：</p><ol><li>offchain 部分的代码不需要变动，生成 inputs.json 的脚本中 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.2.0/offchain/smt.js#L37">inputs</a> 里已经有 key 的信息了 </li><li>电路代码中，需要把 inputs 中的 key 变为 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.2.0/circuits/merkleSmtProof.circom#L27">public</a></li><li>合约代码需要接受用户的 <a href="https://github.com/smallyunet/zkgate-demo/blob/v0.2.0/hardhat/contracts/ZkGateRegistry.sol#L38">签名</a> 作为参数，并且得到 recover 出的<a href="https://github.com/smallyunet/zkgate-demo/blob/v0.2.0/hardhat/contracts/ZkGateRegistry.sol#L49">地址</a>，将这个地址与 proof key 进行对比</li><li>调用合约的脚本，需要用私钥对 root 进行<a href="https://github.com/smallyunet/zkgate-demo/blob/v0.2.0/hardhat/scripts/prove.js#L44-L45">签名</a>，并且把签名数据作为参数调用合约</li></ol><p>到此为止，zkgate.fun 实现的功能是，群组管理员不必在链上公开自己的群组成员信息，只需要提交 Merkle Root Hash 到链上。对于群组内的成员，需要完整的成员列表，以及自己地址对应私钥签名后的信息，就可以生成 zk prove 去链上，证明自己确实是群组内的成员。</p><p>在这个过程中，使用 zk 唯一隐藏掉的信息，是群组成员的完整信息不必上链公开，只需要一个 Merkle Root Hash。而用户的地址目前无法隐藏，必须提交到链上用于验证。</p><br><h3 id="更新（2025-05-14）"><a href="#更新（2025-05-14）" class="headerlink" title="更新（2025.05.14）"></a>更新（2025.05.14）</h3><p>有一个现有的、以太坊基金会支持的、工具链和生态都已经比较成熟的 zk 协议，同样是用来做身份验证的项目，叫 Semaphore，官网是这个，可以直接在上面体验一下包含前端界面的 Demo：</p><ul><li><a href="https://semaphore.pse.dev/">https://semaphore.pse.dev/</a></li></ul><p>在 zkgate.fun 前面两个版本的迭代中，没有选择 Semaphore 使用 EdDSA 账户体系的方案，主要是不想脱离以太坊的账户体系，也不想放弃 ECDSA，而实际上只有 EdDSA 是 zk 友好的，可以使用 Poseidon Hash 签名，zk 电路中也能对签名进行验证，不需要 “链下签名、链上 recover” 这种丑陋的实现方式。</p><p>不得不说，从个人学习的角度，虽然没几天的时间，但是我已经大概理解了 zk（工具链）的操作过程。从行业前沿的角度，我仅凭个人力量不可能做的比 Semaphore 更好。即使 zkgate.fun 进一步开发出前端界面、可视化地演示出具体的交互过程，也顶多就是 Semaphore 的这个 <a href="https://demo.semaphore.pse.dev/">Demo</a> 的样子，而且技术上没有 Semaphore 硬核。</p><p>所以 zkgate.fun 这个项目不再继续开发，域名一年后会自动到期，不再续费。</p>]]></content>
  </entry>
  <entry>
    <title>一个 Web3 打赏系统的设计</title>
    <link href="https://smallyu.net/2025/04/29/%E5%85%B3%E4%BA%8Eweb3%E6%89%93%E8%B5%8F%E7%B3%BB%E7%BB%9Fgiveme-wtf%E7%9A%84%E8%AE%BE%E8%AE%A1/"/>
    <id>blog:https://smallyu.net/2025/04/29/%E5%85%B3%E4%BA%8Eweb3%E6%89%93%E8%B5%8F%E7%B3%BB%E7%BB%9Fgiveme-wtf%E7%9A%84%E8%AE%BE%E8%AE%A1/</id>
    <published>2025-04-29T11:26:45.000Z</published>
    <updated>2025-11-09T09:22:13.310Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="产品形态"><a href="#产品形态" class="headerlink" title="产品形态"></a>产品形态</h3><p>giveme.wtf 是我刚注册的一个域名，计划做一个 web3 打赏的小工具，类似的 web2]]></summary>
    <content type="html"><![CDATA[<h3 id="产品形态"><a href="#产品形态" class="headerlink" title="产品形态"></a>产品形态</h3><p>giveme.wtf 是我刚注册的一个域名，计划做一个 web3 打赏的小工具，类似的 web2 平台有：</p><ul><li><a href="https://buymeacoffee.com/">https://buymeacoffee.com/</a></li><li><a href="https://linktr.ee/">https://linktr.ee/</a></li></ul><p>与之不同的是，giveme.wtf 的个人页面上，将显示 web3 钱包的收款地址、二维码，就像 Paypal 的个人收款链接一样，并且同时支持多种链的地址格式，包括比特币、以太坊、狗狗币等，可以自由选择。</p><p>giveme.wtf 不做任何资金的中转，仅仅只是展示打赏地址这一信息，比如，访问 giveme.wtf&#x2F;{username}，这个页面将显示出 username 设置好的收款地址信息，包括以太坊地址文本是什么，二维码是什么。就这么简单。</p><p>当然 giveme.wtf&#x2F;{username} 下，也可以设置简单的 bio，头像、域名、社交媒体等，像是一个小型的个人主页，让人知道你是谁，稍微更值得分享出去一点。</p><h3 id="技术实现"><a href="#技术实现" class="headerlink" title="技术实现"></a>技术实现</h3><ul><li>注册</li></ul><p>user 使用 MetaMask 钱包注册，连接钱包后可以设置 username，username 是全局唯一的，在智能合约上管理，user 需要发一笔与合约交互的交易，来将自己心仪的 username 提交到合约上。</p><ul><li>profile 信息</li></ul><p>绑定好 EVM 地址与 username 的关系后，就可以设置 profile 信息，包括头像、bio、钱包地址等。</p><p>填写信息后，前端页面将数据提交到后端，后端用 IPFS 节点保存这些数据（长期开启 Pin），同时生成 CID 信息，将 CID 返回给前端。</p><p>前端收到 CID 后，再发起一次合约交互，将 username-&gt;CID 的映射关系，写入到智能合约里。这个步骤可以和注册步骤合并，也可以拆开，因为有时候 user 只想注册，不想设置 profile。</p><ul><li>展示</li></ul><p>合约上的 username-&gt;CID 是最权威的数据，前端页面将根据 giveme.wtf&#x2F;{username} 中的 username，从合约中获取到 CID，再拿着 CID 去 IPFS 的网关查询出具体数据，根据数据渲染出页面。</p><p>profile 会是一些非常精简的 json 数据，数据量很小，同时为了加快网关的查询速度，可以用 Cloudflare 提供的 web3 gateway CDN。</p><ul><li>网络选择</li></ul><p>智能合约部署在 base 上。</p><h3 id="扩展优化"><a href="#扩展优化" class="headerlink" title="扩展优化"></a>扩展优化</h3><p>后期可以根据链上数据，统计出使用打赏系统的收款地址，以及收到打赏的金额总量，做个排行榜，按照 username 或者链分类，分析出一堆数据。</p><p>如果上了排行榜，username 下的 bio 可以增大曝光率。给你心目中的偶像上分吧，让他保持在榜首。</p><p>还可以增加一些 24小时榜单、PK 性质之类的排名。</p><p>同时也可以扩展到社交系统，如有打赏记录的地址可以形成关系图谱，甚至可以直接以某种 IM 工具的方式通讯、自动拉群等。</p><h4 id="username-找回"><a href="#username-找回" class="headerlink" title="username 找回"></a>username 找回</h4><p>MetaMask 钱包注册的问题在于，钱包丢了怎么办，是不是就失去了对 username 的控制。这里可以设计一个恢复机制，比如允许 username 设置一个恢复地址列表，只要是这个恢复列表中的地址，都可以找回 username 的控制权，进而改变 username 对应的 CID。这个机制主要是针对钱包遗失的情况。</p><p>至于钱包被黑了怎么办，黑客岂不是能直接修改恢复地址的列表。他都已经有 username 控制权了，再改也是改成他的地址，加固他对 username 的控制权。那么有没有钱包被黑还能夺回控制权的办法？web3 里没有。</p><h4 id="网络的选择"><a href="#网络的选择" class="headerlink" title="网络的选择"></a>网络的选择</h4><p>目前必须要选择一条链来部署智能合约，智能合约是数据正确性的来源。那么选择哪条链其实是个问题，因为作为 user，不一定有链上的代币作手续费。</p><p>比如选择了 base，那么 user 首先得有 ETH，其次得在 base 上有 ETH，然后才能后续的操作。光是这两步，就能劝退大多数人。</p><p>那么为了解决这个问题，后面可以考虑的方向是手续费代付，用 ERC-4337 （现在差不多凉了）的 paymaster，或者比较原始的 Meta Transaction 方式。但是又得考虑到薅羊毛的问题，代付也得付得起才行。</p><h4 id="数据可用性"><a href="#数据可用性" class="headerlink" title="数据可用性"></a>数据可用性</h4><p>MVP 里的方案是，数据用 IPFS 存，但仅仅只有一个服务器。IPFS 是比较底层的文件路由协议，可以考虑在上面包一层，像 Filecoin 一样，但是不会有 Filecoin 那么复杂，因为 giveme.wtf 的数据量比较小。PoST 难用的地方就在于需要对文件做加密解密，因为文件太大又不能全量校验，但 giveme.wtf 不一样，往简单了做就行，比如验证一下 Merkle Root Hash，也就是说，后面需要在 IPFS 的基础上，加上适当的文件校验和激励机制，让更多的节点愿意存下 giveme.wtf 完整的数据，然后用一种方式来定期检查每个节点是否真的储存了完整数据，如果存了，就给一点奖励。具体奖励给什么再说。</p><h4 id="链下数据缓存"><a href="#链下数据缓存" class="headerlink" title="链下数据缓存"></a>链下数据缓存</h4><p>每次前端页面都从合约上查 username-&gt;CID，交互太慢了，而且消耗节点的 rpc 资源。需要考虑链下来缓存这部分数据，比如有一个中心化的后台程序，监听合约的事件，实时拿到 username-&gt;CID 的内容，然后写入到 Cloudflare Workers KV 服务里。前端页面首先请求 Cloudflare Workers KV，如果没有内容再 fallback 到合约上查。</p><p>那么这里又涉及到一个问题，如果中心化的服务作恶，或者被黑了怎么办，username-&gt;CID 的映射关系一改，钱直接打到黑客的地址上了。</p><p>这个链下数据完整性校验的问题，其实是 Optimistic Rollup 在解决的问题，也有相对成熟的方案。然后结合 Zetachain 的跨链逻辑，可以这样设想。</p><p>首先用来缓存的链下程序，将每一个 username-&gt;CID 的数据作为子节点，构建一个 Merkle Tree，最终会得到一个 Merkle Root Hash，这个 root hash 将是校验数据完整性的凭证，把这个 root hash 定时提交到合约上，前端页面去合约上查一下这个 root hash，就可以知道从缓存里拿到的 CID 有没有被篡改。</p><p>其次链下的索引程序可以有多个，通过 TSS 协商出一个私钥，只有这个私钥，才可以向合约提交 Metkle Hash Root，并且这多个索引程序，只有 root hash 相同，才会协商成功。相当于做了多签。</p><p>最后是冷静期+挑战期，Merkle Root 提交之后，在冷静期内不生效，同时任何人都可以发起挑战，如果挑战成功，则新提交的 Root 作废，继续用旧的 Root。当然这个步骤中的挑战是很麻烦的，得考虑到怎么发起挑战，尤其是怎么挑战才算是成功这个机制。但是好在不用着急做那么复杂，这个属于后期可以优化的方向。</p>]]></content>
  </entry>
  <entry>
    <title>我为什么把大部分资产换成比特币</title>
    <link href="https://crazy.smallyu.net/2025/04/27/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E6%8A%8A%E5%A4%A7%E9%83%A8%E5%88%86%E8%B5%84%E4%BA%A7%E6%8D%A2%E6%88%90%E6%AF%94%E7%89%B9%E5%B8%81/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2025/04/27/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E6%8A%8A%E5%A4%A7%E9%83%A8%E5%88%86%E8%B5%84%E4%BA%A7%E6%8D%A2%E6%88%90%E6%AF%94%E7%89%B9%E5%B8%81/</id>
    <published>2025-04-27T14:57:59.000Z</published>
    <updated>2026-07-04T17:36:19.134Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>首先不想把大量资产以人民币的形式放在银行。</p>
<p>一方面预期人民币的汇率会降低，如果美国的关税进一步提高，人民币的汇率变动会很大。哪怕没有政策因素的影响，长期来看，人民币的价值也是不如美元的。</p>
<p>另一方面，放在银行的钱实际上不是你自己的钱，是国家的钱。再]]></summary>
    <content type="html"><![CDATA[<p>首先不想把大量资产以人民币的形式放在银行。</p><p>一方面预期人民币的汇率会降低，如果美国的关税进一步提高，人民币的汇率变动会很大。哪怕没有政策因素的影响，长期来看，人民币的价值也是不如美元的。</p><p>另一方面，放在银行的钱实际上不是你自己的钱，是国家的钱。再者如果因为异常交易被冻卡了，处理起来也是很麻烦的，有钱花不了。所以把钱存在银行不是一个安全的选择。</p><p>那么人民币之外的选择，就只有黄金、股票、加密货币。</p><p>黄金的话，在国内敢买实体黄金？印象里银行不离柜的黄金，都有生锈的先例，所以这个东西咱不懂，怕买到假的，不太靠谱。尤其是国内民风淳朴，咱是了解的。</p><p>至于股票，国内的股票就别买了。国外的股票，我没有账户去买，不知道怎么买。</p><p>然后就是加密货币。加密货币只有两个选择，BTC 和 USDC。</p><p>稳定币里，在 USDT 和 USDC 之间做选择的话，还是 USDC 靠谱。</p><p>加密货币之间，山寨币就不要考虑了，ETH 可以稍微玩一玩，比 ETH 还山寨的，别想着重仓。</p><p>那么 BTC 和 USDC 做对比的话，BTC 的好处是，BTC 是一种加密货币，是纯粹的去中心化 coin，不是某一家公司发行的，不受控制，不会突然消失。坏处是，价格波动太大。</p><p>UDSC 的好处是，稳定币，价值稳定，不会跌。坏处是，比如在以太坊链上发行的 USDC，那以太坊要是没了怎么办？</p><p>所以 BTC 和 USDC 选择性的分配资产上去。</p><h3 id="补充（2025-05-11）"><a href="#补充（2025-05-11）" class="headerlink" title="补充（2025.05.11）"></a>补充（2025.05.11）</h3><p>才知道有锚定黄金价格的加密货币，按照 1 盎司记价、1:1 实体储备，所以从避险资产的角度考虑，一定要配置一些黄金货币。</p><h3 id="更新（2025-07-30）"><a href="#更新（2025-07-30）" class="headerlink" title="更新（2025.07.30）"></a>更新（2025.07.30）</h3><p>Kraken 上可以买美股了，代币在 Solana 链上，挺有意思。现在的选择更多了一点。</p>]]></content>
  </entry>
  <entry>
    <title>回顾过往失败的职业经历</title>
    <link href="https://b.smallyu.net/2025/04/27/%E5%9B%9E%E9%A1%BE%E8%BF%87%E5%BE%80%E5%A4%B1%E8%B4%A5%E7%9A%84%E8%81%8C%E4%B8%9A%E7%BB%8F%E5%8E%86/"/>
    <id>blog-b:https://b.smallyu.net/2025/04/27/%E5%9B%9E%E9%A1%BE%E8%BF%87%E5%BE%80%E5%A4%B1%E8%B4%A5%E7%9A%84%E8%81%8C%E4%B8%9A%E7%BB%8F%E5%8E%86/</id>
    <published>2025-04-26T16:59:41.000Z</published>
    <updated>2025-12-03T09:25:54.155Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>以下内容不涉及现状和未来，只分析和反思过去已经是既定事实的情况。</p>
<ul>
<li>**</li>
</ul>
<p>刚毕业的时候，误打误撞进入了一家内部孵化联盟链的公司。一开始在 ****  的另一个部门实习，好像叫话费业务部，整天写 SQL]]></summary>
    <content type="html"><![CDATA[<p>以下内容不涉及现状和未来，只分析和反思过去已经是既定事实的情况。</p><ul><li>**</li></ul><p>刚毕业的时候，误打误撞进入了一家内部孵化联盟链的公司。一开始在 ****  的另一个部门实习，好像叫话费业务部，整天写 SQL 语句查数据什么的，后来部门招了个外包，不要我了，还把我的简历发给了其他部门，然后我就到了技术发展部，做区块链的部门。</p><p>转正后，我做了一段时间前端开发，展示比特币行情数据、区块链业界数据等到一个大屏幕上。后来开始做普通的 Java 后端开发，开发了个什么业务系统。再然后，开始接触到区块链的应用层开发，也就是用 Java 调用另一个小组开发的底层区块链。最后，由于底层区块链小组有人走了，我就转到底层，开始用 Go 语言，接触并且学习开发联盟链的一些技术。</p><p>在这第一段职业生涯中，理所当然是十分迷茫的，对于未来的职业方向几乎没有规划，公司让干啥我就干啥。</p><p>期间我尝试和学习各种编程语言，除了 <a href="/2018/10/31/Java11%E6%95%99%E7%A8%8B/">Java</a> 外（大学学过），还学习 <a href="/2018/11/01/PHP7%E8%AE%A9%E4%BB%A3%E7%A0%81%E6%9B%B4%E4%BC%98%E9%9B%85/">PHP</a>、<a href="/2018/12/02/Python%E8%8E%B7%E5%8F%96%E6%B5%B7%E8%B4%BC%E7%8E%8B%E6%9B%B4%E6%96%B0%E4%BF%A1%E6%81%AF/">Python</a>、<a href="/2018/12/17/Scala%E8%AF%AD%E6%B3%95%E5%9F%BA%E7%A1%80/">Scala</a>、<a href="/2019/03/15/Go%E8%AF%AD%E8%A8%80%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95/">Go</a>、<a href="/2019/07/06/Kotlin%EF%BC%9A%E7%AE%80%E5%8C%96%E7%89%88%E7%9A%84Scala/">Kotlin</a>、<a href="/2019/08/19/Rust%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95%E6%A6%82%E8%BF%B0/">Rust</a>、、<a href="/2019/11/26/Haskell%E4%B8%AD%E7%9A%84Monad%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F/">Haskell</a>、<a href="/2020/03/31/%E4%BB%8EErlang%E5%BC%80%E5%A7%8B%E4%BA%86%E8%A7%A3Actor%E6%A8%A1%E5%9E%8B/">Erlang</a> 等，但实际上都比较浅，了解一下语法、写写 Demo，而且接触过多种语言后，就会发现其实编程概念和语法都大差不差。</p><p>期间也尝试学习一些其他领域的东西，比如 <a href="https://github.com/smallyunet/data-engrg-cookbook">大数据分析</a>、<a href="https://github.com/smallyunet/advanced-java">Java进阶</a> 之类的内容，但都没有坚持和深入下去。</p><p>当时换工作是主动跳槽的，因为做了一段时间底层开发后，发现当时的联盟链，实际上用了 Tendermint 的共识，在上面加了一些杂七杂八的东西，比如同时支持 MySQL、TiDB、MongoDB、LevelDB 等作为数据源，算作一种亮点。当时公司也把区块链的重心，放在了信通院的测评上，信通院提出各种测试标准，各家厂商积极配合去获得一个证书。</p><p>工作过程中，也有搭建和接触 Hyperledger Fabric 之类，搞过基于 Hyperledger Indy 的 DID 程序，当时写的 <a href="https://slide-share.smallyu.net/">PPT</a> 都有保留。</p><p>经历过那些工作内容后，我开始逐渐意识到，联盟链和公链完全是两个技术体系，联盟链根本不是真正的区块链，也导致我后来对联盟链的 <a href="/2021/09/29/%E8%81%94%E7%9B%9F%E9%93%BE%E6%AF%94%E5%85%AC%E6%9C%89%E9%93%BE%E5%B7%AE%E5%9C%A8%E5%93%AA%E5%84%BF/">成见挺大</a>。于是我主动换工作，到了一家做公链项目的公司。</p><ul><li>**</li></ul><p>****  其实是一家很厉害的公司，在国内做区块链的人，（2年前，新入行的不算）如果没有听过**** 这家公司，那么只有两种可能：1. 不是真正做区块链开发的。2. 还没有真正入行。</p><p>我刚进 ****  的时候也不懂区块链，是真的不懂，哪怕已经理解了 PBFT 的过程，知道 VBFT 共识是怎么回事，在技术上知道了区块链的四大件，共识、数据库、存储，还有一个什么来着。</p><p>你可以不知道 **** ，但你不能不知道 ** 、**，包括 ** 和 ** 都是这家公司发的。我们当时的项目基于 ** 节点做开发。</p><p>你一旦知道了 **** ，就会开始知道 ** 的创始人 **，顺藤摸瓜开始了解到 2017 年区块链行业的 ICO 热潮，了解到以太坊创始人 Vitalik 到中国融资的故事，开始了解到天使投资人、比特币首富李笑来，开始了解到分叉了以太坊的、帮助币安融资的郭宏才，开始知道赵长鹏、李林、孙宇晨、杜均这些名字，开始了解到真正的币圈。</p><p>在这一段职业生涯中，最大的问题就是 ** 太有钱了，给我们项目组很不错的工资，以及几乎等于零的工作任务和工作压力，过程中我学习到很多东西，包括 <a href="/2022/12/14/%E5%AF%B9-S-PDP-%E6%96%87%E4%BB%B6%E8%AF%81%E6%98%8E%E7%9A%84%E7%A4%BA%E4%BE%8B%E5%92%8C%E8%A7%A3%E9%87%8A/">PDP 证明</a>、<a href="/2022/12/20/Proof-of-Storage-Space-Replication-%E7%9A%84%E5%8C%BA%E5%88%AB/">PoST</a> 等比较硬核的技术概念。但糟糕的是项目没有上线，直接裁掉，达叔也放弃中国市场，跑到美国去了。</p><p>基于在 **** 和 ****  做区块链项目的工作经历，让我误以为自己拥有开发区块链的能力，总是站在区块链开发的立场思考工作以及对未来的职业规划。</p><ul><li>**</li></ul><p>这是一家创业公司，我工作了两个星期就离开了。这么短的工作时间本可以忽略不用提，有意思的是这家公司要做的事情，以及吸引我的地方。</p><p>财经大学有个叫 ** 的教授，好像也是央行的专家，提出了一种利用 **** （经济学里的博弈理论）来让区块链系统达成共识的方法，这家公司就负责对这种理论做工程化的实现。这样的工作假如靠谱的话，简直是我梦寐以求的。当然事实证明不靠谱。</p><ul><li>**</li></ul><p>你可能没听过 **** ，但是也许知道 ** 年底在币安上线的 **，开盘最高价 ** 美元，现在的价格是 ** 美元，市值排名最高 ** 左右，现在降到 ** 名附近。很负责任的说，这家公司的游戏开发人员都是在扎实开发游戏的那种，币价真的跟他们没关系，要怪就去怪投资人吧。</p><p>说来讽刺，我离开 ****  的理由是，我觉得工作中只是在使用区块链，不是在开发区块链。而到目前为止，我工作以来，最能拿得出手、有实际结果的工作，恰恰是搭建了 *** 主网这一条，</p><p>我一直觉得使用区块链要比开发区块链简单得多，不就拿开源软件来运行吗？你可以说苹果手机多么厉害，但从来不会有人觉得，使用苹果手机的人厉害。一样的道理，你可以说以太坊节点很优秀，但是不会有人觉得，会运行以太坊节点是一件厉害的事情。</p><p>这一段职业生涯的结束，也是我主动的选择，当时故意选择最大损失的方式，来声明自己对这次职业选择的决心。我觉得有意愿并且有能力纠正自己的职业道路，本身就是一件很酷的事情。</p><p>我没有机会和能力在一条市值这么高的链上搞点事情，做出更多有价值的成果，算是遗憾。</p><ul><li>**</li></ul><p>离开 ****  之后，我的观点是 <a href="/2024/09/11/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E5%81%9A%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%92%8CDeFi%E5%BC%80%E5%8F%91/">不要做智能合约开发</a> 和 <a href="/2024/09/12/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E5%81%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%9A%84%E4%BA%8C%E6%AC%A1%E5%BC%80%E5%8F%91/">不要做以太坊的二次开发</a> ，其实这两条就堵死了大多数 web3 项目类的工作方向。那么可以做什么？我当时心底是有答案的，也恰好遇到了这样的工作机会——Cosmos 开发。</p><p>我没兴趣刻意去学习 Cosmos SDK 的用法，但如果工作中正好在做这方面的事情，也很乐意接触一下。事实上用 Cosmos SDK 开发一条链，仍然回到了 “使用区块链而不是开发区块链” 的困境，Cosmos SDK 本质上是 SDK，就是在以比较低的上手门槛，给广大开发者用的，用起来没有太大难度。用 Cosmos SDK 开发东西，几乎不需要懂共识、交易、区块链，就像开发智能合约一样——其实 Cosmos SDK 本身就是对标智能合约的产物。</p><p>****  的项目并不算难，我当时还很大言不惭的写，如何 <a href="/2024/10/15/%E7%9C%8B%E6%87%82%E4%BB%BB%E6%84%8F%E5%8C%BA%E5%9D%97%E9%93%BE%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84/">看懂任意区块链项目的技术架构</a>。****  有很大的复杂度来自于 Zeta Chain 的跨链逻辑，因为 ****  的原代码是从 Zeta Chain fork 出来的。</p><p>在这一段职业生涯中，我也学到不少东西，尤其是 Leader 的大厂式做派，让我大概体会到所谓大厂的工作模式是什么样子。我确实没有进过大厂，但自从知道币圈公司多有钱后，也不再有向往大厂之类的情绪。</p><p>这家公司也是我主动离开的，当一个环境对你不好的时候，有意愿并且有能力主动离开，我觉得这同样是一件很酷的事情。</p><h3 id="假如"><a href="#假如" class="headerlink" title="假如"></a>假如</h3><p>在过去的这些职业经历中，很多次都是在主动放弃一些选择的机会。</p><p>假如从一开始就认真学习智能合约开发，也许现在已经熟悉各种链的智能合约语言，包括 EVM、SOL、APT 等平台，并且可以熟练进行开发了，如果运气好，遇到靠谱的项目方，也许已经有了不少真正上线的智能合约项目。要知道，现在 web3 行业的招聘，很缺智能合约开发。</p><p>假如从一开始就接触 DeFi 开发（智能合约），并且坚持学习 DeFi 行业的各种项目，Uniswap、AAVE、跨链桥等，也许现在已经精通 DEX 的运作逻辑，无论是 CEX 还是 DEX 项目，都会在一定程度上需要熟悉这些技术的开发人员。</p><p>假如从一开始就认准 Cosmos SDK 的开发，并且在这条道路上坚持下去，也许现在已经是资深的 Cosmos 开发者了，踩过各种 Cosmos 的坑，熟悉 Cosmos 各个版本的迭代，甚至给 Cosmos 贡献代码。毕竟到现在仍然有不少项目方愿意用 Cosmos 来构建自己的项目，</p><p>假如从一开始就坚持学习以太坊的源码，积极跟进以太坊的代码内容以及各个版本的功能迭代，甚至能够对其中的部分环节作出性能优化，也许现在可以是一个靠谱的能够承担以太坊节点二次开发工作的开发者了。以太坊的 L2 叙事让很多项目方在执行层节点的性能方面蠢蠢欲动，想搞出一个自己定制化的版本。</p><p>假如一直坚守在联盟链开发的领域，虽然不会了解到币圈的波澜壮阔，但是随着技术的不断提高和深入，搞搞国密、存证、平台化、Baas，也许有机会进入长安链甚至腾讯的区块链项目组，自得其乐过日子也挺好的。</p><p>假如从一开始没有了解到区块链，踏踏实实做互联网的后端开发，也许现在能够精通数据库、缓存、中间件等常用业务组件，不用担心在面试的时候回答不上来 “Go 语言的 GMP 调度原理是什么” 这种问题了，互联网的后端开发没别的可学，可不就研究这些东西了吗。好处就是互联网大厂到现在还在，几年内也不会倒，总会有后端开发的容身之处。</p><p>假如……</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>总的来说，过往的职业经历是非常失败的，我一直在试图去做真正的区块链开发，但最后连门都没有摸到，只做了一些边边角角的事情。</p><p>现在随着行业环境的变化，事实上从 2019 年之后，区块链 L1 的战争就基本上结束了，到了 2023 年左右，随着币安、波场、火币离开大陆，随着 ** 放弃中国市场，国内几乎已经没有正经做区块链开发的公司，这个世界不再需要 “区块链开发” 了。</p><p><br><br></p><h3 id="附"><a href="#附" class="headerlink" title="附"></a>附</h3><h4 id="的技术架构"><a href="#的技术架构" class="headerlink" title="****  的技术架构"></a>****  的技术架构</h4><p>****  是一家传统支付公司内部孵化的区块链项目，项目的 Team Leader 在 2019 年离开公司后，作为合伙人创建了**** 。长安链一开始发布的时候，技术特性上能看到不少 ****  的影子。后来长安链搞得比较好，和腾讯合作开发，知名度高一点，。</p><p>关于 ****  的技术架构之前在《<a href="/2022/09/03/VRF-BFT-%E5%85%B1%E8%AF%86%E5%BC%95%E8%B5%B7%E4%BA%A4%E6%98%93%E5%A4%B1%E8%B4%A5%E7%9A%84%E9%97%AE%E9%A2%98/">VRF + BFT 共识引起交易失败的问题</a>》中有提到过。</p><p>****  的内核是 Tendermint Core，直接把代码集成到项目中，进行了很多二次开发。主要改进的地方有：</p><ul><li>VRF 选择提案节点</li><li>分层共识（换共识组）</li><li>有限的智能合约支持</li><li>支持不同类型的数据库</li><li>异构多链</li></ul><h4 id="SaveFS-的技术架构"><a href="#SaveFS-的技术架构" class="headerlink" title="SaveFS 的技术架构"></a>SaveFS 的技术架构</h4><p>SaveFS 也叫 saveio，是 ****  内部孵化的区块链项目，2022 年 ****  公司解散的时候，整个项目被裁掉了。</p><p>关于 SaveFS 相关的技术之前在《<a href="/2022/08/27/%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">一年的工作回顾</a>》中提到过。</p><p>SaveFS 项目整体比较复杂，相当于整合了这样几个项目：</p><ul><li>Ontology</li><li>Lighting Network</li><li>IPFS</li></ul><p>为什么会出现 “相当于整合” 这种情况？当年**** 打着 “做中国的以太坊” 的旗号，成为了非常成功的项目，猜测 SaveFS 也继承了这种基因，大概类似于 “做中国的 Filecoin”。</p>]]></content>
  </entry>
  <entry>
    <title>因为同事的不尊重，我换工作了</title>
    <link href="https://b.smallyu.net/2025/04/13/%E5%9B%A0%E4%B8%BA%E5%90%8C%E4%BA%8B%E7%9A%84%E4%B8%8D%E5%B0%8A%E9%87%8D%EF%BC%8C%E6%88%91%E6%8D%A2%E5%B7%A5%E4%BD%9C%E4%BA%86/"/>
    <id>blog-b:https://b.smallyu.net/2025/04/13/%E5%9B%A0%E4%B8%BA%E5%90%8C%E4%BA%8B%E7%9A%84%E4%B8%8D%E5%B0%8A%E9%87%8D%EF%BC%8C%E6%88%91%E6%8D%A2%E5%B7%A5%E4%BD%9C%E4%BA%86/</id>
    <published>2025-04-13T03:15:26.000Z</published>
    <updated>2025-12-03T10:02:00.863Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>这些内容在 4月2日就写好了，原计划进入新工作后一周再发出来。这是我自己对这件事情的总结。</p>
</blockquote>
<h3 id="契机"><a href="#契机" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<blockquote><p>这些内容在 4月2日就写好了，原计划进入新工作后一周再发出来。这是我自己对这件事情的总结。</p></blockquote><h3 id="契机"><a href="#契机" class="headerlink" title="契机"></a>契机</h3><p>前段时间有一个同事（老员工，被重用那种，不然也不会摆那么大的谱），在群里发表了针对我的不友善言论，让我感觉有点生气，他说的话类似于 “你写的代码很垃圾”、“以后不要再让我 review 你的代码”、“这种代码谁爱合谁合，反正我不合” 之类，与其说是在表达对我代码的不满意，更像是在撒泼式的宣泄自己内心对生活的不如意，随便找个借口找个场合发泄。</p><p>这件事情本身的前因后果我都没有动力去讨论，因为很明显不是行为规范的问题，而仅仅只是他个人的情绪问题。我对造成这件事情的深层原因，总结为团队内部的管理混乱、每个人职责不分明。但原因是什么不重要，我会用实际行动来表达对这种工作环境的不满意。</p><p>在这件事情的过程中，我感受到的是一种不尊重，也因此写了《<a href="/2025/03/22/%E4%BB%8E%E5%9B%A2%E9%98%9F%E5%86%85%E9%83%A8%E7%9A%84%E6%B7%B7%E4%B9%B1%E6%83%B3%E5%88%B0%E2%80%A6%E2%80%A6/">从团队内部的混乱想到……</a>》和《<a href="/2025/03/25/%E5%85%B3%E4%BA%8E-Code-Review-%E7%9A%84%E7%A4%BC%E8%8A%82/">关于 Code Review 的礼节</a>》来委婉的提及一些当时的情况。</p><p>“尊重” 重要吗？我的出身并不好，谈不上什么尊重，更没有资格要求别人尊重我什么的，毕竟别人对你怎么样，是别人的事情，我又怎么能左右呢，说到底还是我自己的能力不够强大，强大到让别人主动尊重我。那么抛开原生家庭和个人教养的问题，对于我来说，在这件事情上，“尊重” 重要吗？</p><p>很简单，如果我能找到工作，那么就很重要，这件事情已经是一个非常充足的让我换工作的理由。如果我找不到工作，那就不重要，在生存和挣钱面前，受这么点气算什么呢，我要是一旦离开这个项目就再也找不到工作了，那我也就这么点水平，受气也是活该，忍着呗，还能怎么着。</p><p>我是毫无理由去忍受这种来自同事的情绪的，所以我现在确实已经离职、并且开始新的工作了。这件情绪上的事情算是一个契机，让我有足够动力开始改好简历、进行找工作这件事情，不然可能不会这么早主动换工作，会稍微晚一点，等等看项目进一步的情况。但是因为这件事情，我就不想等了。</p><h3 id="整体原因"><a href="#整体原因" class="headerlink" title="整体原因"></a>整体原因</h3><p>对于换工作的原因，除了这件情绪上的事情作为契机外，也有一些项目整体的因素在里面，总体来说，为什么现在到了一个需要换工作的时候？</p><p>从项目整体看，项目现在在往 AI 方向发展，全面转型到 AI，几乎放弃了区块链方面的叙事，老板从外部邀请了整个 AI 团队做事情，后续在区块链方面不需要有什么功能上的迭代。我也有听到说，老板提到过精简团队的事情，需要用到人再招，也确实精简掉一个人。虽然没有精简掉我，但这显然是一个不好的信号。</p><p>从内部管理看，团队内部的管理比较混乱，人员之间的协作很糟糕，工作协调起来比较困难，尤其是作息时间上的差异，偶尔会引起一些问题。人员素质层次不齐，虽然现在人数逐渐减少、没几个人了。整体工作氛围让人不是很舒服。</p><p>在工作内容上，最近一段时间开始，逐渐进入了没事找事的状态，没有什么紧急的需求需要做，尤其最近做的大都是一些不重要的事情，做也行不做也没差，纯粹只是为了工作而工作，让每个人显得在工作。一般来说工作进入到这种状态，也是一种非常不好的的信号。</p><p>从内部团队的前景看，整个团队能不能做成事情，几乎依赖于 Leader 的个人判断，能做什么事情、需要做什么事情、交付结果的上限是什么，都取决于 Leader 的个人能力，这对团队来说不是好事。曾经就出现过 Leader 一人判断失误，导致整个团队的努力都白费的情况。当然 Leader 本人的学习速度和改进自己的速度非常快，在意识到失误后能够在短时间内频繁做出调整，整体上是在往好的方向发展的，这一点上我还是佩服的。如果不是 Leader 有这种迅速调整的能力，我换工作可能比现在还得提前几个月。</p><p>总的来说，从各方面角度看，都有一些让自己换工作的理由，所以总结起来，目前到了一个需要换工作的时候。</p><p>（注意，换工作的原因里完全不包括我自己对项目和赛道的评价和看法。我在入职 3 天的情况下头脑里就对这个项目产生过怀疑，具体细节在《<a href="/2024/11/18/Restaking%E9%A1%B9%E7%9B%AE%E7%9A%84%E7%BB%8F%E6%B5%8E%E9%9A%BE%E9%A2%98/">Restaking 项目的经济难题</a>》，时至今日我作为项目内部的开发人员，都没有找到这个问题的答案。但我想说的是，这些丝毫不影响我愿意在这个项目上继续工作，并且希望能把项目做好。事实上，我们比外部的人更希望项目能越来越好，因为我们本身就是利益相关者。所以，我想再次强调，换工作和项目本身的好坏无关，只是工作氛围的问题） </p><br><h3 id="补充（2025-04-20）"><a href="#补充（2025-04-20）" class="headerlink" title="补充（2025.04.20）"></a>补充（2025.04.20）</h3><p>不尊重人这件事情，真是一种习惯。在离职后的工作交接中，他希望我拿出一天的时间来做某件事情，我答应了，说是周末可以。</p><ul><li>我周六上午问，今天还是明天，要不今天（周六）吧？他说周日。</li><li>我周日上午 9 点问，几点开始？他 12 点左右回复，原话是 “我有一个思路了。看晚点儿 meeting 过一下”。</li><li>我接着问，“晚点儿” 是指晚上吗？（对方已读）</li><li>我迟迟（3个小时内）没有收到回复。</li></ul><p>单从这个对话内容看，我实在没看懂什么意思，到底是要我干嘛，到底是什么时候？我已经预先准备出了一天的时间，对方反而爱搭不理的样子。难道是觉得我一整天都会坐在电脑前等待回复，处于待命状态吗？搞不懂。难道是觉得我应该迁就他的时间吗？我已经离职了呀。</p><p>要么就是不尊重人，要么就是缺乏基本的职业素养，约个时间约个会这么简单的事情都做不好，搞不懂……</p><p>话说回来，其实从我入职以来，在他的作息时间上，就感觉有很多问题。比如，几乎每天的早会，他都是 “在外面”，要么直接就不参加早会了，三番五次缺席早会，上午基本上处于不太在线的状态。再比如，中午 12 点到 3 点之间，基本上不在线，要午休。再比如，下午 5 点开始出门去打球，5点到7点左右必然不在线。</p><p>他最活跃的时间段是晚上 10 点到 12 点，每天 10 点开始，群里就开始有消息了，甚至 12 点直接给我打电话，说哪里的代码怎么怎么样。</p><p>我刚入职的时候，本来白天就正常工作了 8 个小时，到晚上该下班了，结果一到 9 点多 10 点，他上线并且开始活跃了，开始进一步推进工作，我作为新人只好奉陪了几天。也就导致我刚入职的一段时间，加班频率和强度都挺高的，根本原因就是在迁就他的作息时间。</p><p>后来由于工作内容的变化，我和他合作没那么紧密，我就开始忽略他的消息了，只要超过 10 点钟的消息，我直接就不看了。</p><p>从我的描述应该能看出来，跟这样的人一起工作其实很难受，作息时间上存在很大的差异，你找他他不在，他找你你不想回，工作很难推进。更大的问题在于，团队默认允许这种的现象存在，你说团队的问题到底来自于哪里？</p><br><h3 id="补充（2025-11-22）"><a href="#补充（2025-11-22）" class="headerlink" title="补充（2025.11.22）"></a>补充（2025.11.22）</h3><p>写完《<a href="https://smallyu.net/2025/11/20/%E5%A4%8D%E7%9B%98%E4%B8%8A%E4%B8%80%E6%AC%A1%E8%B7%B3%E6%A7%BD%E7%9A%84%E5%8E%9F%E5%9B%A0/">复盘上一次跳槽的原因</a>》后有感，一个从未在工作中表现出优秀技术能力的人（顶多算合格），试图通过控制 review 流程的方式，试图通过代码仓库的管理权限，来保护自己的技术地位。</p><p>你不 review 我的代码，我还是我，我的技术还是我的技术，我一直在走我的路。离开了你，离开了公司，我依然是我。我从来不需要在团队内部证明什么，我有话都是敢公开说的，我一直在这里。</p><p>被 review 不会对我有显著提高，而 review 是限制我工作效率的枷锁。我当然需要高水平的人来 review 和帮助我，但是水平不够的人就不要有莫名其妙的情绪了。</p>]]></content>
  </entry>
  <entry>
    <title>鼓吹 Cursor 的人技术能力都差</title>
    <link href="https://smallyu.net/2025/04/12/%E9%BC%93%E5%90%B9Cursor%E7%9A%84%E4%BA%BA%E6%8A%80%E6%9C%AF%E8%83%BD%E5%8A%9B%E9%83%BD%E5%B7%AE/"/>
    <id>blog:https://smallyu.net/2025/04/12/%E9%BC%93%E5%90%B9Cursor%E7%9A%84%E4%BA%BA%E6%8A%80%E6%9C%AF%E8%83%BD%E5%8A%9B%E9%83%BD%E5%B7%AE/</id>
    <published>2025-04-12T12:33:38.000Z</published>
    <updated>2025-12-04T10:51:53.972Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>有点标题党，不要太介意。我想表达的是不应该过于关注使用的工具。很简单的逻辑，只有自己工程能力不如 Cursor，才会觉得 Cursor 厉害，干什么都行。当然这句话属于比较空的废话。</p>
<p>事实上，Cursor 的代码补全能力没有比 GitHub Copilot]]></summary>
    <content type="html"><![CDATA[<p>有点标题党，不要太介意。我想表达的是不应该过于关注使用的工具。很简单的逻辑，只有自己工程能力不如 Cursor，才会觉得 Cursor 厉害，干什么都行。当然这句话属于比较空的废话。</p><p>事实上，Cursor 的代码补全能力没有比 GitHub Copilot 好多少，底层使用的模型是一样的，不是 Claude 就是GPT。而在工程化调教方面，Cursor 和 Copilot 都是在把一些文件作为 context，继续后面的对话。</p><p>Cursor 比 Copilot 好一点的地方在于，会自己去当前工程目录下，搜索和参考其他文件的写法，这一点确实有用，你不需要告诉他具体引用那哪些文件，他自己会不断的尝试，Copilot 这种插件是不具备这种能力的，这确实是好的一面，如果项目下存在大量可复用的代码，Cursor 可以比较好的发挥出它的能力。</p><p>但有时候又会觉得 Cursor 过度智能，它甚至会自己在你的工程下面创建新文件，而不需要经过你同意，这就导致在用 Cursor 的时候需要时刻关注，他是否改变了你预期之外的代码文件。相比之下，（GoLand 下的）Copilot 只是插件的形式，只会给出代码片段，用不用是你自己的事情。VS Code 下的 Copilot 现在和 Cursor 倒是有类似的体验了，会给你一个接受或不接受更改的选项。</p><p>所以相比来说， Cursor 和 Copilot 使用了一样的大语言模型（不会有人觉得 Cursor 自己训练了个模型出来吧），然后 Cursor 拥有更大的、项目级别的控制力，而 Copilot 像他的名字一样，只是辅助级别的能力，这是它们最大的区别。</p><p>回到模型本身，o1 是迄今为止最厉害的模型，在日常工作中深有体会，我经常用 o1 来精准定位编程中遇到的 bug，而对于相同的问题，其他模型往往给出错误或者不准确的解释，包括 o3-mini-high 和 4o。</p><p>比如，在调用智能合约的时候，原本的命令是</p><pre><code>cast call requestPrice(string) &quot;BTC&quot; —-rpc-url=http://eth:8545</code></pre><p>现在需要调用另一个函数，比原本的函数多了一个入参，我就直接复制代码写成</p><pre><code>cast call requestPrice(string) &quot;BTC&quot; &quot;USD&quot; —-rpc-url=http://eth:8545</code></pre><p>不知道你有没有第一时间看出问题？其实 4o 倒是给出了正确的分析，只是没有特别精准，给出了 3 种有可能的错误原因，而 o1 直接就说对了。</p><p>当然大模型之间的差异不会体现在这么微小的问题上，只是正好有印象就随便提一下，我想表达的是，从日常体验来看，o1 是最好用的模型。</p><p>我严重怀疑鼓吹 Cursor 的人，都是之前没有使用过 AI、体会过 AI 强大能力的人，在用到 Cursor 之后，才明白原来现在的生成式 AI 已经这么强大了，欣喜若狂。而当需要使用生成式 AI 的时候，他们的第一反应不是打开 ChatGPT 的聊天框或者 Gotk3 的界面，而是打开了 Cursor 的代码框，开始去聊天。</p><p>所以鼓吹 Cursor 的人，实际上是把生成式 AI 的能力，误以为是 Cursor 的能力，才因此觉得 Cursor 异常强大。</p><p>我在工作中就不止一次被强烈推荐使用 Cursor ，让我别再用 GoLand，还说出 “GoLand 就是垃圾” 这种话，Cursor 最好用什么的。</p><p>首先我一直觉得喜欢用什么编辑器是个人的选择，管这个干啥。其次如果觉得使用什么编辑器会给使用者带来鄙视链和优越感，未免有点小儿科。最后就是我喜欢用 GoLand 的理由，只有两点：1.箭头非常直观的表达了接口的实现关系。2.前进后退快捷键很好用。基于这两点，我才可以比较快速的读懂和理解代码。</p><p>也因此带来一个差异是，使用 GoLand 的人，往往更加关注代码逻辑，比如在寻找代码位置的时候，喜欢通过代码之间的跳转，例如接口的实现关系等。而使用 Cursor（VS Code）的人，更加关注项目的目录结构、文件名、文件的位置，因为 Cursor 没有提供很好的代码跳转功能，所以不得不更加依赖通过项目结构来梳理代码功能。</p><p>代码的自动补全方面，GoLand+Copilot 插件能应付日常场景，需要补全的往往是打日志之类的内容，简单用用就可以，我不太敢用 AI 写侧重逻辑的代码。</p><p>给我推荐使用 Cursor 可能还有一种心理就是，觉得我不知道怎么使用 AI，或者觉得我不知道怎么使用 Cursor (?)，也挺奇怪的。我在 2023 年（ChatGPT 开始大火的那段时间）就试用了 ChatGPT，还写了《<a href="/2023/03/30/%E4%B8%8D%E8%A6%81%E5%B0%8F%E7%9E%A7-ChatGPT/">不要小瞧 ChatGPT</a>》，而现在不论是日常工作还是生活，都在高频率使用 ChatGPT。</p><p>总的来说，我的意思是，你可以喜欢 Cursor，也可以使用 Cursor，但最好不要鼓吹 Cursor。</p>]]></content>
  </entry>
  <entry>
    <title>2025 年 4 月面试的经历</title>
    <link href="https://b.smallyu.net/2025/04/11/2025%E5%B9%B44%E6%9C%88%E9%9D%A2%E8%AF%95%E7%9A%84%E7%BB%8F%E5%8E%86/"/>
    <id>blog-b:https://b.smallyu.net/2025/04/11/2025%E5%B9%B44%E6%9C%88%E9%9D%A2%E8%AF%95%E7%9A%84%E7%BB%8F%E5%8E%86/</id>
    <published>2025-04-11T13:28:11.000Z</published>
    <updated>2025-12-04T13:51:06.722Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>根据以往找工作的经历看，一般至少面试 20 次左右才会找到合适的工作，所以不用着急也没办法着急。</p>
<p>面试有两种情况，一种是先看过你的简历，然后约你面试，面试的过程中都不怎么 “考核”]]></summary>
    <content type="html"><![CDATA[<p>根据以往找工作的经历看，一般至少面试 20 次左右才会找到合适的工作，所以不用着急也没办法着急。</p><p>面试有两种情况，一种是先看过你的简历，然后约你面试，面试的过程中都不怎么 “考核” 你，就是在聊天。还有一种是流水线式的面试，面试官往往在面试开始后，才会第一次看你的简历，而且会问你各种各样具体的问题。前一种情况希望比较大，后一种情况则大多数成不了，不太靠谱。</p><ul><li>4月2日，不知道什么公司</li></ul><p>不知道对方是什么公司，面试了十来分钟吧，说不匹配对方的职位。对方的项目是在基于 Cosmos SDK 搞一条新的链，这条链要集成 EVM，并且做一些性能上优化，因为 Evmos 在性能上存在瓶颈，听起来像是要和 Evmos 做竞争。EVM 之外还在尝试做一些 ZK Layer 2 方向上的探索。然后说我因为缺少这方面的经验，就不匹配了。</p><ul><li>4月3日，某个交易所钱包开发岗位，一面</li></ul><p>对方不愿意透漏自己是哪家交易所，钱包产品类似于币安内置的 web3 钱包，也就是自己管理自己资产那种，而不是托管钱包，所以技术上没怎么问有深度的内容，问了一些比较浅显的问题，也可能开发钱包的都是这种类型的知识面吧。</p><ul><li>4月7日，敦煌网</li></ul><p>很经典的剧情，传统公司试图做联盟链并且向 web3 靠拢。</p><ul><li>4月8日，Gate.io，Golang 开发</li></ul><p>比较常规的面试，实际上需要 web2 相关的技能，关注 Go 语言、数据库的使用、数据库的迁移等。</p><ul><li>4月8日，Bitget，节点工程师</li></ul><p>对方在招聘的职位主要是想做 Solona 节点的 RPC 性能优化，因为目前 Solona 的 RPC 查询有 1 秒左右的延迟，一方面想在代码层面做提升，另一方面兼顾节点的运维，保证节点的高可用。</p><ul><li>4月10日，某个交易所钱包开发岗位，线下二面</li></ul><p>HR 面的时候才知道这家交易所是 coinstone。和面试官感觉聊的不错，然后 HR 说需要再等一段时间，还在面试其他人。</p><p>不过说实话我觉得面试官技术能力不太好，如果让这样的人当我的上级，我感觉不一定会开心，所以即使真的给我发 offer 了，我都可能得纠结一下，要是没 offer 就算了。</p><p>（2025年04月22日补充）偶然想起来，简单补充下当时的一些对话内容：</p><p>我说助记词的原理是，有一个事先定义好的单词表，会从这个单词表里挑几个出来作为助记词。对方说，不是这样的，一个助记词就是一个 seed，然后这个 seed 可以扩展为一个树结构，这个树结构上的每一个节点都是一个公私钥对。</p><p>我说现在钱包的标准是 BIP-39，他说不对，钱包的标准是 BIP-44。</p><p>他问我，在服务器上 grep 命令匹配到数据后，会显示几条记录？假如只有一个匹配项。（这个问题让我得出 “对方技术能力不好” 这个结论的）</p><!--- 4月11日，不知道哪个项目，钱包开发一面，面试官是有技术水平的，一听就挺有经验。二面，是 CTO，问了相对简单的问题。HR 面，主要是了解我的薪资情况、确认入职日期等。--><ul><li>4月11日</li></ul><p>不找了……</p>]]></content>
  </entry>
  <entry>
    <title>AI 是一个正在发生的大趋势。训练模型一类的事情成本非常高，没有 500M 资金都不够资格做 VC。调用 API 之类的...</title>
    <link href="https://t.smallyu.net/#2025-10"/>
    <id>micro:2781196817</id>
    <published>2025-04-06T03:19:31Z</published>
    <updated>2025-04-06T03:19:31Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>AI 是一个正在发生的大趋势。训练模型一类的事情成本非常高，没有 500M 资金都不够资格做 VC。调用 API 之类的 Agent 应用又比较简单，平民化。那么如何在这两类事情之间，找到一种项目的发展方向？</p>]]></summary>
    <content type="html"><![CDATA[<p>AI 是一个正在发生的大趋势。训练模型一类的事情成本非常高，没有 500M 资金都不够资格做 VC。调用 API 之类的 Agent 应用又比较简单，平民化。那么如何在这两类事情之间，找到一种项目的发展方向？</p>
]]></content>
  </entry>
  <entry>
    <title>关于 Code Review 的礼节</title>
    <link href="https://smallyu.net/2025/03/25/%E5%85%B3%E4%BA%8E-Code-Review-%E7%9A%84%E7%A4%BC%E8%8A%82/"/>
    <id>blog:https://smallyu.net/2025/03/25/%E5%85%B3%E4%BA%8E-Code-Review-%E7%9A%84%E7%A4%BC%E8%8A%82/</id>
    <published>2025-03-25T13:45:43.000Z</published>
    <updated>2026-07-25T07:05:50.695Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>前情提要，推荐王垠的两篇博客文章：</p>
<ul>
<li>《<a]]></summary>
    <content type="html"><![CDATA[<p>前情提要，推荐王垠的两篇博客文章：</p><ul><li>《<a href="https://www.yinwang.org/blog-cn/2015/03/03/how-to-respect-a-programmer">怎样尊重一个程序员</a>》</li><li>《<a href="https://www.yinwang.org/blog-cn/2015/03/11/git-etiquette">关于Git的礼节</a>》</li></ul><p>由于过往不规范的工作经历，我之前是缺少对 Code Review 的理解的。最近因为同事对这个问题情绪化的表达，我开始关注到关于 Code Review 的问题。</p><h3 id="基本礼仪：不要用-FYI"><a href="#基本礼仪：不要用-FYI" class="headerlink" title="基本礼仪：不要用 FYI"></a>基本礼仪：不要用 FYI</h3><p>谷歌公开出来的 Code Review 规范 《<a href="https://google.github.io/eng-practices/review/reviewer/standard.html">The Standard of Code Review</a>》已经非常具有指导意义，内容很全面，包括我现在实际遇到的流程问题，也完全可以依照这个规范来消化解决。当然前提是所有团队成员事先对这个规范的内容已经达成一致，而不是假设公司的员工已经知道并且开始遵循这个规范。</p><p>关于规范（TSCR）中已经提到的流程问题、礼貌问题，这里是不需要赘述的。我关注到的是其中一个小章节《<a href="https://google.github.io/eng-practices/review/reviewer/comments.html#label-comment-severity">Label comment severity</a>》，也就是对 Code Review 之后的 comment 进行重要程度的区分，并且加上前缀，让 author 可以明确知道哪些留言是必须要改的，哪些是无关紧要的。</p><p>除去必须要改的 comment 不加前缀，谷歌的规范中提到有三类前缀，这些都是指站在 Reviewer 的立场，如何去写 comment，本质上这三类前缀都不影响代码的 approve 和合并：</p><ul><li><code>Nit</code> (Nitpick): 你应该改，但是不改我也能接受。</li><li><code>Optional</code>：只是建议，你自由选择改还是不改。</li><li><code>FYI</code> (For Your Information)：这个 PR 中完全不需要因此有改动，但我觉得这是一个有意思的点，后续你可以关注下。</li></ul><p>其中第三个前缀 FYI，每当看到 For Your Information 这个短语的时候，我总是下意识的会把这个短语翻译为中国传统社会普遍流行的一句古话： “为了你好”。</p><p>相信在中国本土长大的华人，即使没有遭受过严苛古怪的家庭教育，也都能深刻理解到 “为了你好” 的威力。</p><p>为了你好，你要好好学习<br>为了你好，你不能打游戏<br>为了你好，你要考公务员<br>为了你好，你要早点结婚<br>为了你好，你必须生孩子<br>……</p><p>一些情况下，父母的 “为了你好” 只是他们满足自己变态控制欲望的借口，另一些情况下，有些父母发自真心的 “为了你好”，然后由于自身有限的眼光给出了不正确的建议。</p><p>总的来说，中文语境下的 “为了你好” 绝不是什么好词，如果把这种话语带到工作中，就更匪夷所思了。虽然 For Your Information 并不能直译为 “为了你好”，但是为了避免歧义，还是建议大家不要使用这样的话术。</p><p>所以，Code Review 的基本礼仪就是，不要用 FYI。</p><h3 id="为什么-“为了你好”-往往是错的"><a href="#为什么-“为了你好”-往往是错的" class="headerlink" title="为什么 “为了你好” 往往是错的"></a>为什么 “为了你好” 往往是错的</h3><h4 id="先说结论"><a href="#先说结论" class="headerlink" title="先说结论"></a>先说结论</h4><p>因为没有人可以在实际上了解另一个人。</p><p>父母真的了解自己的孩子吗？结婚多年的夫妻，真的知道对方的心思吗？审查犯人的警察，足够了解自己在调查的罪犯了吗？心理学的专家，能猜到自己女朋友早上为什么生气吗？对于每一个人，你真的了解自己吗？</p><p>所以其实可以得到这样一个和技术无关的结论，出于礼貌，我们应该尽量避免对别人说 “为了你好”。</p><h4 id="具体事例"><a href="#具体事例" class="headerlink" title="具体事例"></a>具体事例</h4><p>最近的工作中，我提交的代码包含一个简单的事件总线（Event bus）的实现，其中事件的 Publish 和 Subcribe 都用了 RW 锁来保证 map 读写的线程安全：</p><pre><code class="Go">func (eb *EventBus) Publish(event Event) &#123;    eb.mu.RLock()    defer eb.mu.RUnlock()    if ch, exists := eb.channels[event]; exists &#123;        ch &lt;- event    &#125;&#125;</code></pre><p>而我得到的 CR 建议是用 Sync map 改写为：</p><pre><code class="Go">func (eb *EventBus) Publish(event Event) &#123;    if ch, ok := eb.channels.Load(event); ok &#123;        // 注：这里需要类型断言        ch.(chan Event) &lt;- event    &#125;&#125;</code></pre><p>这实际上最多是一个 Nit 级别的 comment，我是不太在意的，这个事情的处理起来也非常简单。</p><p>而事实上问题在于，我听到了类似于 “为了你好” 的话，大致意思是，为了你好，你要了解清楚 RW 锁、互斥锁、Sync map 的区别，然后选择在 Event bus 场景下最正确的实现方式，并且能够条理清晰地去说服别人。</p><p>如果说我从自身技术发展的角度，是不太在乎这种问题的。这个问题本质上是我们平时面试时候说的八股文，随着最近几年面试风向的转变，也越来越多的人开始逐渐达成一致、反感八股文一类的东西了。</p><p>当然追求这一类底层问题到极致的人，肯定是有技术追求的人，这并不是什么坏事，我们应该尊重任何努力以及对技术较真的人。只是技术也分很多种方面。</p><h4 id="我的兴趣"><a href="#我的兴趣" class="headerlink" title="我的兴趣"></a>我的兴趣</h4><p>我算不算有技术追求的人呢？也许有时候算吧。无论是技术还是别的东西，其实我们所有人都愿意追求有趣的东西。</p><p>从过往经历来看，我关心的技术话题并且乐于出自兴趣去学习、思考的，比如：</p><ul><li><p>PoW 和 PoS 的本质区别是什么，PoW 好还是 PoS 好</p><ul><li>《<a href="/2024/04/14/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%AF%B4PoW%E6%AF%94PoS%E6%9B%B4%E5%8A%A0%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96/">为什么说 PoW 比 PoS 更加去中心化</a>》</li></ul></li><li><p>以太坊的 PoS 和 Cardano 的 PoS 有什么区别</p><ul><li>为什么说 Cardano 的 PoS 是比较纯粹的 PoS，又为什么以太坊的 PoS 更加去中心化</li></ul></li><li><p>PBFT 的优缺点是什么，PBFT 有哪些优化的空间</p><ul><li>《<a href="/2025/01/05/%E6%89%80%E6%9C%89-BFT-%E5%85%B1%E8%AF%86%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E9%83%BD%E6%98%AF%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84/">所有 BFT 共识的区块链都是中心化的</a>》</li><li>《<a href="/2024/06/09/Ethereum-Casper-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81-EIP-7251/">Ethereum Casper 为什么需要 EIP-7251</a>》</li><li>《<a href="/2024/06/03/%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%AD%E7%9A%84PBFT%E4%B8%8D%E9%9C%80%E8%A6%81%E7%AC%AC%E4%BA%8C%E6%AC%A1%E6%8A%95%E7%A5%A8/">区块链中的 PBFT 不需要第二次投票</a>》</li></ul></li><li><p>不同类型的区块链是如何处理分叉的</p><ul><li>《<a href="/2023/07/01/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E5%85%B1%E8%AF%86%E6%9C%BA%E5%88%B6%E7%9A%84%E7%90%86%E8%A7%A3/">对区块链共识机制的理解</a>》</li><li>《<a href="/2024/08/22/PoS%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%88%86%E5%8F%89/">PoS 类型的区块链如何处理分叉</a>》</li></ul></li><li><p>区块链可能有哪些有趣的应用场景</p><ul><li>《<a href="/2023/05/18/Pebbling-Game-%E9%B9%85%E5%8D%B5%E7%9F%B3%E6%B8%B8%E6%88%8F/">Pebbling Game 鹅卵石游戏</a>》</li><li>《<a href="/2023/02/22/%E4%B8%80%E7%A7%8D%E5%9C%A8%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%8A%E7%94%9F%E6%88%90%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%9A%84%E6%9C%BA%E5%88%B6/">一种在区块链上生成随机数的机制</a>》</li><li>《<a href="/2022/12/27/%E2%80%9C%E7%8C%9C%E5%9D%87%E5%80%BC%E7%9A%842-3%E2%80%9DdApp-%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1/">“猜均值的2&#x2F;3” dApp 游戏设计</a>》</li></ul></li></ul><p>知道这些东西有用吗？没什么用，面试的时候几乎不会有人问，工作中更是用不到，就仅仅只是出于兴趣爱好去探索这些技术问题。这些问题的答案，从来也都不是现成的，网络上是搜索不到的，ChatGPT 也是没办法精准回答的，只有经过一段时间的学习，加上查阅论文资料，结合自己的亲身经历和理解，才可以形成技术观点，无论观点本身是对还是错。</p><p>因此可能出于某种思维上的惯性，我很少关心太过基础的编程类问题。这种事情因人而异，不能强求，自然也不能强迫别人因为 FYI 就去关心某些问题。</p><h4 id="FYI：成为好的-writer"><a href="#FYI：成为好的-writer" class="headerlink" title="FYI：成为好的 writer"></a>FYI：成为好的 writer</h4><p>（刚说完不要 FYI，我这里就在 FYI）</p><p>《<a href="https://www.joecotellese.com/posts/rework-book-summary/">Rework</a>》 这本书里有一个章节印象挺深，标题是 “Hire great writers”，书中的观点是，不是因为工作中需要发表什么文章、写什么报告，而是好的 writer 往往具备逻辑清晰表达问题的能力，可以帮助到工作。</p><p>回到技术问题上，现在各种形式的技术文章也都非常普遍，比如对锁的使用场景比较有心得的话，完全可以落实到文字上，输出成果形成一篇文章，分门别类的介绍锁的种类、最佳的使用场景，然后发表到各种平台上，获得成千上万人的关注，再然后如果对其他技术细节也有心得，内容逐渐丰富，直到写出了一本书，甚至有出版社看上，或者公开到网络上作为电子书开源……FYI……何必跟我较真呢。</p><h3 id="补充（2025-12-13）"><a href="#补充（2025-12-13）" class="headerlink" title="补充（2025.12.13）"></a>补充（2025.12.13）</h3><p>为什么只敢，并且很乐于在 “窝里” 横呢？这是很奇怪的现象。我根本不在乎你的 “窝”，我随时可以离开。</p>]]></content>
  </entry>
  <entry>
    <title>从团队内部的混乱想到……</title>
    <link href="https://b.smallyu.net/2025/03/22/%E4%BB%8E%E5%9B%A2%E9%98%9F%E5%86%85%E9%83%A8%E7%9A%84%E6%B7%B7%E4%B9%B1%E6%83%B3%E5%88%B0%E2%80%A6%E2%80%A6/"/>
    <id>blog-b:https://b.smallyu.net/2025/03/22/%E4%BB%8E%E5%9B%A2%E9%98%9F%E5%86%85%E9%83%A8%E7%9A%84%E6%B7%B7%E4%B9%B1%E6%83%B3%E5%88%B0%E2%80%A6%E2%80%A6/</id>
    <published>2025-03-22T12:23:47.000Z</published>
    <updated>2025-12-03T10:02:00.861Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>首先推荐两篇王垠的博客文章：</p>
<ul>
<li>《<a]]></summary>
    <content type="html"><![CDATA[<p>首先推荐两篇王垠的博客文章：</p><ul><li>《<a href="https://yinwang-wiki.github.io/feeds/2015-03-03-how-to-respect-a-programmer.html">怎样尊重一个程序员</a>》</li><li>《<a href="https://yinwang-wiki.github.io/feeds/2015-03-11-git-etiquette.html">关于Git的礼节</a>》</li></ul><p>今天回看了一遍王垠的这两篇文章，比较庆幸的是，自己在平日的工作中，很少在无意间触犯到王垠提到的这些礼节问题。</p><p>会突然想起这个话题是因为工作中的一点小事，也挺有意思。起因是我擅自 merge 了没有经过 review 的代码，我的同事就开始在群里批判我的代码，也许是他觉得不经过他 review 就合并代码的行为，伤到了他在团队中的尊严和地位。</p><p>我现在在一个 web3 项目的开发团队工作，团队总共也就四五个人，内部管理却非常混乱，这是我在之前的工作中没有遇到过的。不过说实话我之前的工作经历不太够看，没有什么参考价值，所以我总结不出什么有用的结论。</p><p>要我对比的话，现在的工作和以前的工作，工作方式上最大的区别，在于分配任务的粒度不同，或者说分配到个人头上，负责的事情大小不同。</p><p>比如我在 ____ 工作的时候，需要开发 Solidity 合约，来支持我们的分布式文件系统对 EVM 链的兼容，那么这件事情就是我在做，有人 review，但实际上整个合约仓库的代码只有我一个人提交（这里不是在强调提交人数的问题），在这样的模式下，自然也就不存在现在遇到的什么代码质量之类的问题。</p><p>（____ 这家公司已经解散了，当时项目的代码并没有开源，现在的代码仓库是我私自备份下来的，两年过去了，应该不会有什么风险吧）</p><p>再比如我在 ____ 工作的时候，整个 ____ 的网络是我一个人启动并维护的，没出过什么问题。主网上线的时候有一个专业的运维同事帮忙开服务器、配置 Docker 之类。</p><p>（我已经离职了说出来应该没事吧）</p><p>包括更早先的工作经历，不管是我自己还是同事，直观感受上就是每个人都会负责某一块的业务，对整体业务负责而不是对某个具体的开发任务负责，个人的职责相对明确，在负责事情的时间长度上，都是几周到几个月为单位的，所以倒是没有出现过管理混乱的情况。</p><p>现在的工作模式是不太完整的 Scrum 风格，每个任务都是两到三天的开发周期，也就是小的开发任务，这些开发任务一定程度上是不区分业务线（代码仓库）的，开发人员会随机参与到不同的事情上。每个人都是在对自己的开发任务（PR）负责，而不是整个仓库负责。这种模式下，每一个开发任务都会有不同的负责人，造成感官上是比较混乱的。</p><p>侧面来对比的话，我之前的工作，如果某个人离职，是需要做很长时间工作交接的，因为需要一段时间来让别人接手。现在的工作，如果某个人离职，其实也没啥需要交接的，最多也就两三天的任务内容。不知道是不是远程工作的缘故，让公司被迫选择这样的管理方式。</p><p>我的大老板曾经把这种工作模式上的差异，总结为中国式的管理风格和欧美式的管理风格之间的差异。</p><p>我只是个普普通通的开发人员，没有管理经验，也不懂这些管理模式什么的，并不想也没什么机会需要我去思考这些问题。只是现在有点能感受到，其实管理本身是一门学问，挺大的学问……</p><br><h3 id="补充（2025-04-20）"><a href="#补充（2025-04-20）" class="headerlink" title="补充（2025.04.20）"></a>补充（2025.04.20）</h3><p>解释一下 “不完整的 Scrum” 风格是什么意思。上面的内容看起来是开放式结尾，实际上是在对 Scrum 风格表达不满，只是因为当时还在职，不好意思说太明白。</p><p>原版的 Scrum 敏捷开发，是指团队成员之间互相平等，产品经理来决定事情的优先级，而具体事情在技术上怎么分工怎么做，完全是团队成员自发决定的事情。团队成员真的就是在合作，共同完成某些目标。</p><p>在原版 Scrum 敏捷开发中，是没有管理员（Leader，领导）这种角色的，只有产品经理+技术团队，技术工作不是来自于领导的分配，而是团队成员协商决定的，这样不但每个人都有参与感，任务完成后，也会有成就感和归属感。Scrum Master 属于仆人式领导，主要帮助成员解决技术问题，以及让团队贯彻 Scrum 模式，而不是对团队进行管理。</p><p>而 “不完整的Scrum”，是指 Leader 既不愿意放弃自己的领导身份，放下对团队成员管理的权力，又希望使用 Scrum 框架里 Sprint 的模式进行开发任务的管理。</p><p>相当于想把传统瀑布式管理的好处，和 Scrum 管理的好处结合起来。事实证明这种做法是非常糟糕的。</p><p>如果在 Scrum 管理模式下，当 Sprint 任务来自于领导的策划和分配，而不是团队成员自发组织时，首先就会让团队成员失去责任感，失去 Owner 精神。任务是领导事先规划好的，我操什么心？岂不是安心做一个 Code monkey 就好？也因此在团队里能留下来的，大概率是安心做 Code monkey 的人。</p><p>其次就是没有成就感，一个任务也就两三天的时间，做完一个任务接着做下一个任务，上一个任务做完就跟我没关系了，紧接着进行下一个，完全是外包式的工作。只有当上一个任务的内容出现 bug，才需要回过头去修复，只要不出 bug，就不需要任何优化（显然是没有编程经验的人才会是这种想法）。我常有的一个体会是，做的越快，下一个任务就来的越快，导致效率越高反而做的越多。</p><p>然后是领导的问题，从领导的角度，感觉每天做任务分配就是他的职责，一旦把任务分配好，就松了一口气，安心了。刚才提到的，开发工作，是经常需要一些持续性的优化的，哪有一个需求开发完就再也不去动的道理。而领导似乎不懂这一点，一旦一个任务标记为完成，如果第二天说优化了什么什么，他会不理解，“这个需求不是已经 close 了吗？”</p><p>再然后是测试的问题，我们团队内没有专门的测试人员，而神奇的事情是，似乎领导觉得不需要测试人员，甚至连集成测试都是极其不重要的，最最重要的竟然是单元测试。上面提到，一个需求标记为 close 了，标记为 close 的标准是什么？标准是写完了代码以及单元测试。集成测试是什么？没听说过。这种模式下会发生什么情况？情况就是上线的（公开测试网）的代码，是完全没有经过集成测试的。也因此确实出现过很多次上线事故，大概上线 5 次测试网宕机 4 次这样的频率吧。</p><p>最后是 Sprint planning 管理表格的问题。目前的方式是一个任务对应一个 PR，单看这句话的描述，是不是觉得很外行？怎么就能恰好是一个PR？PR可大可小。比如，命令行 description 里存在一个 typo，就一行代码，我提了一个 PR，需不需要大动干戈地到 Scrum 表格上加上这一条？如果加吧，Scrum 上的任务可以理解为 OA 系统中的流程条目，每个步骤都会艾特相关的人，而且需要填很多字段，比如属于哪个项目，优先级是多少，reviewer 是谁等，为了修复一个 typo 就艾特那么多人实在不值得。可如果不修吧，难道就眼睁睁看着这个问题一直存在吗？于是，实际上经常发生的情况是，大家会在一个正规的 PR 里杂糅进去一些不相干的优化，让 Scrum 表格整体的使用体验非常糟糕。</p>]]></content>
  </entry>
  <entry>
    <title>当人们重视学历的时候，能考上什么大学大概率取决于初中 3 年+高中 3 年，一共 6 年时间的学习成果。 工作以后，6...</title>
    <link href="https://t.smallyu.net/#2025-9"/>
    <id>micro:2716157887</id>
    <published>2025-03-12T01:43:58Z</published>
    <updated>2025-03-12T01:43:58Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>当人们重视学历的时候，能考上什么大学大概率取决于初中 3 年+高中 3 年，一共 6 年时间的学习成果。 工作以后，6 年的时间实际上很短暂，本科毕业到 30 岁之间，就隔了 6 年。 也就是说，即使是在工作以后，利用好 6 年的时间，完全可以实现 “再考一次大学”，只不过这 6 年的时间里，没有人逼你学习，没有人给你...</p>]]></summary>
    <content type="html"><![CDATA[<p>当人们重视学历的时候，能考上什么大学大概率取决于初中 3 年+高中 3 年，一共 6 年时间的学习成果。</p>
<p>工作以后，6 年的时间实际上很短暂，本科毕业到 30 岁之间，就隔了 6 年。</p>
<p>也就是说，即使是在工作以后，利用好 6 年的时间，完全可以实现 “再考一次大学”，只不过这 6 年的时间里，没有人逼你学习，没有人给你讲课，没有人给你发试卷，没有老师监考。也没有固定的学科内容，社会上的课，其实比学校里的课难得多。</p>
<p>我的意思是，只要利用好人生中的时间，是可以弥补一些之前缺陷的，哪怕没有太多人愿意承认这一点（因为大多数人离开学校就不学习了）。</p>
<p>如果一个人毕业以及工作 6 年后，还拿着学历说事，就可见他实际上这 6 年没什么长进。</p>
]]></content>
  </entry>
  <entry>
    <title>手里拿着几个亿的富豪在想着怎么割韭菜，发个币让散户接盘； 我们挣着每月几千块钱的工资，在想着怎么让加密世界更美好。</title>
    <link href="https://t.smallyu.net/#2025-8"/>
    <id>micro:2668487766</id>
    <published>2025-02-19T12:17:10Z</published>
    <updated>2025-02-19T12:17:10Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>手里拿着几个亿的富豪在想着怎么割韭菜，发个币让散户接盘； 我们挣着每月几千块钱的工资，在想着怎么让加密世界更美好。</p>]]></summary>
    <content type="html"><![CDATA[<p>手里拿着几个亿的富豪在想着怎么割韭菜，发个币让散户接盘；</p>
<p>我们挣着每月几千块钱的工资，在想着怎么让加密世界更美好。</p>
]]></content>
  </entry>
  <entry>
    <title>以太坊的开发流程： Devnet ( pectra-devnets ) Testnet ( holesky ) Main...</title>
    <link href="https://t.smallyu.net/#2025-7"/>
    <id>micro:2646106034</id>
    <published>2025-02-09T07:25:07Z</published>
    <updated>2025-02-09T07:25:07Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>以太坊的开发流程： Devnet ( pectra-devnets ) Testnet ( holesky ) Mainnet ( mainnet.yaml )</p>]]></summary>
    <content type="html"><![CDATA[<p>以太坊的开发流程：</p>
<ol>
<li>Devnet (<a href="https://github.com/ethpandaops/pectra-devnets">pectra-devnets</a>) </li>
<li>Testnet (<a href="https://github.com/eth-clients/holesky">holesky</a>) </li>
<li>Mainnet (<a href="https://github.com/ethereum/consensus-specs/blob/dev/configs/mainnet.yaml">mainnet.yaml</a>)</li>
</ol>
]]></content>
  </entry>
  <entry>
    <title>假如启动一个新的以太坊 PoS 网络</title>
    <link href="https://smallyu.net/2025/01/28/%E5%81%87%E5%A6%82%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E5%8F%AB-Oiia-Network-%E7%9A%84%E4%BB%A5%E5%A4%AA%E5%9D%8A-PoS-%E7%BD%91%E7%BB%9C/"/>
    <id>blog:https://smallyu.net/2025/01/28/%E5%81%87%E5%A6%82%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E5%8F%AB-Oiia-Network-%E7%9A%84%E4%BB%A5%E5%A4%AA%E5%9D%8A-PoS-%E7%BD%91%E7%BB%9C/</id>
    <published>2025-01-28T15:26:40.000Z</published>
    <updated>2026-08-04T11:38:27.312Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>OIIA OIIA（Spining Cat）是最近很火的一只鬼畜旋转猫，对比 PoW 链上的 DOGE，OIIA 将是 PoS 链上的猫主题 memecoin。</p>
<p>OIIA 与 pump.fun 发行的 memecoin，以及 $Trump]]></summary>
    <content type="html"><![CDATA[<p>OIIA OIIA（Spining Cat）是最近很火的一只鬼畜旋转猫，对比 PoW 链上的 DOGE，OIIA 将是 PoS 链上的猫主题 memecoin。</p><p>OIIA 与 pump.fun 发行的 memecoin，以及 $Trump 之类不同的地方在于，所有代币的发行量都将通过 PoS 挖矿新增，没有任何预分配（可以验证 genesis 文件），未通过挖矿产生的代币，花钱都买不到。</p><h3 id="网络动机"><a href="#网络动机" class="headerlink" title="网络动机"></a>网络动机</h3><ol><li>《<a href="/2025/01/10/%E5%8F%91%E8%A1%8C%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E7%9A%84%E6%9C%80%E5%A5%BD%E6%96%B9%E5%BC%8F/">发行加密货币的最好方式</a>》</li><li>Oiia 将会提供更便捷的搭建以太坊 PoS 网络的工具，进一步降低搭建以太坊 PoS 网络的难度</li></ol><h4 id="为什么使用者要参与"><a href="#为什么使用者要参与" class="headerlink" title="为什么使用者要参与"></a>为什么使用者要参与</h4><p>如果参与者没有相关经验，作为学习者，可以：</p><ol><li>学习如何搭建一个完整的以太坊 PoS 网络</li><li>学习如何启动和运维一个以太坊 Validator 节点，如何质押、如何解除质押</li><li>学习如何熟练使用以太坊生态节点相关的工具</li><li>发现并解决以太坊生态工具使用上的问题，给以太坊生态做贡献</li></ol><h4 id="为什么不用以太坊测试网"><a href="#为什么不用以太坊测试网" class="headerlink" title="为什么不用以太坊测试网"></a>为什么不用以太坊测试网</h4><p>作为以太坊网络的学习者，为什么不直接用 Sepolia 这样的测试网去用，而是选择 Oiia Network？</p><p>因为 Oiia Network 的定位是 memecoin。</p><h3 id="网络-Spec"><a href="#网络-Spec" class="headerlink" title="网络 Spec"></a>网络 Spec</h3><h4 id="技术基础"><a href="#技术基础" class="headerlink" title="技术基础"></a>技术基础</h4><p>使用以太坊客户端 Geth + Lighthouse 作为初始节点。只修改启动配置和 genesis 文件，不修改代码。</p><h4 id="Chain-ID-以及-Network-ID"><a href="#Chain-ID-以及-Network-ID" class="headerlink" title="Chain ID 以及 Network ID"></a>Chain ID 以及 Network ID</h4><p>十进制：</p><pre><code>20220915</code></pre><p>十六进制：</p><pre><code>0x1348BF3</code></pre><h4 id="初始-Validator"><a href="#初始-Validator" class="headerlink" title="初始 Validator"></a>初始 Validator</h4><p>128 个，这个是网络启动的最小规模，会直接写入到 genesis.ssz 文件中。</p><h4 id="初始-Faucet"><a href="#初始-Faucet" class="headerlink" title="初始 Faucet"></a>初始 Faucet</h4><p>由于一开始网络的参与人数会比较少，会预留 128*32 &#x3D; 4096 OIIA 作为水龙头余额，放到水龙头地址中。</p><p>水龙头使用 PoW Faucet（网页挖矿）的形式来分配。</p><p>水龙头的目的是提供少量的流通金额用于网络的测试使用，以及早期愿意参与到网络中的 Validator（虽然靠水龙头很难领到 32 个 OIIA）。预留额度上，如果有 128 个 solo-staker，这个网络就算是巨大的成功了，所以认为预留 4096 个 OIIA 够用。</p><h4 id="初始发行量"><a href="#初始发行量" class="headerlink" title="初始发行量"></a>初始发行量</h4><p>为了避免类似以太坊基金会抛售的问题，OIIA 不会预分配任何金额给开发人员或 DAO，几乎所有网络都会因为预分配受到怀疑。</p><p>以太坊的 PoS 共识没有发行量上限，所以网络的初始发行量就是 4096 个 OIIA。网络启动后的流通量全部依靠挖矿奖励来产出，就像比特币一样。</p><p>也就是说，从 Oiia Network 的 genesis 文件来看，除了 4096 个 OIIA 预留用于的空投外（创世节点的 128 个 Validator 不体现在 genesis 文件上，价值 4096 OIIA），不会再预分配任何金额给任何地址。</p><h4 id="如何成为-Validator"><a href="#如何成为-Validator" class="headerlink" title="如何成为 Validator"></a>如何成为 Validator</h4><p>由于网络初始代币发行量特别少，Faucet 上又领不到足够多的 OIIA，所以可以在社区中申请成为 Validator，社区直接从 Faucet 地址转账 32 OIIA 到申请地址。</p><h4 id="网络启动进度"><a href="#网络启动进度" class="headerlink" title="网络启动进度"></a>网络启动进度</h4><p>由于没有任何商业目的，网络的启动进度会比较随心所欲。</p>]]></content>
  </entry>
  <entry>
    <title>你发表了一种观点说，一加一等于二； 然后过来一个人为了体现自己厉害，就说，一加一不等于二； 这个时候有两种可能性，一种可...</title>
    <link href="https://t.smallyu.net/#2025-6"/>
    <id>micro:2615645926</id>
    <published>2025-01-27T12:35:42Z</published>
    <updated>2025-01-27T12:35:42Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>你发表了一种观点说，一加一等于二； 然后过来一个人为了体现自己厉害，就说，一加一不等于二； 这个时候有两种可能性，一种可能是，对方是某方面的专家，考虑到非标准数学系统，会有不同规则的加法运算；考虑到量子物理学的叠加状态，普通加法并不适用；考虑到哲学方面，情感中一加一等于一个整体，等等。 另一种可能是，对方没有学过小学数...</p>]]></summary>
    <content type="html"><![CDATA[<p>你发表了一种观点说，一加一等于二；    </p>
<p>然后过来一个人为了体现自己厉害，就说，一加一不等于二；    </p>
<p>这个时候有两种可能性，一种可能是，对方是某方面的专家，考虑到非标准数学系统，会有不同规则的加法运算；考虑到量子物理学的叠加状态，普通加法并不适用；考虑到哲学方面，情感中一加一等于一个整体，等等。</p>
<p>另一种可能是，对方没有学过小学数学，连生活中常识性的数学运算都不知道。</p>
<p>无论是哪种可能性，你都没有任何理由去和对方争论对错，不应该浪费彼此的时间。</p>
]]></content>
  </entry>
  <entry>
    <title>作为一个凡人，有不懂的东西很正常； 但是如果非要不懂装懂，就有问题了； 如果在不懂装懂的情况下，把自己骗了，自以为很懂，...</title>
    <link href="https://t.smallyu.net/#2025-5"/>
    <id>micro:2614033943</id>
    <published>2025-01-25T17:11:06Z</published>
    <updated>2025-01-25T17:13:43Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>作为一个凡人，有不懂的东西很正常； 但是如果非要不懂装懂，就有问题了； 如果在不懂装懂的情况下，把自己骗了，自以为很懂，就出问题了； 如果不但把自己骗了，还要拿一些肤浅的道理试图教育别人，就是一种可笑的行为了。</p>]]></summary>
    <content type="html"><![CDATA[<p>作为一个凡人，有不懂的东西很正常；<br>但是如果非要不懂装懂，就有问题了；<br>如果在不懂装懂的情况下，把自己骗了，自以为很懂，就出问题了；<br>如果不但把自己骗了，还要拿一些肤浅的道理试图教育别人，就是一种可笑的行为了。    </p>
]]></content>
  </entry>
  <entry>
    <title>EVM 是以太坊最成功的特性，Layer 2 是以太坊最失败的特性 以太坊的网络是去中心化的，比 Solana 好很多：...</title>
    <link href="https://t.smallyu.net/#2025-4"/>
    <id>micro:2613720734</id>
    <published>2025-01-25T01:58:44Z</published>
    <updated>2025-01-25T01:58:44Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>EVM 是以太坊最成功的特性，Layer 2 是以太坊最失败的特性 以太坊的网络是去中心化的，比 Solana 好很多：但是以太坊的发展方向不是去中心化，而是一个人说了算的，这一点没比 Solana 强 如果以太坊的 Layer 2 发展成型，那不就类似于子网络的模式吗，扩容方式和 Avalance / Cosmos...</p>]]></summary>
    <content type="html"><![CDATA[<ol>
<li>EVM 是以太坊最成功的特性，Layer 2 是以太坊最失败的特性</li>
<li>以太坊的网络是去中心化的，比 Solana 好很多：但是以太坊的发展方向不是去中心化，而是一个人说了算的，这一点没比 Solana 强</li>
<li>如果以太坊的 Layer 2 发展成型，那不就类似于子网络的模式吗，扩容方式和 Avalance / Cosmos 没有本质区别</li>
<li>如果拿 ETH L2 和 Solana 比，都是中心化的服务</li>
<li>Solana 可以把余额全部发送出去</li>
<li>所以Solana 的潜力比以太坊大，如果以太坊要坚持 L2 路线图的话</li>
<li>没有人可以预测未来，但我们又总是尝试着预测未来，因为投资本就需要预测未来的趋势</li>
</ol>
]]></content>
  </entry>
  <entry>
    <title>畅想未来：memecoin 社交，每个人都会发行属于自己的 memecoin，好朋友之间会互相购买和持有对方的 meme...</title>
    <link href="https://t.smallyu.net/#2025-3"/>
    <id>micro:2599813491</id>
    <published>2025-01-18T18:08:28Z</published>
    <updated>2025-01-18T18:08:28Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>畅想未来：memecoin 社交，每个人都会发行属于自己的 memecoin，好朋友之间会互相购买和持有对方的 memecoin。自己持有的 memecoin 代表了自己的社交关系图谱，代币越多关系越铁。</p>]]></summary>
    <content type="html"><![CDATA[<p>畅想未来：memecoin 社交，每个人都会发行属于自己的 memecoin，好朋友之间会互相购买和持有对方的 memecoin。自己持有的 memecoin 代表了自己的社交关系图谱，代币越多关系越铁。</p>
]]></content>
  </entry>
  <entry>
    <title>以太坊的手续费机制，有个很让人烦的地方是，无法让钱包地址的余额归零，想全部转出？不可以，钱包上总会剩下 0.000000...</title>
    <link href="https://t.smallyu.net/#2025-2"/>
    <id>micro:2591678846</id>
    <published>2025-01-15T05:24:32Z</published>
    <updated>2025-01-15T05:24:32Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>以太坊的手续费机制，有个很让人烦的地方是，无法让钱包地址的余额归零，想全部转出？不可以，钱包上总会剩下 0.0000000001234xxxx 余额。</p>]]></summary>
    <content type="html"><![CDATA[<p>以太坊的手续费机制，有个很让人烦的地方是，无法让钱包地址的余额归零，想全部转出？不可以，钱包上总会剩下 0.0000000001234xxxx 余额。</p>
]]></content>
  </entry>
  <entry>
    <title>发行加密货币的最好方式</title>
    <link href="https://smallyu.net/2025/01/10/%E5%8F%91%E8%A1%8C%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E7%9A%84%E6%9C%80%E5%A5%BD%E6%96%B9%E5%BC%8F/"/>
    <id>blog:https://smallyu.net/2025/01/10/%E5%8F%91%E8%A1%8C%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E7%9A%84%E6%9C%80%E5%A5%BD%E6%96%B9%E5%BC%8F/</id>
    <published>2025-01-09T16:39:12.000Z</published>
    <updated>2026-08-04T11:43:17.271Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>前几天某个互联网无关行业的知名人物，在 pump.fun 上发行了一个 memecoin。然后这两天看到有人在公开频道里讨论，关于把 memecoin 迁移为公链的方案，比如保留原始地址和余额启动新链之类。</p>
<p>这个 memecoin]]></summary>
    <content type="html"><![CDATA[<p>前几天某个互联网无关行业的知名人物，在 pump.fun 上发行了一个 memecoin。然后这两天看到有人在公开频道里讨论，关于把 memecoin 迁移为公链的方案，比如保留原始地址和余额启动新链之类。</p><p>这个 memecoin 的动机很简单，就是发行者需要募集资金，因为他们从事的活动需要资金来源，也因为他们在从事的活动，这个 memecoin 已经被很多钱包屏蔽掉了。</p><p>当然我们这里不会讨论发行加密货币的动机，只会讨论发行加密货币的技术手段，并且对技术手段进行对比。</p><h3 id="最好的方式"><a href="#最好的方式" class="headerlink" title="最好的方式"></a>最好的方式</h3><p>先说结论，发行加密货币，最可靠的技术方案是，直接使用以太坊的客户端，运行一条和以太坊 Chain ID 不同的链。</p><h3 id="为什么不是-pump-fun"><a href="#为什么不是-pump-fun" class="headerlink" title="为什么不是 pump.fun"></a>为什么不是 pump.fun</h3><p>pump.fun 是一个很好的平台，提供了一键发币的能力，能保证合约的安全性，不 rug pull，没有预售，没有安全漏洞。这一点相比于自己写合约发币，要方便和安全很多，</p><p>pump.fun 最厉害的地方在于，发币即可交易，使用 bonding curve 机制来定义价格，让一个币种即使交易者很少，也可以正常交易，这是其他发币方式做不到的。</p><p>不过 pump.fun 也有问题，首先是 SOL 生态，不知道为什么 pump.fun 最初选择了 Solana 而不是 Ethereum，买家在购买新发的币种之前，要先理解和拥有 SOL 才可以继续后续的步骤。虽然 SOL 也非常知名了，但买家为什么要先知道 SOL？</p><p>其次是当币种市值在 100k 以下，这个币的交易行为就和 pump.fun 平台绑定了，不访问 pump.fun 这个网站，你就找不到可以交易的地方。如果网站没了，或者域名没了，就真的没有入口了，这对于币种的长期发展并不友好。市值到 100k 以上就会进入 Raydium，那么有多少买家理解 Raydium是什么？岂不是又依赖于一个Dex平台？</p><p>所以享受 pump.fun 提供便利的同时，就要承担 pump.fun 这个平台本身的风险，还要承受 Solana 这条链有可能出现的风险，比如，Solana 会长久存在吗？多久算久？</p><p>pump,fun 对自己的定位还挺准确的，memecoin 发行平台。</p><h3 id="为什么不是-PoW"><a href="#为什么不是-PoW" class="headerlink" title="为什么不是 PoW"></a>为什么不是 PoW</h3><p>PoW 是最去中心化的技术形式，但是发行 PoW 链的成本太高了，不但没有现成的技术框架可以复用，需要硬核的技术，而且维护成本也很高，没有人挖矿就得自己挖，算力还不能太低。</p><h3 id="为什么不是-Cosmos"><a href="#为什么不是-Cosmos" class="headerlink" title="为什么不是 Cosmos"></a>为什么不是 Cosmos</h3><p>Cosmos 生态的项目往往伴随着两个负面的关键词，BFT，联盟链，所以可以排除了。</p><p>ATOM 是一个市值仅排名 50 左右的币种，生态上有自己的垂直领域，可以说，如果不知道为什么要用，就不要用。</p><p>另外 Cosmos 的生态建设其实不好，到目前都没有一个像 Metamask 一样能连接任意 RPC 的钱包，要真用上 Cosmos 会遇到不少问题。</p><h3 id="为什么不是-Polkadot-x2F-Avalanche"><a href="#为什么不是-Polkadot-x2F-Avalanche" class="headerlink" title="为什么不是 Polkadot &#x2F; Avalanche"></a>为什么不是 Polkadot &#x2F; Avalanche</h3><p>区块链行业专业的从业者，估计都没整明白、用不来这两条链，不在于它们无法理解，而是理解成本高。</p><p>而且像 Polkadot 比如 Existential Deposit 这种特性简直离谱，不明白为什么会存在。类似的未知问题还有很多，是不能轻易选择使用的。</p><h3 id="为什么不是-Ethereum-Layer-2"><a href="#为什么不是-Ethereum-Layer-2" class="headerlink" title="为什么不是 Ethereum Layer 2"></a>为什么不是 Ethereum Layer 2</h3><p>以太坊的 Layer 2 本身也不是发币用的，是给项目方挣协议费的，L2 是以太坊的扩展，原生代币仍然是 ETH。而且 L2 虽然技术开源也好用，但是需要中心化的运营，以及不间断提交 fault proofs 到 Layer 1，手续费得用真实的 ETH，挺贵的，如果用户少，手续费都挣不回来。</p><h3 id="为什么不在-Ethereum-上发行-ERC-20"><a href="#为什么不在-Ethereum-上发行-ERC-20" class="headerlink" title="为什么不在 Ethereum 上发行 ERC-20"></a>为什么不在 Ethereum 上发行 ERC-20</h3><p>智能合约一般人写不明白，主要是安全漏洞风险高，即使发行方觉得合约没问题，买家也很难判断合约安不安全，识别难度很高，所以不推荐这种方式。即使合约没问题，以太坊的手续费也很贵，很不友好。</p><p>Layer 2上发行 ERC-20 呢？问题是选择哪个 L2 网络？L2 网络的手续费倒是低，但是不同网络数据又不互通，从这个角度，L2 在杀掉以太坊，至少让以太坊变得分裂，而不是在帮助以太坊。</p><h3 id="为什么是-Ethereum"><a href="#为什么是-Ethereum" class="headerlink" title="为什么是 Ethereum"></a>为什么是 Ethereum</h3><p>不可否认的几点事实是：</p><ol><li>以太坊的 EVM 已经成为区块链行业最广泛认可和使用的智能合约标准</li><li>以太坊的 PoS 是除了 PoW 之外最去中心化的共识机制</li><li>以太坊的地位无法撼动，ETH Killer 也许会在某些指标上超越以太坊，但 EVM 标准这一点不会</li><li>相比于其他公链，以太坊的社区生态更加活跃，基础设施更加完善</li><li>新兴公链都在试图兼容 EVM，而不是推翻 EVM</li></ol><p>基于这些事实，发行区块链网络最好的方式只有一种：</p><ul><li>使用以太坊客户端，修改配置文件和启动参数之后，启动一个 Layer 1 网络</li></ul><p>从网络运行的角度，即使只使用目前版本的以太坊客户端，哪怕后续客户端不再跟随以太坊的步骤进行升级，也可以让网络长久稳定运行下去。</p><p>至于手续费，币价低手续费就便宜，所以几乎不太可能贵到手续费无法接受。</p><h3 id="如何解决初期交易和空投问题"><a href="#如何解决初期交易和空投问题" class="headerlink" title="如何解决初期交易和空投问题"></a>如何解决初期交易和空投问题</h3><p>除了 pump.fun 平台和 PoW 链，其余的发币方式都无法解决初始阶段币种交易的问题，初期上不了 CEX 也上不了 DEX，买家怎么买，拿什么买？</p><p>唯一能想到的就是以 ICO 的方式预售，在 TGE 的时候正式启动网络。尽管这个过程中往往会产生一大堆不和谐的事件和争议，但是如果用以太坊的节点，只要把 Genesis 文件中的每一个地址都说明，网络本身就可以是大家认可并且没有问题的。</p><p>网络创世没问题之后，剩下的就交给网络自身的通胀，也不会有明显的问题，网络就能平稳运行下去了。</p>]]></content>
  </entry>
  <entry>
    <title>Happy New Year</title>
    <link href="https://t.smallyu.net/#2025-1"/>
    <id>micro:2571574344</id>
    <published>2025-01-05T10:16:00Z</published>
    <updated>2025-01-05T10:16:00Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Happy New Year</p>]]></summary>
    <content type="html"><![CDATA[<p>Happy New Year</p>
]]></content>
  </entry>
  <entry>
    <title>所有 BFT 共识的区块链都是中心化的</title>
    <link href="https://smallyu.net/2025/01/05/%E6%89%80%E6%9C%89-BFT-%E5%85%B1%E8%AF%86%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E9%83%BD%E6%98%AF%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84/"/>
    <id>blog:https://smallyu.net/2025/01/05/%E6%89%80%E6%9C%89-BFT-%E5%85%B1%E8%AF%86%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E9%83%BD%E6%98%AF%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84/</id>
    <published>2025-01-05T03:57:59.000Z</published>
    <updated>2026-08-04T11:43:16.732Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>首先给出一个共识机制在去中心化程度上的排名，这个排名几乎是毋庸置疑的：</p>
<p>PoW &gt; PoS &gt; DPoS &gt; BFT</p>
<p>然后从处理分叉的角度，对比一下 PoS 和 BFT 的差异。</p>
<p>因为 BFT]]></summary>
    <content type="html"><![CDATA[<p>首先给出一个共识机制在去中心化程度上的排名，这个排名几乎是毋庸置疑的：</p><p>PoW &gt; PoS &gt; DPoS &gt; BFT</p><p>然后从处理分叉的角度，对比一下 PoS 和 BFT 的差异。</p><p>因为 BFT 算法本身决定了，所有使用 BFT 共识的链，都不会存在分叉，无论是软分叉还是硬分叉。没有分叉的链，意味着整个网络同一时刻只会有一个版本，而这个版本取决于项目发行方，哪怕项目发行方不是官方，这一版本也只能来自于某个中心化的组织。所以，使用 BFT 共识的区块链都是中心化的。</p><p>假如网络发行方对网络进行了让人无法接受的更改，会发生什么？</p><p>在 PoS 共识下，验证者可以选择旧的规则，也可以选择新的规则，这两种规则可以同时存在，直到大多数验证者达成一致，网络恢复一致。如果验证者始终无法达成一致，就会一直分叉下去。</p><p>在 BFT 共识下，验证者可以选择旧的规则，也可以选择新的规则，但是如果一方数量达到半数，网络将会停止。直到验证者线下达成一致，网络才会重新启动。</p><p>也就是说，当面临本应该分叉的情形时，BFT 会直接停机，这也是为什么 Solana 和 SUI 都出现过网络停止的原因。</p><p>到这里你就明白，这里说的中心化，是指在 BFT 网络中不会同时存在两个网络，当然使用其他共识的网络也几乎不会出现这种情况，但是容许这种情况发生。</p><p>更进一步的说明，这里说的中心化，是指 BFT 网络中如果一定比例的验证者想要让网络停止，网络就可以停止，只能通过新启动另外一个网络（其实也属于硬分叉的一种）来让网络恢复正常。</p><p>这种差异会产生什么影响？以太坊网络中，即使大多数节点已经挂掉，只要还有少数存在，网络就能够正常运行。而 BFT 网络对验证者的容错能力不到一半，如果半数验证者停掉，网络会直接瘫痪，你的所有链上资产无法继续转移。</p><p>从投资的角度，如果你打算长期持有某种代币，你觉得哪种网络更安全，更能让你的资产安全受到保障？</p><p>不过还要注意的是一点，网络的可靠性不一定来自于去中心化程度，Coinbase 的 Base 网络可靠性来自于美国政府的监管和半合规化，很多交易所和政府机构都会把钱放到 Coinbase Prime 的信托服务里，所以 Base 网络也是比较可靠的。</p>]]></content>
  </entry>
  <entry>
    <title>This year (2024)</title>
    <link href="https://crazy.smallyu.net/2024/12/31/this-year-2024/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2024/12/31/this-year-2024/</id>
    <published>2024-12-30T16:28:43.000Z</published>
    <updated>2025-10-01T00:52:55.639Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>This was probably the most exhausting year over the past several years, and I made an objective choice to avoid going the wrong way. And]]></summary>
    <content type="html"><![CDATA[<p>This was probably the most exhausting year over the past several years, and I made an objective choice to avoid going the wrong way. And then… maybe did some things that I can’t consider as completely wrong.</p><p>I practiced English every day using the Duolingo app and have already kept it up for 150 days. It’s actually helpful for improving my English, but my English is still terrible now.</p><p>This year, I also learned some lessons about what real investing is. I paid a high price—like an expensive tuition fee—for these lessons and realized that it’s important not to make margin trades at any time.</p><p>This year wasn’t too bad overall. I went on a solo trip to several cities. Although I didn’t feel many happy moments, I still gained some fresh experiences. It taught me how to face a completely unfamiliar environment. I also realized that travel itself doesn’t bring happiness—true happiness should come from a stress-free life.</p><p>About relationships, it seems they are heading in a better direction, and I made many beautiful memories this year. I didn’t make any new friends and spent almost all my time on work or rest. By the way, I don’t need internet friends. Never.</p><p>About my career, although I did something significant in my last job, it didn’t have much impact, and it’s unlikely to have any effect on my future either. Still, I don’t regret it.</p><p>Next year will also be a challenging year. I just hope life can get better, even in a seemingly hopeless situation.</p>]]></content>
  </entry>
  <entry>
    <title>最好的工作总结是自己的简历，在做的工作有没有价值、有没有意义、有没有含金量、有没有竞争力、有没有份量，只需要看假设你在写...</title>
    <link href="https://t.smallyu.net/#2024-59"/>
    <id>micro:2564617140</id>
    <published>2024-12-29T05:20:39Z</published>
    <updated>2024-12-29T05:20:39Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最好的工作总结是自己的简历，在做的工作有没有价值、有没有意义、有没有含金量、有没有竞争力、有没有份量，只需要看假设你在写简历，会不会把这些事情写上去。 简历是体现工作成果最精炼的地方，往往需要用一两句话把一段工作经历最重要的内容描述清楚，再用另外一两句话详细解释具体内容。 有时候你做了一年的工作，每天都很忙，但是写简历...</p>]]></summary>
    <content type="html"><![CDATA[<p>最好的工作总结是自己的简历，在做的工作有没有价值、有没有意义、有没有含金量、有没有竞争力、有没有份量，只需要看假设你在写简历，会不会把这些事情写上去。</p>
<p>简历是体现工作成果最精炼的地方，往往需要用一两句话把一段工作经历最重要的内容描述清楚，再用另外一两句话详细解释具体内容。</p>
<p>有时候你做了一年的工作，每天都很忙，但是写简历的时候发现只能一句带过，多写一句都是浪费篇幅；还有的工作只做了一个月，却愿意放在显眼的地方。</p>
<p>比起年终总结，简历的要求更高，年终总结是对内部的，竞争对手是同一家公司的同事，而简历是面向整个招聘市场的，需要和不同公司的人竞争。</p>
]]></content>
  </entry>
  <entry>
    <title>其实早就应该转变观念，从 “创建一种新类型的 coin” 转变为 “如何利用好现有的 coin 生态”。</title>
    <link href="https://t.smallyu.net/#2024-58"/>
    <id>micro:2547514546</id>
    <published>2024-12-17T05:03:20Z</published>
    <updated>2024-12-17T05:03:49Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>其实早就应该转变观念，从 “创建一种新类型的 coin” 转变为 “如何利用好现有的 coin 生态”。</p>]]></summary>
    <content type="html"><![CDATA[<p>其实早就应该转变观念，从 “创建一种新类型的 coin” 转变为 “如何利用好现有的 coin 生态”。</p>
]]></content>
  </entry>
  <entry>
    <title>对 2025 年区块链行业的预测</title>
    <link href="https://smallyu.net/2024/12/16/%E5%AF%B92025%E5%B9%B4%E5%8C%BA%E5%9D%97%E9%93%BE%E8%A1%8C%E4%B8%9A%E7%9A%84%E9%A2%84%E6%B5%8B/"/>
    <id>blog:https://smallyu.net/2024/12/16/%E5%AF%B92025%E5%B9%B4%E5%8C%BA%E5%9D%97%E9%93%BE%E8%A1%8C%E4%B8%9A%E7%9A%84%E9%A2%84%E6%B5%8B/</id>
    <published>2024-12-16T15:04:43.000Z</published>
    <updated>2026-08-04T11:43:17.357Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>2024 年发生的事情：</p>
<ol>
<li><p>比特币减半、比特币通过现货 ETF、比特币新高</p>
</li>
<li><p>特朗普喊单 BTC，马斯克喊单 DOGE</p>
</li>
<li><p>比特币叙事熄火，铭文、符文无人问津，Layer 2]]></summary>
    <content type="html"><![CDATA[<p>2024 年发生的事情：</p><ol><li><p>比特币减半、比特币通过现货 ETF、比特币新高</p></li><li><p>特朗普喊单 BTC，马斯克喊单 DOGE</p></li><li><p>比特币叙事熄火，铭文、符文无人问津，Layer 2 技术没有一个出圈（Lighting Network、Taproot、RGB、RGB++），Layer 2 项目没有一个靠谱（Nervos、Merlin、Nubit、Fractal Bitcoin)</p></li><li><p>以太坊 Cancun 升级引入 Blob，让 Layer 2 成本大幅降低，但是现在 Layer 2 充值到交易所仍然需要25分钟等待期，这一点体验很不好，既然有可能重组，交易就是不安全的</p></li><li><p>NFT 市场消失，Coinbase 和 Binance 关闭 NFT 交易市场</p></li><li><p>DEXX 交易所被盗，上千名用户上千万资金，交易所是华人背景，用户也是华人背景，小白多</p></li></ol><hr><p>2025 年的趋势预测：</p><ol><li><p>比特币价格新高到 14 万美元</p></li><li><p>比特币不需要 OP_CAT</p></li><li><p>以太坊的地位无法撼动，所有 ETH Killer 都没有潜力，包括 Solana、Ton、Tron、Polkadot、Cardano、Avalanche、Cosmos、SUI</p></li><li><p>现有的公链格局不会改变，也不会有新的高市值 Layer 1 出现</p></li><li><p>会有新的技术整合类型的链出现，把低成本的东西作为原生功能，比如预言机、随机数、链上治理、Subnet、Web Assembly、DID 等老技术大杂烩，为了提高吸引力，还会蹭 ZK 和 AI 热度，但会发现实际上 ZK 起不到作用，和 AI 也没有关系</p></li><li><p>跨链一直是刚需，但一直没有去中心化的方案落地，以后也不会有</p></li><li><p>新的链一定会兼容 EVM，新的项目也会优先支持 EVM</p></li><li><p>生态类的项目还会不断出现，这些项目会追随某一条公链的技术，干自己的事情，Ethereum &#x2F; Polkadot &#x2F; Cosmos &#x2F; Internet Computer &#x2F; Avalanche 都提供了这样的生态环境</p></li></ol><hr><p>作为一个普通人，想参与到区块链中，能做的只有 3 件事:</p><ol><li><p>定投比特币</p></li><li><p>定投比特币</p></li><li><p>定投比特币</p></li></ol>]]></content>
  </entry>
  <entry>
    <title>想家了</title>
    <link href="https://t.smallyu.net/#2024-57"/>
    <id>micro:2541798988</id>
    <published>2024-12-13T16:20:13Z</published>
    <updated>2024-12-13T16:20:13Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想家了</p>]]></summary>
    <content type="html"><![CDATA[<p>想家了</p>
]]></content>
  </entry>
  <entry>
    <title>Restaking 项目的经济难题</title>
    <link href="https://smallyu.net/2024/11/18/Restaking%E9%A1%B9%E7%9B%AE%E7%9A%84%E7%BB%8F%E6%B5%8E%E9%9A%BE%E9%A2%98/"/>
    <id>blog:https://smallyu.net/2024/11/18/Restaking%E9%A1%B9%E7%9B%AE%E7%9A%84%E7%BB%8F%E6%B5%8E%E9%9A%BE%E9%A2%98/</id>
    <published>2024-11-18T15:13:15.000Z</published>
    <updated>2025-11-09T09:22:13.309Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Restaking 是一个相对早期的赛道，其中比较有名的项目是 Eigen Layer，有一段时间很火，因为 Eigen Layer 高薪聘请了以太坊基金会的]]></summary>
    <content type="html"><![CDATA[<p>Restaking 是一个相对早期的赛道，其中比较有名的项目是 Eigen Layer，有一段时间很火，因为 Eigen Layer 高薪聘请了以太坊基金会的 Researcher，舆论认为以太坊基金会的成员拿了好处，以至于让以太坊往中心化的方向发展了。</p><p>Eigen Layer 搞得声势浩大，不可否认的是 Restaking 的商业模式行得通，因为 Eigen Layer 已经把路走出来了，在运作模式上不用做过多怀疑。</p><p>但是回到 Restaking 的定义上，仍然有问题值得思考。比如，为什么是 Restaking，而不是 Staking？</p><p>因为 Restaking 项目的本质不是技术问题，而是经济问题。换句话说，Restaking 项目没有技术壁垒，有的是商业模式壁垒，关键看在商业合作上能不能运转起来。</p><p>为什么这么说？</p><p>为什么要 Restaking？因为收益有限。作为一个质押用户，我先把 ETH 质押成 stETH，可以稳定拿 3% 的质押收益，在此基础上，我把 stETH 质押到 Eigen Layer 上，有收益最好，没有也无所谓，反正是白给的，哪怕没有收益，我还有 3% 的保底收益。</p><p>如果是 Staking 呢？就有问题了。我手里拿着 ETH，是去拿 stETH 的稳定 3%，还是去拿 Eigne Layer 上不靠谱的项目收益？</p><p>这里就涉及到一个问题，Eigen Layer 的收益来自哪里？</p><p>PoS 链的质押奖励是原生的，非常稳定。Eigen Layer 呢？奖励只能是来自于使用 AVS 提供服务的用户。那么，AVS 提供了什么服务？</p><p>有一个理论是这样：</p><p>对于 PoS 链的逻辑，用户质押了 token，来给 validator 提供质押权重，然后，validator 提供对块数据的验证。</p><p>Restaking 项目中，用户质押了 token，来给 operator 提供质押权重，然后，operator 可以对任意计算任务提供验证。</p><p>听起来是不是很诱人？PoS 链竟然是 Restaking 项目的子集，这么说起来 Restaking 大有可为。</p><p>这种理论有一定道理，不过稍微较真一点，和 Restaking 比较的应该是 DPoS 共识，而不是 PoS 共识。在去中心化程度上，DPoS 是要比 PoS 差的。</p><p>那么就拿 DPoS 和 Restaking 项目比，Restaking 项目会具有更大的优势吗？</p><p>这里得再考虑一个问题，为什么 DPoS 优先被用于对块数据的验证了？而没有拿着用户的质押份额去验证别的东西？</p><p>答案很简单，因为没有比用户资产更重要的数据了。比如，是银行存款的余额数据重要，还是明天天气预报数据的准确度重要？所以 DPoS 在此前有且仅有一个场景，那就是验证区块交易数据，而且，想再找到一个比资产数据更重要的场景，是非常困难的。</p><p>在明确了这个概念后，回到 Restaking 收益的问题，假如 DPoS 能提供 3% 的质押收益，Restaking 能提供多少收益呢？按道理是少于 3% 的，因为 Restaking 在验证的数据，不会比用户的资产数据更重要。</p><p>这就是为什么 Restaking 项目一定要 Restaking 而不是直接 Staking，因为收益率比不过 Staking。在 Staking 的基础上做 Restaking，性质就不一样了。</p><p>回到收益来源的问题，其实 DPoS 和 Restaking 的质押收益，都来自于使用服务的用户。</p><p>DPoS 中，有一批人质押了 token 成为 validator，另一批人依赖于 validator 提供的资产安全能力。所以用户允许 DPoS 链增发 3% 的 token 作为块奖励。供应总量增加，不就相当于洗劫了所有人嘛。</p><p>Restaking 中，有一批人质押了 token 成为 operator，另一批人依赖于 operator 提供的数据验证能力，基本逻辑和 DPoS 是相似的。这里的 “另一批人”，就指使用 AVS 服务的用户，而这些用户，也将会为 Restaking 的收益付费。</p><p>Restaking 的收益不可能凭空产生，直接来源就是用户，而付费方式也可以很简单，就是字面意思的付费，我调用一次 AVS 上的某个数据，就付费 0.1 美元，类似这种方式，直接计费就好了，都不需要涉及什么供应量。</p><p>用户支付的费用，有多少才够呢，假如有 1M 的 stETH 质押量，为了给质押者提供 1% 的年化，假如有 1 万个用户每天使用一次的话……</p><p>到这里问题就又来了，有哪个冤种用户会愿意为了这种服务花钱？要知道以太坊 L1 的链上交易，一次 1 美元可就贵死了，更是有很多很多人，舍不得开 9 块钱的爱奇艺会员看视频，无数程序员，舍不得为自己日夜使用的 IDEA 买个正版……</p><p>当然，只要泡沫不破裂，大家的财富就都在膨胀，牛市来临之后，没有人是在亏钱的，只要泡沫不破裂，只要能够在泡沫破裂前离场，一切都会很美好。</p>]]></content>
  </entry>
  <entry>
    <title>提个小问题：coin 和 token 的区别是什么？ 把这个基础概念搞清楚，对 web3 行业的了解会更清晰一点。</title>
    <link href="https://t.smallyu.net/#2024-56"/>
    <id>micro:2452979178</id>
    <published>2024-11-02T12:45:02Z</published>
    <updated>2024-11-02T12:46:38Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>提个小问题：coin 和 token 的区别是什么？ 把这个基础概念搞清楚，对 web3 行业的了解会更清晰一点。</p>]]></summary>
    <content type="html"><![CDATA[<p>提个小问题：coin 和 token 的区别是什么？</p>
<p>把这个基础概念搞清楚，对 web3 行业的了解会更清晰一点。</p>
]]></content>
  </entry>
  <entry>
    <title>如何看懂任意区块链项目的技术架构</title>
    <link href="https://smallyu.net/2024/10/15/%E7%9C%8B%E6%87%82%E4%BB%BB%E6%84%8F%E5%8C%BA%E5%9D%97%E9%93%BE%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84/"/>
    <id>blog:https://smallyu.net/2024/10/15/%E7%9C%8B%E6%87%82%E4%BB%BB%E6%84%8F%E5%8C%BA%E5%9D%97%E9%93%BE%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84/</id>
    <published>2024-10-15T15:43:36.000Z</published>
    <updated>2025-11-09T09:22:13.493Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="基本结构"><a href="#基本结构" class="headerlink" title="基本结构"></a>基本结构</h3><p>最基本的区块链，就是一条区块链本身，包含有通过共识出块的能力，可能有很多节点，也可能只有一个节点，每个节点都提供接收交易的]]></summary>
    <content type="html"><![CDATA[<h3 id="基本结构"><a href="#基本结构" class="headerlink" title="基本结构"></a>基本结构</h3><p>最基本的区块链，就是一条区块链本身，包含有通过共识出块的能力，可能有很多节点，也可能只有一个节点，每个节点都提供接收交易的 RPC 接口：</p><img src="1.png" width="60%"><p>因为以太坊的诞生，区块链的交易不仅仅是交易，还具有了智能合约的能力：</p><img src="2.png" width="60%"><p>总会有一个外部的程序来和智能合约交互，也就是发起交易：</p><img src="3.png" width="60%"><p>从这里开始需要明确两种行为：</p><ol><li>凡是和区块链有交互的，可能是提交交易或者查询交易，都算是链上交互</li><li>和区块链没有任何交互的，属于链下行为</li></ol><p>向智能合约发起交互一定属于链上交互，同样的，无论发起交易的外部程序，是用什么语言写的，可能是 Javascript 或者 Golang，都叫做智能合约的 SDK：</p><img src="4.png" width="60%"><p>除了以太坊的 EVM 合约，还有可能是其他虚拟机（SVM、WASM）的合约，或者 Cosmos 直接操作状态数据库的方式（Native合约），可以统一理解为链上智能合约：</p><img src="5.png" width="60%"><p>只要是链上合约，都会需要链下程序来发起交易，才能够实现某些功能。</p><p>而当智能合约有了具体的逻辑，很可能会触发一些事件，这些事件往往由链下节点来监听和处理：</p><img src="6.png" width="60%"><p>这个链下节点起什么名字都可以，用什么语言写都可以，总之会获取到合约中的事件，一般监听事件的方式有两种：</p><ol><li>主动查，不断请求节点的接口，看有没有新的事件</li><li>被动接受，比如 websocket 建立的长链接</li></ol><p>当合约里触发某个事件后，链下节点监听到事件，会根据事件进入不同代码分支，后面进行多么复杂的操作都可以。</p><p>链下节点可能有多个，也可能有多种角色，但是不重要，重要的是，他们都是在和链上的事件进行交互：</p><img src="7.png" width="60%"><p>一般链下节点之间不会擅自进行通信，而是紧跟区块链的块内容，因为链下节点也需要保持状态的一致，区块链场景下，链本身已经是非常好的能提供状态一致的手段了：</p><img src="8.png" width="60%"><p>所以，这个时候你就知道，其实对于区块链项目来说，链下节点和链上节点之间，只有两种动作：</p><ol><li>通过交易向区块链发送数据</li><li>通过监听事件来从区块链查询事件</li></ol><p>Cosmos 有一个能支持 EVM 合约的项目，还提供了 evm_hook 的接口，当 EVM 合约触发事件的时候会主动调用接口函数。这种 hook 函数本质上也是合约事件的被动监听，无非是从合约事件到链下节点调用的方式，从 RPC 请求变成了函数的直接调用。唯一增加的复杂度是 EVM 合约触发了 Cosmos 模块的函数，把两种合约的实现方式串起来了：</p><img src="9.png" width="60%"><p>复杂架构也不会改变的是，链下节点和链上节点之前的交互，只有两种动作。</p><p>如果再复杂一点的话，会往什么方向复杂呢，链下节点开始向链上提交交易了：</p><img src="10.png" width="60%"><p>也许在监听到事件后提交了一笔交易，交易触发了另一个事件，监听到另一个事件后进行了更多的操作。但是总之，链下节点和链上节点之前的交互，仍然只有两种动作。</p><h3 id="填充业务逻辑"><a href="#填充业务逻辑" class="headerlink" title="填充业务逻辑"></a>填充业务逻辑</h3><p>有了基本的技术手段，再往上填充业务逻辑，就容易理解了。</p><p>面对很长的业务逻辑，总是能分清楚哪些部分是链上交互、哪些部分是链下行为，核心区别在于数据状态存在哪里，是区块链上，还是链下节点：</p><ol><li>如果是通过交易发送到链上，业务的复杂程度就取决于合约的逻辑。</li><li>如果是链下节点监听到事件后的行为，那就取决于链下代码的复杂程度。</li></ol><p>如果复杂度超出了上述两种情况，就只能是链下节点之间脱离区块链进行了擅自的通信，并且还产生了不一致的状态，这样的链下节点可以认为已经在区块链项目之外了。</p>]]></content>
  </entry>
  <entry>
    <title>10 月份的面试记录</title>
    <link href="https://b.smallyu.net/2024/10/12/10%E6%9C%88%E4%BB%BD%E7%9A%84%E9%9D%A2%E8%AF%95%E8%AE%B0%E5%BD%95/"/>
    <id>blog-b:https://b.smallyu.net/2024/10/12/10%E6%9C%88%E4%BB%BD%E7%9A%84%E9%9D%A2%E8%AF%95%E8%AE%B0%E5%BD%95/</id>
    <published>2024-10-12T08:01:25.000Z</published>
    <updated>2025-12-04T13:51:05.015Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>接下来关于面试的记录，我觉得有必要明确几点：</p>
<ol>
<li>只记录面试的公司及日期</li>
<li>不再表达对面试过程的感受，以免有些公司或者面试官担心我乱说，不约我面试</li>
<li>不再发表对面试官本人的评价。我参加了<a]]></summary>
    <content type="html"><![CDATA[<p>接下来关于面试的记录，我觉得有必要明确几点：</p><ol><li>只记录面试的公司及日期</li><li>不再表达对面试过程的感受，以免有些公司或者面试官担心我乱说，不约我面试</li><li>不再发表对面试官本人的评价。我参加了<a href="/tags/%E6%89%BE%E5%B7%A5%E4%BD%9C/">很多次面试</a>，虽然都是被面试的立场，但面试的多了其实也大概能有感觉。所以我接下来不会再说面试官水平怎样之类的话</li></ol><p>如果一个人要创业，那么他必须拥有 200% 并且是盲目的信心，在任何时候都坚定不移的相信，自己在做正确的事情，否则在创业的道路上，他会被别人击败无数次，也会在受到质疑的时候，被自己击败。</p><p>找工作（个人的职业道路上）也是如此，必须拥有 200% 且盲目的信心，相信自己的方向是对的。</p><h3 id="9月23日"><a href="#9月23日" class="headerlink" title="9月23日"></a>9月23日</h3><ul><li><a href="https://nextmate.ai/">Nextmate.ai</a></li></ul><p>面试对方是项目经理，现在 all in 这个创业项目。项目是一个 Ton 小游戏，结合 AI 做一些玩法，主要招聘前端开发和智能合约开发。</p><h3 id="9月24日"><a href="#9月24日" class="headerlink" title="9月24日"></a>9月24日</h3><ul><li>不知道什么公司（海投简历，没好意思问）</li></ul><p>团队是坐市商，技术人员有两种，一种是纯后端技术开发，另一种是策略开发。团队会同时给多个交易所提供报价，技术方面主要是在调用各个交易所的 API。</p><ul><li>Gate.io （浏览器部门）</li></ul><p>一面竟然通过了，我感觉回答的一塌糊涂，面试过程让我写代码我也懒得写。面试官是面试的时候临时看简历的。</p><h3 id="9月25日"><a href="#9月25日" class="headerlink" title="9月25日"></a>9月25日</h3><ul><li>Gate.io （浏览器部门）</li></ul><p>二面是交叉面，二面的时候才知道这是哪个部门、具体做什么事情的，因为一面的时候没有给我留反问环节。</p><p>（另外，有很多猎头打着 Gate 的名义在招聘。离谱的是，其他公司的猎头至少上来就会说明他们是猎头，而 Gate 的猎头上来就说自己是 Gate 的 HR，但是 Gate 会有 HR 面试环节，那个才是真正的 HR）</p><h3 id="9月26日"><a href="#9月26日" class="headerlink" title="9月26日"></a>9月26日</h3><ul><li>Cycle Network</li></ul><p>一面，常规面试。</p><p>听说 Cycle Network 的创始人是百度区块链的部门负责人，估计面试流程上也保留了百度的传统，一面会让一线打工人出来问一些常规问题、写写代码。</p><h3 id="10月11日"><a href="#10月11日" class="headerlink" title="10月11日"></a>10月11日</h3><ul><li>上海金润信息技术有限公司</li></ul><p>公司想搭建一条联盟链，用来做数据上链、存证溯源类型的事情。</p><ul><li><a href="https://www.arcblock.io/">ArcBlock</a></li></ul><p>这家公司没面试，只是和 HR 沟通，然后不想面试了。有趣的是，可以在 V2EX 上搜一下这家公司的招聘流程。</p><!--- [**](https://**/)挺好的。--><h3 id="10月12日"><a href="#10月12日" class="headerlink" title="10月12日"></a>10月12日</h3><p>不找了。</p>]]></content>
  </entry>
  <entry>
    <title>近期的 Solo Travel</title>
    <link href="https://crazy.smallyu.net/2024/10/06/%E8%BF%91%E6%9C%9F%E7%9A%84-Solo-Travel/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2024/10/06/%E8%BF%91%E6%9C%9F%E7%9A%84-Solo-Travel/</id>
    <published>2024-10-06T12:52:45.000Z</published>
    <updated>2025-08-16T03:27:07.620Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<blockquote>
<p><strong>提醒：这个页面包含大量未压缩的高清图片和视频，而且没有任何缓冲机制</strong></p>
</blockquote>
<p>Solo Travel]]></summary>
    <content type="html"><![CDATA[<blockquote><p><strong>提醒：这个页面包含大量未压缩的高清图片和视频，而且没有任何缓冲机制</strong></p></blockquote><p>Solo Travel 是一个人的冒险。</p><p>最近正好是中秋节和国庆节假期，出门去附近的城市逛一逛，前后去了天津、唐山、西安。总共没去几天，在一个城市呆最多三四天就累了，觉得没什么好逛的了，就那么几个景点。</p><h3 id="天津"><a href="#天津" class="headerlink" title="天津"></a>天津</h3><p>这是去天津的攻略图，准备去这几个景点，它们在地图上的位置是邻近的，或者有顺序的，去的时候照着地图的位置走就可以了：</p><img src="1.png" width="40%"><h4 id="天津之眼"><a href="#天津之眼" class="headerlink" title="天津之眼"></a>天津之眼</h4><p>首先去的是天津之眼，天津的标志性建筑：</p><img src="2.png" width="40%"><p>沿途的水景很美，随便一拍就很好看：</p><img src="3.png" width="60%"><p>天津之眼下面是一条类似于商业街的街道，沿河两边有很多人，像是休闲广场一样的氛围。有跳广场舞的，也有不少开直播唱歌的，可以点歌也可以唱歌。也有小吃街：</p><img src="4.png" width="40%"><p>夜景真的挺出片：</p><img src="5.png" width="60%"><p>这个无意间拍到游船的视频挺好看，水面和灯光的颜色混合在一起，加上远处的夜景：</p><video controls width="40%" preload="metadata">  <source src="6.mp4" type="video/mp4"></video><p>这是好吃街的正面，在一开始图片的对岸：</p><img src="7.png" width="40%"><p>这张街边小摊的照片也不错：</p><img src="8.png" width="60%"><p>在天津等你，这是一家啤酒店的牌子和座位，几乎没有生意：</p><img src="9.png" width="40%"><p>在另一家小店门口看到了路飞的人偶站在阳光号上：</p><img src="10.png" width="40%"><p>在天津之眼的行程就这样结束了。</p><h4 id="天津古文化街"><a href="#天津古文化街" class="headerlink" title="天津古文化街"></a>天津古文化街</h4><p>古文化街就是一条商业街，有一堆卖古玩手串之类的摊位，再就是一些比较常见的店面，两侧行人也不少：</p><img src="11.png" width="40%"><p>拍到了一个不知道什么来头的菩萨雕塑：</p><img src="12.png" width="40%"><p>街上有不少揽客听相声的小摊位，正好累了就随便找了一家进去休息一下，作为听了几十遍郭德纲相声录音的听众来说，这家小馆子的相声还可以，有内容也好笑，觉得出乎意料值得票钱：</p><img src="13.png" width="40%"><p>听完相声出来就离开古文化街了。</p><h4 id="意大利风情街区"><a href="#意大利风情街区" class="headerlink" title="意大利风情街区"></a>意大利风情街区</h4><p>简称意风区：</p><img src="14.png" width="60%"><p>入口有一些欧式建筑适合女生拍照，此外就是一条普通的商业街了，和798一样的感觉。遇到一个破旧的雕塑尺度还挺大：</p><img src="15.png" width="40%"><h4 id="瓷房子"><a href="#瓷房子" class="headerlink" title="瓷房子"></a>瓷房子</h4><p>瓷房子装修很华丽，人也是真的多，别说进去要不要门票，人多到根本进不去：</p><video controls width="40%" preload="metadata">  <source src="16.mp4" type="video/mp4"></video><p>在门口看了看就走了：</p><img src="17.png" width="60%"><h4 id="津湾广场"><a href="#津湾广场" class="headerlink" title="津湾广场"></a>津湾广场</h4><p>在天津的最后一站津湾广场：</p><img src="18.png" width="40%"><p>人很多挺热闹：</p><video controls width="40%" preload="metadata">  <source src="19.mp4" type="video/mp4"></video><p>整体风景不错，吃完饭遛弯的好去处，从旅游的角度倒是没多大看头。</p><h4 id="滨海新区"><a href="#滨海新区" class="headerlink" title="滨海新区"></a>滨海新区</h4><p>最后没去滨海新区，在小红书上坏评价很多，关键是离天津太远，来回都很麻烦，而且不知道现在不是海鸥的季节，如果在公园里能喂海鸥的话我是一定会去一趟的，但是最近似乎不一定有海鸥：</p><img src="20.png" width="40%"><h3 id="唐山"><a href="#唐山" class="headerlink" title="唐山"></a>唐山</h3><h4 id="河头老街"><a href="#河头老街" class="headerlink" title="河头老街"></a>河头老街</h4><p>去唐山不需要做什么攻略，因为只去了一个景点，河头老街，据说风景很好很出片，还有演出。</p><img src="21.png" width="60%"><p>去的比较早天还没黑：</p><img src="22.png" width="40%"><p>偷拍了一个小姐姐的背影，汉服真的挺好看：</p><img src="23.png" width="40%"><p>有一个湖里游着很多鲤鱼，场景是很多小和尚看着一个大书生，好像是有一段故事的，没太留意具体的故事：</p><video controls width="40%" preload="metadata">  <source src="24.mp4" type="video/mp4"></video><p>到了晚上，街边的灯就开了，各种演出也才开始，真正进入河头老街好玩的时间段。</p><p>先是看到了路边小姐姐跳舞：</p><video controls width="40%" preload="metadata">  <source src="25.mp4" type="video/mp4"></video><p>于此同时，隔壁有一个王府招亲的互动演出：</p><video controls width="40%" preload="metadata">  <source src="26.mp4" type="video/mp4"></video><p>再往前走，街边有个小摊变小魔术：</p><video controls width="40%" preload="metadata">  <source src="27.mp4" type="video/mp4"></video><p>还有放电影的，播的大话西游：</p><video controls width="40%" preload="metadata">  <source src="28.mp4" type="video/mp4"></video><p>到了晚上，白天的书生雕塑更好看了：</p><img src="29.png" width="40%"><p>表演杂技的：</p><video controls width="40%" preload="metadata">  <source src="30.mp4" type="video/mp4"></video><p>整个河头老街最美的风景位置：</p><p>图片：</p><img src="31.png" width="40%"><p>视频：</p><video controls width="40%" preload="metadata">  <source src="32.mp4" type="video/mp4"></video><p>更完整的视频：</p><video controls width="40%" preload="metadata">  <source src="33.mp4" type="video/mp4"></video><p>非常非常美，号称水上大唐不夜城，有美景有演出，整个唐朝元素的热闹市井形象，都体现出来了（比西安真正的大唐不夜城好太多了）。</p><p>身处于美丽的景色中：</p><video controls width="40%" preload="metadata">  <source src="34.mp4" type="video/mp4"></video><p>会变颜色的大树和跳舞的小姐姐：</p><video controls width="40%" preload="metadata">  <source src="35.mp4" type="video/mp4"></video><p>吹笛子演出：</p><video controls width="40%" preload="metadata">  <source src="36.mp4" type="video/mp4"></video><p>第二个最美的风景位置：</p><p>图片：</p><img src="37.png" width="40%"><p>视频：</p><video controls width="40%" preload="metadata">  <source src="38.mp4" type="video/mp4"></video><p>人是真的多：</p><img src="39.png" width="40%"><p>街边还有很多各式各样的小表演。</p><p>整个景点最最最最精彩的压轴演出是打铁花，光是这个看台的位置就很值得期待了，和在广场上的封闭环境不一样，这里能看到整个街区的夜景：</p><video controls width="60%" preload="metadata">  <source src="40.mp4" type="video/mp4"></video><p>非常华丽的开场，配合背景音乐很燃：</p><video controls width="60%" preload="metadata">  <source src="41.mp4" type="video/mp4"></video><p>这一段是凑齐了各种要素，打铁花、火魔方、水上飞人：</p><video controls width="60%" preload="metadata">  <source src="42.mp4" type="video/mp4"></video><p>看完打铁花出来，紧接着就能看凤凰飞天表演：</p><p>精简版视频：</p><video controls width="40%" preload="metadata">  <source src="43.mp4" type="video/mp4"></video><p>完整版视频：</p><video controls width="40%" preload="metadata">  <source src="44.mp4" type="video/mp4"></video><p>看一次这样的演出才真的不虚此行！</p><h3 id="西安"><a href="#西安" class="headerlink" title="西安"></a>西安</h3><p>去西安准备的攻略图，就这么几个地方，最开始的动机还是想看看真正的大唐不夜城。</p><img src="45.png" width="40%"><h4 id="兵马俑"><a href="#兵马俑" class="headerlink" title="兵马俑"></a>兵马俑</h4><p>本来没想看兵马俑，后来有人推荐可以去，说场面挺震撼，其实我看后确实没太大感觉，一堆土坑和一堆泥人，可能是我没理解吧。去看兵马俑的人特别特别多。</p><img src="46.png" width="40%"><p>兵马俑的 3 个坑出来后紧接着去丽山园，秦始皇真正的坟墓在丽山园里，公开对外参观的是几个陪陵墓。最出名的可能是这几匹马：</p><img src="47.png" width="40%"><h4 id="大唐不夜城"><a href="#大唐不夜城" class="headerlink" title="大唐不夜城"></a>大唐不夜城</h4><p>大唐不夜城徒有虚名，名气很大实际上啥也没有，表演也都放到白天了。</p><p>这么个小演出人挤的里三层外三层：</p><video controls width="40%" preload="metadata">  <source src="48.mp4" type="video/mp4"></video><p>人好多：</p><img src="49.png" width="40%"><p>偷拍到两个小姐姐的背影，衣服挺好看：</p><img src="50.png" width="40%"><p>天终于黑了，以为晚上灯光会好看一点，结果啥也没有，和唐山差远了，纯粹的商业街，两边都是卖小吃的：</p><img src="51.png" width="40%"><p>通向出口的单向通道上：</p><video controls width="40%" preload="metadata">  <source src="52.mp4" type="video/mp4"></video><p>最好看的大雁塔照片是在北广场拍的，已经出了大唐不夜城，就是表演音乐喷泉那里：</p><img src="53.png" width="40%"><h4 id="大唐芙蓉园"><a href="#大唐芙蓉园" class="headerlink" title="大唐芙蓉园"></a>大唐芙蓉园</h4><p>大唐芙蓉园是西安最值得去的地方，体验比不夜城好很多，里面有很多大大小小的表演，追着节目的演出节奏跑，能让人一整天都有事干不闲着。</p><p>观看顺序上，一进门就可以看到迎宾演出，接着跟着巡游队伍走：</p><video controls width="40%" preload="metadata">  <source src="54.mp4" type="video/mp4"></video><p>巡游队伍会一路走到紫云楼北广场，然后开始一场梦回大唐的表演：</p><img src="54.png" width="60%"><p>演出结束紧接着是音乐喷泉的表演：</p><video controls width="60%" preload="metadata">  <source src="55.mp4" type="video/mp4"></video><p>这一系列小演出就接近 1 个小时时间，让你入园后的 1 个小时都没闲着，这个时候芙蓉园还一点都没逛呢。</p><p>还是在北广场这里，如果时间合适的话，恰好能看到锦绣中华演出，性质上属于汇演，也就是能演的都演，时长 1 个小时，有喷泉、舞蹈和舞狮：</p><video controls width="60%" preload="metadata">  <source src="56.mp4" type="video/mp4"></video><p>结束后，还能在其他地点看到一些小表演，比如这个音乐：</p><video controls width="40%" preload="metadata">  <source src="57.mp4" type="video/mp4"></video><p>关于茶神的故事：</p><video controls width="40%" preload="metadata">  <source src="58.mp4" type="video/mp4"></video><p>长安码头上小姐姐跳舞：</p><video controls width="40%" preload="metadata">  <source src="59.mp4" type="video/mp4"></video><p>仕女馆里，非常美丽的不倒翁，这不比不夜城里的好看多了：</p><video controls width="40%" preload="metadata">  <source src="60.mp4" type="video/mp4"></video><p>不倒翁之后有个李白的对诗表演：</p><video controls width="40%" preload="metadata">  <source src="61.mp4" type="video/mp4"></video><p>后面仕女馆舞台还有个叫曲江花月宴的表演，我没时间看了，因为要赶着去看最终的大表演大唐追梦。</p><p>大唐追梦要坐在船上，船会把观众拉到湖中间，紫云楼对面，然后开始演出。</p><p>这个视频可以感受到整体的场景：</p><video controls width="60%" preload="metadata">  <source src="62.mp4" type="video/mp4"></video><p>过程中有 3D 水影的动画：</p><video controls width="40%" preload="metadata">  <source src="63.mp4" type="video/mp4"></video><p>楼梯上是有人跳舞的：</p><video controls width="40%" preload="metadata">  <source src="64.mp4" type="video/mp4"></video><p>快到结尾处的一个片段：</p><video controls width="40%" preload="metadata">  <source src="65.mp4" type="video/mp4"></video><p>整体非常精彩！这样的表演才是真正的大唐风范！</p><h4 id="鼓楼、永兴坊"><a href="#鼓楼、永兴坊" class="headerlink" title="鼓楼、永兴坊"></a>鼓楼、永兴坊</h4><p>西安的旅程还没有结束，先去了名气很大的赛格，但是感觉没啥逛的，两层女装、一层男装、一层运动装、一层珠宝，让人逛啥，还不如朝阳大悦城好逛。</p><img src="66.png" width="40%"><p>然后准备去高家大院，门口看了一眼就知道进不去了：</p><img src="67.png" width="40%"><p>原来高家大院和鼓楼在一条街上，就顺着人流往鼓楼方向走，有一种鼓楼大街的感觉：</p><img src="68.png" width="40%"><p>鼓楼也就长这样，没兴趣上楼了。</p><img src="69.png" width="40%"><p>出鼓楼的路上有点累，随便找了家皮影看，顺便休息，表演还可以，三打白骨精，像是低配动画片：</p><img src="70.png" width="60%"><img src="71.png" width="40%"><p>鼓楼出来就去了永兴坊：</p><img src="72.png" width="40%"><p>永兴坊里有个网红摔碗酒：</p><video controls width="40%" preload="metadata">  <source src="73.mp4" type="video/mp4"></video><p>虽然也是商业街但还挺热闹的一个地方，还有木偶戏表演：</p><video controls width="40%" preload="metadata">  <source src="74.mp4" type="video/mp4"></video><p>抖音上很火的铜人可以一起合影：</p><img src="75.png" width="40%"><p>到了晚上配上灯笼的灯光更有气氛一点：</p><img src="76.png" width="40%"><p>永兴坊门口就是西安城墙，不过不想上去。</p><p>到这里西安的行程就结束了。</p><h4 id="其他城市"><a href="#其他城市" class="headerlink" title="其他城市"></a>其他城市</h4><p>本来是规划了很多地方的，计划在回北京的路上顺便就去了，包括洛阳的老君山、开封的清明上河园、济南的大明湖等，最终没去成，这两天酒店普遍溢价，看演出也有种 “五岳归来不看山” 的感觉，看过唐山和西安的演出后，不太想看别的了。</p><img src="77.png" width="40%"><h3 id="结束"><a href="#结束" class="headerlink" title="结束"></a>结束</h3><p>最后很喜欢李白在船上吟诗这一段：</p><video controls width="40%" preload="metadata">  <source src="78.mp4" type="video/mp4"></video><p>天生我材必有用，千金散尽还复来！</p>]]></content>
  </entry>
  <entry>
    <title>关于工作的反思和规划</title>
    <link href="https://b.smallyu.net/2024/10/04/%E5%85%B3%E4%BA%8E%E5%B7%A5%E4%BD%9C%E7%9A%84%E5%8F%8D%E6%80%9D%E5%92%8C%E8%A7%84%E5%88%92/"/>
    <id>blog-b:https://b.smallyu.net/2024/10/04/%E5%85%B3%E4%BA%8E%E5%B7%A5%E4%BD%9C%E7%9A%84%E5%8F%8D%E6%80%9D%E5%92%8C%E8%A7%84%E5%88%92/</id>
    <published>2024-10-04T07:55:48.000Z</published>
    <updated>2025-12-03T10:02:00.862Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>之前啰嗦说了一堆辞职的原因，经过这两天的沉淀和思考，我想可以更简洁的描述辞职原因以及职业方面的规划。换句话说，想清楚了自己为什么辞职以及到底想要什么。</p>
<p>上一份工作让我处于对技术能力的焦虑中，需要时刻担心技术能力是不是有退步、技术能力的增长能不能跟得上年龄的增长]]></summary>
    <content type="html"><![CDATA[<p>之前啰嗦说了一堆辞职的原因，经过这两天的沉淀和思考，我想可以更简洁的描述辞职原因以及职业方面的规划。换句话说，想清楚了自己为什么辞职以及到底想要什么。</p><p>上一份工作让我处于对技术能力的焦虑中，需要时刻担心技术能力是不是有退步、技术能力的增长能不能跟得上年龄的增长、假如离开这家公司后还能不能找到工作等。</p><p>那份工作能让人挣钱，但是不能让人安心，所以接下来我想找能让人安心的工作。</p><p>比起现在有没有工作，我更担心以后能不能找到工作，现在挣多少钱只是一时的，我还是希望自己能在技术的道路上走的更远一点，希望能在技术方面有持续的积累。</p><p>接下来我找工作的理想类型优先级从高到低是：</p><ol><li>区块链开发，指链本身的开发，哪条链都可以</li><li>纯 web3 项目，比如 SocialFi、GameFi 之类</li><li>区块链相关的后端开发，如果我能胜任的话</li></ol><p>找到这几种类型工作的难度也是从高到低的，区块链开发职位数量最少、要求最高，区块链相关的后端开发则职位数量多一点，各种交易所都是。</p><p>结合这两年找工作面试的经历来看，面试官大多数是传统的后端开发出身，从提问的问题能看出来。真正能提出区块链方面技术问题的屈指可数。为什么会存在这样的现象？</p><p>我盲目猜测，做区块链开发的人都还没当上面试官，或者说，坐在面试官位置上的人大概率是因为历史原因或其他原因。区块链行业还没有培养出一批人，就已经在熊市的时候淘汰掉很多人了。</p><p>（到目前为止我遇到过最有水平的问题，就是 “PBFT为什么需要第二次投票？” 这个问题去年被问到过两三次，有趣的是，提问问题的这几个面试官，对这个问题的答案是不一样的。后来我意识到这是一个复杂且充满争议、没那么肤浅的问题，还写过《<a href="/2024/06/03/%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%AD%E7%9A%84PBFT%E4%B8%8D%E9%9C%80%E8%A6%81%E7%AC%AC%E4%BA%8C%E6%AC%A1%E6%8A%95%E7%A5%A8/">区块链中的 PBFT 不需要第二次投票</a>》来描述我对这个问题的理解）</p><p>关于职业方向，我是迷茫的，其实任何人都应该迷茫。区块链到现在总共十来年，从2017年山寨币大爆发到现在更是只有五六年的时间，还不足以让一个行业形成完整的职业体系。</p><p>技术方面该学什么？该往什么方向深入？完全没有答案，没有先例，谁也说不准接下来的趋势。</p><p>尤其是 web3 公司的变化速度快，技术创新快、公司变动快，牛市会产生一些新叙事，然后又很大一批公司抗不过熊市，不稳定是 web3 公司本应该的基调。</p><p>在这样的情况下，对于没有背景的打工人，能依靠的只有自己的技术能力，所以要持续提高自己的技术能力。至于往哪个方向提升是另一个问题。至少不可能依赖于公司。</p><p>那么如果我接下来找不到工作怎么办？</p><p>假如经过了足够长的几个月时间，我确信整个北京以及全世界的远程工作，没有任何一家公司的工作，我能够胜任，可能就需要进入另一种模式。</p><p>我需要重新审视和思考自身的技术能力，以及重新了解和学习整个区块链行业的现状，根据市场情况来调整自己的认知以及预期，调整自己在职业方向上的期望，需要什么我就学什么，能做什么我就做什么。</p><p>这是一段有趣的旅程，虽然过程中充满痛苦，如果赢了，自己会变得更强大，如果输了，就看会输到什么程度。</p>]]></content>
  </entry>
  <entry>
    <title>想起来前前公司的老板说，“EOS 为什么没 ETH 发展的好？因为 EOS 的代码是用 C 语言写的，代码写的太好了，社...</title>
    <link href="https://t.smallyu.net/#2024-55"/>
    <id>micro:2377575649</id>
    <published>2024-09-26T17:45:17Z</published>
    <updated>2024-09-26T17:45:17Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想起来前前公司的老板说，“EOS 为什么没 ETH 发展的好？因为 EOS 的代码是用 C 语言写的，代码写的太好了，社区没办法参与。而 ETH 的代码写的不好，社区参与度高，所以很火。” 这句话都不知道从哪儿开始吐槽合适。EOS 的天使投资人是李笑来，直到有一天李笑来卖掉了自己所有的 EOS… 为什么总有人觉得项目是...</p>]]></summary>
    <content type="html"><![CDATA[<p>想起来前前公司的老板说，“EOS 为什么没 ETH 发展的好？因为 EOS 的代码是用 C 语言写的，代码写的太好了，社区没办法参与。而 ETH 的代码写的不好，社区参与度高，所以很火。”</p>
<p>这句话都不知道从哪儿开始吐槽合适。EOS 的天使投资人是李笑来，直到有一天李笑来卖掉了自己所有的 EOS…</p>
<p>为什么总有人觉得项目是否成功取决于代码写的好不好？方向是对的，怎么做都是对的，方向是错的，怎么做都是错的。</p>
]]></content>
  </entry>
  <entry>
    <title>一份工作只要能满足以下任意一个要素，就算是难得的好工作了： 有趣 有用 有积累</title>
    <link href="https://t.smallyu.net/#2024-54"/>
    <id>micro:2365005951</id>
    <published>2024-09-21T05:14:45Z</published>
    <updated>2024-09-21T05:14:45Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>一份工作只要能满足以下任意一个要素，就算是难得的好工作了： 有趣 有用 有积累</p>]]></summary>
    <content type="html"><![CDATA[<p>一份工作只要能满足以下任意一个要素，就算是难得的好工作了：</p>
<ul>
<li>有趣</li>
<li>有用</li>
<li>有积累</li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>如果学好 “编程语言的语法” 就可以挣到很多钱，那每一个刚毕业的大学生都可以挣很多钱。 如果做好 “高考题” 就可以挣到...</title>
    <link href="https://t.smallyu.net/#2024-53"/>
    <id>micro:2358865209</id>
    <published>2024-09-18T16:02:42Z</published>
    <updated>2024-09-18T16:03:12Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果学好 “编程语言的语法” 就可以挣到很多钱，那每一个刚毕业的大学生都可以挣很多钱。 如果做好 “高考题” 就可以挣到很多钱，那每一个参加高考的考生都可以挣到很多钱——然而我们都懂的，高考一旦结束，那些高考题我们就再也做不出来了。</p>]]></summary>
    <content type="html"><![CDATA[<p>如果学好 “编程语言的语法” 就可以挣到很多钱，那每一个刚毕业的大学生都可以挣很多钱。</p>
<p>如果做好 “高考题” 就可以挣到很多钱，那每一个参加高考的考生都可以挣到很多钱——然而我们都懂的，高考一旦结束，那些高考题我们就再也做不出来了。</p>
]]></content>
  </entry>
  <entry>
    <title>想到一个类比。前段时间的面试中，我被问到过一个问题： “如果让你设计一个消息队列，你会考虑哪些方面？” 这是一个 web...</title>
    <link href="https://t.smallyu.net/#2024-52"/>
    <id>micro:2358127226</id>
    <published>2024-09-18T10:41:31Z</published>
    <updated>2024-09-18T15:56:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想到一个类比。前段时间的面试中，我被问到过一个问题： “如果让你设计一个消息队列，你会考虑哪些方面？” 这是一个 web2 风格浓重的问题，我从来没有思考过这个问题，自然也说不出什么。 做一个类比，在 web3 的技术领域，这个问题应该怎么问？ 如果让你设计一条区块链，你会考虑哪些方面？ 事实上不太会有工作需求去真的设...</p>]]></summary>
    <content type="html"><![CDATA[<p>想到一个类比。前段时间的面试中，我被问到过一个问题：</p>
<blockquote>
<p>“如果让你设计一个消息队列，你会考虑哪些方面？”</p>
</blockquote>
<p>这是一个 web2 风格浓重的问题，我从来没有思考过这个问题，自然也说不出什么。<br>做一个类比，在 web3 的技术领域，这个问题应该怎么问？</p>
<blockquote>
<p>如果让你设计一条区块链，你会考虑哪些方面？</p>
</blockquote>
<p>事实上不太会有工作需求去真的设计一个消息队列，但是 web2 的技术会喜欢往这方面考虑。<br>同样的道理，我知道现实中几乎没有可能让我去设计一条区块链，但如果被问到这个问题，我真的有很多话可说。</p>
]]></content>
  </entry>
  <entry>
    <title>裸辞的真相</title>
    <link href="https://b.smallyu.net/2024/09/16/%E8%A3%B8%E8%BE%9E%E7%9A%84%E7%9C%9F%E7%9B%B8/"/>
    <id>blog-b:https://b.smallyu.net/2024/09/16/%E8%A3%B8%E8%BE%9E%E7%9A%84%E7%9C%9F%E7%9B%B8/</id>
    <published>2024-09-16T02:16:23.000Z</published>
    <updated>2025-12-03T10:02:00.871Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>没忍住发出来了，哈哈，不吐不快，不好意思。</p>
<p>正好前几天有同事在公司群里说，“我们是一群热爱游戏的传统游戏开发者，区块链跟我们没关系”（他说的话跟我工作一年以来对公司的感受相符）。这样气质组合起来的一家公司，怎么可能搞得好 web3]]></summary>
    <content type="html"><![CDATA[<blockquote><p>没忍住发出来了，哈哈，不吐不快，不好意思。</p><p>正好前几天有同事在公司群里说，“我们是一群热爱游戏的传统游戏开发者，区块链跟我们没关系”（他说的话跟我工作一年以来对公司的感受相符）。这样气质组合起来的一家公司，怎么可能搞得好 web3 呢？</p><p>而新来公司两个星期的同事，也已经意识到了某些问题……</p></blockquote><p>这些内容不方便写到博客里去，《<a href="/2024/07/28/%E8%A3%B8%E8%BE%9E%E4%BA%86/">裸辞了</a>》中提到的内容都是比较空洞、表面的。而真正裸辞的原因涉及到太具体的人和事，只有当这些人和事成为“过去”的时候，我才能把内容发布出来。</p><p>如果这些内容过早发出来，我觉得会带来的影响是：</p><ul><li>被我的上级看到，对我有意见，假如我后续工作需要背调之类可能会造成影响</li><li>被招聘公司看到，对我产生意见，觉得我工作上意见多棱角多不方便管理，或者觉得我做事不地道，有意见离职后还写出来，从而不给我面试机会、不聘用我</li><li>因为带着情绪在回忆这些“往事”，也许难免会用词过重、情绪过重等</li><li>也许会提到太过具体的工作内容，而我需要把工作身份和真实身份区分开</li></ul><p>所以我现在先写到私有的 notes 里，也许一年后等所有事情过去，再发到博客上。这篇文章的内容完成于 2024年09月03日。至于什么时候会 publish 出来，我也不知道。</p><p>总体来说，裸辞是因为我和上级之间存在一些意见上的不和，这些不和并没有体现在表面上，没有发生语言或者其他任何形式的冲突，仅仅是在埋藏在我心里，所以我积怨已久，直到某一天选择裸辞——这也是我能想到的最体面的退场方式了。</p><p>既然我说长时间忍受了一些痛苦的工作，那这些具体的工作是指什么，引发裸辞的最后一根稻草又是什么？</p><h3 id="“你看看吧”-（一）"><a href="#“你看看吧”-（一）" class="headerlink" title="“你看看吧” （一）"></a>“你看看吧” （一）</h3><p>“你看看吧”这句话令人印象深刻，也是这句话引发了辞职的念头。这话发生在什么场景呢？</p><ul><li>他：某某软件出现了一个问题，存在预期之外的行为。</li><li>我：出现这个问题的原因是……带来的影响是……解决这个问题的办法是……</li><li>他：你看看吧。</li></ul><p>我的内心OS：我看什么？我已经把问题的前因后果以及解决方法说出来了，我看什么？我再看 10 分钟也不会改变想法，再看 10 天也不会改变想法，我看什么？我已经把能说的都说了啊？</p><p>举个更浅显一点的例子：</p><ul><li>他：1 加 1 等于几？</li><li>我：等于 2.</li><li>他：你看看吧。1 加 1 到底等于几，需要确定下来。</li></ul><p>我看什么？1 加 1 不等于 2 吗？你有其他答案吗？如果不是 2，你就告诉我我说的是错误的。如果等于 2，你就告诉我我说的是正确的。我再看 100 年我的视角里 1 加 1 也是等于 2，我看什么？我已经回答了问题并且把我的结论确定下来了，我看什么？</p><p>我经历了很多次 “你看看吧” 的场景，每一次都感觉特别无语，我总是觉得 “我不知道你在说什么” 。</p><h3 id="“你看看吧”-（二）"><a href="#“你看看吧”-（二）" class="headerlink" title="“你看看吧” （二）"></a>“你看看吧” （二）</h3><p>“你看看吧” 的另一个含义是，我觉得我在浪费时间不知道看什么。</p><p>具体事情是网络上需要部署一个 USDC 合约，关键是这个合约的 owner 权限、admin 权限、各种权限最终都不可能是我控制。在我看来就只是部署一个合约的事情，然后反复的 “让我看看”。我看什么？这个合约最终一定是他来操作，具体调用某个函数来进行一些操作，那我看什么？我看着玩？我看完了以后讲一遍？关键是他不会单纯相信我说的，为什么不自己看？</p><h3 id="软件的-Benchmark-（一）"><a href="#软件的-Benchmark-（一）" class="headerlink" title="软件的 Benchmark （一）"></a>软件的 Benchmark （一）</h3><p>压垮骆驼的倒数第二根稻草，是一个做测试软件性能数据的工作。这件工作我甚至没有写到简历上，因为我感觉确实没做什么，不值得写。</p><p>网络用了 5 种以太坊的客户端，这项工作的内容，是测试这 5 种客户端执行 EVM 指令的速度，通过统计每秒钟的 Gas 消耗量来进行对比。到这里其实还没什么问题，关心 EVM 性能明明是一件有意义的事情。</p><p>但让我不能理解的是，进行这项工作的本意并不是关心 EVM 的性能，而是想到深入到具体的 function 上，定位到某个客户端的某一个功能模块的某一个函数，对比在语言层面写法上带来的性能差异，调用了多少 CPU 或者占用了多少内存，甚至用了哪种架构的指令集这种。对于他来说，物理机器方面的性能指标是非常重要的。</p><p>那么我为什么会对此表示不能理解呢？因为关注太过底层方面的性能，和区块链就完全无关了。任何一个软件，任何用 Go 语言或者 Java 或者什么语言写的软件，都可以有 Benchmark 来测试某些方面的性能，都可以来对比什么 CPU、内存、磁盘的占用情况，都可以进行指令层面的优化。但是这一切，都和区块链无关。</p><p>那什么性能指标和区块链有关？我举几个例子：</p><ul><li>TPS，这是房间里的大象，都看得到，都不去优化，因为难</li><li>接受交易的速度、交易池的容量和性能</li><li>打包块的速度、效率、延迟（从交易池取交易）</li><li>共识层投票的速度、效率、延迟（如果共识有投票环节）</li><li>网络软分叉后恢复正常的速率</li><li>轻节点、客户端同步块的效率</li><li>验证交易余额的速度和性能（SPV 方向）</li><li>等等</li></ul><p>在我看来，有许许多多区块链领域、区块链行业方向的性能问题可以去关心，而上级选择了一个和区块链完全无关的方向，并且接下来一段时间，可能是几个月、甚至一年的工作，都会围绕这个和区块链无关的 Benchmark 展开，让我觉得实在无法忍受，我没法再继续作为他的下属来给他完成这些工作了。</p><p>而作出这个选择背后的原因，我说的稍微过分一点，是他其实不懂区块链开发。整家公司是一家游戏公司，他本人也是做游戏开发出身，根本不具备区块链方面的技术基础，也不会从区块链开发的角度去思考问题、从而决定下一步的工作内容。</p><p>如果一个人非常懂区块链，在许许多多事情中挑了一件和区块链无关的工作，我是非常接受的，因为这么选择一定有更深层的原因。而如果一个人不太懂区块链，就选择了一件和区块链无关的事情，因为在这方面自己比较擅长、工作内容和工作成果可控，这种模式我是有点难以接受的。</p><p>其实从加密货币用户的交易，关心的问题就两个：手续费能不能更低？交易速度能不能更快？</p><p>现在的区块链根本没有成熟到体系已经完整、去拼谁少占用了 2GB 内存的阶段。如果一条链具有各方面优势而仅仅只是对硬件性能稍微高，不会有人否认这条链。如果一条链不行，哪怕用再低的硬件资源，又能吸引多少开发者和用户呢。</p><h3 id="软件的-Benchmark-（二）"><a href="#软件的-Benchmark-（二）" class="headerlink" title="软件的 Benchmark （二）"></a>软件的 Benchmark （二）</h3><p>面对上述这种情况，我有没有提出过自己的想法呢，我为什么选择辞职，而不是和上级好好沟通，说服对方并且进行一些我提到的方向上的工作呢？如果我无法说服别人，是否证明我是错的？</p><p>首先我有可能是错的。其次不知道大家有没有一种感觉，就是很难让一个不懂的人明白你懂，并且相信你。再深入一点，想让一个不太懂的人能够站在懂的角度思考问题，是不太可能的事情。</p><p>在日常的工作中，我已经很多次感受到两点：1.他的思路和我不一样；2.他不相信我。所以我后期没有太多尝试去改变什么。</p><p>举例来说，比如我提到过在网络中提高 ENS 的使用。其实公司有很好的用户基础，都是游戏玩家，把 ENS 用上我觉得是挺有意思的一件事情，比如把游戏身份和 ENS 绑定起来。Vitalik 曾经说 ENS 是以太坊上非金融领域最成功的 DAPP，前段时间 Base 网络也正是推出了由官方运行的 ENS 服务。很多钱包里也可以看到，现在凡是搞链的都会搞一搞 ENS，大家都在搞。那么我上级的说法是什么呢，“即使是 web2 领域，需要域名的也只是少数”，因此这件事情是没有任何后续的。</p><p>再举个例子就是我提到过更多的使用 DAO，同样是因为有那么好的用户基础，一批真实的游戏玩家，DAO 简直太合适了，其他链想用都没地方用。ATOM 在钱包里直接集成了根据 ATOM 持有量来对提案投票的能力，Cardano 两天前完成的 Chang 大版本升级最大的宣传点，就是“链上治理”（我没了解这个词的含义）。总之 DAO 是一个挺有意思的东西，但是这个方向在上级眼里仍然是不值得被关注的方向。</p><p>再比如，我提到可以在 Benchmark 中增加对共识层投票效率方面的数据，他的说法是，“咱们也不关心这个啊”。（从这里就可见工作内容的出发点是他本人的兴趣，而不是公司或者行业或者某些外部需要，也不是什么技术方面的逻辑。当然人家是老板&#x2F;CTO&#x2F;Cofounder，想做什么事情还不是人家说了算吗）</p><p>以及其他一些事情，总之因为经历过许多次，所以后期并不期望他会接受我的提议，去做某些方向的工作，而是我直接选择了辞职。</p><h3 id="软件的-Benchmark-（三）"><a href="#软件的-Benchmark-（三）" class="headerlink" title="软件的 Benchmark （三）"></a>软件的 Benchmark （三）</h3><p>还有一个事情是关于网络的 Solo Staker。网络使用了以太坊的客户端，所有机制和以太坊一样，也就有 Solo Staker 的问题。他采用的方式是，将网络原生的质押收益率翻倍，原先是 12% 的收益率，有额外奖励后变成了 24%，以此来鼓励更多的人加入到 Solo Staker 的行列，让网络变得更加去中心化。</p><p>在质押刚上线的时候，社区里有人质疑为什么收益率才 15%（刚上线的时候）这么点，当时他的态度是，这个收益率已经很高了，不能和那些人一般见识。</p><p>我也提到过要不要举行一种一次性奖励形式的活动，比如成功成为质押者就奖励一点钱那种，单靠收益率是不可能吸引到人的，举办一场活动也许还能有一些留存的用户，至少让大家能玩起来。当然结果就是，只要不是他自己提出的想法，就是没有后续的。</p><p>24% 的收益率高吗？中规中矩吧。Polkdot 在钱包里直接质押的收益率是 17%，Cosmos 在钱包里直接质押的收益率是 15%。这是在完全不需要额外技能以及硬件服务器资源的情况下，加上钱包已经抽取手续费之后的数值。其他乱七八糟的高收益率小币种就不用提了。而且 DOT 和 ATOM 的价格一定比小币种的价格稳的多，作为一个想赚点利息的 crypto 用户，我会选择哪种方式来进行质押呢？</p><p>这个问题本身不重要，重要的是说明他本人不是 crypto 用户，我盲目猜测，他没有炒币方面的经验。如果和传统金融行业的利息率相比，15% 的收益绝对很高，但这是 crypto 行业，比特币都能一天涨跌 10%，何况是小币种呢。在这样的前提下，一个不是 web3 用户的人，是无法成为 web3 行业好的 builder 的。这个道理就类似于，有人吐槽很多链游公司不可能做出好游戏，因为那些人不喜欢玩游戏，也不懂做游戏，怎么可能做得出好游戏呢？同样的道理，不是 web3 行业的玩家，又怎么能构建出更好的 web3 世界呢？</p><h3 id="信任问题（一）"><a href="#信任问题（一）" class="headerlink" title="信任问题（一）"></a>信任问题（一）</h3><p>在具体的工作方面，也存在一个长期让人不爽的地方，就是当工作遇到问题的时候，他会优先怀疑你而不是怀疑软件。</p><p>比如，当使用某个软件的时候，我说这个软件用参数 a 会运行异常，所以建议暂时不要用参数 a。当我把这个问题告诉他后，他的第一反应不是接受 “暂时不要用参数 a” 这个建议，而是首先怀疑 “是吗？你是怎么操作的？具体日志是什么？”</p><p>还有的时候我说这里有问题那里有问题，他会直接说 “不可能，那么大一个软件，肯定是你的使用方法有问题”。</p><p>我好奇的一点是，抛开开发者的身份，我哪怕作为一个普通的用户，去使用一个开源软件，我按照软件的文档操作然后遇到了问题，那是我的问题吗？对于用户有可能遇到的异常，软件本身应该发出提醒，对于用户有可能的配置错误，软件应该作出容错的处理。如果是软件本身的逻辑问题，那就更和我无关了。</p><p>然后经常出现的情况是，我说通过 a-&gt;b-&gt;c-&gt;d 四个操作步骤后，我提议 a 方案解决或 b 方案解决。这个场景下问题就来了，因为他会优先怀疑我而不是怀疑软件，要么他自己亲自操作一遍所有步骤，遇到了相同的问题，要么我把所有步骤操作的详细过程截图给他看，把整个运作流程说清楚，再结合他自己查一堆资料，他才会相信确实会出现问题，然后开始讨论怎么解决。而我从一开始就提出了解决方案。</p><p>这样的模式下，解决问题需要花费成倍的时间和精力，简单来说就是我了解一遍然后他了解一遍，时间是两倍，而且在他了解的过程中我还需要陪同作出一些解释，详细描述我的操作和对问题的理解。而这些冗余的过程，对于解决问题几乎没有帮助，解决的只是让他相信 “软件确实存在问题” 这个问题。</p><p>所以到后来我就明白了，我自己得出的结论他是不会信的，我到后面直接就放弃思考、放弃得出结论了。我也学会了，如果他需要让我做什么事情，我会从一开始就保留操作记录，有问题直接丢截图、找到具体的代码位置给他，把能找到的周边资料都发给他，而不是自己的出结论，更不会自己去浪费脑力思考解决方案。既然最终解决问题的前提是需要他完全理解整个问题，那为什么不从一开始就由他自己来发现问题呢？（也可能是我这种做法的缘故，他才开始说 “你看看吧”）</p><p>而这种不信任的做事模式，还会给我带来两个副作用：1.做事没有成就感；2.没有责任方面的负担。既然他事必躬亲，事实上所有大大小小的决定都是他作出的，那么我其实没有选择的余地。没有成就感是一方面，另一方面是我不需要这方面的责任心，不是我做的决定就不需要我承担责任，后续产生问题也和我无关了。但是，但是，不需要承担责任难道不是好事吗？问题在于，他会要求你明白事情的前因后果、了解事情有可能出现的问题、希望你以责任人的身份去思考问题，而并不会给你真正承担责任的机会。（这也就引起了我最近在吐槽工作的时候老说 “关我啥事？”）</p><p>所以在信任方面，我始终是感受到存在很大问题的。他可能会说信任你，但是这种信任在我看来，是对 “我会认真工作” 的信任，而不是对 “我的技术决策是正确的” 的信任。</p><p>提到信任，我想起在我提离职后，他也发出过试图解决问题、挽留人的态度，说挺相信我、认可我之类。在我看来，这种相信和认可都是对于 “我会负责任工作”、“我会勤奋工作”、“我会加班工作” 这些方面，并不是相信和认可 “我的技术理念”、“对某些问题的理解”、“面对问题会作出的决策” 等。所以这种信任和认可算是好事吗，也许算吧。</p><p>打个比方来说，我家里养了一头牛（我还真是属牛），这头牛勤勤恳恳干活，从来没有过抱怨。我对这头牛说，我很欣赏你，相信你会认真完成好你的工作，希望你能一直给我干活。这种认可牛听了会开心吗？简直是骂人好吧，奴隶当惯了？牛也许会想，凭什么我不是人？如果牛发明了一种耕地的机器，不但工作的效率增加了，牛自己还变得轻松了，这个时候我去夸奖我的牛，牛才会真的开心吧。</p><h3 id="信任问题（二）"><a href="#信任问题（二）" class="headerlink" title="信任问题（二）"></a>信任问题（二）</h3><p>信任问题和 “你看看吧” 相结合的场景，比较典型的问题是，当一个方案不可行，我怎么证明这个方案不可行？</p><ul><li>他：这个问题如果改一改 x 部分的数据也许可以。</li><li>我：x 部分的数据不能改。</li><li>他：你看看吧。</li></ul><p>家人们谁懂啊，你们理解这种奔溃吗，一种做法不可行，我怎么证明这种做法不可行？如果一种做法可行，我把它做出来了，我就证明这件事情完成了。如果一种做法不可行，那要我怎么证明？我应该作出什么样的行为，才能证明方案不可行这一点？不可行我看什么？</p><h3 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h3><p>我想说的都在这里了。希望不会给我带来不良的影响。带来了也没办法。我还是会说出我想说的话。</p><p>虽然我表达了种种对公司和上级的不满，但我本身并没有敌意，其实我还是希望上级能够招到称心如意、志同道合的员工，来继续发展项目和网络，只不过那个人不是我。</p><h3 id="补充（2024-09-08）"><a href="#补充（2024-09-08）" class="headerlink" title="补充（2024.09.08）"></a>补充（2024.09.08）</h3><p>关于裸辞的的时间，在我来看也是比较突然的，背后的大概逻辑是，提出辞职的时间点差不多是我入职刚满一周年的时间。</p><p>相信公司从我入职起就对我抱以某种方面的信任——否则公司不会让我入职的，那么我也用至少一年的工作时间来完成了对公司信任的回报，至于是否值得就看公司怎么想了。我想我已经做了所有能做的事情，而接下来公司几乎没有我能做的事情了，辞职是我唯一的选择。</p><p>其实说再多裸辞的原因，把各种理由一一列举出来，也无非是找足理由去支撑自己选择裸辞的这一决定，而这个决定是对是错，我自己也没底。要离职没太大悬念，形式上是不是裸辞也无关紧要，主要没底的还是自己对公司前景（web3 方向）的判断。</p>]]></content>
  </entry>
  <entry>
    <title>为什么不要做以太坊的二次开发</title>
    <link href="https://smallyu.net/2024/09/12/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E5%81%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%9A%84%E4%BA%8C%E6%AC%A1%E5%BC%80%E5%8F%91/"/>
    <id>blog:https://smallyu.net/2024/09/12/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E5%81%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%9A%84%E4%BA%8C%E6%AC%A1%E5%BC%80%E5%8F%91/</id>
    <published>2024-09-12T07:29:05.000Z</published>
    <updated>2025-11-09T09:22:13.309Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>道理很简单，以太坊是有核心开发团队的，以太坊基金会为中心，各个以太坊客户端的开发团队，都拿了以太坊基金会的钱给以太坊做开发。Vitalik 来中国融资，拿完钱到某个国家组建开发团队，密集开发一年后有了以太坊。当年以太坊基金会以不到 $1 的价格参与以太坊的 ICO，现在]]></summary>
    <content type="html"><![CDATA[<p>道理很简单，以太坊是有核心开发团队的，以太坊基金会为中心，各个以太坊客户端的开发团队，都拿了以太坊基金会的钱给以太坊做开发。Vitalik 来中国融资，拿完钱到某个国家组建开发团队，密集开发一年后有了以太坊。当年以太坊基金会以不到 $1 的价格参与以太坊的 ICO，现在 ETH 的价格已经涨了几千倍，以太坊基金会的钱就是这么来的。</p><p>以太坊生态主要有三个部分，Layer 1、Layer 2 以及生态类项目。（Staking 类不需要你开发，Restaking 和技术有关系？）</p><p>Layer 1 部分，有几大客户端团队，执行层的 Geth、Nethermind、Besu、Erigon、Reth，共识层的 Prysm、Lighthouse、Teku、Nimbus、Lodestar，先不管这些团队和以太坊的利益关系如何，如果你自己或者你所在的公司，说是想要基于以太坊的客户端做二次开发，那么请问，要开发什么？</p><p>如果是对以太坊网络本身有益的改进，能够提高性能、优化数据结构之类，你大可以直接给以太坊提交 Issue 以及 PR，甚至建立合作关系，直接让以太坊客户端的官方版本来支持你的优化。何况这些客户端的创始团队仍然处于活跃的开发状态，你觉得自己有理由可以比他们 “自己人” 做的更出色吗？无论是客户端功能方面还是性能方面，无论你是个人还是公司的力量。</p><p>例如并行 EVM，试图提高 EVM 交易的执行速度，这是 Geth 团队都没能解决的难题，随便一个小团队能做得成？</p><p>如果是对以太坊无益而对自己链有益的改进，你预期以太坊的开发团队不会接受你的提议和改进，那这个问题就更加奇特，你的链是有多么特殊的需求，需要做这些必须 “自有” 的开发？以太坊的完成度已经比较高了，如果遇到这样的场景，似乎需要回到一开始的需求来评估整件事情。</p><p>Layer 2 的部分，比较大的团队有 Polygon、Optimism、Zksync 等。以太坊的 Layer 2 为什么能做大做强能火？Layer 2 是 Vitalik 认可的方向。ENS 项目为什么能广泛普及？ENS 是 Vitalik 认可的项目。AA 钱包为什么热闹了一段时间？Vitalik 喊灵魂绑定带起来的。你可以从 Vitalik 的博客中看到，凡是目前比较大的生态类项目，都和 Vitalik 本人有直接的联系，这些项目的创始人都是可以和 Vitalik 说上话的。</p><p>Vitalik 是整个以太坊生态背后的大 Boss，那么假如你说你想搞一个以太坊生态的项目，是优先考虑技术能力方面的问题吗？一个项目能不能成，先看什么？先看以太坊的 Roadmap 有没有这个方向，再看以太坊生态里这个方向的头部项目是哪个，然后呢？你会发现跟你没什么关系。以太坊基金会又没有给你钱，你凑什么热闹？</p><p>站在开发者的角度，假如你想参与以太坊的生态建设，那么请问，要以太坊的核心团队干什么？如果你想改进 Op Stack 的 Fault Proofs，那么请问，要 Optimism 的核心团队干什么？你作为一个局外人，花费时间和资源去给别人抬轿子？</p>]]></content>
  </entry>
  <entry>
    <title>为什么不要做智能合约开发和 DeFi 开发</title>
    <link href="https://smallyu.net/2024/09/11/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E5%81%9A%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%92%8CDeFi%E5%BC%80%E5%8F%91/"/>
    <id>blog:https://smallyu.net/2024/09/11/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E8%A6%81%E5%81%9A%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91%E5%92%8CDeFi%E5%BC%80%E5%8F%91/</id>
    <published>2024-09-11T12:51:35.000Z</published>
    <updated>2026-08-04T11:43:16.383Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>目前市场上的招聘，“合约开发”一般指“以太坊上的EVM合约开发”。而事实上，世界上不只有以太坊一条链，可能有上百条链，也不止以太坊有智能合约，Solana 有 SVM，Polkadot 有 Wasm，Cosmos]]></summary>
    <content type="html"><![CDATA[<p>目前市场上的招聘，“合约开发”一般指“以太坊上的EVM合约开发”。而事实上，世界上不只有以太坊一条链，可能有上百条链，也不止以太坊有智能合约，Solana 有 SVM，Polkadot 有 Wasm，Cosmos 在用平行链的方式达到智能合约的效果，等等，还有很多各种各样的实现形式。</p><p>所以看出问题了吗？如果一个程序员号称自己是 “合约开发”，说明他把自己局限在了一个狭窄的方向上。Solidity 是以太坊团队创造出来的脚本语言，而“合约开发”把自己的职业生涯交付在了这一种不成熟脚本语言上。至少，咱们应该是 “程序员”，而不是 “Solidity 程序员” 吧。</p><p>程序员可以在需要的时候，做一些合约开发的工作，而合约开发者，就只能做开发合约的工作。单就 Solidity 这种语言来说，语法的学习成本是多高呢？一般半个星期左右就可以开始上手写。</p><p>再是关于 DeFi 开发，因为做合约开发的大多都在学习 DeFi 开发。这里的问题在于，无论是 Centralized Finance，还是 Decentralized Finance，本质都是 Finance，核心是 “金融”，“去中心化” 只是金融的修饰词。</p><p>“金融”是什么？完全和“程序员”是两个行业，全世界的精英都在华尔街搞金融，一个半路出道的程序员，你能搞金融？现在的 DeFi 项目是不是都和杠杆、质押、借贷有关？Luna 暴雷是不是杠杆加太高了？Luna 背后有几家公司的资本力量参与？一般人能整明白 Luna 暴雷的原因吗？整不明白的，专业的金融人士分析半天也许能有点结果。</p><p>也就是说，专业的金融人士未必是程序员，而程序员几乎不可能成为专业的金融人士。金融领域的水很深，不是会写代码学一学 Solidoty 就可以的，更不是一个程序员励志要做 DeFi，就能学得会的。</p><p>更进一步，假如程序员把 DeFi 学懂了，能做些什么事情？能做的就是给资本大佬打工，让你实现什么业务逻辑就实现什么业务逻辑，有自由发挥的余地吗？难道你要自己设计一种金融逻辑？搞笑呢？有权力控制大量资产的一定不是程序员，而程序员一定没有权力控制大量资产。</p><p>我的意思是，如果一个程序员想搞懂金融然后表达对整个金融行业独到的见解，是…几乎不可能的，难度非常非常大，有那样能力的人不会是程序员。而如果你只是想要搞懂某个技术领域的情况然后发表一些观点，还是存在可能性的，至少不需要你拥有（或者替别人管理）大量资产吧。</p><p>如果懂金融的程序员自己开一家金融公司呢？你确定？</p>]]></content>
  </entry>
  <entry>
    <title>最近找工作的记录</title>
    <link href="https://b.smallyu.net/2024/09/11/%E6%9C%80%E8%BF%91%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E8%AE%B0%E5%BD%95/"/>
    <id>blog-b:https://b.smallyu.net/2024/09/11/%E6%9C%80%E8%BF%91%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E8%AE%B0%E5%BD%95/</id>
    <published>2024-09-11T09:00:00.000Z</published>
    <updated>2025-12-04T13:51:18.013Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>web3]]></summary>
    <content type="html"><![CDATA[<p>web3 行业大多是一些创业公司和创业团队，记录所谓的面经没有意义，不像互联网大厂已经形成标准化的选择员工的流程。而且我也希望目标公司能够务实一点，如果在面试前突击准备两天就能通过面试，没准备就不能通过面试，那样的面试有什么意义呢？何况面试通没通过也不能说明什么，又不是高考一样相同试卷比分数，只能说明双方意向不匹配。所以不打算记录具体的面试问题，仅仅只记录一下面试过的公司，以及简要感受。</p><ul><li><a href="https://lumoz.org/">Lumoz</a></li></ul><p>做 Baas 平台的，说跟 Merlin Chain 合作过。我一面之后拒绝了二面。</p><p>一方面不喜欢 Baas 平台，光是 Baas 这个词就很老土，而且是 to B 的业务，这种业务都不挣钱，工作内容上就是部署一些 L2 网络，很没意思，跟官网上提到的 Computer Layer 也没有任何关系。</p><p>另一方面，我觉得 Merlin Chain 是骗子项目，和这样项目合作的平台，一定也不怎么样。Merlin Chain 用了以太坊的代码做 BTC L2，是不是很魔幻，而且是中国人搞的，项目里处处体现出中国智慧。</p><ul><li><a href="https://rss3.io/">RSS3</a></li></ul><p>RSS3 是一个 OP 的 L2 网络，现在想要提高执行层客户端的 TPS，有两个优化方向，并行 EVM 和数据库优化。</p><p>我记得之前 L2 的 TPS 受限于 L1 上每一笔交易的具体大小，后来有了 blob 之后就不太清楚 L2 的 TPS 瓶颈是不是在 DA 上了。</p><ul><li><a href="https://web3.bitget.com/en/">Bitget Wallet</a></li></ul><p>Bitget Wallet 用户增长部门，非常注重 web2 方面的技能，包括中间件的使用、编程语言方面的细节。</p><ul><li><a href="https://www.nubit.org/">Nubit</a></li></ul><p>一个比特币 L2 项目。HR 面试让做了一些笔试题，主要是基础类的问题，比如比特币的 21M 是怎么来的。出这份题的人一定喜欢区块链，而且真的“懂”区块链，我挺喜欢这种感觉。</p><p>技术面试的过程中详细了解了一下，其实不是比特币 L2，而是比特币 DA，他们用 Cosmos 搭了一条链，然后用比特币的块高度做为数据索引，标识 DA 数据是什么时间上传到链上的。</p><p>如果其他链将这条链作为 DA 层把数据传上来，就需要一个索引来知道怎么找到自己的 DA 数据，比特币的块高度就起到索引的功能。所以这个项目其实只是蹭比特币热度，和比特币没啥关系。</p><ul><li><a href="https://baike.baidu.com/item/%E4%BA%A6%E6%9D%A5%E4%BA%91/23681499">亦来云</a></li></ul><p>如果算是面试的话。面试非常草率，只是电话聊了 10 分钟。要做的是一个为期 3 个月的项目，比特币相关的，搭建比特币节点以及需要开发一些中间件之类。为期 3 个月的含义是，1 个月调研、1 个月开发、1 个月交付，项目结束就散伙。可惜我忘了打听一下具体是做什么的。</p><p>这里想说的是，从我的感受上，对于项目期限非常明确的项目，有两种情况，一种情况是发起人特别厉害，有非常丰富的项目管理和开发经验，以及项目本身没什么技术含量、开发难度低的情况下，才有可能预先把时间控制到那么准。第二种情况就是，发起人想赚快钱，但是没技术也没钱，而且无知，既没有能力预判到项目的技术难度，也没有能力组建团队来长期运行下去。由于项目周期里包含了调研，所以这家公司在做的项目显然属于后者。</p><ul><li><a href="https://group.hashkey.com/en">HashKey Group</a></li></ul><p>面试体验比较好的一次，面试官看起来比较有阅历，面试中提问题都是想到哪儿问哪儿，至少说话在同一个频道上，而不是给人刻板的感觉。</p><p>对方是做交易所钱包的，所以要招聘的人需要了解各种区块链尤其是收发交易方面，主要关心会不会分叉、回滚之类的问题，然后同时需要要兼顾做后端开发，关心一些中间件、数据库相关的问题。</p><p>经过<a href="/2023/06/29/%E6%9C%80%E8%BF%91%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%886%E6%9C%88%E4%BB%BD%EF%BC%89/">去年</a>和今年的面试经历，根据整体感受能得出结论，就是对于交易所的钱包部门，“懂区块链的 web2 后端开发” 属于他们的理想型。候选人首先有 web2 后端开发的经验，然后再懂一些区块链的基本概念，能够理解如何处理交易，这样的人是最好的。</p><p>web2 后端开发在技术方面的特点，是熟悉中间件和数据库的使用以及原理，比如 Kafka、Redis 这些，面试中可能会问你怎么设计和实现一个消息队列，或者如何解决 MySQL 分布式事务的问题，这些都是 web2 互联网开发的经典套路。</p><p>当然在 web2 方面我几乎是不了解的，每次面试中也是一问到就抓瞎，后来我知道自己不懂，面试中只要问这方面，我就直接说不知道。如果我没有从事区块链行业的话，可能也会往那些技术方向上去深入吧。记得我刚毕业的时候，还试着一边翻译一边学习一些 <a href="https://github.com/smallyunet/advanced-java">经典的技术话题</a>。</p><p>另一个这次面试体验比较好的点是，面试官没有问 “Go 语言的 GMP 调度原理是什么” 这种问题。我遇到过很多很多次问这个问题的，直到现在我也没兴趣去搜索一下这个问题想要的答案是什么。可以在 Google 和 YouTube 上搜一下 “Golang GMP” 这个关键词，看看结果列表里中文的比例有多大，到底是哪些人在关心这种问题？</p><ul><li><a href="https://www.matchain.io/">Matchain</a></li></ul><p>HR 人不错，挺可爱的，说项目是用 Cosmos 开发的一条链，已经上线了测试网而且有很多用户，准备上线主网。</p><p>面试官水平比较差，全程一直在问 L2 的细节，我说了不清楚不了解，还继续问，问的我都无语了。而且只问 L2 的细节，问不出别的。后续了解到现在是用 opBNB 的一条 L2，看来是 BNB 生态的项目。</p><ul><li><a href="https://www.zhipin.com/gongsi/9f4beb0fb87ed3bf1nJz2t60Fw~~.html">TokenInsight</a></li></ul><p>面试体验还算不错（面试体验和面试结果、双方意向是否匹配无关）。面试官即兴提问，有点像 HashKey Group 的面试官，语速稍慢，一边思考一边提问。</p><p>这家公司是做托管钱包的。主要问了一些区块链方面的基础概念。</p><p>面试中让做一道笔试题，题目属于 Leetcode 的“简单”题，在合并有序链表和翻转链表中挑一个做。最近长时间都没怎么关心这方面的问题，也没有刷题，估计面试过程中写出来的代码是错的。</p><p>有意思的一点是，我早在几年前详细写过关于这两道题目的 <a href="https://gub.smallyu.net/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%93%E9%A2%98/Linked%20list/%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html">解析</a>。</p><p>解析的内容属于《<a href="https://gub.smallyu.net/%E5%B0%81%E9%9D%A2.html">Ground-Up Blockchain</a>》中的一个章节，这本”书”起源于《<a href="https://smallyu.net/2021/10/02/Ground-Up-Blockchain-%E5%89%8D%E8%A8%80/">『Ground-Up Blockchain』前言</a>》，是我自己写的，源码在这里 <a href="https://github.com/smallyunet/ground-up-blockchain">smallyunet&#x2F;ground-up-blockchain</a>。写这本书的计划已经荒废很久很久了。</p><ul><li><a href="https://www.gate.io/">Gate.io</a> （现货交易部门）</li></ul><p>闲聊局，本以为 “交易所 + Golang” 标签的职位会问很多 Go 语言技术细节的问题，没想到只是简单聊了一些比较宏观的问题，比如区块链在现实生活中有什么实际用处之类。估计面试官在面试之前就已经做出了决定，放弃了面试吧。</p><ul><li><a href="https://www.gate.io/">Gate.io</a> （Gate Chain 部门）</li></ul><p>从 HR 角度了解到的是，项目是一个 Layer 2 的链，模仿 opBNB 做了一些优化，然后也在模仿 TIA 做 DA 方面的事情。</p><p>技术面试的过程还挺有意思，不过懒得具体写了 :P</p><p>另外有趣的一点是，面试前 HR 再三叮嘱好好准备面试，这两天可以复习一下什么的。这种突如其来的 “好意” 引起人的警觉，我忽然不明白这是啥意思，可能是 HR 有一定的提成吧。</p><p>我一直不知道面试前有什么好准备的，本职工作是时刻在脑子里的，非本职工作则准备两天也根本不可能有结果，简单来说就是会的已经会了，不会的三两天也学不会，所以面试前到底应该准备什么？</p><p>而对于招聘方，看的应该也是一个人整体上近几年的工作经历，而不仅仅是有没有准备个两天三天的。</p><h3 id="阶段性小结"><a href="#阶段性小结" class="headerlink" title="阶段性小结"></a>阶段性小结</h3><p>目前还没有找到工作，并没有结束找工作，只是时间跨度有点长，这篇博客有必要先结束，日后新开一篇。至于记录面试经历这种事情，似乎自从工作开始，我都会把每一次 <a href="/tags/%E6%89%BE%E5%B7%A5%E4%BD%9C/">找工作</a> 相关的内容记录下来，以前会，以后应该也会的。</p><p>这次阶段性的记录大致从 7月20日开始，到 9月15日结束。</p><p>7月20日左右我开始产生离职的想法，并且开始第一次面试。9月15日则是我正式离职的日子。我最近大半个月几乎没有投简历，因为还没有彻底离职，也没太想过早开启全力找工作的阶段。</p><p>今年找工作方面的行情怎么样呢，反正没比去年好，感受上今年在招聘的岗位更少了。面对这种情况应该是什么心情呢？大致应该是，对过去不后悔，对未来的不确定存在轻微恐惧，并且对未来抱有盲目的乐观情绪。</p><p>话说回来，现在整个加密货币行业的市值在 2 万亿美元左右，你说咱能在这个行业里面，找到一份 3000 块钱让自己生存下来的工作吗？这个世界会给我们留下这样的机会吗？</p>]]></content>
  </entry>
  <entry>
    <title>本来想租矿机挖 FB，结果一不小心租了 sha256dt 算法的矿机，现在不得不莫名其妙挖一堆 Novo 了</title>
    <link href="https://t.smallyu.net/#2024-51"/>
    <id>micro:2341329905</id>
    <published>2024-09-10T15:51:57Z</published>
    <updated>2024-09-10T15:51:57Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>本来想租矿机挖 FB，结果一不小心租了 sha256dt 算法的矿机，现在不得不莫名其妙挖一堆 Novo 了</p>]]></summary>
    <content type="html"><![CDATA[<p>本来想租矿机挖 FB，结果一不小心租了 sha256dt 算法的矿机，现在不得不莫名其妙挖一堆 Novo 了</p>
]]></content>
  </entry>
  <entry>
    <title>在互联网上，最有效的沟通方式是写文章。 出自文章《 大部分群聊是浪费生命 》——李笑来.</title>
    <link href="https://t.smallyu.net/#2024-50"/>
    <id>micro:2336691778</id>
    <published>2024-09-08T13:42:47Z</published>
    <updated>2024-09-08T13:42:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>在互联网上，最有效的沟通方式是写文章。 出自文章《 大部分群聊是浪费生命 》——李笑来.</p>]]></summary>
    <content type="html"><![CDATA[<blockquote>
<p>在互联网上，最有效的沟通方式是写文章。    </p>
</blockquote>
<p>出自文章《<a href="https://github.com/xiaolai/reborn/blob/master/C05.md">大部分群聊是浪费生命</a>》——李笑来.   </p>
]]></content>
  </entry>
  <entry>
    <title>不要试图寻找“下一个比特币” 不要试图创造“下一个以太坊” 不要试图成为“下一个xxx” 不要继续使用“下一个…”的句式...</title>
    <link href="https://t.smallyu.net/#2024-49"/>
    <id>micro:2323231364</id>
    <published>2024-09-01T08:29:35Z</published>
    <updated>2024-09-01T08:29:35Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>不要试图寻找“下一个比特币” 不要试图创造“下一个以太坊” 不要试图成为“下一个xxx” 不要继续使用“下一个…”的句式 不要…</p>]]></summary>
    <content type="html"><![CDATA[<ul>
<li>不要试图寻找“下一个比特币”</li>
<li>不要试图创造“下一个以太坊”</li>
<li>不要试图成为“下一个xxx”</li>
<li>不要继续使用“下一个…”的句式</li>
<li>不要…</li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>区块链内行与外行的本质区别，在于是否理解“比特币是一种去中心化货币”的含义。 如果一个人会写以太坊的智能合约、知道怎么发...</title>
    <link href="https://t.smallyu.net/#2024-48"/>
    <id>micro:2323110519</id>
    <published>2024-09-01T01:47:37Z</published>
    <updated>2024-09-01T01:50:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>区块链内行与外行的本质区别，在于是否理解“比特币是一种去中心化货币”的含义。 如果一个人会写以太坊的智能合约、知道怎么发送交易、天天在交易所炒币盯盘、关注什么 DeFi、RWA、美联储、牛熊、冲 Meme，把币圈赌场，成为资深赌徒，这些都不叫“懂区块链”。 而懂的人，会从懂的角度思考问题，不懂的人，会从不懂的角度思考问...</p>]]></summary>
    <content type="html"><![CDATA[<p>区块链内行与外行的本质区别，在于是否理解“比特币是一种去中心化货币”的含义。</p>
<p>如果一个人会写以太坊的智能合约、知道怎么发送交易、天天在交易所炒币盯盘、关注什么 DeFi、RWA、美联储、牛熊、冲 Meme，把币圈赌场，成为资深赌徒，这些都不叫“懂区块链”。</p>
<p>而懂的人，会从懂的角度思考问题，不懂的人，会从不懂的角度思考问题。</p>
]]></content>
  </entry>
  <entry>
    <title>写博客的意义是什么</title>
    <link href="https://crazy.smallyu.net/2024/08/30/%E5%86%99%E5%8D%9A%E5%AE%A2%E7%9A%84%E6%84%8F%E4%B9%89%E6%98%AF%E4%BB%80%E4%B9%88/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2024/08/30/%E5%86%99%E5%8D%9A%E5%AE%A2%E7%9A%84%E6%84%8F%E4%B9%89%E6%98%AF%E4%BB%80%E4%B9%88/</id>
    <published>2024-08-30T05:25:34.000Z</published>
    <updated>2026-08-11T01:22:23.526Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>当世界上没有人再记得你，你就会真正死去。</p>
<p>如果你的生活里有观众，就让生活中的观众记住你，他们可以是家人、爱人、朋友、同事。</p>
<p>而如果你的生活里没有观众，你也许想留下一些自己活过的证据。</p>
<p>可能除了你自己，没有人会关心博客里的内容。</p]]></summary>
    <content type="html"><![CDATA[<p>当世界上没有人再记得你，你就会真正死去。</p><p>如果你的生活里有观众，就让生活中的观众记住你，他们可以是家人、爱人、朋友、同事。</p><p>而如果你的生活里没有观众，你也许想留下一些自己活过的证据。</p><p>可能除了你自己，没有人会关心博客里的内容。</p><p>但在曾经的某时某刻，你真真切切地在思考一些问题，真真切切地感受到了某些情绪。</p><p>你不可能跟爱人分享递归的三种写法，也不可能和同事分享你对爱的感悟。</p><p>你没办法跟父母分享你的许多快乐和悲伤，也不可能让亲戚来体会你的喜怒哀乐。</p><p>世界上没有人会理解你，就像你总是无法理解别人。</p><p>所以把这些东西记录下来，转化成文字、图片、视频。</p><p>即使你的肉体死去，也许还会有人看到你的文字，交到一个跨越时空的朋友，和他进行精神上的对话（这本是书籍的意义）。</p><p>如果已经有人理解你，你不需要写下什么，只管尽情地表演，让观众记住更多的你。也许你停留在生活的小圈子，那就跟所有人分享你知晓的一切。也许你是功成名就的公众人物，那就发表更多作品和言论，会不断有追随者记住你。</p><p>而如果现在还没有人理解你，没有人关心你在乎的话题，那么就写下来，然后等一等，也许会有人发现这些历史的遗迹。</p><p>哪怕是自己老后，回顾一下曾经的自己。哪怕自己不是最后一代，让子孙来认识年轻的你。</p><p>这就是写博客的意义。</p>]]></content>
  </entry>
  <entry>
    <title>一件事情有没有意义，是谁说了算呢？首先是花钱的人说了算，一般是是投资人。再就是有权力的人说了算，大股东、合伙人、部门负责...</title>
    <link href="https://t.smallyu.net/#2024-47"/>
    <id>micro:2317291457</id>
    <published>2024-08-29T10:40:36Z</published>
    <updated>2024-08-29T10:40:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>一件事情有没有意义，是谁说了算呢？首先是花钱的人说了算，一般是是投资人。再就是有权力的人说了算，大股东、合伙人、部门负责人、小组长……所以其实世界上很多事情不讲道理，或者说不需要讲道理。</p>]]></summary>
    <content type="html"><![CDATA[<p>一件事情有没有意义，是谁说了算呢？首先是花钱的人说了算，一般是是投资人。再就是有权力的人说了算，大股东、合伙人、部门负责人、小组长……所以其实世界上很多事情不讲道理，或者说不需要讲道理。</p>
]]></content>
  </entry>
  <entry>
    <title>我的加密货币定投策略（一）</title>
    <link href="https://smallyu.net/2024/08/28/%E6%88%91%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E5%AE%9A%E6%8A%95%E7%AD%96%E7%95%A5%EF%BC%88%E4%B8%80%EF%BC%89/"/>
    <id>blog:https://smallyu.net/2024/08/28/%E6%88%91%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E5%AE%9A%E6%8A%95%E7%AD%96%E7%95%A5%EF%BC%88%E4%B8%80%EF%BC%89/</id>
    <published>2024-08-27T18:15:14.000Z</published>
    <updated>2025-11-17T14:37:00.733Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<blockquote>
<p>随着时间的推移以及对市场的更深入了解，定投策略尤其是投资组合会产生非常大的变化，所以在标题中用（一）标识，如果定投策略有变动，可能还会有（二）、（三）……当然也会同时说明变动的原因。</p>
</blockquote>
<p>今年以来开始更加关注投]]></summary>
    <content type="html"><![CDATA[<blockquote><p>随着时间的推移以及对市场的更深入了解，定投策略尤其是投资组合会产生非常大的变化，所以在标题中用（一）标识，如果定投策略有变动，可能还会有（二）、（三）……当然也会同时说明变动的原因。</p></blockquote><p>今年以来开始更加关注投资的话题，也因为乱操作损失过一些钱。</p><p>最近中了李笑来的毒，定投策略的理论让人感到很兴奋，可以从以下资料更加深入了解：</p><ul><li>《<a href="https://ri.firesbox.com/#/">定投改变命运</a>》—— 李笑来，所有关于定投的内容都在这本书里</li><li><a href="https://youtu.be/tmRQImBk6NA?si=Cl7Fwiq2WcfM28P2">定投改变命运直播公开课</a> —— Youtube 视频，李笑来本人的解读</li></ul><p>除了定投，还有几个其他投资方面的参考资料：</p><ul><li>《<a href="https://github.com/xiaolai/the-self-cultivation-of-leeks">韭菜的自我修养</a>》—— 李笑来</li><li><a href="https://www.youtube.com/@ChandlerGuoChannel">郭宏才（宝二爷）的 Youtube 频道</a></li></ul><p>我想实践一下定投的投资方式，其中涉及到的几个问题：</p><ol><li>是否要加入李笑来的投资实践群？没有必要，尤其是对于有自制力的人</li><li>是否要买 <a href="https://b.watch/">BOX</a>？江湖传言，李老师的书必须看，课可以听，币千万别买</li><li>定投的方式？Binance 自带的定投功能就可以，0 手续费（要记得时不时提到钱包）</li><li>定投的频率是？每天，因为价格变化太快了，如果频率太低，周期会变得太久</li><li>定投的周期是？目前规划了用来定投 1 年的钱</li><li>定投的标的是？</li></ol><p>我没有盲目跟从李笑来 BOX 中标的的选择和比例。李笑来的 BOX 一开始给了 EOS 很高比例，事实证明 EOS 失败了，所以现在 BOX 的成分里已经不包含 EOS。最新的情况是，BOX 中 BTC 占了 92% 的比例。另外 BOX 的成分中一直含有 XIN，说明人都会受到立场的左右，因为我们大多数人可能都不知道 XIN 是什么，而李笑来多年坚定的选择这个币。</p><p>我选择的标的和分配的比例是：</p><table><thead><tr><th align="center">序号</th><th align="center">标的</th><th align="center">比例</th><th align="center">标签</th><th align="center">风险</th><th align="center">供应量上限</th></tr></thead><tbody><tr><td align="center">1</td><td align="center">BTC</td><td align="center">50%</td><td align="center">PoW, UTXO</td><td align="center">低</td><td align="center">✅</td></tr><tr><td align="center">2</td><td align="center">ETH</td><td align="center">10%</td><td align="center">智能合约平台</td><td align="center">中</td><td align="center">❌</td></tr><tr><td align="center">3</td><td align="center">LTC</td><td align="center">5%</td><td align="center">PoW, UTXO</td><td align="center">高</td><td align="center">✅</td></tr><tr><td align="center">4</td><td align="center">DOGE</td><td align="center">5%</td><td align="center">PoW, UTXO</td><td align="center">高</td><td align="center">❌</td></tr><tr><td align="center">5</td><td align="center">BCH</td><td align="center">5%</td><td align="center">PoW, UTXO</td><td align="center">高</td><td align="center">✅</td></tr><tr><td align="center">6</td><td align="center">ADA</td><td align="center">5%</td><td align="center">PoS, UTXO</td><td align="center">高</td><td align="center">✅</td></tr><tr><td align="center">7</td><td align="center">SOL</td><td align="center">5%</td><td align="center">智能合约平台</td><td align="center">高</td><td align="center">❌</td></tr><tr><td align="center">8</td><td align="center">FIL</td><td align="center">5%</td><td align="center">PoSt</td><td align="center">非常高</td><td align="center">❌</td></tr><tr><td align="center">9</td><td align="center">TON</td><td align="center">5%</td><td align="center">智能合约平台</td><td align="center">非常高</td><td align="center">❌</td></tr><tr><td align="center"><del>10</del></td><td align="center"><del>XEC</del></td><td align="center"><del>3%</del></td><td align="center"><del>PoW, UTXO</del></td><td align="center"><del>非常高</del></td><td align="center"><del>✅</del></td></tr><tr><td align="center"><del>11</del></td><td align="center"><del>DASH</del></td><td align="center"><del>2%</del></td><td align="center"><del>PoW, UTXO</del></td><td align="center"><del>非常高</del></td><td align="center"><del>✅</del></td></tr><tr><td align="center">10</td><td align="center">XMR</td><td align="center">5%</td><td align="center">PoW, UTXO</td><td align="center">非常高</td><td align="center">❌</td></tr></tbody></table><p>（2024.09.26 更新）</p><p>可以从这个公开的 <a href="https://coinmarketcap.com/watchlist/66d339a5c316be09d04b7b16/">Watchlist</a> 看到这些币种的集合，链接会跳转到 CoinMarketCap 网站上。能注意到的是，几乎所有币种的市值排名都在 100 之内，这条原则来自《<a href="/2024/05/04/%E7%82%92%E5%B8%81%E6%8A%95%E8%B5%84%E7%9A%84%E5%B0%8F-tips/">炒币投资的小 tips</a>》第 4 条。</p><p>我的定投组合中，BTC 一定是首位，占 50% 的比例。另外 5 个 PoW 的币总计占了 20% 的比例，也就是说，PoW 币总计占比 70%。PoW 的币大都有供应量上限。</p><p>由于 “比特金，莱特银” 的说法，LTC一直比较强势，DOGE 和 LTC 是难兄难弟，挖矿算法一样，<a href="https://www.litecoinpool.org/">矿池</a>都是同时挖这两个币，所以 LTC 和 DOGE 的价格不能简单像 BTC 一样估算 “矿机关机价”，而 DOGE 又属于 memecoin 的老大，历史久，马斯克喜欢，也放不下的，所以 LTC 和 DOGE 要一起出现。</p><p>BCH 是 BTC 在手续费超高年代（2017年）的 workaround 方案，Blocksize War 真的已经结束了吗？BCH 是大区块的代表，所以要把 BCH 选进来。BTC 已经脱离 “电子现金” 的目的，变成了 “储存价值”，相信这个问题上的争议还没有彻底结束。那后来 BCH 又分叉出了 BSV，为什么没有把 BSV 涵盖进来？BSV 的生态小，而且生态里有一些活跃但无知的项目（Note 之类），BSV 的创始人还在被法院通缉，等等原因。</p><p>DASH 和 XEC 是最没道理的两个，冷门到很多人没听过，也是风险最高的两个。其中 XEC 是因为 BCH 的 <a href="https://github.com/bitcoin-cash-node/bitcoin-cash-node">节点代码</a> fork 自 XEC 的代码，相信 XEC 有不错的技术能力。DASH 是 LTC 的一个 fork，更多是凑数性质，因为很多老牌钱包比如 Unstoppable 支持的币种列表大都是 PoW 系列的币，DASH 就在其中，而且币安的矿池服务支持的币种不多，其中也有 DASH，所以就把 DASH 作为 “电子现金” 的高风险备选了。</p><p>然后是 ADA，学术能力强，纯粹的 PoS 共识，用了 UTXO 模型，属于 BTC 在 PoS 共识上的平替，而且 ADA 技术上在不断更新，如果有一天 PoS 赢了，ADA 绝对是绕不过去的一个，所以预计 ADA 能有更好的未来。</p><p>FIL 的话，属于分布式存储领域。计算机科学有两大方向，分布式计算和分布式存储，ETH 说自己是 “世界计算机”，担起了分布式计算的职责，而 FIL 是存储领域的老大。印象里 libp2p 是 Filcoin 开发的，而很多区块链像 ETH 用的 p2p 模块，就直接用的是 libp2p。以及目前非常广泛使用的 IPFS，也是 Filecoin 实验室开发的。所以 FIL 在研发方面实力很强，未来也许会有得到突破的一天。</p><p>最后是智能合约平台类型。其实我不太喜欢智能合约，很多人喜欢把智能合约等同于区块链，或者认为只有支持智能合约的区块链才叫区块链。在囤币方面，币只是智能合约平台的 <a href="/micro-blog/#2024-31">燃料</a>，又没有供应量上限，囤它干嘛。但是智能合约平台火，玩的人多，价格居高不下。ETH、SOL、TON 的特点都是支持智能合约、现在关注量比较大，所以适当分配一些比例上去。</p><p>另外这是一些热门币没有被涵盖进来的原因：</p><table><thead><tr><th align="center">币种</th><th align="center">未选择原因</th></tr></thead><tbody><tr><td align="center">BNB</td><td align="center">平台币，不是链</td></tr><tr><td align="center">DOT</td><td align="center">没有供应量上限、APR 很高</td></tr><tr><td align="center">ATOM</td><td align="center">没有供应量上限、APR 很高</td></tr><tr><td align="center">AVAX</td><td align="center">没有供应量上限、没看到明显优点</td></tr><tr><td align="center">APT, SUI</td><td align="center">BFT 类共识</td></tr><tr><td align="center">所有 ERC-20 代币</td><td align="center">不是链</td></tr><tr><td align="center">所有 Memecoin</td><td align="center">没有长期价值</td></tr><tr><td align="center">铭文、符文</td><td align="center">BTC 手续费太贵</td></tr></tbody></table><p>祝自己好运！</p><h3 id="更新（2024-09-26）"><a href="#更新（2024-09-26）" class="headerlink" title="更新（2024.09.26）"></a>更新（2024.09.26）</h3><p>去掉了原先投资组合中的 XEC 和 DASH。因为在原先的选择中，XEC 和 DASH 本就是理由不充分的两个标的，而他们的总市值排名在 100 左右甚至之外，社区热度也比较差。</p><table><thead><tr><th align="center"></th><th align="center"></th><th align="center"></th><th align="center"></th><th align="center"></th><th align="center"></th></tr></thead><tbody><tr><td align="center"><del>10</del></td><td align="center"><del>XEC</del></td><td align="center"><del>3%</del></td><td align="center"><del>PoW, UTXO</del></td><td align="center"><del>非常高</del></td><td align="center"><del>✅</del></td></tr><tr><td align="center"><del>11</del></td><td align="center"><del>DASH</del></td><td align="center"><del>2%</del></td><td align="center"><del>PoW, UTXO</del></td><td align="center"><del>非常高</del></td><td align="center"><del>✅</del></td></tr></tbody></table><p>更重要的是，现在要用 XMR 来代替它们原先占有的共 5% 的比例。XMR 是暗网使用的 <a href="https://x.com/DarkDotFail/status/1765104459913330820">主要货币</a> 之一，暗网仅接收 BTC 和 XMR。XMR 在隐私保护方面非常强。而在暗网的应用领域，XMR、XEC、DASH 其实是经常被 <a href="https://x.com/Altcoinbuzznews/status/1746989440373784958">并列讨论</a> 的三个币种。要在这三个同类型代币中选择一个的话，就首选 XMR。</p><table><thead><tr><th align="center"></th><th align="center"></th><th align="center"></th><th align="center"></th><th align="center"></th><th align="center"></th></tr></thead><tbody><tr><td align="center">10</td><td align="center">XMR</td><td align="center">5%</td><td align="center">PoW, UTXO</td><td align="center">非常高</td><td align="center">❌</td></tr></tbody></table>]]></content>
  </entry>
  <entry>
    <title>如果我的苹果手机坏了，第一反应不是交给苹果的维修店，而是自己把手机拆了，把各个功能组件的运作原理研究了一遍，然后找到了出...</title>
    <link href="https://t.smallyu.net/#2024-46"/>
    <id>micro:2311561411</id>
    <published>2024-08-27T04:44:20Z</published>
    <updated>2024-08-27T18:57:41Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果我的苹果手机坏了，第一反应不是交给苹果的维修店，而是自己把手机拆了，把各个功能组件的运作原理研究了一遍，然后找到了出错的地方，去维修店说，“我的手机坏了，在37度的高温环境下主板上第32号位置的电路在a型晶体管的影响下运算会出错，你们要维修的话可以照我这个思路来”。 这是不是一件很诡异的事情？</p>]]></summary>
    <content type="html"><![CDATA[<p>如果我的苹果手机坏了，第一反应不是交给苹果的维修店，而是自己把手机拆了，把各个功能组件的运作原理研究了一遍，然后找到了出错的地方，去维修店说，“我的手机坏了，在37度的高温环境下主板上第32号位置的电路在a型晶体管的影响下运算会出错，你们要维修的话可以照我这个思路来”。</p>
<p>这是不是一件很诡异的事情？ </p>
]]></content>
  </entry>
  <entry>
    <title>PoS 类型的区块链如何处理分叉</title>
    <link href="https://smallyu.net/2024/08/22/PoS%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%88%86%E5%8F%89/"/>
    <id>blog:https://smallyu.net/2024/08/22/PoS%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%88%86%E5%8F%89/</id>
    <published>2024-08-22T09:41:01.000Z</published>
    <updated>2025-11-09T09:22:13.309Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>主流公链从共识机制的角度基本上可以分为 3 类，分别是 PoW、PoS、PBFT。选择了不同的共识，也就很大程度上决定了网络的 TPS、去中心化程度、节点规模。</p>
<p>除了 PoW，另外两种共识 PoS 和 PBFT]]></summary>
    <content type="html"><![CDATA[<p>主流公链从共识机制的角度基本上可以分为 3 类，分别是 PoW、PoS、PBFT。选择了不同的共识，也就很大程度上决定了网络的 TPS、去中心化程度、节点规模。</p><p>除了 PoW，另外两种共识 PoS 和 PBFT 都面临一个基本的问题，就是当网络发生了软分叉，该如何恢复？由于 PoS 和 PBFT 产生块不需要算力成本，也就不能用和 PoW 一样的最长链原则。</p><h3 id="问题背景"><a href="#问题背景" class="headerlink" title="问题背景"></a>问题背景</h3><h4 id="共识概览"><a href="#共识概览" class="headerlink" title="共识概览"></a>共识概览</h4><p>PoW 系列的链有 BTC、BCH、BSV、LTC、DOGE、ZEC 等。PoW 都使用最长链原则，节点在面对多个发生了分叉的链时，直接选择块高度最高的一条就行了。由于每产生一个块都需要庞大的算力，攻击成本比较高。</p><p>PoS 系列的链有 ETH、BNB、TRON、DOT、TON、ADA、AVAX、NEO 等。几乎目前所有智能合约平台类型的链，都属于 PoS 共识。</p><p>PBFT 系列的链有 ATOM、SOL、TON、ONT、APT、SUI 等。其中 Cosmos 最为知名，Solana 有超越以太坊的势头，The Open Network 今年也发展的很好。</p><p>这里可能会觉得有点奇怪，怎么把 SOL 归类到 PBFT 上了？SOL 不是 PoH 共识吗？SOL 不也有质押的功能，比如在 Solflare 钱包上还可以质押获得收益的吗？TON 也有质押和收益啊？</p><p>这里是两个问题。</p><p>首先 Solana 的确开发和使用了 BFT 类的共识，叫 <a href="https://solana.com/news/8-innovations-that-make-solana-the-first-web-scale-blockchain">Tower BFT</a>，PoH 是用来解决 Solana 链上的时钟问题的，而不是一种完整的共识机制。 </p><p>其次是 PoS+BFT 类共识，算 PoS 还是 BFT？上面提到的分类，PoS 主要指 PoS、dPoS、PoS Casper 这些，凡是用到 BFT 的都归类为 PBFT 作为区分。最明显的就是 Cosmos 也有质押和收益功能，但很少有人会说 Cosmos 用的是 PoS。</p><h4 id="关于分叉"><a href="#关于分叉" class="headerlink" title="关于分叉"></a>关于分叉</h4><p>PoS 共识和 PBFT 共识面对分叉问题的时候，有两个方面。</p><p>一方面是质押者列表（以太坊叫 <code>Validators</code>，Cardano 叫 <code>Stakeholders</code>）是否一致，因为 PoS 和 PBFT 大都是使用 VRF 从一组候选列表中选择出一个节点作为出块节点，那么 PoS 和 PBFT 类共识在处理这个问题的时候有哪些异同？</p><p>另一方面是当网络分叉后，在选择链的规则（以太坊叫 <code>Forkchoice</code>，Cardano 叫 <code>Chain selection rule</code>）方面有什么异同？</p><h3 id="质押者列表不一致"><a href="#质押者列表不一致" class="headerlink" title="质押者列表不一致"></a>质押者列表不一致</h3><h4 id="联盟链"><a href="#联盟链" class="headerlink" title="联盟链"></a>联盟链</h4><p>从最简单的联盟链开始分析。联盟链的特点是没有 coin，也就完全没有质押方面的内容，只是单纯的 PBFT。</p><p>联盟链顾名思义，有非常高的准入门槛，需要经过审核或者某种授权也能够成为联盟成员。具体到技术层面，就是想要加入网络，需要在其他节点都知道的情况下，比如所有节点的配置文件里，都包含一个网络成员的列表，列表里定义了网络的节点公钥以及对应的 index，想要增加节点就需要其他所有节点都改一下配置文件。</p><p>节点在出块的时候，就会从这个列表中使用 VRF 随机选择一个作为出块节点。一般 VRF 返回的是一个简单的数字，对应公钥列表的 index，出块节点用这个公钥来对块签名。</p><p>这样的做法比较笨拙，但也是联盟链的特点。在这种模式下，节点的质押着列表不太可能不一致，如果不一致就是配置文件写错了。而且配置错误的情况下，它将永远是错误的，排查起来很简单。</p><h4 id="Cosmos"><a href="#Cosmos" class="headerlink" title="Cosmos"></a>Cosmos</h4><p>Cosmos Hub 用的共识叫 <a href="https://docs.cometbft.com/v0.37/introduction/">CometBFT</a>，基本流程是花费不少于 180 个 ATOM 注册成为 Validaotr，然后就有可能会选为出块节点。</p><p>由于 BFT 类共识在出块之前就需要投票，所以假如网络中真的出现了质押者列表不一致的情况，在同一个块高度会有两个节点产生出两个块，此时网络中的其他节点会对这两个块进行投票。</p><p>这个时候也分两个场景，就是网络正常和网络异常的情况。</p><p>在网络正常的情况下，现在有两个块，一定只能有一个块收到大于 2&#x2F;3 的投票，不可能两个块都收到大于 2&#x2F;3 的投票。所以在出块之前，就已经把质押者列表和其他节点不一致的节点排除在外了，不会影响后续流程。</p><p>在网络异常的情况下，节点感知不到其他节点的存在，即使当前节点的质押者列表正好是当前子网络中的有限几个节点，其他几个节点也不会把票投过来。除非整个子网络都断网了、质押者列表还发生了一样的错误，那这个自网络就自己在局域网玩吧。网络异常本身就是一种异常情况了，与外界隔绝。</p><h4 id="Cardano"><a href="#Cardano" class="headerlink" title="Cardano"></a>Cardano</h4><p>Cardano 的 PoS 是最纯粹的 PoS，没有投票机制。Cardano 的共识经历了<a href="https://iohk.io/en/blog/posts/2022/06/03/from-classic-to-chronos-the-implementations-of-ouroboros-explained/">很多次演进</a>（内容很多很复杂，我没看完）。</p><p>Cardano 网络的规则是，任何人都可以质押任意金额到 Stake pools 中成为 <a href="https://docs.cardano.org/about-cardano/learn/delegation/">Delegator</a>，这些 Delegator 按照质押金额的比例共享矿池的收益，但是不会有出块的资格。</p><p>在 Cardano 网络中真正有出块权限的是 Stake pools，也就是说有可能被选为出块节点的节点，都在 <a href="https://preprod.cexplorer.io/pool">矿池列表上</a> 了，数量不多，目前大概 300 个左右，每个 solt 将从中随机选择一个来产生块。</p><p>那么 Stake pools 节点注册之后，如果节点之间出现 Stake pools 列表不一致的情况怎么办？Cardano 的文档中有 <a href="https://developers.cardano.org/docs/operate-a-stake-pool/introduction-to-cardano#how-it-works">描述</a>，当遇到同一 slot 产生了两个块的时候，就开始启用链选择的规则（Chain Selection Rule）了。也就是说，实际上当第二个块被产生出来，链就已经分叉了，然后所有节点都启用链选择的规则，来进行恢复。</p><h4 id="Ethereum"><a href="#Ethereum" class="headerlink" title="Ethereum"></a>Ethereum</h4><p>以太坊要成为 Validator 需要花费 32 个 ETH 把节点信息注册到 <a href="https://etherscan.io/address/0x00000000219ab540356cbb839cbe05303d7705fa">质押合约</a> 上，然后其他所有的 Validator 都会从质押合约获取质押者列表的信息。</p><p>那怎么确定其他 Validators 都已经把质押者信息从合约同步到本地了？你可以在 Beacon Chain 浏览器的任意一个 <a href="https://beaconcha.in/block/20584195">块信息</a> 上，找到一个叫 <a href="https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/validator.md#eth1-data">Eth Data</a> 的字段，这个字段对于质押者列表非常重要，当一个 validator 被选为出块节点时，它会把当前节点同步到的质押者列表信息，一起打包进块里，包括质押者的总数以及 Deposit root 信息。</p><p>以太坊网络大概每 17 个小时进行一次 <a href="https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/validator.md#process-deposit">质押者列表的更新</a>。在这个周期中，只有超过半数区块的 Eth Data 包含了新增的 validator，新的 validator 才会真正加入到网络中。</p><p>所以以太坊要加入 validators 的过程是漫长而且严格的，首先要确认其他 proposer 已经同步了相关信息，才会真正更新质押者列表。在这样的规则模式下，质押者列表很难不一致。</p><h3 id="分叉链选择"><a href="#分叉链选择" class="headerlink" title="分叉链选择"></a>分叉链选择</h3><h4 id="Ethereum-1"><a href="#Ethereum-1" class="headerlink" title="Ethereum"></a>Ethereum</h4><p>以太坊中如果出现了多条分叉的链，选择起来时相对容易的，因为以太坊有投票机制，每一个块上都包含了有多少个 validators 对块进行了投票。可以猜想到，在发生分叉时，只要不断选择投票数多的块就可以了。</p><p>而实际上以太坊的分叉选择基于 <a href="https://ethos.dev/beacon-chain">checkpoint 机制</a>，每个块是一个 slot，每 32 个 slot 是一个 epoch，每个 epoch 都是一个检查点。一个检查点收到大于 2&#x2F;3 的投票，就进入了 justified 的状态，当一个检查点的下下个检查点也进入 justified 状态，当前检查点就认为是 finalized 状态了。所以在以太坊中，一笔交易最终被标记为 finalized 需要 15 分钟。</p><p>这里提到的检查点，也就是 <a href="https://arxiv.org/abs/1710.09437">FFG</a> 进行 forkchoice 的依据，每条链会选择 checkpoint 多的链。所以以太坊的共识不是选择 “有最多块的链” 原则，而是选择 “有最多检查点的链” 原则，检查点最多的链就是主链。</p><h4 id="Cardano-1"><a href="#Cardano-1" class="headerlink" title="Cardano"></a>Cardano</h4><p>Cardano 最新在使用 <a href="https://developers.cardano.org/docs/operate-a-stake-pool/introduction-to-cardano/#what-if-for-some-reason-there-is-a-fork">Chain selection rule</a>，是由 <a href="https://dl.acm.org/doi/10.1145/3243734.3243848">Ouroboros Genesis</a> 版本提供的。</p><p>Ouroboros Genesis 的上一个版本是 <a href="https://link.springer.com/chapter/10.1007/978-3-319-78375-8_3">Ouroboros Praos</a>，Praos 版本中提出了一套叫 <code>maxvalid</code> 的规则，Genesis 版本基于 <code>maxvalid</code> 做了一点改进，把 <code>moving checkpoint</code> 的特性结合了进来，形成了新版本叫做 <code>maxvalid-mc</code> 的规则。</p><p>移动检查点简单理解就是，本地链在面对多条分叉链时，如果没有超过 k 个块，就选最长的链，如果超过了 k 个块，就直接不选它。也就是说本地链只会在 k 个块的范围内，选择链最长的一个。而 k 个块的范围就是所谓的移动检查点（moving checkpoint）。加了这样限制的好处就是可以避免最长链攻击。当然 Cardano 制定这样的规则经过了一系列学术上的推演以及实际场景的检验。</p><h4 id="Cosmos-1"><a href="#Cosmos-1" class="headerlink" title="Cosmos"></a>Cosmos</h4><p>PBFT 链在网络正常的情况下，只要保证质押者列表一致，就不会分叉。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>总的来说，每种共识的具体实现，都包含了详细的处理分叉的规则，而且这些老牌公链都经过了实际运行的检验。具体如何实现与链的设计理念有关。</p>]]></content>
  </entry>
  <entry>
    <title>互动式沉浸剧场</title>
    <link href="https://b.smallyu.net/2024/08/18/%E4%BA%92%E5%8A%A8%E5%BC%8F%E6%B2%89%E6%B5%B8%E5%89%A7%E5%9C%BA/"/>
    <id>blog-b:https://b.smallyu.net/2024/08/18/%E4%BA%92%E5%8A%A8%E5%BC%8F%E6%B2%89%E6%B5%B8%E5%89%A7%E5%9C%BA/</id>
    <published>2024-08-18T03:08:40.000Z</published>
    <updated>2026-03-02T09:03:27.089Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>女朋友因为食物中毒在医院躺了一个多月，我很久没有见她，也很久没怎么出门玩了。昨天去玩了一个体验还算不错的互动式沉浸剧场（当然也是她的主意），叫《龙门后传》，在三里屯工体那边的一家店。</p>
<p>我玩过太多次剧本杀，也玩过很多次沉浸剧场，这种全程互动式的沉浸剧场还是第一次]]></summary>
    <content type="html"><![CDATA[<p>女朋友因为食物中毒在医院躺了一个多月，我很久没有见她，也很久没怎么出门玩了。昨天去玩了一个体验还算不错的互动式沉浸剧场（当然也是她的主意），叫《龙门后传》，在三里屯工体那边的一家店。</p><p>我玩过太多次剧本杀，也玩过很多次沉浸剧场，这种全程互动式的沉浸剧场还是第一次玩，玩之前觉得稍微有一点贵，不到 3 个小时的游戏时长，一个人要 500 快钱。但是玩过之后就不会觉得贵了，一共只有 7 个玩家，十几个 NPC 全程陪同互动，1v1 演戏，上下两层几百平米的实景房间，价格算是合理。</p><p>游戏开场前和前台小哥的闲聊中，也得到一些信息，就是今年的文娱类行业非常难做，这家开《龙门后传》的梦径沉浸剧场，在北京算是活得比较好了，这两年倒闭的店家很多。小哥的原话大概是，“现在大家在考虑的是明天怎么生存，谁还会想着花钱来玩这种娱乐类型的游戏啊”。</p><p>这一点我也是有切身体会的，主要在剧本杀方面。几年前剧本杀火爆的时候，不但新的店家层出不穷，也不断有新的剧本内容被创作出来，类型和玩法上都有创新，剧情也是花样百出。去年到今年以来，能明显感受到的是，整个市场上玩剧本杀的、参与剧本杀拼场的玩家大大减少，经常发现想玩但找不到场次，即使有也是一些非常经典的老本。这些剧本的特点是新手友好、百里挑一的好玩，让玩家不会踩雷，比较安全。很多剧本杀商家都觉得现在剧本杀处于夕阳行业了。也因为拼不到新本，我前段时间玩了 3 次《雪乡连环杀人事件》。</p><p>关于互动式沉浸剧场，这里有两个关键词，“互动式” 和 “沉浸剧场”。</p><p>剧本杀是非常侧重互动的游戏，因为整个过程都是玩家之间在玩，但是场地简单，大家都在一个房间里面，摆一张桌子，就行了。也有叫“大演绎本”的剧本杀，虽然还是剧本杀、都在一个房间里，但是配置两三个负责演戏的 DM，演绎出剧本中的一些情节，让玩家更有代入感。这种演绎本大都是情感本，男女人数对等，组成 cp 基于剧本提供的身份，互相谈恋爱或者体验其他类型的感情，亲情、爱情、友情都有。情感本也是我之前最喜欢玩的类型，是我最大的乐趣来源，后来我就不方便玩情感本了，只能玩一玩硬核推理类型的本，最大的乐趣来源没了 :P</p><p>还有一种剧本杀叫“实景搜证”，这类剧本杀大多是阵营本或者推理本，剧本内容相对简单，如果是实景的阵营本，比较适合公司团建之类的活动，人数多、难度低、玩家之间对抗。推理本比较无聊一点，虽然实景搜证但还是得坐在桌子前推理，挺没意思。所以感觉实景搜证类剧本杀不会有太大生存空间。</p><p>然后是沉浸剧场，沉浸剧场有两种，一种是有固定座位的，整个场馆有多个舞台区域，话剧演员会穿插在不同的舞台区域表演，可能就在你身边或者你身后，演员也会随机找一些演员互动，回答个问题、玩个小游戏、上台一起跳舞（E人必备）之类。这种沉浸剧场也是等级划分最鲜明的一种，票价不同座位不同，演员则会更加照顾花钱多的观众。6号线原先有一家有名的繁星剧本杀店，后来那里又搞了个繁星戏剧村，很多这种带座位的沉浸剧场都在那里演出。最让我不能理解的是花 1800 块钱买第一排座位的观众，最后一排的票价只要 180，而第一排观众也就只是当众玩一个小游戏，或者多个 NPC 说两句话。他们没玩过剧本杀吗？花 100 块钱想玩什么小游戏都能满足你。</p><p>还有一种沉浸剧场是没有固定座位、跟随式的，演出场地很大，实景场地，演员按照自己的节奏演，观众可以在场地的任意位置看演员演出，站在演员身边或者面前都可以，为了能看懂剧情，一般会选择一两个演员一直跟着，看看发生在人物身上的故事。这种演出演员会和你有少量的互动，有一些沟通环节，但演员还是以演出为主。</p><p>互动式沉浸剧场的模式，就在剧本杀和沉浸剧场的折中区间，有实景场地、演员全程跟你互动，演员既在表演，也在玩。价格上，桌面剧本杀的价格在 150 左右，演绎剧本杀大概 300 左右。沉浸剧场虽然演员多场地大，但是观众也多，可以容纳 20 多人，所以价格没有太高，大概 400 块钱就够了，也有 300 或 200 票价的，无非就是少看一小段表演。所以整体上互动式沉浸剧场的开销最大，要 500 块钱。（都是人均价格）</p><p>互动式沉浸剧场也有一些缺点，比如剧情相对简单。对新手可能友好，但是如果玩过很多次剧本杀的话，剧情上就显得有点单薄，毕竟剧本杀的游戏时长 6 个小时，需要阅读上万字的剧情，有铺垫有反转有纠葛，沉浸剧场时间短，放不进那那么多东西，玩的开心就好了。</p><p>这是《龙门后传》门口摆着的宣传海报：</p><img src="1.png" width="40%"><p>开场前阅读个人身份背景：</p><img src="5.png" width="40%" style="display: inline-block;margin-left:5%"><img src="6.png" width="40%" style="display: inline-block;margin-left:5%"><p>宁远城紧闭的大门：</p><img src="2.png" width="40%"><p>门后就是实景的场地：</p><img src="3.png" width="40%" style="display: inline-block;margin-left:5%"><img src="4.png" width="40%" style="display: inline-block;margin-left:5%"><p>和所有沉浸剧场一样，开场后的场地和演员都是不能拍照的。</p><p>游戏结束后吃了一顿简单的饭，湘菜，在三里屯 Soho 下沉广场的潇湘阁，两个人 180 块，算是比较便宜了。</p><img src="7.png" width="40%"><p>之前写过《<a href="/2023/03/11/%E5%9C%A8%E5%8C%97%E4%BA%AC%E5%90%83%E4%B8%80%E9%A1%BF%E9%A5%AD%E8%A6%81%E8%8A%B1%E5%A4%9A%E5%B0%91%E9%92%B1/">在北京吃一顿饭要花多少钱</a>》，当时说一顿饭需要人均 180，现在来看其实也没什么问题，如果是在商场内部的五六楼吃饭，差不多就得这种价格，180 有点虚高，可能人均 150 更加合适一点，不浪费那种。两个人点三个菜，差不多就是这样。</p><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>在 MacOS 上管理和阅读 PDF 一直是个问题，之前在用 <a href="https://github.com/Future-Scholars/paperlib">paperlib</a> 还不错挺好用，不过不能导入非论文类 PDF，以及其他一些使用体验上的问题，很久没怎么用，前两天把 paperlib 卸载了，曾经导入的 PDF 都归档在 GitHub 上 <a href="https://github.com/smallyunet/paperlib_backup.git">smallyunet&#x2F;paperlib_backup</a>，以后如果需要，应该可以用软件重新导入。</p><p>因为发现 <a href="https://www.zotero.org/">Zotero</a> 是一个类似 paperlib 但是功能比 paperlib 更加强大好用的工具，Zotero 是一家企业开发的，paperlib 纯粹就是个人在开发维护。Zotero 还可以一键公开自己的 <a href="https://www.zotero.org/smallyuz/library">library</a>。</p><p>另外这本《<a href="https://saifedean.com/tbs">The Bitcoin Stardard</a>》似乎很有名，我在网上买了盗版的纸质书，打算看一看。在 Apple Books 上这本书要 $29 左右，但是买盗版纸质书只需要 ¥29，挺划算的，估计是网上有公开的 PDF，店家自己打印出的书。</p><img src="8.png" width="40%"><p>比起在电脑或者平板屏幕上阅读，我还是更喜欢纸质文档，对眼睛和身体都好。要不是经济条件不允许，我都想买个打印机把要看的 PDF 都打印出来。</p>]]></content>
  </entry>
  <entry>
    <title>合订本： 博文 日期 观点 《 对区块链的理性认识 》 2019年11月 “区块链是骗局” 《 对区块链行业的见闻 》...</title>
    <link href="https://t.smallyu.net/#2024-45"/>
    <id>micro:2293147705</id>
    <published>2024-08-16T09:17:11Z</published>
    <updated>2024-08-16T13:06:32Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>合订本： 博文 日期 观点 《 对区块链的理性认识 》 2019年11月 “区块链是骗局” 《 对区块链行业的见闻 》 2022年11月 “未来属于以太坊” 《 为什么炒币不是一个好主意 》 2023年3月 “不要炒币” 《 炒币投资的小 tips 》 2024年5月 “不但要炒币，还要学技巧” 《 裸辞了 》 202...</p>]]></summary>
    <content type="html"><![CDATA[<p>合订本： </p>
<table>
<thead>
<tr>
<th>博文</th>
<th>日期</th>
<th>观点</th>
</tr>
</thead>
<tbody><tr>
<td>《<a href="https://smallyu.net/2019/11/05/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E7%9A%84%E7%90%86%E6%80%A7%E8%AE%A4%E8%AF%86/">对区块链的理性认识</a>》</td>
<td>2019年11月</td>
<td>“区块链是骗局”</td>
</tr>
<tr>
<td>《<a href="https://smallyu.net/2022/11/15/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E8%A1%8C%E4%B8%9A%E7%9A%84%E8%A7%81%E9%97%BB/">对区块链行业的见闻</a>》</td>
<td>2022年11月</td>
<td>“未来属于以太坊”</td>
</tr>
<tr>
<td>《<a href="https://smallyu.net/2023/03/15/%E4%B8%BA%E4%BB%80%E4%B9%88%E7%82%92%E5%B8%81%E4%B8%8D%E6%98%AF%E4%B8%80%E4%B8%AA%E5%A5%BD%E4%B8%BB%E6%84%8F/">为什么炒币不是一个好主意</a>》</td>
<td>2023年3月</td>
<td>“不要炒币”</td>
</tr>
<tr>
<td>《<a href="https://smallyu.net/2024/05/04/%E7%82%92%E5%B8%81%E6%8A%95%E8%B5%84%E7%9A%84%E5%B0%8F-tips/">炒币投资的小 tips</a>》</td>
<td>2024年5月</td>
<td>“不但要炒币，还要学技巧”</td>
</tr>
<tr>
<td>《<a href="https://smallyu.net/2024/07/28/%E8%A3%B8%E8%BE%9E%E4%BA%86/">裸辞了</a>》</td>
<td>2024年7月</td>
<td>“比特币是唯一的王”</td>
</tr>
</tbody></table>
]]></content>
  </entry>
  <entry>
    <title>最早注意到 33357.xyz 这个博客是因为其中有一篇文章《 不受单个矿工控制的链上随机数生成方法 》，我之前写过类似...</title>
    <link href="https://t.smallyu.net/#2024-44"/>
    <id>micro:2282191724</id>
    <published>2024-08-10T15:49:42Z</published>
    <updated>2024-08-10T15:49:42Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最早注意到 33357.xyz 这个博客是因为其中有一篇文章《 不受单个矿工控制的链上随机数生成方法 》，我之前写过类似的《 一种在区块链上生成随机数的机制 》，其实基本思路非常相似，都是用“未来的块”来生成随机数。 想稍微吐槽一下的是，也许在合约开发者眼里，容易忽略合约是需要调用的，等待 256 个块还不是最大的灾难...</p>]]></summary>
    <content type="html"><![CDATA[<p>最早注意到 <a href="https://33357.xyz/">33357.xyz</a> 这个博客是因为其中有一篇文章《<a href="https://github.com/33357/smartcontract-apps/blob/main/Solidity/Other/random.md">不受单个矿工控制的链上随机数生成方法</a>》，我之前写过类似的《<a href="https://smallyu.net/2023/02/22/%E4%B8%80%E7%A7%8D%E5%9C%A8%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%8A%E7%94%9F%E6%88%90%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%9A%84%E6%9C%BA%E5%88%B6/">一种在区块链上生成随机数的机制</a>》，其实基本思路非常相似，都是用“未来的块”来生成随机数。</p>
<p>想稍微吐槽一下的是，也许在合约开发者眼里，容易忽略合约是需要调用的，等待 256 个块还不是最大的灾难，而是需要 256 笔交易。矿工、合约、交易是三个概念，而且不是所有区块链都有智能合约，这就是合约开发的局限性。</p>
]]></content>
  </entry>
  <entry>
    <title>2024年已经出现了至少 5 次 “币圈519事件”，经过这几轮的洗礼和教训，我得出的投资原则是： 不加杠杆，不开合约，...</title>
    <link href="https://t.smallyu.net/#2024-43"/>
    <id>micro:2268986475</id>
    <published>2024-08-05T12:43:37Z</published>
    <updated>2024-08-05T12:43:37Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>2024年已经出现了至少 5 次 “币圈519事件”，经过这几轮的洗礼和教训，我得出的投资原则是： 不加杠杆，不开合约，不借贷 只买BTC 坚持这两条，可能少赚，但不会多亏……</p>]]></summary>
    <content type="html"><![CDATA[<p>2024年已经出现了至少 5 次 “币圈519事件”，经过这几轮的洗礼和教训，我得出的投资原则是：</p>
<ol>
<li>不加杠杆，不开合约，不借贷</li>
<li>只买BTC</li>
</ol>
<p>坚持这两条，可能少赚，但不会多亏……</p>
]]></content>
  </entry>
  <entry>
    <title>回忆在大学上培训班的经历</title>
    <link href="https://b.smallyu.net/2024/08/04/%E5%9B%9E%E5%BF%86%E5%9C%A8%E5%A4%A7%E5%AD%A6%E4%B8%8A%E5%9F%B9%E8%AE%AD%E7%8F%AD%E7%9A%84%E7%BB%8F%E5%8E%86/"/>
    <id>blog-b:https://b.smallyu.net/2024/08/04/%E5%9B%9E%E5%BF%86%E5%9C%A8%E5%A4%A7%E5%AD%A6%E4%B8%8A%E5%9F%B9%E8%AE%AD%E7%8F%AD%E7%9A%84%E7%BB%8F%E5%8E%86/</id>
    <published>2024-08-03T19:08:54.000Z</published>
    <updated>2026-03-02T09:09:31.194Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>由于喝了咖啡大脑过度兴奋，无意间想起这个话题。刚才提到关于 <a href="/micro-blog/#2024-42">网页样式</a> 的问题，包括 V2EX 的网页在 iPad mini 5 竖屏尺寸下显示非常糟糕，以及想起来我现在的公司有一个]]></summary>
    <content type="html"><![CDATA[<p>由于喝了咖啡大脑过度兴奋，无意间想起这个话题。刚才提到关于 <a href="/micro-blog/#2024-42">网页样式</a> 的问题，包括 V2EX 的网页在 iPad mini 5 竖屏尺寸下显示非常糟糕，以及想起来我现在的公司有一个 blog，样式很简陋，我曾经直接提到其中非常明显的样式错误，但是一直没有被解决。因为我有博客，平时也很注重博客样式的优化，虽然整体是 copy 王垠的博客样式，但细节上做了一些改善，如果博客中出现明显的样式问题我是不能忍受、会迫不及待改正的。所以我猜测虽然某些样式错误在我看来是一两行代码就能解决的问题，但是对于没有相关经验的人，可能觉得有难度，所以迟迟没有去解决。</p><p>这个道理可能类似于，乔布斯曾经有从事印刷行业的经历，所以在苹果设备上非常注重字体显示的美观，苹果电脑自己设计了效果更好的字体，而不是使用微软的字体。其实从我们非专业用户的角度看，字体不一样甚至都看不出来他们不一样，但是在专业人士眼里，人家就非常在意。</p><p>那么回到网页样式的问题，我就想，我关于网页样式的经验是从哪里来的呢？我实实在在的掌握原生 HTML 标签和 CSS 样式，这些经历似乎已经非常久远，追溯到很久以前……再就是今天看到 V2EX 上有一偏帖子《<a href="https://www.v2ex.com/t/1062263#reply63">学习困难户工作 9 年依然很菜。大家有木有什么建议</a>》，从帖子中的描述来看有一种 “菜的熟悉” 的感觉，似曾相识，像是大学班上的妹子在问我问题，他们都有一些共性，听起来是靠死记硬背在学习编程，也由此想到我之前经过了漫长的学习和动手折腾代码的过程……</p><p>我一直觉得上过培训班是一种耻辱的经历，所以一直不想提。但是现在已经过了很多很多年，而且我的培训班是在大学在校期间参加的，和那种毕业之后找不到工作、为了找一份程序员的工作而目的性很强特训几个月的情况不太一样。毕业之后再培训的，一方面不是出于兴趣在学，技术一般都很差，另一方面培训班为了让他们能找到工作，会教他们面试和简历造假，给参加过培训班的整个群体都留下不好的印象。（实际上我参加的培训班，和我一个班的同学水平也都很差。</p><p>我参加的培训班属于学校认可的 3+1 模式，也就是前 3 年校内正常上课，第 4 年上校外的培训课，不需要上学校的课了，能正常拿学分毕业。当然要交培训班的培训费，每个人 1 万 8 千元人民币（校内领导肯定拿了回扣）。在培训班给我们上课的老师就是我们学校计算机系的正经老师，所以课程内容上问题不大，只是更加侧重动手敲代码而不是理论。我本身不是计算机专业，加上对编程很感兴趣，就选择了这种方式。</p><p>在确切的时间点上，我们从大三下半学期就开始，每周末坐一个多小时的公交车去校外上课，然后大四上半学期每天上课，相当于在培训班学习整整一年的时间。大四下半学期我就到北京实习开始工作了。培训班的课程主要涵盖 HTML、CSS、Javascript、Oracle、Java、Java Web 等基础技术，而这段学习过程中，最重要的不是课程的内容而是学习的经历。印象最深的一次是我下午在宿舍看视频敲代码，舍友准备去上课了，等他下课回来惊讶的说，你坐在这里一下午都没动吗？他说的时候我才意识到，已经不知不觉过了好几个小时。</p><p>我翻了一下仓库竟然保留了当时的一些学习的记录，在 <a href="https://github.com/smallyunet/Java1006/tree/main">Java1006</a> 和 <a href="https://github.com/smallyunet/java1008">Java1008</a> 里。记得之前在学习 Vue.js 的时候跟着教程一步一步做出了一个像样的电商 APP，学习 React.js 的时候也做出了一个聊天 APP，可惜不知道当时怎么想的，觉得也没什么技术含量，不应该留在我的仓库上，当时认为我以后一定会写出更有价值的、自己开发的代码……所以就删掉了，后来想找也找不回来。 现在来看其实是一种有价值的学习记录，这件事情也给我个教训，不能轻易删除自己在网络上的内容，即使现在不想要，也许日后有一天需要。所以我的博客内容只要写了就不会删掉。</p><p>培训班的内容也不是什么都好，比如很扯淡的事情是，一进去的时候就让我们练打字，用金山打字通，还比谁打字快，而且<a href="https://github.com/smallyunet/Java1006/blob/main/TypingSpeed/2018.03/README.md">每天都要来一遍</a>。当然我的打字速度每次都是第一名，虽然现在看来这种事情很可笑。</p><p>培训班的课程其实也简单，关于 HTML、CSS、Javascript 的部分，我在上课之前就会了。我早就自学过 <a href="http://old-blog.smallyu.net/indexadbc.html?id=56">PHP 和 MySQL</a>，还跟着教程实现过 HTML 版本的 <a href="https://old-blog.smallyu.net/indexfddb.html?id=52">音乐可视化</a>。培训班方面，上完课后有一个 <a href="https://github.com/smallyunet/Java1006/blob/main/CSS/Templates/README.md">仿站</a> 的作业，就是老师找几个网站，学生手敲 HTML 和 CSS 模仿个一模一样的网站出来，我当时模仿出来的两个网页还有保留 <a href="https://smallyunet.github.io/Java1006/CSS/Templates/demo1/">网页1</a> 和 <a href="https://smallyunet.github.io/Java1006/CSS/Templates/demo2/">网页2</a>。</p><p>其实培训班对我来说最有帮助的是 Java 部分，我们专业是没有 Java 这门课的（有微机、电路啥的），但是培训班的经历让我实实在在把 Java 学了一遍，给我们上课的就是计算机系的老师。每天上完课都需要做一些 <a href="https://github.com/smallyunet/Java1008/blob/main/CoreJava/README.md">练习作业</a>，我还写了简单的 <a href="https://www.yuque.com/smallyu/usualroad/java-language-foundation">学习笔记</a>。虽然我已经很久不写 Java 了，但是面向对象的思想算是正经学过，Java 这个语言也实际学过，也在工作中用过一年左右。相反虽然我后来用 Go 语言作为工作语言，但其实没有正经学过。</p><p>除了在培训班的学习经历，还有一部分重要的就是自学的经历，主要用 <a href="https://www.imooc.com/">慕课网</a> 看网课、跟着视频里敲代码，具体内容就比较杂了，想学什么学什么。有一个数字是，在慕课网的学习时间是 650 个小时，也就是视频播放时长是 650 个小时，我现在回头来看觉得这是一个挺大的数字。当然这是好多年前的记录，我工作之后就不需要慕课网这种教程了。</p><img src="mooc.png" style="width:100%;" /><p>总的来看，在培训班的学习加上自学，是有不少代码经验的，所以在实际写代码方面我不太担心自己达不到 “合格的程序员” 的水平，不过在计算机理论和算法方面其实有很多欠缺，比如我至今分不清堆和栈，面试中被问到变量被具体分配到哪里这种问题，我都是直接说不会，然后面试官看一眼专业，哦，不是计算机，明白了。主要是我在工作中还从来没遇到过，有什么工作是需要了解这些才能够完成的。也许我将来会出于感兴趣补一补课，但肯定不会是为了面试。</p><p>算法方面，我很久之前也试着刷一刷 <a href="https://leetcode.cn/u/smallyu/">Leedcode</a>，但我的刷法其实没有用，刷了一大堆简单题。一方面是避免一开始有太多挫败感，找找感觉，另一方面是在上班也不太有大量时间去想着做有难度的题。这方面也是个不小的欠缺吧。</p><img src="leetcode.png" width="50%" /><p>天亮了，去睡觉了。</p>]]></content>
  </entry>
  <entry>
    <title>网页的样式既重要也不重要，既简单也不简单，简洁和简陋也是两码事。比如 V2EX 的网页在 iPad mini 5 竖屏的...</title>
    <link href="https://t.smallyu.net/#2024-42"/>
    <id>micro:2267091294</id>
    <published>2024-08-03T18:12:24Z</published>
    <updated>2024-08-03T18:12:24Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>网页的样式既重要也不重要，既简单也不简单，简洁和简陋也是两码事。比如 V2EX 的网页在 iPad mini 5 竖屏的尺寸下显示非常糟糕，比如王垠的博客在任何移动设备尺寸下显示都很糟糕。 这个博客的样式模仿自王垠的博客，但是细节上经过了很多细致的调整，至少移动设备上看起来良好。</p>]]></summary>
    <content type="html"><![CDATA[<p>网页的样式既重要也不重要，既简单也不简单，简洁和简陋也是两码事。比如 V2EX 的网页在 iPad mini 5 竖屏的尺寸下显示非常糟糕，比如王垠的博客在任何移动设备尺寸下显示都很糟糕。</p>
<p>这个博客的样式模仿自王垠的博客，但是细节上经过了很多细致的调整，至少移动设备上看起来良好。</p>
]]></content>
  </entry>
  <entry>
    <title>一直由于 Cosmos 用了 BFT 类共识觉得 Cosmos 属于落后的技术，虽然 CometBFT 中有关于质押的内...</title>
    <link href="https://t.smallyu.net/#2024-41"/>
    <id>micro:2264724325</id>
    <published>2024-08-02T07:12:42Z</published>
    <updated>2024-08-02T07:12:42Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>一直由于 Cosmos 用了 BFT 类共识觉得 Cosmos 属于落后的技术，虽然 CometBFT 中有关于质押的内容，但仍然落后……受限于 BFT，它的整个网络不可能很“大”。</p>]]></summary>
    <content type="html"><![CDATA[<p>一直由于 Cosmos 用了 BFT 类共识觉得 Cosmos 属于落后的技术，虽然 CometBFT 中有关于质押的内容，但仍然落后……受限于 BFT，它的整个网络不可能很“大”。</p>
]]></content>
  </entry>
  <entry>
    <title>某海外公司HR：我们公司属于初创阶段，处于快速发展期，节奏快，可能工作压力有时比较大，也可能偶尔需要加班…… 我：我每天...</title>
    <link href="https://t.smallyu.net/#2024-40"/>
    <id>micro:2261995058</id>
    <published>2024-08-01T04:27:27Z</published>
    <updated>2024-08-01T04:27:27Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>某海外公司HR：我们公司属于初创阶段，处于快速发展期，节奏快，可能工作压力有时比较大，也可能偶尔需要加班…… 我：我每天 9 点下班 HR：啊？你们要工作那么久啊？</p>]]></summary>
    <content type="html"><![CDATA[<p>某海外公司HR：我们公司属于初创阶段，处于快速发展期，节奏快，可能工作压力有时比较大，也可能偶尔需要加班……</p>
<p>我：我每天 9 点下班</p>
<p>HR：啊？你们要工作那么久啊？</p>
]]></content>
  </entry>
  <entry>
    <title>裸辞了</title>
    <link href="https://b.smallyu.net/2024/07/28/%E8%A3%B8%E8%BE%9E%E4%BA%86/"/>
    <id>blog-b:https://b.smallyu.net/2024/07/28/%E8%A3%B8%E8%BE%9E%E4%BA%86/</id>
    <published>2024-07-28T07:20:46.000Z</published>
    <updated>2025-12-03T09:25:54.153Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>前几天我已经正式提出离职，再经过一段时间的交接，就能够离开这份自工作以来感觉最痛苦的工作了。去年的勇者故事中，我给自己定下的基调是 <a]]></summary>
    <content type="html"><![CDATA[<p>前几天我已经正式提出离职，再经过一段时间的交接，就能够离开这份自工作以来感觉最痛苦的工作了。去年的勇者故事中，我给自己定下的基调是 <a href="/2023/10/03/%E6%B5%B7%E8%B4%BC/">海贼</a>，因为海贼是隐忍的，可以被关进推进城大牢后放出来仍然是正义的侠客，也可以在邪恶海贼船上做苦工而仍然拥有梦想。所以虽然离职的想法从形成到提出在一周内，但其实这份痛苦由来已久……</p><p>我本以为那是成年人挣钱本应该承受的痛苦，直到有一天突然不想继续下去了。谁会跟钱过不去呢，而且是那么多钱。但是换个角度想象一下，宁愿挣不到钱也不愿意再忍受的工作是什么样子呢？没有单一的原因会引起这样的结果，但我没办法把所有原因都写下来，只能挑一些冠冕堂皇的东西说。</p><h3 id="为什么要离职"><a href="#为什么要离职" class="headerlink" title="为什么要离职"></a>为什么要离职</h3><h4 id="远程工作"><a href="#远程工作" class="headerlink" title="远程工作"></a>远程工作</h4><p>在远程工作的形式下需要全程开摄像头，估计只有 Bitget 那种不尊重员工的公司才会采取这样的制度。如果工作有鄙视链的话，不打卡的公司会鄙视打卡的公司，打卡的公司会鄙视监控员工的公司，监控员工的公司会鄙视不能联网的外包公司，等等。需要开摄像头的公司一定处于鄙视链的下端，因为这种制度体现出对员工的不信任以及工厂式的作派，“你应该完成具体的任务而不是帮助团队承担更关键的事情”，就是这种制度表现出来的潜台词。以保证员工工作时长来保证工作进度的公司，同时还接受远程工作的形式，逻辑上是扭曲的。（我知道这不是我公司的本意，但是这样的形式会给人这样的感觉）</p><p>需要强调的是，我并非不能理解和接受这样的工作制度，相反我已经在这样的模式下工作了一年，如果下一份工作仍然是这样的制度，我也会坦然接受。说出这些内容只是因为我知道，这不是最好的，从一开始就知道。</p><p>我相信国内的大多数公司都不具备针对远程工作的管理能力，一方面相关经验和文化少，另一方面对管理者的要求高。比如左耳朵耗子成立的 MegaEase 就是远程工作的形式，他还写过博客来介绍《<a href="https://coolshell.cn/articles/20765.html">MegaEase 的远程工作文化</a>》，但也就左耳朵耗子那么知名且经验丰富的人，才能搞定这样的事情。另外令人可惜的一点是，左耳朵耗子已经因为心梗离世，也应该给我们带来深深思考，到底是“厉害”重要，还是活的久重要？</p><h4 id="早会"><a href="#早会" class="headerlink" title="早会"></a>早会</h4><p>早会会给人带来巨大的心理压力，尤其是远程工作的情况下，你需要为了证明你没有偷懒而做足够多的事情。当工作比较多的时候心态相对轻松，工作比较少的时候反而压力更大，因为没话可说。即使工作繁忙的时候，也经常面临的情况是不可能事情到一天下班结束的时候，恰好就到某一个关键节点用于汇报，只能赶赶进度到关键点上，这样会带来额外的压力。凡是工作过的人，只要提到早会这个词就应该明白什么意思，不用多描述了。</p><h4 id="工作时间"><a href="#工作时间" class="headerlink" title="工作时间"></a>工作时间</h4><p>目前在工作时间上属于常态化加班，9 点下班。习惯于加班的打工人可能觉得这不算什么，像 OKX 也是 9 点正常下班，很多部门 11 点才逐渐走完。不过对于远程工作来说多了一层压力，就是摸鱼没有意义，干了多少事情就是多少事情，而且有早会，我本身也不是很喜欢偷懒，就导致我每天是真的在加班工作。感觉心态上坐班更加轻松，只要人在公司，就属于在上班。远程工作的信任情况会稍差一点，我记得刚入职的时候也被问到过最近在干什么，可我似乎只是半天没有发消息。</p><p>据我所知国内没有游戏公司不加班的，有些公司加班到更晚，也许这属于业界常态。不过单就工作内容来说，我没遇到过有什么工作非得常态化加班才能完成的，能想到的理由要么是让老板觉得钱花的值，自己的员工在加班干活，占了便宜，要么就是员工自己想表现，毕竟国内的工作环境，这种想表现的心情再理解不过了，互联网大厂也都是常态化加班，而且大小周或单休的。</p><p>再次强调一下我并非不能接受这样的工作时长，我已经这样工作了一年，单纯想吐槽一下。希望所有 web3 行业的员工，都可以去了解一下币圈曾经暴富的人以及他们的生活状态，了解一下财富自由之后的生活是怎么样，以及他们获得如此多财富是不是因为加班得到的。</p><h4 id="成就感"><a href="#成就感" class="headerlink" title="成就感"></a>成就感</h4><p>这一年来这个博客很少有技术方面的内容更新，一方面因为工作时间长，没有多余的时间和精力去了解其他东西。另一方面，难道长时间的工作中没有什么可以拿来分享的吗？还真没有。我做的大多数工作是拿一些现成的开源软件来部署，同时也需要在部署过程中了解清楚相关的技术，了解清楚也是为了能部署明白。总的来说我干了什么呢，其实啥也没干，开源软件用到的技术再好也跟我没关系，再差也跟我没关系，又不是我开发的，我只是使用它而已。文档写得好我用起来就顺畅，文档写得不好用起来就坎坎坷坷，但好不好用关我什么事？</p><p>假如说我需要通过权衡对比同类型的各种技术，通过了解试用分析后得到结论，哪个好哪个不好，最终决定去选择使用哪个，这样的过程其实也是有趣的，而且不需要有权力下决定，光是能提供参考意见也行，但事实上连这样的机会都没有。我面对的工作是一条非常明确的路径，动机明确结果明确，只需要把过程走通就可以。整个过程中没有任何成就感。</p><p>好比你是一个程序员，有一个开发任务，你的上级非常清晰的告诉你要改哪个文件的哪个函数，预期得到什么样的结果，你的任务就是实际操作一下，给你多长时间，越快越好，是不是会很无聊，而且还有压力，什么叫越快越好。事实上程序员的工作是有自由发挥余地的，产品经理说一个需求，至于这个需求对应要改哪个函数，用递归还是用迭代，随你高兴，程序员的小乐趣也在于此，有空间自己去实现一些东西，有一种创造的快乐。会有人 review 也是查缺补漏性质的，根据规范提出让代码更好的建议。</p><h3 id="关于钱"><a href="#关于钱" class="headerlink" title="关于钱"></a>关于钱</h3><p>在选择离职的原因中，唯一能排除的就是工资方面的原因，现在的工资对我来说很好了，估计再找工作也不会找到这样工资的工作。</p><p>关于钱的问题，我相信的一点是，老板花钱，是他有某些想法让你来帮他实现，所以他才花钱雇人做事，所以在工作中我几乎不会提反对意见，大多数情况属于不理解但尊重，事情该怎么做就怎么做，这样的例子不少。而且我面对的也大多是现成的任务，没什么提意见的空间。</p><p>同样是关于花钱，我想起一件事。在我入职现在的公司之前，也就是我的上家公司，我在里面工作了两个星期，然后离职了，我去年还隐晦的写了《<a href="/2023/10/04/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AF%94%E7%89%B9%E5%B8%81%E4%B8%8D%E7%94%A8%E6%A6%82%E7%8E%87%E5%8A%A0%E5%AF%86%E5%87%BD%E6%95%B0/">为什么比特币不用概率加密函数</a>》来表达对那家公司的不满。由于签了保密协议，我没注意保密协议有没有时间限制，总之我到现在也没办法具体说出那个项目的核心技术，不然我很有兴趣写出来让别人感受一下那个项目的不靠谱程度。</p><p>我当时提离职的时候，老板提议因为他的项目得继续做下去，想让我周末用半天时间，以兼职的形式来工作。我拒绝了，主要原因有两个，一个是我离职的时候，因为只工作了两个星期，工资算起来比较简单，他直接转账给我。但就是两个星期的工资，他都是按 30 天工作日来算，结果是少于我的预期的。我当时没说什么，我也确实不在乎那点钱，也许他觉得自己占到了便宜吧，还挺开心的。我当时更担心的是在离职程序上影响到我入职现在的公司。但就这种小事上能体现出来他的人品，我怎么可能继续兼职给他干活。</p><p>另外一个更加重要的原因是，他做这个项目的时候，他的合伙人不愿意和他一起，而是找了个工作去上班了。他一直不理解，明明之前的项目他们一起挣了很多钱，现在这个项目也有可能挣钱，为什么他的合伙人不愿意跟他一起。当时我拒绝兼职的时候，我也反复说不是钱的问题，他似乎恍然大悟一样说有点明白为什么他的合伙人不和他一起做这个项目了。其实我当时也似懂非懂，我也好奇到底为什么，虽然我说不是钱的问题，但具体是什么问题呢？时隔一年，我想我得到了比较明确的答案。</p><p>关于花钱这事，你可以通过花钱买到劳动力，买到别人的时间、精力，让别人给你工作、给你干活，但是花钱并不能让别人认可你，认可你的项目、认可你的公司、认可你的选择、认可你的战略方向。</p><h3 id="为什么选择裸辞"><a href="#为什么选择裸辞" class="headerlink" title="为什么选择裸辞"></a>为什么选择裸辞</h3><p>我知道目前国内经济形势不好这一点，也看到不止一次有人发帖劝告能忍就忍，现在工作不好找之类，我也清楚现在几乎没有 web3 类型的工作，岗位比去年找工作的时候还要少。我的意思是，我在了解这些信息的情况下，仍然选择离职，而且是裸辞。</p><h4 id="为什么不先找好下家？"><a href="#为什么不先找好下家？" class="headerlink" title="为什么不先找好下家？"></a>为什么不先找好下家？</h4><p>因为没有时间和精力。现在的工作要是轻松到有空闲时间和心情找工作，我也就不离职了。</p><p>其实时间是其次，主要是心情。自从来了这家公司，我才开始跟朋友抱怨 “不想上班”，这在我之前的工作中是非常少见的。我第一次觉得上班是痛苦的，周末都在担心 “明天又要上班了”，真正理解了打工人的四大精神支柱 “等下班、等周五、等工资、等快递”，这样的心情不知道从什么时候开始。始终有一座大山一样的压力在心上，我甚至搞不清楚这种压力的来源是什么。我想只有离职才能不再承受这样的压力吧。</p><p>我跟朋友甚至父母提起有工作压力想辞职的时候，他们的第一反应往往是谁工作没有压力啊，谁挣钱不承受点压力啊？再找工作难道就没有压力了吗？我想了想，我确实受不了了，我要离职，不管以后的工作好不好。</p><h4 id="为什么敢裸辞？"><a href="#为什么敢裸辞？" class="headerlink" title="为什么敢裸辞？"></a>为什么敢裸辞？</h4><p>经济方面的损失对于裸辞来说是重点考虑且让人犹豫的，毕竟大家工作就是为了挣钱，如果不考虑钱大家直接不上班了。因为需要钱才上班，而裸辞就意味着损失了钱。</p><p>从更大一点的视角来看，在一个经济下行的国家，web3 行业被禁止的状态下，有一份工资还不错的工作，工作内容虽然不完全理想但至少属于 web3 行业，只不过是工作压力稍大一点，起码能保证双休，你不应该咬咬牙坚持下去多挣几年钱吗？现在的钱多难挣，很多人想工作都没机会。哪怕将就一下，多熬一天就能多挣一天的钱。</p><p>但是换个角度想，在世界第二大经济体的国家，位于一线城市的年轻人，没有车贷房贷没有家庭需要养，存款够生活 3 个月以上，工作压力大到让自己极度不开心，难道不可以去寻找一份自己喜欢的工作，去追求自己向往的世界吗？如果现在就开始将就，将就一年？十年？假如坚持了五十年挣了很多钱，但是这半辈子都在不开心中度过，而且人已经老了，攒那么多钱又有什么意义？</p><p>挣钱是为了什么？为了开心，无论是让自己开心还是让别人开心。有些人挣钱本身就会感到开心，看着自己的余额在增加就开心，这样的人钱是一定有地方花的。还有些人挣钱是为了让别人开心，可以给自己的孩子买更好的玩具，让家人开心。反正我的钱攒下也没地方花，挣钱的过程是不开心的，挣完了钱结果也是不开心的，我的净资产是 0.1 BTC 还是 0.2 BTC 有区别吗？不过是个数字而已。</p><p>什么最重要，开心最重要，身体健康最重要，身体不健康人就会不开心，所以最终还是开心最重要。</p><h4 id="吸取教训"><a href="#吸取教训" class="headerlink" title="吸取教训"></a>吸取教训</h4><p>还有一个裸辞的小原因，是集卡式的。我一共在 4 家公司工作过：</p><ul><li>第一家（找好下家，主动离职）</li><li>第二家（被裁员）</li><li>第三家（找好下家，主动离职）</li><li>第四家（裸辞）</li></ul><p>人生本就是体验的过程，我正好可以体验一下裸辞的感觉。如果这次的裸辞能让我长记性，明白裸辞后找不到工作会让人心态奔溃，陷入深深的自我怀疑之中，裸辞后也会给自己带来巨大的经济损失，等等。</p><p>如果从这次裸辞能吸取到教训，自这次之后再也不敢了，也算是一种收获。就像炒币一样，只有实实在在亏过钱，才知道什么能买什么不能买。</p><p>其实炒币属于低俗的话题，但是这个博客上最近的一些内容却频繁提到。如果有人现在问我如何进入 web3 行业，如何学习区块链技术，我的第一回答一定是，先学一学炒币。重点不是学怎么开 100 倍杠杆的合约，而是知道什么能买什么不能买，为什么可以买为什么不可以买，去理解每一种币背后的项目，项目方是谁，项目规模多大，用了什么技术，有哪些关键的历史节点，为什么可以有目前的成就，有哪些欠缺，为什么无法超越同类型的项目，是否有更大的潜力，等等。</p><h3 id="裸辞后干什么"><a href="#裸辞后干什么" class="headerlink" title="裸辞后干什么"></a>裸辞后干什么</h3><p>对于裸辞后找工作的进度，我预期是 3 个月左右。不指望 3 个月以内能找到，也不要因为 3 个月没找到而慌张，这是初步给自己留下的空间，想焦虑就 3 个月以后再开始焦虑。</p><p>由于在工作时对时间的欠缺，我相信在没找到工作的日子里，也有不少可以做的事情，比如：</p><ul><li>休息一下，健康最重要，开心最重要</li><li>复习一下 Go 语言以及其他编程语言，最近的工作实在是让这方面能力有点荒废</li><li>提高一下英语，我一年前就买了《<a href="https://coolshell.cn/articles/9156.html">rework</a>》的实体书，但是以我的词汇量其实看不懂，这种书的用词都比普通的技术文档难，我到现在也看不懂</li><li>人只有闲下来之后才会找一些自己感兴趣的东西看，比如：<ul><li>在 YouTube 上收藏了上百个频道但是都没怎么看</li><li>之前想了解清楚 Cardano 的 PoS 进化了 3 次，具体都有哪些变化，但是东西有点多懒得看</li><li>搞清楚 PoW 和 PoS 的区别，为什么 PoS 在 Bitcoiner 眼里属于 <a href="https://github.com/libbitcoin/libbitcoin-system/wiki/Shitcoin-Definition">Shitcoin</a>。表面上的区别肯定知道，本质上的区别隐隐有感觉但是差点什么</li><li>更多了解一下比特币的技术，BTC 是唯一的王</li><li>了解一下其他小币种，比如 Peercoin 经过了十年后还在<a href="https://talk.peercoin.net/t/fundraising-for-bittrex-replacement-exchange/16199">筹集上币费</a>准备上交易所</li><li>以及其他……</li></ul></li></ul><h3 id="补充（2024-09-30）"><a href="#补充（2024-09-30）" class="headerlink" title="补充（2024.09.30）"></a>补充（2024.09.30）</h3><p>最近在外旅行，无意间翻到了写于 2023年11月22日的一篇 note，记录了当时对 “没时间写博客” 这个问题的反思，侧面印证了对这份工作确实早有怨言：</p><img src="1.png" width="60%">]]></content>
  </entry>
  <entry>
    <title>“李老师的币千万不能买，李老师的书必须看”，造成这种现象背后的原因是什么？ 一是说明了成功不可能复制，一个有钱人即使他很...</title>
    <link href="https://t.smallyu.net/#2024-39"/>
    <id>micro:2240935007</id>
    <published>2024-07-20T05:39:57Z</published>
    <updated>2024-07-20T05:39:57Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“李老师的币千万不能买，李老师的书必须看”，造成这种现象背后的原因是什么？ 一是说明了成功不可能复制，一个有钱人即使他很乐意教会你如何挣钱，你也学不会。 二是李笑来本人不是赌徒，他说的更多是当你有钱以后，如何掌握财富，不乱操作，而不能教会你如何获得财富。他书里强调“增加场外赚钱的能力”，就属于非常无聊的观点了，能场外赚...</p>]]></summary>
    <content type="html"><![CDATA[<p>“李老师的币千万不能买，李老师的书必须看”，造成这种现象背后的原因是什么？</p>
<p>一是说明了成功不可能复制，一个有钱人即使他很乐意教会你如何挣钱，你也学不会。</p>
<p>二是李笑来本人不是赌徒，他说的更多是当你有钱以后，如何掌握财富，不乱操作，而不能教会你如何获得财富。他书里强调“增加场外赚钱的能力”，就属于非常无聊的观点了，能场外赚钱谁愿意赌啊？</p>
]]></content>
  </entry>
  <entry>
    <title>To be what you want to be.</title>
    <link href="https://t.smallyu.net/#2024-38"/>
    <id>micro:2230628784</id>
    <published>2024-07-16T11:09:36Z</published>
    <updated>2024-07-16T11:09:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>To be what you want to be.</p>]]></summary>
    <content type="html"><![CDATA[<p>To be what you want to be.</p>
]]></content>
  </entry>
  <entry>
    <title>ADA 是学术性的产物，设计上经得起研究、值得学习，比如用了 UTXO 和最长链原则之类，但也有一些不流行的原因，比如用...</title>
    <link href="https://t.smallyu.net/#2024-37"/>
    <id>micro:2227392693</id>
    <published>2024-07-14T15:49:01Z</published>
    <updated>2024-07-14T15:49:01Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>ADA 是学术性的产物，设计上经得起研究、值得学习，比如用了 UTXO 和最长链原则之类，但也有一些不流行的原因，比如用 Haskell 开发、运营能力差、生态差，光是钱包就很难用，黑客松也很少，以及其他营销手段… AVAX 其实也不错…但是也非常少见有新闻…</p>]]></summary>
    <content type="html"><![CDATA[<p>ADA 是学术性的产物，设计上经得起研究、值得学习，比如用了 UTXO 和最长链原则之类，但也有一些不流行的原因，比如用 Haskell 开发、运营能力差、生态差，光是钱包就很难用，黑客松也很少，以及其他营销手段…</p>
<p>AVAX 其实也不错…但是也非常少见有新闻…</p>
]]></content>
  </entry>
  <entry>
    <title>PoS 也搞递减的块奖励机制不行吗？也行的，ADA 就有固定供应量，而且先于 ETH 用上了“真正的” PoS。 所以块...</title>
    <link href="https://t.smallyu.net/#2024-36"/>
    <id>micro:2227368366</id>
    <published>2024-07-14T14:27:07Z</published>
    <updated>2024-07-14T14:48:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>PoS 也搞递减的块奖励机制不行吗？也行的，ADA 就有固定供应量，而且先于 ETH 用上了“真正的” PoS。 所以块奖励减少并不会让 PoS 网络崩溃，怎么分配全看链怎么设计。Vitalik 从中国学了不少东西😏</p>]]></summary>
    <content type="html"><![CDATA[<p>PoS 也搞递减的块奖励机制不行吗？也行的，ADA 就有固定供应量，而且先于 ETH 用上了“真正的” PoS。</p>
<p>所以块奖励减少并不会让 PoS 网络崩溃，怎么分配全看链怎么设计。Vitalik 从中国学了不少东西😏</p>
]]></content>
  </entry>
  <entry>
    <title>无限供应量的无限就无限在，给矿工的块奖励是无限的，ETH 无限保证了矿工的利益，只要继续参与，就给 3%。至于总供应量，...</title>
    <link href="https://t.smallyu.net/#2024-35"/>
    <id>micro:2227363437</id>
    <published>2024-07-14T14:11:32Z</published>
    <updated>2024-07-14T14:11:32Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>无限供应量的无限就无限在，给矿工的块奖励是无限的，ETH 无限保证了矿工的利益，只要继续参与，就给 3%。至于总供应量，就从交易者手里扣掉一部分，来维持稳定吧。 而且 PoS 的硬件成本忽略不计，既得利益者将永远享受固定收益率，没上车的只能通过买，而且是从矿工手里买。 PoW 则通过减半来逐渐削减矿工的收益。同样是买，...</p>]]></summary>
    <content type="html"><![CDATA[<p>无限供应量的无限就无限在，给矿工的块奖励是无限的，ETH 无限保证了矿工的利益，只要继续参与，就给 3%。至于总供应量，就从交易者手里扣掉一部分，来维持稳定吧。</p>
<p>而且 PoS 的硬件成本忽略不计，既得利益者将永远享受固定收益率，没上车的只能通过买，而且是从矿工手里买。</p>
<p>PoW 则通过减半来逐渐削减矿工的收益。同样是买，既得利益者手里的筹码越来越少。BTC 的矿工会不会在没有块奖励后全部撤离？bitcoin bro 有 100 年的时间来搞清楚这个问题。</p>
]]></content>
  </entry>
  <entry>
    <title>关于 ETH 最大供应量没有上限的问题，表面上因为 EIP-1559 的存在，总供应量增长非常缓慢，一年不到 1%。 目...</title>
    <link href="https://t.smallyu.net/#2024-34"/>
    <id>micro:2227189880</id>
    <published>2024-07-14T04:17:16Z</published>
    <updated>2024-07-14T04:17:16Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>关于 ETH 最大供应量没有上限的问题，表面上因为 EIP-1559 的存在，总供应量增长非常缓慢，一年不到 1%。 目前整个网络的质押率在 30% 左右，可以认为有 30% 的 miner 和 70% 的 trader。 EIP-1559 带来的影响是，为了维持总供应量，miner 在稳定保持年化 3% 收益不变的情...</p>]]></summary>
    <content type="html"><![CDATA[<p>关于 ETH 最大供应量没有上限的问题，表面上因为 EIP-1559 的存在，总供应量增长非常缓慢，一年不到 1%。</p>
<p>目前整个网络的质押率在 30% 左右，可以认为有 30% 的 miner 和 70% 的 trader。</p>
<p>EIP-1559 带来的影响是，为了维持总供应量，miner 在稳定保持年化 3% 收益不变的情况下，trader 的一部分手续费将会被烧掉，整体上总量不变，但实际上 70% 的 trader 在为 30% 的 miner 买单。</p>
<p>trader 烧掉的手续费，正是保持 miner 收益不下降的原因。看出这里面的荒唐之处了吗，富者更富。</p>
]]></content>
  </entry>
  <entry>
    <title>PoS 类共识不适合囤币的另一个原因是，所有 PoS 币都是没有发行量上限的，因为 PoS 需要靠不断的激励来维持运行。...</title>
    <link href="https://t.smallyu.net/#2024-33"/>
    <id>micro:2225039801</id>
    <published>2024-07-12T08:01:22Z</published>
    <updated>2024-07-12T08:01:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>PoS 类共识不适合囤币的另一个原因是，所有 PoS 币都是没有发行量上限的，因为 PoS 需要靠不断的激励来维持运行。增量比例少的像 ETH 每年 3%，多的像 DOT 每年 20%。 如果你持有币而没有去质押，你的资产价值天然每年缩水 3%。</p>]]></summary>
    <content type="html"><![CDATA[<p>PoS 类共识不适合囤币的另一个原因是，所有 PoS 币都是没有发行量上限的，因为 PoS 需要靠不断的激励来维持运行。增量比例少的像 ETH 每年 3%，多的像 DOT 每年 20%。</p>
<p>如果你持有币而没有去质押，你的资产价值天然每年缩水 3%。</p>
]]></content>
  </entry>
  <entry>
    <title>对于新玩家 “李笑来” 这个名字可能是传奇，属于历史人物，存在于故事之中，不过其实李笑来至今都活跃在互联网上，而且留下很...</title>
    <link href="https://t.smallyu.net/#2024-32"/>
    <id>micro:2220852028</id>
    <published>2024-07-10T15:37:25Z</published>
    <updated>2024-07-10T15:37:25Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>对于新玩家 “李笑来” 这个名字可能是传奇，属于历史人物，存在于故事之中，不过其实李笑来至今都活跃在互联网上，而且留下很多 “著作”，这本书《 韭菜的自我修养 》就非常有意思。 让人唏嘘的一点是，李笑来现在的年纪已经不小了，09 年就确诊糖尿病，“比特币首富” 这个名号对他来说并不是很重要，而且他的脑子很复杂，复杂到非...</p>]]></summary>
    <content type="html"><![CDATA[<p>对于新玩家 “李笑来” 这个名字可能是传奇，属于历史人物，存在于故事之中，不过其实李笑来至今都活跃在互联网上，而且留下很多 “著作”，这本书《<a href="https://github.com/xiaolai/the-self-cultivation-of-leeks/blob/master/The-Self-Cultivation-of-Leeks-cn.md#1-%E6%9D%8E%E7%AC%91%E6%9D%A5%E4%BB%8E%E6%9D%A5%E9%83%BD%E4%B8%8D%E6%98%AF%E6%AF%94%E7%89%B9%E5%B8%81%E9%A6%96%E5%AF%8C">韭菜的自我修养</a>》就非常有意思。</p>
<p>让人唏嘘的一点是，李笑来现在的年纪已经不小了，09 年就确诊糖尿病，“比特币首富” 这个名号对他来说并不是很重要，而且他的脑子很复杂，复杂到非常复杂……</p>
<p>另外我们需要思考的一点是，假如现在投资比特币，在经历了几个周期后翻了几倍，但那时已经人老珠黄，到那时这样的财富还有意义吗？</p>
]]></content>
  </entry>
  <entry>
    <title>所有智能合约链的原生代币都不适合也不应该用来囤币，比如 ETH、SOL、TON。 因为原生代币是智能合约平台的手续费，属...</title>
    <link href="https://t.smallyu.net/#2024-31"/>
    <id>micro:2212508065</id>
    <published>2024-07-07T16:56:21Z</published>
    <updated>2024-07-07T16:56:21Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>所有智能合约链的原生代币都不适合也不应该用来囤币，比如 ETH、SOL、TON。 因为原生代币是智能合约平台的手续费，属于消耗品、消耗类资源。基于智能合约平台发的币可以价格很高，可以值一千一万块，取决于代币的标的，但是手续费本身理应越便宜越好。 好比实体资源石油，随着使用的人越来越多、场景越来越丰富，石油的价格也会增长...</p>]]></summary>
    <content type="html"><![CDATA[<p>所有智能合约链的原生代币都不适合也不应该用来囤币，比如 ETH、SOL、TON。</p>
<p>因为原生代币是智能合约平台的手续费，属于消耗品、消耗类资源。基于智能合约平台发的币可以价格很高，可以值一千一万块，取决于代币的标的，但是手续费本身理应越便宜越好。</p>
<p>好比实体资源石油，随着使用的人越来越多、场景越来越丰富，石油的价格也会增长，并且相对稳定在某一个位置上。但是使用者一定是希望价格变低的，而且很少有人会囤两箱石油回家。</p>
]]></content>
  </entry>
  <entry>
    <title>赌场上没有运气，只有千术的高低</title>
    <link href="https://t.smallyu.net/#2024-30"/>
    <id>micro:2206591738</id>
    <published>2024-07-03T15:36:57Z</published>
    <updated>2024-07-03T15:36:57Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>赌场上没有运气，只有千术的高低</p>]]></summary>
    <content type="html"><![CDATA[<p>赌场上没有运气，只有千术的高低</p>
]]></content>
  </entry>
  <entry>
    <title>Ethereum Casper 为什么需要 EIP-7251</title>
    <link href="https://smallyu.net/2024/06/09/Ethereum-Casper-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81-EIP-7251/"/>
    <id>blog:https://smallyu.net/2024/06/09/Ethereum-Casper-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81-EIP-7251/</id>
    <published>2024-06-09T15:57:17.000Z</published>
    <updated>2025-11-09T09:22:13.307Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p><a href="https://arxiv.org/abs/1710.09437">Casper the Friendly Finality Gadget</a> 是以太坊现在使用的共识机制，属于 PoS 的一种实现。这种关系类似于同样是 PoW 挖矿，Bitcoin]]></summary>
    <content type="html"><![CDATA[<p><a href="https://arxiv.org/abs/1710.09437">Casper the Friendly Finality Gadget</a> 是以太坊现在使用的共识机制，属于 PoS 的一种实现。这种关系类似于同样是 PoW 挖矿，Bitcoin 使用 sha256 而 Dogecoin 使用 scrypt。其他的 PoS 实现还有比如 Cardano 的 Ouroboros。</p><p><a href="https://eips.ethereum.org/EIPS/eip-7251">EIP-7251</a> 的主张是增加单个验证者的质押额度上限，原先是 32 ETH，希望改为 2048 ETH，这样可以有效减少验证者的数量，同时有效 P2P 网络的通信量。</p><p>这项改动有点迫在眉睫，因为以太坊在测试环境中模拟了大量质押者的情况，<a href="https://notes.ethereum.org/@parithosh/bigboi-beaconchain-test-2">测试结果</a> 显示，当质押者数量达到 2.1 M，网络的投票率会不到 50%，已经不能正常进入 Final 状态，意味着检查点机制失效，整个网络处于非常不安全的状态。而以太坊现在的验证者数量已经达到了 <a href="https://beaconscan.com/stat/validator">1.4M</a>。如果不及时做出改变，以太坊网络将在不久的将来奔溃。</p><p>那为什么以太坊会面临这样的困境？PoS 不是公链专属的共识机制，能够适用于大规模网络的吗？</p><p>究其原因，Ehtereum Casper 其实是对 BFT 的改进，而不是对 PoS 的改进。</p><p>先来看看 Vitalik 是怎么描述 Ethereum Casper 的，他把 Ehtereum Casper 相对于 BFT 的改进视为重中之重：</p><img src="1.png" /><p>再来看一下 Ehtereum Casper 的具体流程：节点质押资产成为验证者，然后通过 VRF 来随机选择一个节点出块，出块后所有验证者都对块的有效性进行一次投票。这些投票会先投递给委员会的成员，委员会成员聚合投票结果之后，再在委员会成员之间同步。委员会成员是每隔一段时间随机选举出来的。</p><p>对于了解 BFT 但是不了解 Ethereum Casper 的人，在接触到以太坊网络后，当知道只有收到 2&#x2F;3 投票的块才有资格被标记为 Final 状态时，会不会对 2&#x2F;3 这个数字有点敏感？因为 2&#x2F;3 是 BFT 一直在强调的投票比例，以保证 3f+1 的容错能力。</p><p>BFT 的投票机制保障了网络绝对不存在分叉，以太坊引入了 BFT 的这个优点，使得 Ethereum Casper 处理分叉场景相对容易，只需要判断哪个区块的得票率最高，就可以认定主流块了。如果验证者同时对两个块投票，验证者会为此受到惩罚，这也是以太坊在众多 PoS 链中唯一一个有 Slash 机制的原因。同时结合 checkpoint 机制，以太坊就可以面对非常复杂的分叉情况，整个网络分叉成树都能从中找出主链。</p><p>问题在于，Ethereum Casper 在引入 BFT 优点的同时也引入了 BFT 的缺点，那就是通信量过大。BFT 的通信量是 O(n<sup>2</sup>) 级别的，一般只能承受 100 个以下的节点规模，例如 <a href="https://ar5iv.labs.arxiv.org/html/2303.11045">这篇报告</a> 就给出了具体的数值。</p><p>可以大致计算对比一下 BFT 和 Ethereum Casper 的消息量。</p><p>BFT 在 100 个节点的时候大概是 50 tps 的能力，消息膨胀量 O(n<sup>2</sup>)，那么消息数量是：</p><pre><code>n = (100^2) * 50)  = 500000  = 0.5 M/s</code></pre><p>Ethereum Casper 在 2M 验证者的时候大概 50% 的投票率，以太坊的块时间是 12 秒，一共 64 个委员会，消息膨胀量 O(n)，那么消息数量为：</p><pre><code>n = 2M * 0.5 / 12 * 64  = 1000000 / 12 * 64  = 5 M/s</code></pre><p>这样计算比较草率和粗略，结果数字上差了一个数量级，但是考虑到两种共识机制具体实现上有很大差异，包括测试的硬件环境差异，有出入很正常，总体上差不太多。</p><p>所以由于以太坊集成了 BFT 的投票机制，导致以太坊网络需要大量的通信量。或者说，Ehtereum Casper 改进了 BFT 并且把 Stake 机制加入其中，使得 BFT 更进一步能够支撑起十万规模的节点数量。</p><p>同时，有没有注意到，Ethereum Casper 的消息膨胀量仅仅只是 O(n)，为什么呢，因为 Ethereum Caspe 不需要进行第二次投票，一次就够了。</p><p>另外，委员会机制有点像联盟链的分层共识。有些国内公司需要在没有 token 概念的前提下，对区块链技术进行改进，但是 BFT 算法最多只能撑起几十个节点的规模，于是有了基于 BFT 的分层共识，基本思路是，从所有节点中选出一部分节点作为提案节点，然后提案节点来进行出块和投票，其他节点只接收数据，并且每隔一段时间换一次共识组（提案节点）。</p><p>对于联盟链，VRF + BFT + 分层共识已经是比较完善的技术组合了。</p><p>与之相比，以太坊多出来的是 Stake 机制，联盟链中每一个节点都是验证者，都有机会出块，而以太坊想成为验证者，需要事先质押一定量的 token 才行。后面的委员会机制相比分层共识，也有一些改进，委员会机制保留了每一个验证者的投票权，只是选出一些代表来归集投票结果。而分层共识直接剥夺了多数节点的出块权，只有少数节点负责出块。</p><p>所以以太坊的共识能简单理解为 Stake + VRF + BFT + 委员会机制。</p>]]></content>
  </entry>
  <entry>
    <title>Cardano 的 PoS 没有投票环节，面对分叉选择会更加艰难。 Ethereum 的 PoS 投票很重要，不够 2/...</title>
    <link href="https://t.smallyu.net/#2024-29"/>
    <id>micro:2150289520</id>
    <published>2024-06-05T14:57:56Z</published>
    <updated>2024-06-05T14:57:56Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Cardano 的 PoS 没有投票环节，面对分叉选择会更加艰难。 Ethereum 的 PoS 投票很重要，不够 2/3 不能 finnal。</p>]]></summary>
    <content type="html"><![CDATA[<p>Cardano 的 PoS 没有投票环节，面对分叉选择会更加艰难。<br>Ethereum 的 PoS 投票很重要，不够 2/3 不能 finnal。</p>
]]></content>
  </entry>
  <entry>
    <title>PoW 的价格是电费的体现，挖矿需要多少煤炭、风力资源，价格是这些自然资源的反映。 PoS 的价格是利息的体现，如果不把...</title>
    <link href="https://t.smallyu.net/#2024-28"/>
    <id>micro:2147736590</id>
    <published>2024-06-04T14:50:40Z</published>
    <updated>2024-06-04T14:50:40Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>PoW 的价格是电费的体现，挖矿需要多少煤炭、风力资源，价格是这些自然资源的反映。 PoS 的价格是利息的体现，如果不把钱质押进来，有机会在其他地方获得多少收益，价格是这方面的补偿。</p>]]></summary>
    <content type="html"><![CDATA[<p>PoW 的价格是电费的体现，挖矿需要多少煤炭、风力资源，价格是这些自然资源的反映。<br>PoS 的价格是利息的体现，如果不把钱质押进来，有机会在其他地方获得多少收益，价格是这方面的补偿。</p>
]]></content>
  </entry>
  <entry>
    <title>区块链中的 PBFT 不需要第二次投票</title>
    <link href="https://smallyu.net/2024/06/03/%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%AD%E7%9A%84PBFT%E4%B8%8D%E9%9C%80%E8%A6%81%E7%AC%AC%E4%BA%8C%E6%AC%A1%E6%8A%95%E7%A5%A8/"/>
    <id>blog:https://smallyu.net/2024/06/03/%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%AD%E7%9A%84PBFT%E4%B8%8D%E9%9C%80%E8%A6%81%E7%AC%AC%E4%BA%8C%E6%AC%A1%E6%8A%95%E7%A5%A8/</id>
    <published>2024-06-03T03:09:21.000Z</published>
    <updated>2025-11-09T09:22:13.311Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>PBFT 为什么需要进行两次投票，第二次投票的作用是什么？这个问题困扰我很久。</p>
<h3 id="逆向推导"><a href="#逆向推导" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>PBFT 为什么需要进行两次投票，第二次投票的作用是什么？这个问题困扰我很久。</p><h3 id="逆向推导"><a href="#逆向推导" class="headerlink" title="逆向推导"></a>逆向推导</h3><p>从这个角度想，第二次投票在什么情况下是发挥作用的？在第二次投票的结果和第一次不一致的情况下，才是发挥作用的。如果第二次投票的结果和第一次严格一致，那当然没有必要进行第二次投票。</p><p>那在什么情况下，第二次投票的结果会和第一次不一样？只有当恶意节点存在并且刻意在第二次投票阶段投出不同的票，两次投票的结果才会不一样。</p><p>这是传统 PBFT 的常规操作流程图，其中节点 3 是错误节点或者恶意节点，从始至终没有响应：</p><img src="1.png" width="70%"><p>这是去掉 prepare 阶段，只保留一次投票过程的流程图，其中节点 3 仍然是错误节点，没有响应：</p><img src="2.png" width="60%"><p>关键在于，在这个场景中，节点 0、1、2 都是诚实节点，绝不可能恶意投票或者不投票，那么 commit 阶段的结果一定是和 prepare 的结果一致的，所以即使去掉 prepare 阶段，系统最终也会达成一致。</p><p>节点 3 一直都是恶意节点，如果在 commit 阶段，0、1、2 中的某个节点投出了和 prepare 不一致的票，整个系统就存在超过 1 个恶意节点，超出了容错能力。</p><h3 id="正向理解"><a href="#正向理解" class="headerlink" title="正向理解"></a>正向理解</h3><p>要证明第二次投票是必要的，等同于说明如果没有第二次投票，系统将会无法正常运转。</p><p>逻辑上，即使说第二次投票有各种各样的好处，通过冗余来增加系统的容错能力、能够及时发现错误并且快速调整到一致的状态等，也不能说明第二次投票是非要不可的。比如这个 <a href="https://cs.stackexchange.com/questions/54152/why-is-the-commit-phase-in-pbft-necessary">Why is the commit phase in PBFT necessary?</a> 中的高赞回答，说了很多但只是正向解释了 commit 阶段的设计和作用。</p><p>我目前看到比较靠谱的一个解释在这里：<a href="https://stackoverflow.com/questions/51125238/pbft-why-cant-the-replicas-perform-the-request-after-2-3-have-prepared-why-do">PBFT: Why cant the replicas perform the request after 2&#x2F;3 have prepared? why do we need commit phase?</a> </p><p>其中提到如果没有 commit 阶段，当 view change 的时候，节点将无法保证请求执行的顺序。</p><p>我觉得 StackOverFlow 中的描述和高赞回答提到的论文含义还是有出入的。高赞回答的意思是，节点的 execute 因为缺少 commit 阶段而不一致，有的快有的慢。但即使有两轮投票，节点也可能在 commit 阶段之后 execute 之前发生故障，导致执行上的差异，所以这种故障还不是关键场景。</p><p>更加合理的场景是论文 <a href="https://pmg.csail.mit.edu/papers/bft-tocs.pdf">Practical Byzantine Fault Tolerance and Proactive Recovery </a> 中提到的，view change 发生的时候，不同的请求使用了相同的序列号，被打包进不同的 view 中。（这句话很凌乱）</p><blockquote><p>Replicas may collect prepared certificates in different views with the same sequence number and different requests. The commit phase solves this problem as follows.</p></blockquote><h3 id="单次投票流程"><a href="#单次投票流程" class="headerlink" title="单次投票流程"></a>单次投票流程</h3><p>这个场景基于只投票一次的流程，也就是没有 prepare 阶段的流程。</p><h4 id="场景设置"><a href="#场景设置" class="headerlink" title="场景设置"></a>场景设置</h4><p><strong>视图 V1</strong></p><ol><li>R1 提出提议 P，并广播给 R2, R3, R4。</li><li>提议 P 在 R2, R3, R4 被执行，但 R1 未执行</li></ol><pre><code>R1: --R2: P --&gt; 执行 PR3: P --&gt; 执行 PR4: P --&gt; 执行 P</code></pre><p><strong>视图切换到 V2</strong></p><ol><li>假设 R1 发生故障，视图切换到 V2</li><li>R2 提出新的提议 P’</li><li>R2 提出新的提议 P’ 并广播给 R1, R3, R4</li><li>新的提议 P’ 被所有副本执行</li></ol><pre><code>R1: --      P&#39; --&gt; 执行 P&#39;R2: P --&gt; 执行 P      P&#39; --&gt; 执行 P&#39;R3: P --&gt; 执行 P      P&#39; --&gt; 执行 P&#39;R4: P --&gt; 执行 P      P&#39; --&gt; 执行 P&#39;</code></pre><h4 id="具体示例"><a href="#具体示例" class="headerlink" title="具体示例"></a>具体示例</h4><p>假设提议 P 和 P’ 是对相同账户余额的操作：</p><ul><li>提议 P：增加账户 A 的余额 10 单位。</li><li>提议 P’：减少账户 A 的余额 5 单位。</li></ul><p>在视图 V1 和 V2 中的操作顺序和结果如下：</p><p><strong>视图 V1</strong></p><pre><code>R1: 账户 A 余额 = 100 (未执行 P)R2: 账户 A 余额 = 110 (执行 P)R3: 账户 A 余额 = 110 (执行 P)R4: 账户 A 余额 = 110 (执行 P)</code></pre><p><strong>视图 V2</strong></p><pre><code>R1: 账户 A 余额 = 100 (未执行 P) --&gt; 执行 P&#39; --&gt; 账户 A 余额 = 95R2: 账户 A 余额 = 110 (执行 P) --&gt; 执行 P&#39; --&gt; 账户 A 余额 = 105R3: 账户 A 余额 = 110 (执行 P) --&gt; 执行 P&#39; --&gt; 账户 A 余额 = 105R4: 账户 A 余额 = 110 (执行 P) --&gt; 执行 P&#39; --&gt; 账户 A 余额 = 105</code></pre><h4 id="场景分析"><a href="#场景分析" class="headerlink" title="场景分析"></a>场景分析</h4><p>再来重复一下这句话，不同的请求（R2）使用了相同的序列号（R1 认为是 P），被打包进不同的 view （P’）中。相同的序列号应该是指执行的时序，就是当前时间点轮到哪个请求执行了。</p><p>在上面这个场景中，确实由于 A 节点故障导致最终状态出现了不一致。</p><h3 id="两次投票"><a href="#两次投票" class="headerlink" title="两次投票"></a>两次投票</h3><p>两次投票的流程又是如何解决上述场景中的问题？</p><ol><li>如果 A 节点故障发生在收到 prepare 结果之后、开始 commit 之前，所有节点都不会进入 execute 阶段。</li><li>如果 A 节点故障发生在收到 commit 结果之后、开始 execute 之前，A 节点会根据 commit 结果再次尝试执行 P，然后再执行 P’</li></ol><h4 id="场景分析-1"><a href="#场景分析-1" class="headerlink" title="场景分析"></a>场景分析</h4><p>是不是注意到，第 2 条存在一点不公平？</p><p>两次投票的场景下，A 节点可以根据 commit 结果再次尝试执行 P。</p><p>单词投票的场景下，A 节点并没有根据 commit 的结果再次尝试执行 P，而是直接执行了 P’。</p><p>那么其实两次投票并没有完全避免在 execute 之前节点故障导致的状态不一致，仅仅只是通过增加一次通讯的形式，来反复确认其他节点的状态和自己预期是一致的，减少状态不一致的风险。</p><p>两次投票把发现故障的时间提前了，如果节点 A 没有在 commit 阶段发出投票，其他节点就知道 A 节点故障了，而不是等到自己已经 execute 了，才发现 A 没有 execute。多一次确认多一份保障，减少系统 execute 后回滚的成本，尽可能在 execute 之前就商量好。两次投票最大的作用应该也就这样了。</p><p>总的来说，第二次投票始终都没有体现出必须存在的意义，而只是带来了一些好处，加强了系统的安全性。这个问题可能类似于，TCP 为什么需要 3 次握手才能建立连接？2 次不行吗？估计 1 次也行，只是会引起一些麻烦，3 次确认足够保险。</p><h3 id="无状态与有状态"><a href="#无状态与有状态" class="headerlink" title="无状态与有状态"></a>无状态与有状态</h3><p>为什么 PBFT 需要反复确认，尽量避免 execute 之后的状态不一致呢？也许任何系统的回滚都是一件非常慎重的事情，所以不惜增加 execute 之前的沟通成本。</p><h4 id="无状态"><a href="#无状态" class="headerlink" title="无状态"></a>无状态</h4><p>回到上面单次投票的场景，出故障的 A 节点在什么情况下就不会执行 P’ 了？</p><ol><li>A 节点知道自己执行 P 失败了</li><li>执行 P’ 之前一定要执行 P</li></ol><p>满足这两个条件，即使是单次投票，也可以实现和两次投票一样的效果。</p><p>对于无状态的系统，如果节点只记录了一个最终的数字，那还挺难办的，节点知道自己没有执行 P，然后收到了一个 P‘，节点 A 将无法分辨 P’ 的位置，是在 P 后面还是和 P 同等位置。</p><p>正常顺序是：</p><pre><code>O -&gt; P -&gt; P&#39;</code></pre><p>对于 A 节点来说，知道自己没有执行 P，但是收到了一个 P’：</p><pre><code>O -&gt; (P&#39;)?</code></pre><p>要不要执行呢？A 节点就执行了，状态就错乱了。</p><p>基于这一点原因，无状态的系统的 execute 是非常慎重的。</p><h4 id="有状态"><a href="#有状态" class="headerlink" title="有状态"></a>有状态</h4><p>区块链属于有状态的系统，天然记录了自己的执行记录（区块），以及会对请求进行强制的排序（区块哈希、父哈希）。</p><p>一个节点收到了区块，它一定能够判断出这个区块的位置，是否应该本轮执行，以及自己是否缺少区块，及时从其他节点把区块同步过来。</p><p>所以在区块链的使用场景下，如果只是为了达到多数节点最终状态一致的效果，完全没有必要进行第二次投票。</p><h3 id="疑问"><a href="#疑问" class="headerlink" title="疑问"></a>疑问</h3><p>PBFT 为什么需要进行两次投票？这个问题在 GPT-4o 的知识边界，详细追问它，它就会开始胡说八道了，这符合 GPT-4o 不了解就开始编造的特点。</p><p>以我有限的互联网信息搜索能力，我一直没有找到一个足以让我信服的理由，证明 PBFT 中的第二次投票是必要的。</p><p>经过我自己反复的推演，我能得到的结论只有二次投票并不是必须的，仅有一次投票，也可以达到多数节点一致的结果。</p><p>可为什么长久以来，PBFT 包括各种变体 Tendermint、HotStuff，都保留了两次投票的流程？为什么从来没有人质疑过第二次投票其实不需要？</p><p>我到底错在哪里？也许是对 PBFT 了解不够深入，还没有触及到第二次投票真正发挥作用的场景吧？可如果真的存在这样的场景，为什么没有找到资料把这种场景直接了当地描述出来？</p>]]></content>
  </entry>
  <entry>
    <title>暂时的结论是，PBFT的第二次投票不是必要的。第二次投票只有在可能和第一次投票不一样的情况下，才有效果。</title>
    <link href="https://t.smallyu.net/#2024-27"/>
    <id>micro:2143910444</id>
    <published>2024-06-02T15:54:28Z</published>
    <updated>2024-06-02T15:54:28Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>暂时的结论是，PBFT的第二次投票不是必要的。第二次投票只有在可能和第一次投票不一样的情况下，才有效果。</p>]]></summary>
    <content type="html"><![CDATA[<p>暂时的结论是，PBFT的第二次投票不是必要的。第二次投票只有在可能和第一次投票不一样的情况下，才有效果。</p>
]]></content>
  </entry>
  <entry>
    <title>开发者的思维方式</title>
    <link href="https://smallyu.net/2024/05/30/%E5%BC%80%E5%8F%91%E8%80%85%E7%9A%84%E6%80%9D%E7%BB%B4%E6%96%B9%E5%BC%8F/"/>
    <id>blog:https://smallyu.net/2024/05/30/%E5%BC%80%E5%8F%91%E8%80%85%E7%9A%84%E6%80%9D%E7%BB%B4%E6%96%B9%E5%BC%8F/</id>
    <published>2024-05-30T05:46:26.000Z</published>
    <updated>2025-11-09T09:22:13.448Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>前情提要：《<a href="https://www.yinwang.org/blog-cn/2015/02/01/creative-thinking">创造者的思维方式</a>》——王垠</p>
<hr>
<p>发现一个现象，当你说 A 好的时候，别人会说 A 没有 B]]></summary>
    <content type="html"><![CDATA[<p>前情提要：《<a href="https://www.yinwang.org/blog-cn/2015/02/01/creative-thinking">创造者的思维方式</a>》——王垠</p><hr><p>发现一个现象，当你说 A 好的时候，别人会说 A 没有 B 好，所以 A 不好。</p><p>第一个案例是当你说 SOL 的技术比 BNB 好的时候，就会引来争议了。有人拿 SOL 宕机过几次来证明 SOL 技术不好，还有人说炒币根本不是技术导向，而是资本导向，技术好不好不重要。这些观点反映了各自不同的立场。</p><p>从开发者的角度，没有人会把 BNB 看作一条区块链，因为它是平台币，节点中心化运维，运营模式也不是链的方式。技术上 fork Geth 的代码做了一些魔改，比 Geth 早一步用上了 PoS，以增加对整条链的控制。ETH 完成坎昆升级后，BNB 也模仿着搞上了自己的 BIP-4844，显然和 ETH 属于相同的技术体系。</p><p>另一个观察角度是，ETH 的 ETF 接近通过后，大家开始讨论下一个能上 ETF 的是 DOGE 还是 SOL，甚至是 DOT，但没有人会提到 BNB，充分说明了 BNB 和其他公链不一样，都不是一个赛道。判断两个产品是否属于同一个赛道的方法，可以看其是否存在竞争关系，你死我活那种。如果 BNB 用了 ETH 的技术还希望 ETH 死掉，在逻辑上是不通顺的。正常逻辑应该是希望 ETH 更好，BNB 也会跟着受益。</p><p>而从使用者（炒币）的角度，管你用的什么技术，管你技术好不好，一个表情包都能市值前十，一个戴帽子的狗都能市值上亿，投资人在哪儿我就去哪儿，资本炒什么我就买什么，FOMO 就完事了。</p><p>第二个案例是当你说 SOL 技术好的时候，别人会说 ETH 更好，所以 SOL 不好。</p><p>同样是立场问题，站在使用者的角度，有无数理由来对比两个项目的好坏。当你说 A 好的时候，总是有人可以找到一个比 A 好的 B，或者只有某个方面好于 A 的 C。使用这样的技巧，他们可以打败任何人、任何项目。而且这里面也存在非常大的争议空间、鄙视链，就好像到底 PHP 是不是世界上最好的语言？</p><p>但是站在开发者的角度，如果我要开发一条链，我的链要和 SOL 比技术、抢市场，我能不能做的比 SOL 更好？肯定不能。那么在这个立场下，我说一句 SOL 技术挺好，不过分吧？</p><p>这里的 SOL 只是举例，其实只要是 CMC 前 100 的老牌公链，都有一些闪光点，尤其是开创和尝试了不一样共识算法的，它们也许不如 ETH 和 SOL 备受关注，但是也做出了不错的成绩。</p>]]></content>
  </entry>
  <entry>
    <title>发币的核心要点</title>
    <link href="https://smallyu.net/2024/05/26/%E5%8F%91%E5%B8%81%E7%9A%84%E6%A0%B8%E5%BF%83%E8%A6%81%E7%82%B9/"/>
    <id>blog:https://smallyu.net/2024/05/26/%E5%8F%91%E5%B8%81%E7%9A%84%E6%A0%B8%E5%BF%83%E8%A6%81%E7%82%B9/</id>
    <published>2024-05-26T14:31:26.000Z</published>
    <updated>2026-06-30T07:15:33.012Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>首先关于《炒币投资的小 tips》再补充两点：</p>
<ol>
<li><p>比特币本位还是法币本位或者其他币本位，主要还看手里有什么、什么币来的容易，没有银弹的逻辑适用于任何场合.</p>
</li>
<li><p>随着 ETH 的 ETF 通过了一半，意味着 SEC]]></summary>
    <content type="html"><![CDATA[<p>首先关于《炒币投资的小 tips》再补充两点：</p><ol><li><p>比特币本位还是法币本位或者其他币本位，主要还看手里有什么、什么币来的容易，没有银弹的逻辑适用于任何场合.</p></li><li><p>随着 ETH 的 ETF 通过了一半，意味着 SEC 也许会接受 PoS，只是要求 ETF 的资金不能用于质押（我还没理解为什么）。之前提到要在 CMC 前 100 里挑，可能需要再加一个条件，就是没有曾经被 SEC 称作证券的。也许在换人后，或者新法案通过后，加密货币将不归 SEC 管，但至少说明在同等的判断标准下，很多币明显存在问题，ETH 一直属于模棱两可的状态，所以目前在 ETF 的状况比较复杂。<br>  其实比较安全可靠的币屈指可数。例如 DOT 的出镜率不高，SEC 没有对 DOT 有过定义，但是 DOT 的质押率已经达到流通量的 57%，而且还保持着 17% 的年利率，我还无法理解这是一种什么样的状况，质押率高的后果是什么，为什么 DOT 收益率可以这么高，假如所有持有者都平等获得年利率，不就相当于通胀吗，币价得跌。对于网络来说，质押率越高倒是越安全。但是流通中的币越少，说明这个币没啥用，甚至不能用于合约的手续费来消耗。这种理解不了的币也是不能买的。</p></li></ol><p>然后是关于发币。最近无意间听到李笑来以前在网上流传的录音，还是有不少启发。</p><p>所有币的核心要点就一个，就是把币通过有价值的形式分发出去。持有者认为它值什么价格，它就是什么价格，只要持有者不卖，价格就不会跌。包括 BTC，是通过挖矿的形式分发，10 分钟发一次，无论多少人参与，10 分钟、固定数量，总会有一个胜出者，而且胜出者有随机性，增加了活跃参与的程度。</p><p>ETH 也是通过挖矿，每 12 秒钟一次，把块奖励发给矿工，奖励分发上和 BTC 差不太多，ETH 最大的两个黑点是：</p><ol><li>开发团队有预挖，挖了多少不清楚，ICO 低价给了多少人是黑箱</li><li>无限增发的代币模型，总供应量没有上限，是否会带来通胀，是否意味着开发团队可以不断印钱</li></ol><p>李笑来发过一个叫 Caddy 的币，当时给他一个什么社区合作，几百万真实用户，以十分之一的价格给那个群体，让他们在网上点赞转发炒新闻。李笑来自己说，要策划好一个币的前提是自己是网红，有流量、有影响力，是非常重要的条件。因为李笑来自己就算个网红，经常出书、到处演讲、是新东方有名的老师，他的背景是非常深厚的。</p><p>他说的这个关于网红的要点，其实最终作用也就是招来大量粉丝，让这些粉丝认可这个币，币会通过某个价格到达这些粉丝的手里。所以无论是挖矿，还是早期的空投、交易所的 LaunchPool、激励形式的发放，目的都是以有价值的方式发给持有者，持有者必须要付出一点代价，币才会有价值。广撒网白给，币肯定不值钱，但如果和美元一对一锚定，那又是稳定币。所以这个价值还得控制好，不能太具体，也不能没有。</p><p>另外十倍百倍的币是没有逻辑的，一般认为 ETH 的火爆有两个主要原因，一是当时国家出了个政策，交易所里面的 BTC 不能提出去。二是当时有个传销盘，用的 ETH，日利率 1%，大量用户在交易所里花钱买完 ETH 就提出去，放到传销盘里了，币价就涨了上来。好笑的是期间 ETH 的价格涨了上千倍，传销盘甚至可以坚持三年不崩盘……</p><p>FIL 曾经也在国内大量挖矿，价格一度涨到 200，为什么价格那么高，也是传销盘……后来国内不让搞，现在 FIL 就一点活力都没有了，技术是真的好啊。另外一个技术不好的，NEO 也涨了百倍起来的，大家都疯了不知道为什么这么值钱，只有十来个中心化的节点，技术也不行用 C# 写的，号称国产版本的以太坊，主要还是资金盘拉起来的，创始人手里也没多少币，直到现在也能看出来，币价隔一段时间就会拉起一波，只有资金盘能操纵起这样的场面。</p><p>所以技术也不是绝对优先地位，技术属于基础，用来给大家做横向比较的，比如同时有几个项目叫 ETA、ETB、ETC、……、ETH，即使是传销盘也会从中选一个技术相对可靠、有东西可炒作的币来用。然后就是天意了。</p><p>还有是八卦相关的，很多新闻报道李笑来曾经是币圈首富，用四分之一的身价低价买了六位数的比特币，拿了好几年然后经历过好几波牛熊，最后高价卖掉了。但是事情没有那么简单，网上可以查到很多李笑来关于比特币的演讲视频，他绝不是单纯买完币啥也不干，躺着等币价涨，再卖掉。他从复杂的知识层面对比特币有理解、做演讲，肯定是逻辑上相信比特币，才会进入币圈的。这件事情告诉我们，别瞎买，看准了再买，别在交易所上看见个喜欢的代号就买了，或者看见个推广文章就买了，真正能赚钱的人背后都有深厚的逻辑支撑，做了大量功课的。</p><p>另一个版本的八卦是，李笑来曾经组织过一个比特币基金，私募，几万个比特币的规模，用来投资挖矿、交易所、买股票，结果亏的很惨，很多人跟着亏钱还拉了维权群。后来投 EOS 什么的又赚回来了，打折把欠的钱还上。李笑来吹牛自己有六位数的比特币，结果没有啊，警察去搜都搜不着，到现在李笑来都被边控着出不了国。谁知道他到底有没有比特币，他要真有呢，不能放他出去。这件事情告诉我们的道理是，没有人靠炒币发财的，李笑来本来就有钱，有钱了都还在进行各种操作，做投资、搞基金，赚钱总是得做事情，别想着炒币挣钱，买完币放在那儿就等着涨。即使当年属于币圈早期，参与了李笑来比特币基金的人，对比特币的未来也是持怀疑态度，拿不准比特币以后的价值，过程中也洗掉了一大批人。何况现在呢。</p>]]></content>
  </entry>
  <entry>
    <title>乱世的黄金，盛世的古董。 熊市的比特币，牛市的___。</title>
    <link href="https://t.smallyu.net/#2024-26"/>
    <id>micro:2104885543</id>
    <published>2024-05-10T16:21:26Z</published>
    <updated>2024-05-10T16:21:26Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>乱世的黄金，盛世的古董。 熊市的比特币，牛市的___。</p>]]></summary>
    <content type="html"><![CDATA[<p>乱世的黄金，盛世的古董。<br>熊市的比特币，牛市的___。</p>
]]></content>
  </entry>
  <entry>
    <title>目前最好的组合（构建生态），可能是 PoS + 平行链（带 EVM）+ Go 语言（同时支持其他语言）。</title>
    <link href="https://t.smallyu.net/#2024-25"/>
    <id>micro:2097247063</id>
    <published>2024-05-07T01:57:52Z</published>
    <updated>2024-05-07T03:05:54Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>目前最好的组合（构建生态），可能是 PoS + 平行链（带 EVM）+ Go 语言（同时支持其他语言）。</p>]]></summary>
    <content type="html"><![CDATA[<p>目前最好的组合（构建生态），可能是 PoS + 平行链（带 EVM）+ Go 语言（同时支持其他语言）。</p>
]]></content>
  </entry>
  <entry>
    <title>Cosmos 和 Polkdot 都是在用平行链、跨链的方式构建生态。 如果 Cosmos 用的是 PoS 而不是 BF...</title>
    <link href="https://t.smallyu.net/#2024-24"/>
    <id>micro:2097209369</id>
    <published>2024-05-07T01:38:55Z</published>
    <updated>2024-05-07T01:55:00Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Cosmos 和 Polkdot 都是在用平行链、跨链的方式构建生态。 如果 Cosmos 用的是 PoS 而不是 BFT 共识，它会有更好的前景，可惜它没用。 Polkdot 用了 PoS，如果它用 Go 语言开发而不是 Rust，它也会有更好的前景，可惜它没用。</p>]]></summary>
    <content type="html"><![CDATA[<p>Cosmos 和 Polkdot 都是在用平行链、跨链的方式构建生态。</p>
<p>如果 Cosmos 用的是 PoS 而不是 BFT 共识，它会有更好的前景，可惜它没用。</p>
<p>Polkdot 用了 PoS，如果它用 Go 语言开发而不是 Rust，它也会有更好的前景，可惜它没用。</p>
]]></content>
  </entry>
  <entry>
    <title>炒币投资的小 tips</title>
    <link href="https://smallyu.net/2024/05/04/%E7%82%92%E5%B8%81%E6%8A%95%E8%B5%84%E7%9A%84%E5%B0%8F-tips/"/>
    <id>blog:https://smallyu.net/2024/05/04/%E7%82%92%E5%B8%81%E6%8A%95%E8%B5%84%E7%9A%84%E5%B0%8F-tips/</id>
    <published>2024-05-04T12:44:13.000Z</published>
    <updated>2025-11-17T14:37:09.866Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="1-BTC-是行业底线"><a href="#1-BTC-是行业底线" class="headerlink" title="1. BTC 是行业底线"></a>1. BTC 是行业底线</h3><p>有 Bitcoin，才有加密货币的整个行业。如果哪一天]]></summary>
    <content type="html"><![CDATA[<h3 id="1-BTC-是行业底线"><a href="#1-BTC-是行业底线" class="headerlink" title="1. BTC 是行业底线"></a>1. BTC 是行业底线</h3><p>有 Bitcoin，才有加密货币的整个行业。如果哪一天 Bitcoin 被否认了，说 BTC 不安全了、不去中心化了、没有价值了，那么整个行业就没了，BTC 从来没有被超越。而且事实上，除了比特币，其他的全是山寨币，尤其是在老矿工眼里，经历过只有比特币的时代。山寨币都是从作为比特币的模仿者开始，试图做出某些改变，包括以太坊。Vitalik 也搞过染色币、从 PoW 开始发链、来中国募资。一切都从比特币开始。</p><h3 id="2-PoW-抗跌"><a href="#2-PoW-抗跌" class="headerlink" title="2. PoW 抗跌"></a>2. PoW 抗跌</h3><p>2024年4月12日前后，由于多方面因素，普遍认为是因为两个国家擦枪走火、有可能挑起战争的缘故，所有的币平均下跌 20% 左右，币安的 Gainner 排行榜上也全是红色，可以简单将其称为 412 事件。</p><p>观察一下这一波价格变动的情况，可以明显看出，PoW 系列的币，跌幅普遍比 PoS 系列的币小。以 BTC 为首，Doge、LTC、BCH、ZEC、ETC、ETHW。毕竟 PoW 的链是矿工实实在在投入算力在上面，硬件成本在那儿，他们不愿意低价格卖掉。PoS 不一样，把一大堆钱质押进服务器，钱生钱，来的相对容易。ETh、DOT、ADA、COSMOS 等，很多很多，CMC 前 100 估计有 50 个 PoS 的、有质押功能的。</p><h3 id="3-BTC-本位"><a href="#3-BTC-本位" class="headerlink" title="3. BTC 本位"></a>3. BTC 本位</h3><p>炒币的基本逻辑是 BTC 本位的，也就是炒山寨币对比特币的汇率。假如本来有 1 个 BTC，觉得 Doge 最近的上涨幅度会超过 BTC，就把 BTC 换成 Doge，等 Doge 涨完涨了 20%，再把所有的 Doge 换成 BTC，这个时候，BTC 就从 1 个变成了 1.2 个，这就是 BTC 本位的含义。</p><p>从此以后，你将无视市场行情的波动，无惧牛熊，你眼里只有比特币的数量，是 1 个，还是 1.2 个，还是 0.8 个。至于 BTC 对于法币的价格，随便怎么变化，总之每隔 4 年翻一倍，跌了会涨，涨了还会涨，All Time High 反反复复。</p><p>要是用法币本位去炒币，十有九伤，大多会死得很惨。特指现货，合约千万别碰。</p><h3 id="4-挑-CMC-前-100-的买"><a href="#4-挑-CMC-前-100-的买" class="headerlink" title="4. 挑 CMC 前 100 的买"></a>4. 挑 CMC 前 100 的买</h3><p>尽可能把眼光聚焦在 CMC（Coin Market Cap）排行前 100 名的币上，挑这些里面的买。一方面是因为暴跌的概率小，100 名开外的没底。另一方面是生态支持差，没准什么时候钱包不支持了，转不了账带来很多麻烦。或者某个 X-20 币的合约地址变了，就很离谱，前段时间有一个 AI 板块下的，合约地址说变就变，而且原合约的 Dex pool 还在以 20% 的价格运行，合约地址切换后，价格变为了原来的 80% 左右。</p><h3 id="5-创始人的离开是去中心化的开始"><a href="#5-创始人的离开是去中心化的开始" class="headerlink" title="5. 创始人的离开是去中心化的开始"></a>5. 创始人的离开是去中心化的开始</h3><p>BTC 比较特殊，创始人从一开始就隐瞒身份，这是非常聪明的做法。也正因为如此，BTC 才可以被大肆炒作。为什么 BTC 上的资产类型很多，染色币、RGB++、Taproot Assets、铭文、符文，L2 资产还在打架。因为没有人能站出来给 Bitcoin 画一个 Roadmap，谁也不知道接下来应该怎么发展。</p><p>与之相比，ETH 的创始人还在全世界开会、演讲，给 Ethereum 画出了路线图，让 L2 有了整齐划一的技术方向。当 ETH 遭遇黑客攻击，创始人能够带领整个社区把攻击历史分叉掉，还能引领社区把共识机制从 PoW 转换为 PoS。如此大的影响力，说明 ETH 是中心化的。ETH 没有理由能通过 Howey 测试，在 SEC 的标准下，ETH 八九不离十被认定为证券。</p><p>如果一个币是你发的，你在那儿喊单，是不是很不合适？可如果一个币是去中心化的，你随便喊，就喜欢 Doge，就喜欢，怎么喊都行。</p><p>BSV 的 CW 也在今年打输了官司。社区里有人用这一点来安慰自己，说 CW 的离开是好事，BSV 会变成真正社区驱动的币。不管 BSV 前景如何，至少创始人的离开是一个重要的指标。</p><p>还有一个例子是 ETC 和 ETHW。这两个币都是宝二爷分叉出来的，很多人对他有成见，但是这两个币的市值、价格、TVL 摆在那儿，412 这一波，这两个币的抗跌能力有体现。虽然确实不敢买，从 ETH 分叉出来以后，技术上就没有进一步的更新了，GitHub 上活跃度很低，感觉很难长久下去，但价格上又很是让人感到疑惑。ETC 和 ETHW 其实是真正没有创始人而且是 PoW 的币。</p><p>另外一个现象是，自从以太坊将共识机制从 PoW 转为 PoS，ETH 对 BTC 的汇率就一直在下跌，从接近 0.1 到现在 0.05 左右。</p><h3 id="6-其他"><a href="#6-其他" class="headerlink" title="6. 其他"></a>6. 其他</h3><p>拿出 CMC 前 10 来简单对比一下：</p><ol><li>BTC：行业底线，市值占比 50%</li><li>ETH：开创了 EVM 和加密货币版 Defi 市场，有庞大的生态，市值占比 16%</li><li>USDT：使用范围最广的稳定币，美国国债储备</li><li>BNB：世界上最大的交易所平台币</li><li>SOL：PoH+DPoS 共识机制，中心化，依赖于少数排序器对交易排序后，才会交给验证者打包</li><li>USDC：最安全的稳定币，黄金储备</li><li>XRP：RPCA 共识机制</li><li>DOGE：PoW 共识，最大的 Meme 币，马斯克喜欢</li><li>TON：Telegram 发行的链</li><li>ADA：创始人有名气，使用 Haskell 开发，UTXO + PoS</li></ol>]]></content>
  </entry>
  <entry>
    <title>BTC 是加密货币的底线，ETH 是山寨币之王，两个加起来占了总市值的 70%，很难抉择，很难取舍，这两大同时存在是最合...</title>
    <link href="https://t.smallyu.net/#2024-23"/>
    <id>micro:2081912333</id>
    <published>2024-04-29T05:25:40Z</published>
    <updated>2024-04-29T05:25:40Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>BTC 是加密货币的底线，ETH 是山寨币之王，两个加起来占了总市值的 70%，很难抉择，很难取舍，这两大同时存在是最合理的。</p>]]></summary>
    <content type="html"><![CDATA[<p>BTC 是加密货币的底线，ETH 是山寨币之王，两个加起来占了总市值的 70%，很难抉择，很难取舍，这两大同时存在是最合理的。</p>
]]></content>
  </entry>
  <entry>
    <title>Layer 2 的要素，如果不包含就不算 Layer 2: L2 上有和 L1 一样的原生资产，并且价格严格对应。 L1...</title>
    <link href="https://t.smallyu.net/#2024-22"/>
    <id>micro:2068318777</id>
    <published>2024-04-22T01:22:54Z</published>
    <updated>2024-04-22T01:22:54Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Layer 2 的要素，如果不包含就不算 Layer 2: L2 上有和 L1 一样的原生资产，并且价格严格对应。 L1 的资产能跨链到 L2 上 在 L2 停止响应的情况下，可以从 L1 上恢复资产 从这个角度看，染色币、铭文，符文，都不是 L2。闪电网络是，以太坊的 L2 是。</p>]]></summary>
    <content type="html"><![CDATA[<p>Layer 2 的要素，如果不包含就不算 Layer 2:</p>
<ol>
<li>L2 上有和 L1 一样的原生资产，并且价格严格对应。</li>
<li>L1 的资产能跨链到 L2 上</li>
<li>在 L2 停止响应的情况下，可以从 L1 上恢复资产</li>
</ol>
<p>从这个角度看，染色币、铭文，符文，都不是 L2。闪电网络是，以太坊的 L2 是。</p>
]]></content>
  </entry>
  <entry>
    <title>有人乐观地认为，以太坊 L2 的 TVL 几乎和 L1 相当，所以比特币的 L2 也将会有广阔的增长空间，目前比特币 L...</title>
    <link href="https://t.smallyu.net/#2024-21"/>
    <id>micro:2067908884</id>
    <published>2024-04-21T05:20:36Z</published>
    <updated>2024-04-21T05:20:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有人乐观地认为，以太坊 L2 的 TVL 几乎和 L1 相当，所以比特币的 L2 也将会有广阔的增长空间，目前比特币 L2 的市场太小了。 这里存在的问题是，以太坊的 L2 是得到 L1 支持的，以太坊的创始人还在，还画出了 Roadmap，L2 是以太坊的一部分。这是与比特币不一样的地方，比特币不可能专门为了 L2...</p>]]></summary>
    <content type="html"><![CDATA[<p>有人乐观地认为，以太坊 L2 的 TVL 几乎和 L1 相当，所以比特币的 L2 也将会有广阔的增长空间，目前比特币 L2 的市场太小了。</p>
<p>这里存在的问题是，以太坊的 L2 是得到 L1 支持的，以太坊的创始人还在，还画出了 Roadmap，L2 是以太坊的一部分。这是与比特币不一样的地方，比特币不可能专门为了 L2 做出改变。</p>
]]></content>
  </entry>
  <entry>
    <title>判断一个公司或者项目，属不属于某个行业或者赛道，可以看和已有项目存不存在竞争关系。如果有竞争关系，肯定属于同一赛道，如果...</title>
    <link href="https://t.smallyu.net/#2024-20"/>
    <id>micro:2067871433</id>
    <published>2024-04-21T02:58:54Z</published>
    <updated>2024-04-21T02:58:54Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>判断一个公司或者项目，属不属于某个行业或者赛道，可以看和已有项目存不存在竞争关系。如果有竞争关系，肯定属于同一赛道，如果没有竞争关系，至少不在一个赛道上。</p>]]></summary>
    <content type="html"><![CDATA[<p>判断一个公司或者项目，属不属于某个行业或者赛道，可以看和已有项目存不存在竞争关系。如果有竞争关系，肯定属于同一赛道，如果没有竞争关系，至少不在一个赛道上。</p>
]]></content>
  </entry>
  <entry>
    <title>比特币 L2 其实很可怜，在现有规则下，无所不用其极地搞事情。比特币很金贵，一笔交易的 op_return 只有几十个字...</title>
    <link href="https://t.smallyu.net/#2024-19"/>
    <id>micro:2067691445</id>
    <published>2024-04-20T14:29:22Z</published>
    <updated>2024-04-20T14:29:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>比特币 L2 其实很可怜，在现有规则下，无所不用其极地搞事情。比特币很金贵，一笔交易的 op_return 只有几十个字节的空间，Runes 就要利用这么点空间来发 meme。 Runes 不太算是 L2，CKB 更像。但是 L2 没有不中心化的，包括以太坊生态。</p>]]></summary>
    <content type="html"><![CDATA[<p>比特币 L2 其实很可怜，在现有规则下，无所不用其极地搞事情。比特币很金贵，一笔交易的 op_return 只有几十个字节的空间，Runes 就要利用这么点空间来发 meme。</p>
<p>Runes 不太算是 L2，CKB 更像。但是 L2 没有不中心化的，包括以太坊生态。</p>
]]></content>
  </entry>
  <entry>
    <title>最近看了不少香港 Web3 大会的回放，比特币 L2 是非常大的热点，很有意思，仍然有人在推进 Lighting Net...</title>
    <link href="https://t.smallyu.net/#2024-18"/>
    <id>micro:2067686445</id>
    <published>2024-04-20T14:12:19Z</published>
    <updated>2024-04-20T14:12:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最近看了不少香港 Web3 大会的回放，比特币 L2 是非常大的热点，很有意思，仍然有人在推进 Lighting Network，RGB++ 从 2019 年就开始了，Taproot assert 有希望把 USDT 带进比特币，Runes 减半后就要开启了。</p>]]></summary>
    <content type="html"><![CDATA[<p>最近看了不少香港 Web3 大会的回放，比特币 L2 是非常大的热点，很有意思，仍然有人在推进 Lighting Network，RGB++ 从 2019 年就开始了，Taproot assert 有希望把 USDT 带进比特币，Runes 减半后就要开启了。</p>
]]></content>
  </entry>
  <entry>
    <title>Vitalik 开创了区块链能回滚的先河？</title>
    <link href="https://t.smallyu.net/#2024-17"/>
    <id>micro:2053975411</id>
    <published>2024-04-14T09:06:14Z</published>
    <updated>2024-04-14T09:06:14Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Vitalik 开创了区块链能回滚的先河？</p>]]></summary>
    <content type="html"><![CDATA[<p>Vitalik 开创了区块链能回滚的先河？</p>
]]></content>
  </entry>
  <entry>
    <title>为什么说 PoW 比 PoS 更加去中心化</title>
    <link href="https://smallyu.net/2024/04/14/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%AF%B4PoW%E6%AF%94PoS%E6%9B%B4%E5%8A%A0%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96/"/>
    <id>blog:https://smallyu.net/2024/04/14/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%AF%B4PoW%E6%AF%94PoS%E6%9B%B4%E5%8A%A0%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96/</id>
    <published>2024-04-13T16:50:00.000Z</published>
    <updated>2025-11-09T09:22:13.310Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>想从准入门槛的角度对比一下 PoW 和 PoS。</p>
<p>我们经常描述一条链是 permissionless 还是 permissioned 的。其含义是成为出块节点，需要被授权还是不需要被授权。</p>
<p>PoW]]></summary>
    <content type="html"><![CDATA[<p>想从准入门槛的角度对比一下 PoW 和 PoS。</p><p>我们经常描述一条链是 permissionless 还是 permissioned 的。其含义是成为出块节点，需要被授权还是不需要被授权。</p><p>PoW 是公认不需要被授权就可以挖矿的共识机制，只要你有一台计算机，就可以加入网络开始挖矿，只要你能计算出符合要求的哈希值，哪怕手算心算都可以，只要是正确的，你就拥有出块的权利，这个块中包含哪些交易由你来决定。当然能不能算的出来是另一回事。</p><p>BFT 是典型的需要被授权的共识机制。很多使用 BFT 类共识的项目，直接需要 CA 中心来签发证书，只有拥有证书的节点才可以在网络冲承担起挖矿的职责。而 CA 中心为什么要给你签发证书呢，完全是线下行为。成为出块节点的权限牢牢控制在 CA 中心手里。</p><p>PoS 存在一些争议。</p><p>SEC 曾经把 66 种加密货币定义为证券，包括 SOL、ADA 等市值比较高的币种。但其中没有包含 ETH，这一点给了很多人期望，也让 ETH 的 PoS 存在模棱两可的空间。</p><p>一个显著的事实是，PoS 是属于 permissioned 的共识机制。</p><p>在 PoS 中，节点往往会需要质押一定数量的 token 才能成为出块节点，而质押的那么多 token，就是 PoS 的门槛。</p><p>一个节点想成为出块节点，需要获得很多 token，而这些 token 从哪里来？要么来自项目的发行方，在创世阶段就分配出来到钱包里，要么后续从矿工手里买，因为矿工会增加 token 的供应量。</p><p>问题就在这里，设想一种极端的情况，如果所有持有 token 的人不愿意出售持有的 token，整个网络的控制权不就在他们手里了吗？不管他们是十个人还是十万个人，总之是一个圈子。而且在 PoS 的机制中，拥有越多 toekn 权力就越大，更是加剧 PoS 的中心化程度。</p><p>这个时候可能有疑问，以太坊如此成功，有上千万的持有者，成千的机构组织管理着上万个出块节点，难道还不够去中心化吗？</p><p>所以要区分两个概念，共识机制是去中心化的，和一条链是去中心化的，是两码事。</p><p>只要愿意，即使 BFT 类共识只能支持几十个节点的规模，如果这几十个节点分散在世界各地且有利益冲突的大财团手里，这条链仍然可以认为是去中心化的，因为几十个个利益相关方不可能有超过 2&#x2F;3 比例的数量合作。</p><p>同样的道理，以太坊只是做的去中心化了，它成为了一条去中心化的链，不代表 PoS 是去中心化的技术。</p><p>为什么很多项目方愿意选择 PoS 而不是 PoW 来发币？因为 PoW 太不可控了，被攻击的风险非常高。可以观察一下，目前存在的 PoW 链，几乎都是从比特币分叉而来，而且很少有新增。新出现的山寨币，多数源自以太坊的技术栈。</p><p>PoS 为什么可控？只要你不把创始阶段的钱分散出去，你就拥有整条链的控制权，PoS 让人更有安全感。分散出去也没事，只要整体比例可控，链就仍然在你的控制下。</p><p>那按照这么说，比特币的矿机资源不也被控制在少数生产商手里吗？只要他们不愿意出售矿机，比特币就始终被控制在一定范围内。也不全是，即使没有先进的矿机，也是能够参与挖矿的。落后的矿机堆积的多了，算力也可以很高。至少没有人有权力，剥夺你成为出块节点的资格。</p><p>与之相比，PoS 是不一样的，只要没有足够的钱，就没有成为出块节点的资格。如果 token 持有者不愿意出售，这种资格是你无论花费多少努力都无法获得的。PoS 本质上还是关起门来大家协商的共识机制，在有资格的节点中随机选一个出块，而且还得投票。</p><p>对了，如果存在一种 PoS，没有准入门槛呢？所有节点都是出块节点，每一轮随机选择一个节点负责出块。这样的机制免不了会受到女巫攻击，最终变为比拼节点数量的游戏。其实比拼节点数量也不是不行，节点数量最终也是硬件资源的体现。拥有更多硬件资源的节点有更大几率被选中。我倒是觉得这样的共识机制有进一步思考的空间，不过面临的现实问题也非常多，比如怎么通过 VRF 来选择下一个出块节点，以及如此庞大的出块节点数量，需要的网络带宽也许是不是现有技术能够承载的。另外，其实没有准入门槛就不叫 PoS 了。</p><p>15 年过去了，比特币从未被超越……</p>]]></content>
  </entry>
  <entry>
    <title>DIDs 没有技术创新，只是协议创新，需要发证方和验证方互相认可，而且 DIDs 并不依赖于区块链，甚至是政府数据库都行...</title>
    <link href="https://t.smallyu.net/#2024-16"/>
    <id>micro:2041266386</id>
    <published>2024-04-07T01:29:16Z</published>
    <updated>2024-04-07T01:29:16Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>DIDs 没有技术创新，只是协议创新，需要发证方和验证方互相认可，而且 DIDs 并不依赖于区块链，甚至是政府数据库都行，只要是可信的数据来源都可以。 DIDs 的标准已经有了好几年，但是还没有团队能做的起来，也许因为不只是技术的事。 Space ID 主要是搞域名，和 DIDs 还不一样。</p>]]></summary>
    <content type="html"><![CDATA[<p>DIDs 没有技术创新，只是协议创新，需要发证方和验证方互相认可，而且 DIDs 并不依赖于区块链，甚至是政府数据库都行，只要是可信的数据来源都可以。</p>
<p>DIDs 的标准已经有了好几年，但是还没有团队能做的起来，也许因为不只是技术的事。</p>
<p>Space ID 主要是搞域名，和 DIDs 还不一样。</p>
]]></content>
  </entry>
  <entry>
    <title>香港 web3 大会的参与项目里，仍然有一些在做数字身份相关的。DIDs 的主要的应用场景属于资质证明，其实没什么需求。...</title>
    <link href="https://t.smallyu.net/#2024-15"/>
    <id>micro:2041263349</id>
    <published>2024-04-07T01:17:48Z</published>
    <updated>2024-04-07T01:17:48Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>香港 web3 大会的参与项目里，仍然有一些在做数字身份相关的。DIDs 的主要的应用场景属于资质证明，其实没什么需求。有的提到要和 AI 身份结合，就更没道理了。 这些项目的目的就是发币募资🫤</p>]]></summary>
    <content type="html"><![CDATA[<p>香港 web3 大会的参与项目里，仍然有一些在做数字身份相关的。DIDs 的主要的应用场景属于资质证明，其实没什么需求。有的提到要和 AI 身份结合，就更没道理了。</p>
<p>这些项目的目的就是发币募资🫤</p>
]]></content>
  </entry>
  <entry>
    <title>AI 生成的音乐没有韵律，指中文诗词那种韵律，但也很厉害了。 与 AI 相比，目前的区块链仅仅只是一种支付手段，接下来几...</title>
    <link href="https://t.smallyu.net/#2024-14"/>
    <id>micro:2028553543</id>
    <published>2024-03-31T04:49:10Z</published>
    <updated>2024-03-31T04:50:08Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>AI 生成的音乐没有韵律，指中文诗词那种韵律，但也很厉害了。 与 AI 相比，目前的区块链仅仅只是一种支付手段，接下来几年能把支付场景搞好，就是很大的胜利了。 支付之外的场景，现在还看不到起色，以太坊不火一下就没有希望。Filecoin 之类的更是早就淡出人们的视野了。 AI 也许是下一轮技术革命，但是不清楚普通人有没...</p>]]></summary>
    <content type="html"><![CDATA[<p>AI 生成的音乐没有韵律，指中文诗词那种韵律，但也很厉害了。</p>
<p>与 AI 相比，目前的区块链仅仅只是一种支付手段，接下来几年能把支付场景搞好，就是很大的胜利了。</p>
<p>支付之外的场景，现在还看不到起色，以太坊不火一下就没有希望。Filecoin 之类的更是早就淡出人们的视野了。</p>
<p>AI 也许是下一轮技术革命，但是不清楚普通人有没有机会参与它。让AI来搞创作，是不合理的。</p>
<p>想把 AI 运行在区块链上，不清楚会是什么形态。</p>
]]></content>
  </entry>
  <entry>
    <title>应该去喜欢一切好的东西，而不是执着于某些东西期待它变好。</title>
    <link href="https://t.smallyu.net/#2024-13"/>
    <id>micro:2028552042</id>
    <published>2024-03-31T04:40:25Z</published>
    <updated>2024-03-31T04:40:25Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>应该去喜欢一切好的东西，而不是执着于某些东西期待它变好。</p>]]></summary>
    <content type="html"><![CDATA[<p>应该去喜欢一切好的东西，而不是执着于某些东西期待它变好。</p>
]]></content>
  </entry>
  <entry>
    <title>在一个数据展示为基本功能的区块链上，如果一个人的隐私信息被恶意上传，那么他的隐私将永远保留在链的历史数据中。这显然是不行...</title>
    <link href="https://t.smallyu.net/#2024-12"/>
    <id>micro:2001710365</id>
    <published>2024-03-16T05:15:34Z</published>
    <updated>2024-03-16T05:15:34Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>在一个数据展示为基本功能的区块链上，如果一个人的隐私信息被恶意上传，那么他的隐私将永远保留在链的历史数据中。这显然是不行的，还得是老老实实做coin。</p>]]></summary>
    <content type="html"><![CDATA[<p>在一个数据展示为基本功能的区块链上，如果一个人的隐私信息被恶意上传，那么他的隐私将永远保留在链的历史数据中。这显然是不行的，还得是老老实实做coin。</p>
]]></content>
  </entry>
  <entry>
    <title>目前的数据上链仍然是没逻辑的。有人认为区块链不应该只停留在货币的层面，而是应用于数据。哪怕随着未来的科技发展，有足够的硬...</title>
    <link href="https://t.smallyu.net/#2024-11"/>
    <id>micro:1999048110</id>
    <published>2024-03-15T06:56:42Z</published>
    <updated>2024-03-15T06:56:42Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>目前的数据上链仍然是没逻辑的。有人认为区块链不应该只停留在货币的层面，而是应用于数据。哪怕随着未来的科技发展，有足够的硬件来支持这样的想法，但这样做的目的又是什么？如何解决监管和内容审查的问题？仍然停留在 “互联网” 的范畴应该是不行的。</p>]]></summary>
    <content type="html"><![CDATA[<p>目前的数据上链仍然是没逻辑的。有人认为区块链不应该只停留在货币的层面，而是应用于数据。哪怕随着未来的科技发展，有足够的硬件来支持这样的想法，但这样做的目的又是什么？如何解决监管和内容审查的问题？仍然停留在 “互联网” 的范畴应该是不行的。</p>
]]></content>
  </entry>
  <entry>
    <title>牛市对普通人来说意味着什么</title>
    <link href="https://smallyu.net/2024/03/13/%E7%89%9B%E5%B8%82%E5%AF%B9%E6%99%AE%E9%80%9A%E4%BA%BA%E6%9D%A5%E8%AF%B4%E6%84%8F%E5%91%B3%E7%9D%80%E4%BB%80%E4%B9%88/"/>
    <id>blog:https://smallyu.net/2024/03/13/%E7%89%9B%E5%B8%82%E5%AF%B9%E6%99%AE%E9%80%9A%E4%BA%BA%E6%9D%A5%E8%AF%B4%E6%84%8F%E5%91%B3%E7%9D%80%E4%BB%80%E4%B9%88/</id>
    <published>2024-03-13T15:58:55.000Z</published>
    <updated>2025-06-19T03:30:33.149Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>如果你曾经在市场低迷的时候，持有一些加密货币，那么牛市最大的意义，就是让你有限的资产获得了价值上的增长。</p>
<p>如果你是一位比特币信仰者，牛市最大的意义还在于，能够证明你的信仰是对的、几年前的眼光具有前瞻性，但也仅此而已，如果当时没有投入很多钱的话。</p>
<p>]]></summary>
    <content type="html"><![CDATA[<p>如果你曾经在市场低迷的时候，持有一些加密货币，那么牛市最大的意义，就是让你有限的资产获得了价值上的增长。</p><p>如果你是一位比特币信仰者，牛市最大的意义还在于，能够证明你的信仰是对的、几年前的眼光具有前瞻性，但也仅此而已，如果当时没有投入很多钱的话。</p><p>很多人看到现在 7W 的比特币眼红，后悔当年 3.8W 的时候没有多买点。但是放到 1 年前，3.8W 的比特币你敢买吗？是真不敢，谁知道当时还能跌到什么程度。如果我告诉你，一年后比特币会涨到 20W，你现在敢买吗？也不敢，是真的不敢。很简单的道理，没有人可以预测未来，只有在回顾历史的时候，人人都是股神。</p><p>最近比特币已经上了两次微博热搜，价格一涨人们就开始关注了。我也是眼睁睁看着 ETH 从 3400 掉到 1800，现在又涨到 4000。可是话说回来，这样的波动，能带来多大的改变呢，1W 块钱变 2W 块钱？好像也没太大意思。</p><p>牛市往往伴随着很多暴富故事。按照我的理解，有这么几种赚钱的方式：</p><ol><li><p>炒币，拿现货，价值投资。这样相对稳健，风险可控，但是收益也有限。敢投入多少资金，取决于你自己有多少可用于投资的资金。别看鲸鱼们动不动挣百万千万，他们真实拥有的资产，一定至少在用于投资的 5 倍以上。同样的，收益虽然绝对值多，但其实相对于他们的资产总量，也就那么回事。</p><p> 按照类似的比例，对普通人而言，收益也是有限的。敢把房子卖掉梭哈比特币的，那叫赌狗，那种做法，一般来说，挣多少钱就会赔多少钱，怎么挣来的就会怎么赔进去。除非能赚一波及时收手，可以能收住的也不是一般人，自制力已经超越人性。</p></li><li><p>开合约，加杠杆。这种类型的交易，拿个 10 块 20 块玩一玩就行了。如果不是玩，想赚钱，就不要碰，多少钱都得进去出不来，一般人玩不了这个。庄家做庄可以，如果你有能力控盘，但那个不是一般人。</p></li><li><p>发行 Meme 币。蹭当下的热度，什么火热蹭什么，AI 出新技术了就发个 AI 币，马斯克发推特有火箭的照片，就发个 ROCKET 币。总会有不长眼的玩家，为了热度瞎买，干这种事情，指不定一不小心就能赚很多很多钱。运气成分占很大一部分。另外是要有一定的运营和技术基础，得及时开交易的池子，懂得在社交媒体上推广，还得有一些美术能力，画个像样的 LOGO。</p><p> 哪怕不是 Meme 币，发个土狗币，只要有盘子，有人进来玩，有人愿意接盘，就能赚钱。但是技术、美术、运营各方面条件加起来，也需要点小小的成本。很多暴富的例子其实都是从土狗币来的。我亲眼见过有人干这个事情挣了钱的，但是我不太眼红这个，这种钱咱挣不了。</p></li><li><p>钓鱼网站。这个属于明确的违法行为了，需要黑客基础，以及相关经验，这个是不能考虑的。</p></li><li><p>撸空投。现在的空投猎人已经是一个小产业，批量参与早期项目，广撒网。这个也是随机性很强，需要运气，前段时间疯狂打铭文的，也有很多很多人花了手续费进去，最后啥也没捞到的。另外这里也有一个收益比例的问题，别看有些空投猎人一个项目上拿百万，他能够控制的用于投入的资产一定也非常多，这种机会给你，你也拿不出那么多钱啊，一般人也是没啥机会。我平时接触的空投性质的项目不多，也许是我消息闭塞，不懂这些人是怎么玩的。</p></li><li><p>DeFi。就是赚个收益，把钱压进质押平台，赚几十个点的利息。这种需要承担的是项目方 Rug 的风险，得看准项目方靠不靠谱。</p></li><li><p>MEV。每年几亿的市场，已经被很多有经验的厂商盯着了，想从里面挣钱可能得拼网速。</p></li><li><p>实打实地开发一个有技术含量的项目，作为核心开发成员，拿到初期分配的 token，然后等着 token 翻上几百倍。这种方式显然更安全，但是机会也非常少，尤其是现在的市场环境，几乎没有敢从头搞开发的，大多数项目是拼凑型的，类似于技术方案整合商。有能力在某一个技术方向有突出贡献的项目不但少，而且技术门槛也非常高，这个也不是普通人搞得了的。</p></li><li><p>正经工作，安心打工。像交易所的技术栈和互联网公司其实差别不是很大，办公地点不传统以及工资发 token 属于比较显著的特色。</p></li><li><p>挖矿。现在的挖矿应该不挣钱了。</p></li></ol><p>牛市有两种，一种是政策利好带来的价格增长，另一种是新技术引爆市场，吸引更多玩家进入圈子。目前的牛市属于前者，除了价格很疯狂，似乎没有太显著的技术出现，也没有现象级别的新玩意出现。除了价格在变，似乎什么都没变。或者说，可以认为目前还处于牛市早期，敢加仓的赶紧追高 :P</p><p>还有一点是，牛市会吸引更多资本的眼光，开始投入更多新的项目、新的公司，打工人的工作机会应该会变多一点。最近发现偶尔会出现一些名字小众的小公司，可能用人市场稍微好转了一点点？但是不出意外的话，猜测这些小公司，做的项目，也无非就是想象中的那几样……在哪儿打工不是打呢，身处裁员名单的人可能会觉得轻松点吧。</p><p>对于普通人而言，目前的牛市似乎真的没有意味着什么。今晚以太坊完成了坎昆升级，不知道能不能引起又一波 Layer 2 的风潮。我自己不太是以太坊信仰者，Layer 2 给人一种残缺的感觉，而现在的以太坊致力于推进 Layer 2 的发展。同样的，近期有一些公司在做比特币的 Layer 2 项目，同样不太看好，Bitcoin core 本身没兴趣搞扩容，甚至有能力直接让 BRC-20 一类的项目直接消失。</p><p>那么该信仰比特币吗，比特币好像跟普通人也没啥关系。期待有能代表信仰的项目出现。</p>]]></content>
  </entry>
  <entry>
    <title>打败比特币的一定不是另一个比特币，也不是其他区块链，而是另外的什么东西…</title>
    <link href="https://t.smallyu.net/#2024-10"/>
    <id>micro:1974869283</id>
    <published>2024-03-02T18:15:42Z</published>
    <updated>2024-03-02T18:15:42Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>打败比特币的一定不是另一个比特币，也不是其他区块链，而是另外的什么东西…</p>]]></summary>
    <content type="html"><![CDATA[<p>打败比特币的一定不是另一个比特币，也不是其他区块链，而是另外的什么东西…</p>
]]></content>
  </entry>
  <entry>
    <title>问题来了，Satoshi 设计了 PoH 吗？🧐 https://x.com/jahris_/status/17611...</title>
    <link href="https://t.smallyu.net/#2024-9"/>
    <id>micro:1962846281</id>
    <published>2024-02-25T07:47:48Z</published>
    <updated>2024-02-25T07:47:48Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>问题来了，Satoshi 设计了 PoH 吗？🧐 https://x.com/jahris_/status/1761155331642519886?s=46&amp;amp;t=8czJGF3gTtto8j7SZI_U-g</p>]]></summary>
    <content type="html"><![CDATA[<p>问题来了，Satoshi 设计了 PoH 吗？🧐</p>
<p><a href="https://x.com/jahris_/status/1761155331642519886?s=46&t=8czJGF3gTtto8j7SZI_U-g">https://x.com/jahris_/status/1761155331642519886?s=46&amp;t=8czJGF3gTtto8j7SZI_U-g</a></p>
]]></content>
  </entry>
  <entry>
    <title>看到一个有意思的东西，两天前，Satoshi 的早期合作者 Sirius 公布了他在 2009 年左右与 Satoshi...</title>
    <link href="https://t.smallyu.net/#2024-8"/>
    <id>micro:1962801615</id>
    <published>2024-02-25T03:39:23Z</published>
    <updated>2024-02-25T03:39:23Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>看到一个有意思的东西，两天前，Satoshi 的早期合作者 Sirius 公布了他在 2009 年左右与 Satoshi 的 邮件记录 ，其中有一段话提到，Satoshi 认为，PoW 是去中心化货币的唯一解决方案： https://github.com/mmalmi/mmalmi.github.io/blob/mas...</p>]]></summary>
    <content type="html"><![CDATA[<p>看到一个有意思的东西，两天前，Satoshi 的早期合作者 Sirius 公布了他在 2009 年左右与 Satoshi 的 <a href="https://mmalmi.github.io/satoshi/">邮件记录</a>，其中有一段话提到，Satoshi 认为，PoW 是去中心化货币的唯一解决方案：</p>
<p><a href="https://github.com/mmalmi/mmalmi.github.io/blob/master/satoshi/index.html#L949C1-L953">https://github.com/mmalmi/mmalmi.github.io/blob/master/satoshi/index.html#L949C1-L953</a></p>
<p>我还在想一个问题，Satoshi 如此聪明，为什么没有设计出像 Ethereum 的 PoS 或者 Solona 的 PoH ？</p>
]]></content>
  </entry>
  <entry>
    <title>最近半年的工作</title>
    <link href="https://b.smallyu.net/2024/02/17/%E6%9C%80%E8%BF%91%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C/"/>
    <id>blog-b:https://b.smallyu.net/2024/02/17/%E6%9C%80%E8%BF%91%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C/</id>
    <published>2024-02-17T02:49:03.000Z</published>
    <updated>2026-05-27T07:32:25.446Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>前几年关于工作内容方面的回顾：</p>
<ul>
<li>2023 年：《<a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>前几年关于工作内容方面的回顾：</p><ul><li>2023 年：《<a href="/2023/05/06/%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">半年的工作回顾</a>》</li><li>2022 年：《<a href="/2022/08/27/%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">一年的工作回顾</a>》</li></ul></blockquote><p>最近半年的工作主要是三件事。</p><h4 id="Abstract-Account-ERC-4337-项目的搭建"><a href="#Abstract-Account-ERC-4337-项目的搭建" class="headerlink" title="Abstract Account (ERC-4337) 项目的搭建"></a>Abstract Account (ERC-4337) 项目的搭建</h4><p>AA 账户实际上是一个智能合约，借助额外的 bundler 和 paymaster 实现零手续费、社交恢复等功能。ERC-4337 定义了一套规范，规范包括作为账户的合约支持哪些接口、bundler 如何与合约交互、paymaster 如何发挥作用等，目前各部分组件都有大概三到五种具体的项目实现，细节上有差异，但都是遵循了 ERC-4337 标准。</p><p>去年有一段时间抽象账户的概念挺火热，猜测是因为 Vitalik 提到过 Soulbound，项目方把 AA 账户作为灵魂绑定的解决方案来炒作了。像 ERC-4337 这种规范类的创新，一般来说不会带来太长远的影响，因为技术没变，只是使用方法变了，定义了一系列标准化的使用方法。短时间内用一用、解决燃眉之急也没什么不好。</p><h4 id="Op-Stack-的使用"><a href="#Op-Stack-的使用" class="headerlink" title="Op Stack 的使用"></a>Op Stack 的使用</h4><p>自从 Optimism 开源了 Op Stack 的一整套工具包，发行 Optimismtic 的 Layer 2 就变得容易起来，也就是去年挺火热的一键发链，Base、opBNB 等都是短时间就上线了。虽然 Optimism 的 Fault Proof 还不够完善，但哪怕是中心化一点，项目也是足够稳的，基于 Op Stack 完全能发行自己的网络。</p><p>我们把 AA 账户运行在 Layer 2 网络上，实际支撑了一场小型的游戏活动，虽然过程中遇到一些坎坷，但也算是积累了很有用的经验。从时间上，想非常深入这两种项目当然是不可能的，每个方向都能是一个细分领域。现在只是一个将将能用的状态。</p><p>不过有没有注意到一点，像 AA 账户、一键发链这些概念，都是阶段性的，去年火了今年就没人提了，今年更多提到的是比特币的 Layer 2、铭文、ERC-404 之类，热点总是在不断变化。</p><h4 id="搭建以太坊-PoS-网络"><a href="#搭建以太坊-PoS-网络" class="headerlink" title="搭建以太坊 PoS 网络"></a>搭建以太坊 PoS 网络</h4><p>自从 The Merge 以后，以太坊网络的搭建似乎更复杂了，虽然节省了挖矿的算力消耗，但是需要引入一堆复杂的 Validator 治理机制，来确保出块的有条不紊，PoS 就必然会涉及到如何成为验证者、哪些验证者有效等问题。原先的节点也拆分为两种类型，分成了执行层和共识层。相当于 PoS 解决了 PoW 出块不体面的问题，代价是需要另外一套复杂规则来完成这件事情。</p><p>以太坊是目前生态最丰富的链，执行层和共识层各有五、六种客户端，都实现了标准接口，但具体的体验不完全一样，尤其是性能方面，所以也花了不少时间试用每一种客户端。</p><p>以太坊最出色的应该是 EVM 而不是 PoS，能适配 EVM 已经是各种链的噱头之一。PoS 并不是以太坊的发明，Cardano 从一开始就使用了 PoS 而且保留了 UTXO 模型，所以偶尔会看到有人说 Bitcoin 和 Cardano 才是未来，与以太坊相比，单从共识机制上，Cardano 更像是 Bitcoin 的平替而不是以太坊。</p><p>比特币和以太坊属于两大阵营，比特币执着于加密货币，而以太坊重点探索加密货币在货币之外的应用价值。在每一个阵营下面，又有许许多多的 Altcoin 处于活跃状态。</p>]]></content>
  </entry>
  <entry>
    <title>关心时政，在大是大非上不要出错； 接触英语，未来的机会能越来越多，还能开阔眼界； 强身健体，活得久才是持续的战斗力，不要...</title>
    <link href="https://t.smallyu.net/#2024-7"/>
    <id>micro:1946203697</id>
    <published>2024-02-15T14:26:17Z</published>
    <updated>2024-02-18T12:50:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>关心时政，在大是大非上不要出错； 接触英语，未来的机会能越来越多，还能开阔眼界； 强身健体，活得久才是持续的战斗力，不要争一时之快； 学习技术，其实有很多方向可以深入，只是时间不够多。 想在区块链领域长久，还要克服 FOMO 情绪，能追热点最好，追不上也可以，要学好底层技术逻辑，</p>]]></summary>
    <content type="html"><![CDATA[<p>关心时政，在大是大非上不要出错；<br>接触英语，未来的机会能越来越多，还能开阔眼界；<br>强身健体，活得久才是持续的战斗力，不要争一时之快；<br>学习技术，其实有很多方向可以深入，只是时间不够多。  </p>
<p>想在区块链领域长久，还要克服 FOMO 情绪，能追热点最好，追不上也可以，要学好底层技术逻辑，</p>
]]></content>
  </entry>
  <entry>
    <title>2024 年是开始强身健体的一年！</title>
    <link href="https://t.smallyu.net/#2024-6"/>
    <id>micro:1943700696</id>
    <published>2024-02-14T12:45:06Z</published>
    <updated>2024-02-14T12:45:06Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>2024 年是开始强身健体的一年！</p>]]></summary>
    <content type="html"><![CDATA[<p>2024 年是开始强身健体的一年！</p>
]]></content>
  </entry>
  <entry>
    <title>从这个角度看，Bitcoin 是专注于自己货币的价值，从未偏心。Ethereum 的目标是世界计算机，ETH 是这台计算...</title>
    <link href="https://t.smallyu.net/#2024-5"/>
    <id>micro:1913463696</id>
    <published>2024-01-28T05:54:17Z</published>
    <updated>2024-01-28T05:54:17Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>从这个角度看，Bitcoin 是专注于自己货币的价值，从未偏心。Ethereum 的目标是世界计算机，ETH 是这台计算机运行的燃料费，而且 ETH 是无限增发的模型，没用供应量限制。燃料有没有炒作价格的价值呢，有点存疑了，甚至对于用户来说，燃料费越便宜越好……这是 BTC 和 ETH 从项目定位上就不一样的。</p>]]></summary>
    <content type="html"><![CDATA[<p>从这个角度看，Bitcoin 是专注于自己货币的价值，从未偏心。Ethereum 的目标是世界计算机，ETH 是这台计算机运行的燃料费，而且 ETH 是无限增发的模型，没用供应量限制。燃料有没有炒作价格的价值呢，有点存疑了，甚至对于用户来说，燃料费越便宜越好……这是 BTC 和 ETH 从项目定位上就不一样的。</p>
]]></content>
  </entry>
  <entry>
    <title>很显著的事实是，只要 Bitcoin 想，Bitcoin 就能搞出自己的虚拟机，技术能力上是不需要怀疑的，关键是他不想。</title>
    <link href="https://t.smallyu.net/#2024-4"/>
    <id>micro:1913460503</id>
    <published>2024-01-28T05:36:37Z</published>
    <updated>2024-01-28T05:36:37Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>很显著的事实是，只要 Bitcoin 想，Bitcoin 就能搞出自己的虚拟机，技术能力上是不需要怀疑的，关键是他不想。</p>]]></summary>
    <content type="html"><![CDATA[<p>很显著的事实是，只要 Bitcoin 想，Bitcoin 就能搞出自己的虚拟机，技术能力上是不需要怀疑的，关键是他不想。</p>
]]></content>
  </entry>
  <entry>
    <title>有没有办法把 Bitcoin 和 EVM 结合起来？</title>
    <link href="https://t.smallyu.net/#2024-3"/>
    <id>micro:1913450422</id>
    <published>2024-01-28T04:49:19Z</published>
    <updated>2024-01-28T04:49:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有没有办法把 Bitcoin 和 EVM 结合起来？</p>]]></summary>
    <content type="html"><![CDATA[<p>有没有办法把 Bitcoin 和 EVM 结合起来？</p>
]]></content>
  </entry>
  <entry>
    <title>PSBT 是一个不错的入口，原来 PSBT 从 2018 年开始就在讨论了，Bitcoin 的技术确实很硬核，密码学相关...</title>
    <link href="https://t.smallyu.net/#2024-2"/>
    <id>micro:1913450193</id>
    <published>2024-01-28T04:47:28Z</published>
    <updated>2024-01-28T04:47:28Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>PSBT 是一个不错的入口，原来 PSBT 从 2018 年开始就在讨论了，Bitcoin 的技术确实很硬核，密码学相关的创新比较多，相反看看 Ethereum 最近几年在干什么？</p>]]></summary>
    <content type="html"><![CDATA[<p>PSBT 是一个不错的入口，原来 PSBT 从 2018 年开始就在讨论了，Bitcoin 的技术确实很硬核，密码学相关的创新比较多，相反看看 Ethereum 最近几年在干什么？</p>
]]></content>
  </entry>
  <entry>
    <title>以太坊的 PoS 存在大量人为设计的元素，比如每个 epoch 包含 12 个 slot，为什么是 12 而不是 24、...</title>
    <link href="https://t.smallyu.net/#2024-1"/>
    <id>micro:1913445941</id>
    <published>2024-01-28T04:36:04Z</published>
    <updated>2024-01-28T04:36:04Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>以太坊的 PoS 存在大量人为设计的元素，比如每个 epoch 包含 12 个 slot，为什么是 12 而不是 24、36 ？每个 slot 包含至多 128 个 commitee，128 又是怎么来的？大概率是用一个比较大的数字除一下，保证通信量不会超过负载。 其实 PoS 本质上还是随机哲学，和 PoW 是不一样...</p>]]></summary>
    <content type="html"><![CDATA[<p>以太坊的 PoS 存在大量人为设计的元素，比如每个 epoch 包含 12 个 slot，为什么是 12 而不是 24、36 ？每个 slot 包含至多 128 个 commitee，128 又是怎么来的？大概率是用一个比较大的数字除一下，保证通信量不会超过负载。</p>
<p>其实 PoS 本质上还是随机哲学，和 PoW 是不一样的理念，以太坊 Casper FFG 提供的 finnally 机制从人文角度是可靠的，但总感觉缺少某种计算机层面的规则。</p>
]]></content>
  </entry>
  <entry>
    <title>This year (2023)</title>
    <link href="https://crazy.smallyu.net/2023/12/31/This-year-2023/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2023/12/31/This-year-2023/</id>
    <published>2023-12-31T02:54:51.000Z</published>
    <updated>2025-10-01T00:52:57.472Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>This is the last deep night of 2023, and I only have a little time to summarize the year. I just rented a new house yesterday, and I]]></summary>
    <content type="html"><![CDATA[<p>This is the last deep night of 2023, and I only have a little time to summarize the year. I just rented a new house yesterday, and I must complete moving into the house tomorrow. Meanwhile, today I am playing a mystery game outside.</p><p>Three years have passed, and my English listening ability has not improved as much as I expected. This year, I have listened to podcasts for just less than 100 hours, which is not enough to fully understand everything the speakers are saying. My writing ability has improved a little, but I still have many grammatical issues in sentences that need to be corrected by ChatGPT.</p><p>This year, I learned that many things do not always go as you expect, and many routines can be suddenly broken. For example, if you plan to save money regularly, but something unexpected suddenly disrupts your plan, it’s beyond your control. So, I try to make as few plans as possible about many things and just focus on being happy in the present moment.</p><p>This year, life seemed more hopeless everywhere, but I later realized that it might just be in my mind. Regarding my job, maybe I now have more opportunities to do effective things, although it’s busier than before. Moreover, it’s not the job that defines you, but rather how you define yourself. Therefore, I should strive to discover more new skills within myself.</p><p>This year, I ignored many moments of happiness in the life around me. I have not yet overcome my pain from the past, but it is getting better day by day. We have a good relationship, although it is growing slowly. I hope that next year, I can focus more on beautiful things rather than on unhappy ones. Moreover, I have already found something that makes my body rest and relax. I hope to find more things like this to make life better.</p><p>Regardless, I believe I am on the right road in most aspects.</p>]]></content>
  </entry>
  <entry>
    <title>最近想做一个简单的对比，是 Substack 好，还是 Mirror 好？ https://smallyu.substa...</title>
    <link href="https://t.smallyu.net/#2023-36"/>
    <id>micro:1850302486</id>
    <published>2023-12-11T15:25:22Z</published>
    <updated>2023-12-11T15:25:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最近想做一个简单的对比，是 Substack 好，还是 Mirror 好？ https://smallyu.substack.com/ https://mirror.xyz/smallyu.eth</p>]]></summary>
    <content type="html"><![CDATA[<p>最近想做一个简单的对比，是 Substack 好，还是 Mirror 好？</p>
<ul>
<li><a href="https://smallyu.substack.com/">https://smallyu.substack.com/</a></li>
<li><a href="https://mirror.xyz/smallyu.eth">https://mirror.xyz/smallyu.eth</a></li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>什么是技术好？能写出3D接雨水肯定不算，写得再好也搞不出 BRC20 的。</title>
    <link href="https://t.smallyu.net/#2023-35"/>
    <id>micro:1847292646</id>
    <published>2023-12-08T14:37:22Z</published>
    <updated>2023-12-08T14:37:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>什么是技术好？能写出3D接雨水肯定不算，写得再好也搞不出 BRC20 的。</p>]]></summary>
    <content type="html"><![CDATA[<p>什么是技术好？能写出3D接雨水肯定不算，写得再好也搞不出  BRC20 的。</p>
]]></content>
  </entry>
  <entry>
    <title>比特币虽然年龄最大，但是技术确实很硬核，很多技术都是源自比特币的。早在 2017 年的 BIP-84，就支持给每一笔交易...</title>
    <link href="https://t.smallyu.net/#2023-34"/>
    <id>micro:1843117752</id>
    <published>2023-12-06T15:30:09Z</published>
    <updated>2023-12-06T15:30:09Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>比特币虽然年龄最大，但是技术确实很硬核，很多技术都是源自比特币的。早在 2017 年的 BIP-84，就支持给每一笔交易生成一个新的地址，但都归属于同一个钱包。</p>]]></summary>
    <content type="html"><![CDATA[<p>比特币虽然年龄最大，但是技术确实很硬核，很多技术都是源自比特币的。早在 2017 年的 BIP-84，就支持给每一笔交易生成一个新的地址，但都归属于同一个钱包。</p>
]]></content>
  </entry>
  <entry>
    <title>才知道今年很火的 BRC20 的开发者，是从 BSV 团队出来的。BSV 背后的团队很厉害，技术很厉害，只不过是在维护...</title>
    <link href="https://t.smallyu.net/#2023-33"/>
    <id>micro:1837488479</id>
    <published>2023-12-03T13:58:22Z</published>
    <updated>2023-12-06T15:27:13Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>才知道今年很火的 BRC20 的开发者，是从 BSV 团队出来的。BSV 背后的团队很厉害，技术很厉害，只不过是在维护 BSV 的生态了。</p>]]></summary>
    <content type="html"><![CDATA[<p>才知道今年很火的 BRC20 的开发者，是从 BSV 团队出来的。BSV 背后的团队很厉害，技术很厉害，只不过是在维护 BSV 的生态了。</p>
]]></content>
  </entry>
  <entry>
    <title>曾经和【罗永浩】在直播上约架的【王自如】，现在成了格力的副总裁，最近的舔狗视频很火。 【罗永浩】和【李笑来】是发小，也都...</title>
    <link href="https://t.smallyu.net/#2023-32"/>
    <id>micro:1835664498</id>
    <published>2023-12-01T08:18:12Z</published>
    <updated>2023-12-01T08:18:12Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>曾经和【罗永浩】在直播上约架的【王自如】，现在成了格力的副总裁，最近的舔狗视频很火。 【罗永浩】和【李笑来】是发小，也都曾经是新东方的英语老师。 【李笑来】的一次关于区块链的宣讲，启发【郭宏才】进入币圈。 【郭宏才】在以太坊合并的时候，分叉了以太坊的 PoW 版本。 【李笑来】夸过莱特币，只是改了个数，分叉了比特币，就...</p>]]></summary>
    <content type="html"><![CDATA[<p>曾经和【罗永浩】在直播上约架的【王自如】，现在成了格力的副总裁，最近的舔狗视频很火。<br>【罗永浩】和【李笑来】是发小，也都曾经是新东方的英语老师。<br>【李笑来】的一次关于区块链的宣讲，启发【郭宏才】进入币圈。<br>【郭宏才】在以太坊合并的时候，分叉了以太坊的 PoW 版本。<br>【李笑来】夸过莱特币，只是改了个数，分叉了比特币，就值钱了。<br>莱特币的创始人是【李启威】，【李启威】的哥哥叫【李启元】，开过交易所。<br>直到2023 年，【李启元】和【达鸿飞】还一起在香港开 Foresight 的会。  </p>
]]></content>
  </entry>
  <entry>
    <title>也许事情没那么糟糕</title>
    <link href="https://b.smallyu.net/2023/11/29/%E4%B9%9F%E8%AE%B8%E4%BA%8B%E6%83%85%E6%B2%A1%E9%82%A3%E4%B9%88%E7%B3%9F%E7%B3%95/"/>
    <id>blog-b:https://b.smallyu.net/2023/11/29/%E4%B9%9F%E8%AE%B8%E4%BA%8B%E6%83%85%E6%B2%A1%E9%82%A3%E4%B9%88%E7%B3%9F%E7%B3%95/</id>
    <published>2023-11-29T15:46:00.000Z</published>
    <updated>2026-03-02T09:12:31.003Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近博客的更新频率出问题了，也许很多事情都出问题了。我也在反思到底出了什么问题，原因一定是多方面的。</p>
<h3 id="工作"><a href="#工作" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>最近博客的更新频率出问题了，也许很多事情都出问题了。我也在反思到底出了什么问题，原因一定是多方面的。</p><h3 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h3><p>首先表面上的原因是没有时间，现在每天的有效工作时间平均在 7 小时左右，有效工作时间指去掉了休息时间甚至摸鱼的时间，真正工作过的应该明白这是一种怎么样的强度。</p><p>不管工作效率怎么样，时间是在这儿了。不过奇怪的是即使花了这么多时间，也感觉没做出什么事情，要真干点什么事也就拿出来说了，工作的进度甚至达不到我自己的预期，这种情况无非就两个原因：1.工作效率低，2.对工作进度期望高。</p><h4 id="工作效率低"><a href="#工作效率低" class="headerlink" title="工作效率低"></a>工作效率低</h4><p>我想两方面原因都有。有一些主观原因造成工作效率低的，比如试图用增加体力输入的方式解决 bug，已经不止一次遇到过，在 debug 的时候，觉得即使效率低一点，用笨办法，忍一忍就能把问题给解决了，问题只是暂时的，没想到一进去就出不来了，bug 的复杂程度超过想象。如果一开始就能花更多时间去理解，而不是无脑尝试，可能结果会好一点。</p><p>不过谁能想到仅仅只是把软件运行起来，就会有那么多坑，确实是超过理解了。最近一个新加入的同事也在尝试相关的技术，遇到一个匪夷所思的问题，我花了至少两小时的时间也没能解决，最后爱莫能助了。想起我之前遇到类似匪夷所思的问题，还有很多很多……可能真的是某种奇怪的道路，总得踩几个坑才能过去吧。</p><p>在心态上，我倒是能体谅和理解自己选择笨办法这样的做法。当时刚入职，首要的是能够完成工作任务，把问题解决掉，即使是在表面上，哪怕多花点时间呢，来不及把事情做的体面。另外其实生态内的软件也没那么靠谱，都是几十个 star 的小项目，需要把不同公司开发的、有一定个性化的项目拼接起来，按照自己的预期和逻辑运行。</p><h4 id="对工作进度期望高"><a href="#对工作进度期望高" class="headerlink" title="对工作进度期望高"></a>对工作进度期望高</h4><p>再是对工作进度期望高的问题。这里涉及到一个底层逻辑的变化。对于一个研发型的区块链公司来说，无论项目大小，工作的的逻辑是开发出某个细分技术领域的产品，争取能够做到头部，拉拢一批看好领域前景的粉丝，然后发币挣钱。具体到工作内容上，把开发环境运行起来只是第一步，后续的开发是工作重点。</p><p>而对于一个开发游戏为主的链游公司来说，思路是不一样的，在区块链方面更多是站在使用者的角度，希望能够稳定运行一个区块链网络，然后以某种形式将游戏和区块链的概念结合起来。具体到工作内容上，搭建环境、选择最正确可靠的方式运行一个网络，本身就是工作重点，即使涉及到少许的修改，大多也是对部署工具的整改，以符合自己使用的预期为主。</p><p>这就造成了对工作进度理解的偏差，由于原本的思维惯性，认为搭环境应该是最简单的一件事情，只是第一个步骤而已，都还没有进入正式工作的节奏，所以总觉得进度是延误的，希望尽可能加快进度，给自己也带来很多身心上的负担。但如果换个角度想，搭建环境就已经是工作重点了呢，运行和维护一个不出问题的网络环境，就是正式的工作内容了。这样去理解，事情会清晰很多。</p><p>再一个体验比如工作性质上的差异，区块链项目设想的目标群体是有一定技术背景的、能够理解技术特性的，无论是客户还是用户，所以要求项目要有差异化的东西，如果一个区块链项目实现出了和某知名项目一模一样的功能，甚至直接使用了某某开源代码，并且以此为卖点，其实是一件很奇怪的事情，这个项目本身就没有存在的必要了。相反，每一行代码都自己开发，是一个团队技术能力强的体现。</p><p>链游项目设想的目标群体是不一样的，面对的主要是游戏玩家和羊毛党，所以要求尽可能使用知名品牌的开源项目，最好是一行代码不改，直接运行，用户才比较容易相信你的区块链网络是没有问题的、让人放心的。如果一个技术人员想从链游项目的区块链网络上找区块链的技术特性，并且对此抱有某种信念，那也是挺离谱的事情。一个游戏玩家对游戏抱有信念，并且愿意参与到游戏的周边生态中，才是比较正常的逻辑，</p><h3 id="行业"><a href="#行业" class="headerlink" title="行业"></a>行业</h3><p>更深层次一点的原因是对行业前景失去信心。</p><p>美国是少数全面禁止加密货币的国家，不允许明面上的交易行为，更不能挖矿，发币是虽然没有立法但是明确违法的行为，金融相关的操作也是不可能的，整个行业都处于灰色地带，过去几年知名的区块链公司都逐渐消声匿迹。直观一点看，招聘软件上的职位全是几个月前就存在，或者以前还有现在没有了。行情差的可怕，而且短期内看不到好转的迹象。</p><p>在这样的情况下，难免会有一种无力感。比失败更可怕的是没有前进的机会，如果整个行业都不好，作为从业者又该怎么办呢，看不到希望，就没有昂扬向上的热情，对未来是倍感绝望的，低落的情绪下，也很难发掘有趣的东西。</p><p>以区块链为主导的行业，在美国已经几乎行不通了。</p><p>上面提到了不同类型公司在工作思维上的差异，也因此想到，也许链游还有生存空间呢，链游是以游戏为主导的行业，而正因为有运行区块链网络的需求，多少能给区块链留一点机会。虽然在工作性质上有比较大的差异，但正因为目标群体不同、盈利模式不同，才造成工作内容上的区别。灰色网站还有技术人员负责升级维护呢。</p><p>当然链游也有很多种类型，我相信以区块链为主导的游戏一定会死，但是在游戏上加入区块链元素的模式，就不好说了，关键是游戏公司要有向区块链靠拢的意愿。我不了解游戏行业，链游的情况也比较复杂，印象中游戏在美国是很难活下去的，还是得针对外部市场。总之这是一个不见得有很大希望但至少还不会让人感到绝望的方向，接下来可以多关注一下。</p><h3 id="政治"><a href="#政治" class="headerlink" title="政治"></a>政治</h3><p>最深层次的原因是整体的经济环境不好。</p><p>前两年全世界都处于经济下行的趋势，如今美国面临近几十年来最严重的经济衰退，极有可能在接下来几年进入经济大萧条的时代。所以不仅仅是区块链行业没有前景，尤其在美国，各行各业的情况都非常凄凉，人民看不到任何再次经济崛起的希望。</p><p>由于经常关注一些时政类节目，看到了太多政治体制上的不足，以及发生在社会中的悲惨事件，明白了美国是一个会让人感到人人自危的国家。各种信息和观点似乎都在宣告，美国政体变动频繁，美国社会即将进入动乱，有可能会面临真正的战争，在这样的危机下，个人要做好保护自己的准备。</p><p>不过时间一长，也难免会产生怀疑，真的有那么糟糕吗？就业环境确实差，一年比一年差。只是目测都感觉商场的人变少了，以前最繁华的商圈，也有大批商店关门了。最近商场的服装店开始普遍加顾客好友，像是要从实体拓展线上销售的样子。但仍然有很多企业在正常运作，歌手的演唱会在全世界开，电视节目不断出新，有些优秀的开源软件甚至诞生于爆发战争的几年，某些初创的科技公司也没说社会环境有变化就不干了。</p><p>最近了解到一个词叫 “政治抑郁”，顾名思义就是因为对社会环境不满而导致心情低落，对生活丧失信心的一种现象。在美国，任何社会事件，深挖一锄头，都能挖到执政党身上。但是美国的经济虽然难以再向上增长，由于体量巨大，也不可能在短时间内崩溃，溃而不崩是很多人的共识。也就是说，现在的社会环境让人感到难受，事实是确实会这样持续很多年。</p><p>历史上发生过几次大型的经济萧条，但都没有导致国家层面的颠覆，而是按部就班走过来了。在经济萧条的年代，尽管大多数行业处于衰败的状态，但也有少部分行业能正好顺应经济下行的趋势，显得欣欣向荣。比如很典型的例子是，当经济环境不好的时候，口红的销量会显著增加，因为口红是比较低成本的能够让女性感到愉悦的消费品。再比如当人们的消费能力普遍下降的时候，电影的销量会增加很多，因为看电影是比较省钱的娱乐活动。</p><p>更为显著的例子是，在日本 “失去的三十年” 期间，漫画产业和宅文化变得兴起，很多人愿意沉浸在文化作品中，逃避令人痛苦的现实生活，希望在虚拟的世界中找到快乐。也有一定被迫的因素，在整体经济低迷的环境下、年轻人就业困难，只能呆在家，给宅文化创造了有利的机会。也正是因为类似这样的一些原因，我开始关注和看好链游行业，也许能在其中发现新的机会。</p><h3 id="怎么做"><a href="#怎么做" class="headerlink" title="怎么做"></a>怎么做</h3><p>分享几句听起来有道理的话。</p><p>“一个人赚不到认知以外的钱”，网上有很多钓鱼信息，尤其是加密货币领域的一些骗局，空投、MEV Bot、中奖之类，包括炒币、打铭文、挖矿，该买什么不能买什么，在这种时候就能意识到这句话是对的，如果实实在在上当受骗过，就会格外认为这句话有道理了。</p><p>“一个人的认知配得上他的苦难”，这是用来形容最近很火的一个悲剧事件主人公的一句话，有一对小夫妻在美国买到了烂尾楼，求助无门还被开发商打了。房地产突然暴雷是一方面，他们敢在一个不合时宜的时机买房是另一方面，他们的认知不足以让他们避开苦难，随之而来的痛苦只好自己承担了。这句话可以毫无违和感的应用到其他领域，工作不开心了，生活遇到困难了，都可以归咎于自己的认知不足。</p><p>“当老虎袭来的时候，你不需要跑的比老虎快，只需要跑的比其他人快”，这句话也挺有意思，所以要保持对时事的关注，不见得能从中获得多大的收益，要是能够避开一些大坑，也算是万幸了。</p><p>总之，要关心身边美好的人和事，世界没有想象中那么糟糕。</p>]]></content>
  </entry>
  <entry>
    <title>想到关于技术正确，SOL 的技术好吗？反正挺特立独行的，最近翻了3倍，你不会用他的生态但他就是值钱 TRX的技术呢，当年...</title>
    <link href="https://t.smallyu.net/#2023-31"/>
    <id>micro:1818060672</id>
    <published>2023-11-20T01:10:39Z</published>
    <updated>2023-11-20T01:10:39Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想到关于技术正确，SOL 的技术好吗？反正挺特立独行的，最近翻了3倍，你不会用他的生态但他就是值钱 TRX的技术呢，当年在国内员工拉横幅讨薪，技术能好到哪儿去，白皮书上根本看不到技术特点，但是 TRX 上 USDT 的交易量世界最高，灰色服务都用他，这玩意儿你咋说 NEO 生态的活跃程度很低，但是关联的几个币轮流隔一段...</p>]]></summary>
    <content type="html"><![CDATA[<p>想到关于技术正确，SOL 的技术好吗？反正挺特立独行的，最近翻了3倍，你不会用他的生态但他就是值钱</p>
<p>TRX的技术呢，当年在国内员工拉横幅讨薪，技术能好到哪儿去，白皮书上根本看不到技术特点，但是 TRX 上 USDT 的交易量世界最高，灰色服务都用他，这玩意儿你咋说</p>
<p>NEO 生态的活跃程度很低，但是关联的几个币轮流隔一段时间就拉三分之一，公司整体都很有钱</p>
<p>只不过最近新出的很少，TIA 前两天上线到现在也翻了三倍，要说是技术驱动也很难说</p>
]]></content>
  </entry>
  <entry>
    <title>不过最近有点看不懂，也没新东西出现，行情好转了不少。现在的热点是 BRC-20 ？要全靠 ETF 的消息驱动了。</title>
    <link href="https://t.smallyu.net/#2023-30"/>
    <id>micro:1817742977</id>
    <published>2023-11-19T04:34:47Z</published>
    <updated>2023-11-19T04:34:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>不过最近有点看不懂，也没新东西出现，行情好转了不少。现在的热点是 BRC-20 ？要全靠 ETF 的消息驱动了。</p>]]></summary>
    <content type="html"><![CDATA[<p>不过最近有点看不懂，也没新东西出现，行情好转了不少。现在的热点是 BRC-20 ？要全靠 ETF 的消息驱动了。</p>
]]></content>
  </entry>
  <entry>
    <title>如果把区块链认为是一种软件，那它确实是一种软件。任何软件工程的方法论，都能套用在上面。 不过区块链真正的魅力，是让事情变...</title>
    <link href="https://t.smallyu.net/#2023-29"/>
    <id>micro:1817740824</id>
    <published>2023-11-19T04:20:09Z</published>
    <updated>2023-11-19T04:20:09Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果把区块链认为是一种软件，那它确实是一种软件。任何软件工程的方法论，都能套用在上面。 不过区块链真正的魅力，是让事情变得好玩起来，让更多人参与到某种新的玩法中，理念、信仰……</p>]]></summary>
    <content type="html"><![CDATA[<p>如果把区块链认为是一种软件，那它确实是一种软件。任何软件工程的方法论，都能套用在上面。</p>
<p>不过区块链真正的魅力，是让事情变得好玩起来，让更多人参与到某种新的玩法中，理念、信仰……</p>
]]></content>
  </entry>
  <entry>
    <title>无意间加进一个叫 “PoAI 共识算法研讨” 的微信群，大意是用联邦学习的结果作为工作量证明，在组建社区什么的，从各种角...</title>
    <link href="https://t.smallyu.net/#2023-28"/>
    <id>micro:1817724237</id>
    <published>2023-11-19T02:33:54Z</published>
    <updated>2023-11-19T02:33:54Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>无意间加进一个叫 “PoAI 共识算法研讨” 的微信群，大意是用联邦学习的结果作为工作量证明，在组建社区什么的，从各种角度来看，这事肯定成不了。 由此想到国内的一些不靠谱的项目，尤其是敢说自己要开发共识算法的，基本上都不知道共识算法是什么。说自己要开发区块链的，大多是在做链下应用的开发。 这些项目有一个共同点，就是重点...</p>]]></summary>
    <content type="html"><![CDATA[<p>无意间加进一个叫 “PoAI 共识算法研讨” 的微信群，大意是用联邦学习的结果作为工作量证明，在组建社区什么的，从各种角度来看，这事肯定成不了。</p>
<p>由此想到国内的一些不靠谱的项目，尤其是敢说自己要开发共识算法的，基本上都不知道共识算法是什么。说自己要开发区块链的，大多是在做链下应用的开发。</p>
<p>这些项目有一个共同点，就是重点关心谁能够参与、激励怎么分配，而这些问题恰好是最不重要的，有钱谁不知道怎么花啊？</p>
]]></content>
  </entry>
  <entry>
    <title>最近几个月博客的更新频率出问题了，也许很多事情都出问题了……</title>
    <link href="https://t.smallyu.net/#2023-27"/>
    <id>micro:1806869183</id>
    <published>2023-11-11T17:16:32Z</published>
    <updated>2023-11-11T17:16:32Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最近几个月博客的更新频率出问题了，也许很多事情都出问题了……</p>]]></summary>
    <content type="html"><![CDATA[<p>最近几个月博客的更新频率出问题了，也许很多事情都出问题了……</p>
]]></content>
  </entry>
  <entry>
    <title>web3 社交其实是很奇怪的需求，为什么要和匿名的陌生人社交呢？</title>
    <link href="https://t.smallyu.net/#2023-26"/>
    <id>micro:1802161396</id>
    <published>2023-11-08T15:46:58Z</published>
    <updated>2023-11-08T15:46:58Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>web3 社交其实是很奇怪的需求，为什么要和匿名的陌生人社交呢？</p>]]></summary>
    <content type="html"><![CDATA[<p>web3 社交其实是很奇怪的需求，为什么要和匿名的陌生人社交呢？</p>
]]></content>
  </entry>
  <entry>
    <title>token 价格是反映一个区块链项目真实价值的唯一指标。</title>
    <link href="https://t.smallyu.net/#2023-25"/>
    <id>micro:1773979862</id>
    <published>2023-10-22T03:10:35Z</published>
    <updated>2023-10-22T03:10:35Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>token 价格是反映一个区块链项目真实价值的唯一指标。</p>]]></summary>
    <content type="html"><![CDATA[<p>token 价格是反映一个区块链项目真实价值的唯一指标。</p>
]]></content>
  </entry>
  <entry>
    <title>只有炒币才有币圈的感觉……</title>
    <link href="https://t.smallyu.net/#2023-24"/>
    <id>micro:1773772921</id>
    <published>2023-10-21T12:17:25Z</published>
    <updated>2023-10-21T12:17:25Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>只有炒币才有币圈的感觉……</p>]]></summary>
    <content type="html"><![CDATA[<p>只有炒币才有币圈的感觉……</p>
]]></content>
  </entry>
  <entry>
    <title>如何健康地远程工作</title>
    <link href="https://smallyu.net/2023/10/10/%E5%A6%82%E4%BD%95%E5%81%A5%E5%BA%B7%E5%9C%B0%E8%BF%9C%E7%A8%8B%E5%B7%A5%E4%BD%9C/"/>
    <id>blog:https://smallyu.net/2023/10/10/%E5%A6%82%E4%BD%95%E5%81%A5%E5%BA%B7%E5%9C%B0%E8%BF%9C%E7%A8%8B%E5%B7%A5%E4%BD%9C/</id>
    <published>2023-10-09T16:39:09.000Z</published>
    <updated>2025-11-09T09:22:13.424Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>最近两个月在以远程工作的形式上班，当然远程工作并不是像很多人憧憬的那样，穿着泳衣在沙滩上晒太阳，谈笑之间上百万的交易就成交了。远程工作仅仅只是办公场地的不同，至于工作制度和工作流程，属于整个公司和团队的氛围和文化选择，暂时不讨论这方面的问题。</p>
<p>远程工作和现场办]]></summary>
    <content type="html"><![CDATA[<p>最近两个月在以远程工作的形式上班，当然远程工作并不是像很多人憧憬的那样，穿着泳衣在沙滩上晒太阳，谈笑之间上百万的交易就成交了。远程工作仅仅只是办公场地的不同，至于工作制度和工作流程，属于整个公司和团队的氛围和文化选择，暂时不讨论这方面的问题。</p><p>远程工作和现场办公相比，有好有坏。好的地方是能比较方便打造适合自己的工作环境，比如电脑桌的高度不太对，可以换一张让自己舒服的桌子，在公司的办公桌就不那么方便换掉了。</p><p>也有一些不好的地方，比如生活和工组场所相同导致生活和工作没有明确的边界感，像我之前有过比较离谱的情况，找 bug 没有头绪，心烦意乱，晚上已经躺下准备睡觉了，睡不着，半夜 1 点多起床 debug 了一小时代码，稍微有点进展后继续睡觉，第二天 8 点钟起床继续 debug，然后继续上一天班。一天下来状态会很差，这是非常非常不健康的行为，一定要想办法杜绝。</p><p>为了针对和解决不好的习惯，需要一些明确可行的规则来规范个人行为，主要是作为参与者，应该如何在远程工作的状态下，保持自己的身心健康。</p><h3 id="工作地点"><a href="#工作地点" class="headerlink" title="工作地点"></a>工作地点</h3><p>因为需要合适的工作环境，所以并不能太自由地选择工作地点，比如背上电脑到商场，在咖啡店呆一天，或者找个图书馆、自习室，都是不合适的，不但要花钱买咖啡，而且那种消费类型的座位都不适合久坐，工作中还有需要视频会议的时候，在公共场合的话也不方便。尤其是对于程序员来说，工作需要 27 寸的外接显示器，需要人体工学椅，也需要能让人专注的环境，还涉及到工作时长的问题，如果下班晚，咖啡店不会营业到那个时候，就有麻烦了。</p><p>WeWork 之类的共享办公室本身选择比较少，而且价格很高，一天要 100～300 块钱，长期用的话非常贵了，很多共享办公室也是不支持保存个人物品的，产业整体并不成熟，不是好的选择。</p><p>综合来看，工作地点只能是在自己的房间里。如果有属于自己的房子，有一间闲置的书房，或者空闲的房间，那么多余的房间就可以作为工作地点。</p><p>如果是租房子住，情况会稍微恶劣一点，一般租房子只会租一间自己的卧室，卧室的书桌就变成了工作的地方。如果专门为了远程工作租另外一间屋子，成本是比较高的。而且提供办公场所原本是公司的责任，在远程工作的形式下这个步骤就省略了，如果让这个成本转嫁到员工身上，也挺违反直觉的，所以自己另外租一间房子实在是没有道理。</p><p>还有一种方案是移居到低消费的城市，由于远程工作不受地点约束，降低消费的同时还能提高生活质量是可行的，但是这种方案仅适用于在当前城市没有任何朋友的情况，否则即使只为了某一个人，也没办法换城市。</p><h3 id="生活和工作要要有明确界限"><a href="#生活和工作要要有明确界限" class="headerlink" title="生活和工作要要有明确界限"></a>生活和工作要要有明确界限</h3><p>在现场工作的时候，生活和工作会有明显的区分，至少身处的环境是完全不一样的两个地方，一个是家，一个是公司，比较容易做出生活和工作的区分。可能会有一种感觉，即使工作再累，回到家也是该休息的时候。也许电脑放在公司就不会带回家，也许带回家不打开，也许工作环境在公司内网，你想在家工作都不行。总之种种原因，会给你一个明确的、生活时间和工作时间的区分。</p><p>但是如果生活和工作的场所相同，都在同一间屋子里，而且还是远程工作，就出问题了。</p><p>想象一下，公司在你的办公桌旁边放了一张床，还提供了所有生活所需的物品，然后你今后要住在公司的办公桌旁边，起床就能看见办公桌，是不是一件很可怕的事情。</p><p>再想象一下，你一整天的生活，起床之后一个小时就开始工作，工作结束之后两个小时就准备睡觉，在工作之外的时间你都仍然呆在房间里，是不是一种会让人发疯的场景。</p><p>远程工作最重要的一点，就是要保证生活和工作有明确的界限，为了达到这样的效果，简单列出几点行为：</p><ul><li>按时起床，预留出“通勤”时间</li><li>在原本应该通勤的时间里，出门散步，假装在通勤，绝对不可以睡懒觉</li><li>上班时间要穿好衣服和鞋子，不能穿居家的衣服或睡衣，必须是随时能够出门的状态</li><li>摆正外接摄像头的位置，表示进入上班时间</li><li>打开桌面上的时钟摆件，表示进入上班时间</li><li>打开窗户，表示进入上班时间</li><li>下班时间后，外出散步相当于通勤，结束工作</li><li>下班时间后，回到房间，拖一次地，让地板是湿的</li><li>下班时间后，不在电脑上进行工作相关的操作</li><li>……</li></ul><p>这些行为并不是具体的，也不一定是好的，只是举一些例子，重点是通过一系列物理上的行动，来给自己明确的信号，经过四五种操作以后，就进入上班时间了，经过另外四五种操作以后，就进入下班时间了。单纯光靠时间概念，到点了就上下班，很难让自己有明确的感受，也许本就非常自律的人可以做到，如果还做不到，就需要先依赖一些繁琐的行为，来给自己制造分界线。</p><h3 id="户外活动"><a href="#户外活动" class="headerlink" title="户外活动"></a>户外活动</h3><p>上面有提到，在本应该通勤的时间，要出门散步，假装在通勤。不只是为了保持和现场工作一样的生活节奏，更重要的是为了保持身体健康，确保有足够的时间在户外进行活动，哪怕是简单的散步，也一定好过整天待在家里。</p><p>有人认为远程工作的好处之一是可以省去通勤的时间，用来睡懒觉。这是非常错误的想法，多出来的时间不但不可以用来休息，还要刻意用来锻炼身体才对，天天在家里呆着估计也没人受得了。</p><h3 id="参加社交活动"><a href="#参加社交活动" class="headerlink" title="参加社交活动"></a>参加社交活动</h3><p>远程工作以后，我甚至开始怀疑和人类说话是一种生理需求。也许是认真工作的缘故，也许是工作日从早到晚都在同一个场所中，而且见不到活人、不能和人说话，感觉周末异常想出去玩，然后连续玩两天。</p><p>不在乎游戏好不好玩，只是想换个地方呆着，换换脑筋放松一下，见到不同的人，玩不同的游戏，干点和工作无关的事。</p><h3 id="番茄工作法"><a href="#番茄工作法" class="headerlink" title="番茄工作法"></a>番茄工作法</h3><p>现场办公的时候，可能时不时有人和你说句话、从你工位旁边走过、制造出什么声响，或者自己站起来去饮水机接一杯水、下楼买瓶饮料、去一趟洗手间等，各种各样的小事件，都会分散你的注意力，打断你的思考。这些事情也许会让你觉得麻烦，但是这些事情也能让你不要长时间专注于某件事情。</p><p>过于长时间的专注不是一件好事，会让头脑变得麻木迟钝，对于身体也是一种压力，会让人感觉腰酸背痛。人需要隔一段时间就站起来活动活动、舒展筋骨。</p><p>番茄工作法的大致含义是，每工作 25 分钟，休息 5 分钟，算作一个番茄时间。番茄工作法能有比较高的知名度，还是有一定道理的，这样的时间分配是一种不错的实践。</p><p>不要用 Stretchly 之类会在屏幕上弹窗的软件，使用体验并不好，它会直接打断你正在进行的工作，这很让人生气，你大概率会手动直接关掉它的弹窗。即使有些软件可以提前 30 秒通知你要弹窗了，体验也不会变好，手头上的事情如果在 30 秒内无法放下呢，本次 break time 就直接失效了。而且弹窗直接覆盖掉整个屏幕的方式，会让人有轻微的不安，担心是否有人给自己发消息，担心错过屏幕上的什么动态。</p><p>所以最好用会响起闹铃的倒计时。开始工作后计时，25 分钟后响起闹铃，如果不手动关闭闹铃，闹铃就会一直响下去。这种闹铃其实是一个很好的特性，如果你不放下手上的工作，闹铃就在不断提示你，是时候站起来放松一下了。当然自己也要自律，直到自己真的站起身，再动手把闹铃关掉。</p><p>但有时候开始工作会忘记启动倒计时，而且频繁手动开启倒计时也很麻烦，可以直接设定多个闹钟，在固定的时间响起，比如每个小时的 25 分和 55 分都响起一次。你不一样严格按照闹钟的时间进行工作，但至少闹钟会按时提醒你，该休息了。</p><p>实践证明，适度的休息放松不但不会耽误工作，而且会让工作效率变得更高。有些难题会一时想不到解决办法，往往在休息放松的时候，就有灵感了。</p><h3 id="仪式感"><a href="#仪式感" class="headerlink" title="仪式感"></a>仪式感</h3><p>作为内容的补充，偶然发现上面描述的种种行为，其实是在创造一种仪式感，上班需要仪式感，下班需要仪式感，很多时候仪式感是周围环境创造出来的，有时也可以自己主动去创造。生活需要仪式感。</p>]]></content>
  </entry>
  <entry>
    <title>为什么比特币不用概率加密函数</title>
    <link href="https://smallyu.net/2023/10/04/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AF%94%E7%89%B9%E5%B8%81%E4%B8%8D%E7%94%A8%E6%A6%82%E7%8E%87%E5%8A%A0%E5%AF%86%E5%87%BD%E6%95%B0/"/>
    <id>blog:https://smallyu.net/2023/10/04/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AF%94%E7%89%B9%E5%B8%81%E4%B8%8D%E7%94%A8%E6%A6%82%E7%8E%87%E5%8A%A0%E5%AF%86%E5%87%BD%E6%95%B0/</id>
    <published>2023-10-04T14:36:18.000Z</published>
    <updated>2025-11-09T09:22:13.310Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="概率加密函数"><a href="#概率加密函数" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<h3 id="概率加密函数"><a href="#概率加密函数" class="headerlink" title="概率加密函数"></a>概率加密函数</h3><p>在常用的对称加密中，一个明文对应一个密文。有一种叫概率加密的方式，会在加密的过程中加入随机数，达到一个明文对应多个密文的效果，</p><ol><li>概率加密函数为什么很少用</li></ol><p>需要区分三个概念：加密、签名、哈希。概率加密函数属于对称加密的一种，而实际上区块链系统中很少用到加密，无论是对称加密还是非对称加密。比特币的白皮书中只提到过签名和哈希，签名是在发起交易的时候用来确认资产所有权的，哈希是在挖矿的时候确认出块权的，并没有提到关于加密的使用。</p><p>加密的应用场景比较少是主要原因，存储类项目可能会用到对文件的加密，但也属于用户行为，区块链系统本身不参与数据的加密保护。</p><p>概率加密函数想要替代签名和哈希更是不可能的事情，它本身就不具备那样的能力。</p><ol start="2"><li>概率加密函数的概率分布</li></ol><p>有概率就会有概率分布，比如正态分布。对于概率加密函数来说，均匀的概率分布是比较理想的，否则在概率分布已知的情况下，根据加密出的密文内容，攻击者有可能还原出明文内容，是很危险的。只有随机强度一致，攻击者才无从下手。</p><p>所以概率加密函数几乎没有选择，尽可能分布均匀是常见的做法。</p><h3 id="新式落地窗"><a href="#新式落地窗" class="headerlink" title="新式落地窗"></a>新式落地窗</h3><p>在一个优美和睦的动物森林里，不知怎的流行起了落地窗风格的房子，不仅透光良好，而且设计又美观又高级。小狐狸是有名的建筑师，能够建造出这种流行的带有很大落地窗的房子，森林里的小动物们纷纷找小狐狸盖房子。</p><p>小鹦鹉是森林里的百事通，消息灵通能说会道，同时也是河水霸主河马身边的军师，常常给河马出谋划策。河马听说了最近流行落地窗的房子，也想要盖一间。但是河马碍于比较高的地位和身份，不想直接套用大家都在用的设计，于是让小鹦鹉想想办法。</p><p>小鹦鹉到处打听，无意间听说了“玻璃纤维”这个词，据说是一种新出现的合成材料，不易碎、韧性特别好。小鹦鹉高兴极了，赶紧告诉河马，自己发现了一种新的建筑材料，这是史无前例的伟大创新，能够颠覆传统的建筑方式，用更高级的玻璃纤维来代替玻璃，简直能引领下一代房屋建筑的新潮流！</p><p>河马听了挺满意，出钱出力让小鹦鹉找人把房子盖出来，而且建造方案要保密！可不能让人知道了这么重要的创意。</p><p>小狐狸听说了这件事情，也挺好奇，自己盖房子这么多年，并不知道有什么新材料，小鹦鹉竟然能做出如此重大的创新。正好小鹦鹉的施工队招人，小狐狸欣然报名，参与到河马房子的施工大队中。</p><p>但是小狐狸一进去傻眼了，玻璃纤维不是玻璃，是不透光的呀！怎么能代替玻璃呢？如果坚持用玻璃纤维，这房子就没法住了。如果不用玻璃纤维，就只能用玻璃，那就没有创新了！</p><p>后来小狐狸离开了小鹦鹉的施工队……</p><h3 id="达克效应"><a href="#达克效应" class="headerlink" title="达克效应"></a>达克效应</h3><p>达克效应是认知偏差的一种，尤其用于描述低估或高估自己能力的现象。对于在某一个领域的专家，试图对领域之外的事情进行革命性创新的行为，可以归因于达克效应上，但是也存在细节上的差异，更贴切一点的描述是“超越领域的自信”，或者用更专业的心理学概念描述为“专业人士错觉”。</p><p>从心理学角度解释这种现象是有一定道理的，不过实际上造成这种现象的，还有一个重要的因素，就是存在一种无形的力量……</p>]]></content>
  </entry>
  <entry>
    <title>海贼</title>
    <link href="https://crazy.smallyu.net/2023/10/03/%E6%B5%B7%E8%B4%BC/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2023/10/03/%E6%B5%B7%E8%B4%BC/</id>
    <published>2023-10-03T09:57:04.000Z</published>
    <updated>2025-10-01T00:53:47.054Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>也许勇者走出了迷宫<br>他有点迷糊<br>什么是勇者？<br>心怀正义、保家卫国、屠杀恶龙、解救公主<br>而现在的勇者<br>深居简出、朝不保夕、苦于生计、疲于生活<br>以及<br>恶龙没有摧毁村庄，没有劫走公主<br>没有家园需要保护，没有公主需要解救 ]]></summary>
    <content type="html"><![CDATA[<p>也许勇者走出了迷宫<br>他有点迷糊<br>什么是勇者？<br>心怀正义、保家卫国、屠杀恶龙、解救公主<br>而现在的勇者<br>深居简出、朝不保夕、苦于生计、疲于生活<br>以及<br>恶龙没有摧毁村庄，没有劫走公主<br>没有家园需要保护，没有公主需要解救  </p><p>也许勇者见到过巨龙<br>有的巨龙凶恶、残暴，有的巨龙善良、友好<br>它们遵循着自然法则，弱肉强食、恃强凌弱<br>它们从来没有错  </p><p>不过<br>世界仍然充满着邪恶<br>贫穷、饥饿、战争、暴乱、苦难<br>有比恶龙更可怕的恶魔<br>它们伪装成人类的模样<br>救赎人类<br>毁灭人类<br>成为人类<br>你可以想方设法成为恶魔<br>也可以至少不要变成恶魔  </p><p>要说勇者后来的经历<br>似乎真的平平无奇<br>无非是<br>剑术、魔法、攻击、闪避<br>打怪、升级、装备、金币<br>也经历过一些小的波折<br>也许是大的波折<br>也许<br>是成为勇者的必经之路  </p><p>也许<br>勇者更喜欢广袤的大海<br>成为一名海贼<br>追求自由、冒险、财富<br>生活并不总是充满希望<br>但海贼却经常满怀激情<br>为了理想，或者一时快意  </p><p>无论追求权力、暴虐、统治<br>无论身处孤岛、监狱、绝境<br>他们总能面带笑容<br>以优雅、粗旷、狼狈的姿态<br>面对失败  </p><p>这个世界如你所料<br>悲惨而精彩</p>]]></content>
  </entry>
  <entry>
    <title>试用了一下 friend.tech，感觉像是给 twitter 加了个炒作 crypto 的插件 😂</title>
    <link href="https://t.smallyu.net/#2023-23"/>
    <id>micro:1722434462</id>
    <published>2023-09-17T09:24:14Z</published>
    <updated>2023-09-17T09:24:14Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>试用了一下 friend.tech，感觉像是给 twitter 加了个炒作 crypto 的插件 😂</p>]]></summary>
    <content type="html"><![CDATA[<p>试用了一下 friend.tech，感觉像是给 twitter 加了个炒作 crypto 的插件 😂</p>
]]></content>
  </entry>
  <entry>
    <title>当你看到一个人想把热力学公式套进共识算法里，就知道整件事情有多离谱了……</title>
    <link href="https://t.smallyu.net/#2023-22"/>
    <id>micro:1722427612</id>
    <published>2023-09-17T08:49:34Z</published>
    <updated>2023-09-17T08:49:34Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>当你看到一个人想把热力学公式套进共识算法里，就知道整件事情有多离谱了……</p>]]></summary>
    <content type="html"><![CDATA[<p>当你看到一个人想把热力学公式套进共识算法里，就知道整件事情有多离谱了……</p>
]]></content>
  </entry>
  <entry>
    <title>剧本杀里，有一类玩家被称为“菠萝头”，意思是他们的共情能力比较差，无法设身处地地带入到剧本杀的角色中，更无法体会到自己的...</title>
    <link href="https://t.smallyu.net/#2023-21"/>
    <id>micro:1685291576</id>
    <published>2023-08-20T13:54:37Z</published>
    <updated>2023-08-20T14:30:56Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>剧本杀里，有一类玩家被称为“菠萝头”，意思是他们的共情能力比较差，无法设身处地地带入到剧本杀的角色中，更无法体会到自己的角色在虚幻的故事中所经历的各种情感，他们只会作为旁观者，冷眼看着和自己毫不相关的故事。这类玩家一般适合硬核本，也就是纯逻辑推理破解凶杀案，不需要任何人物关系和感情的一类剧本。 根据我的体会，菠萝头玩家...</p>]]></summary>
    <content type="html"><![CDATA[<p>剧本杀里，有一类玩家被称为“菠萝头”，意思是他们的共情能力比较差，无法设身处地地带入到剧本杀的角色中，更无法体会到自己的角色在虚幻的故事中所经历的各种情感，他们只会作为旁观者，冷眼看着和自己毫不相关的故事。这类玩家一般适合硬核本，也就是纯逻辑推理破解凶杀案，不需要任何人物关系和感情的一类剧本。</p>
<p>根据我的体会，菠萝头玩家一般是在现实生活中比较缺少爱的一类人，他们没有爱别人，也没有被别人爱，也没有自己爱自己。总之，他们不理解“爱”这种东西，所以他们无法体会到剧本中角色的情感。</p>
<p>很多情感本打动人的原因是，剧本中的故事，正好和自己经历的某些事情相像，玩家比较容易带入自己的情感。很多玩家看到故事就感动哭了，其实他们哭的不是剧本中的故事，而是他们想到了自己的故事，产生了情感上共鸣。</p>
<p>所以情感本经常会出现一种现象，对于同一个剧本，有的人特别的喜欢觉得这个本特别好，有的人觉得这个本一点都不好玩，原因就在于每个人的经历不同，能引起自己情感上共鸣的事情也不同。</p>
<p>关于“爱”的解释，推荐复旦教师陈果的系列课程，她的讲解非常全面。</p>
]]></content>
  </entry>
  <entry>
    <title>程序员的 “服从权威” 心理</title>
    <link href="https://smallyu.net/2023/07/30/%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E2%80%9C%E6%9C%8D%E4%BB%8E%E6%9D%83%E5%A8%81%E2%80%9D%E5%BF%83%E7%90%86/"/>
    <id>blog:https://smallyu.net/2023/07/30/%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E2%80%9C%E6%9C%8D%E4%BB%8E%E6%9D%83%E5%A8%81%E2%80%9D%E5%BF%83%E7%90%86/</id>
    <published>2023-07-30T14:35:34.000Z</published>
    <updated>2025-11-20T02:26:34.914Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>最近经历了一件事情，就是入职一家初创公司，工作两周后主动离职。虽然只有短短两周但感觉过了很长时间，从中也学到或者意识到很多东西。离开的原因有很多，也涉及到比较具体的问题，我会继续反思和总结。今天想到一个有意思的话题，可以作为简单的切入点。当然有一些不方便说的内容我是不会说的]]></summary>
    <content type="html"><![CDATA[<p>最近经历了一件事情，就是入职一家初创公司，工作两周后主动离职。虽然只有短短两周但感觉过了很长时间，从中也学到或者意识到很多东西。离开的原因有很多，也涉及到比较具体的问题，我会继续反思和总结。今天想到一个有意思的话题，可以作为简单的切入点。当然有一些不方便说的内容我是不会说的 :P</p><p>我发现程序员群体普遍存在一种 “兽性”：谁技术好谁就厉害，谁技术好我就听谁的、我就服谁，我甚至会叫他大神、大佬，崇拜他，相信他，反之，要是技术不好的人当我的小组长、技术负责人、CTO，支配我的工作，我就不服他、不愿意听他的话。对于管理者来说，如果自己的能力不服众，事情推进起来也会格外艰难。</p><p>这个问题罗永浩在某个节目里也提到过，但是我不记得是在他的创业课播客还是什么访谈节目中了，特意找了一下没有找到，他的语录内容实在太多了。同时我也意识到，当有过加入初创公司的经历，观察到一些现象后，再回头去看他的 <a href="https://www.youtube.com/@zhuangyuanli/videos">创业课播客</a>，觉得他说的那些东西对创业公司还真挺有价值。</p><p>这种现象不止存在于程序员群体，在很多影视剧中都有类似的情节，比如在森林中，战斗力最强的狮子就是王，猴群中最能打的当猴王，或者在骁勇善战的原始人部落，以武力争高低，谁赢了听谁的。再比如西部牛仔比试枪法，胜利者获得某种地位和象征之类，等等。</p><p>这样的现象叫 “服从权威” 心理。分析一下权威这个词。权威其实不是一个负面的词语，虽然我们会看到一些言论说要打倒权威、不要盲目崇信权威，但其实那个语境中的权威是指非法获得的、德不配位的、迷惑群众的权威。“服从权威” 这个词中的权威，指群体中真正的强者。相信大多数人都不会反感真正的强者。</p><p>回到职场关系的问题，按照我粗浅的理解，可以简单把职场关系分为 “合作关系” 和 “从属关系”。</p><p>典型的合作关系比如公司与公司合作、公司的合伙人之间合作、两个部门负责人之间合作、两个小组长之间，等等，地位是平等的，在这种合作的情况下，能力可以是互补的，一方拥有 A 能力，另一方拥有 B 能力，合作起来才能发挥更大作用。很多公司都有 CEO、CTO、COO 的角色，角色背后是极其专业的能力。</p><p>从属关系也好理解，老板和员工之间，领导和下属之间，只要存在上下级关系都属于从属关系。一般来说，从属关系的能力是垂直的，比如 CTO 负责制定技术路线和战略方向，一线的技术人员根据规划完成具体的工作。这个属于角色分工的不同，但 CTO 和下属都是技术背景的人员。如果让公司的 COO 来领导技术团队，事情不就乱套了吗。</p><p>程序员的 “服从权威” 心理就存在于从属关系中，需要有纵向的比较，才能够产生所谓的 “权威”。合作关系中的能力都不同在一个标准下，就很难进行比较。</p><p>既然这种心理现象是普遍存在而且是客观存在的，那对于我们来说有什么启发呢？</p><p>对于非权威一方：明白自己要追求的权威是什么。比如工作中感受到了来自上级的压力，要清楚是有意义的压力还是无意义的压力，如果对方是自己领域的权威，就争取提高自己的能力，打败他，自己成为新的权威。如果对方不是自己领域的权威，只是凭借着某些原因在支配你，你应该奋起反抗，或者及时脱离苦海。</p><p>对于权威一方：明白自己权威的来源是什么。比如技术能力也是分层次的，假如自己有着高瞻远瞩的技术视野，而有些非权威的人拿着一分钟能打多少个字的数据来挑战你，你完全可以置之不理，不需要担心什么。</p><p>如果不具备权威的能力，又身处权威的位置，该怎么办呢？将从属关系变为合作关系，就不用担心有人来挑战权威、自己不能服众、有人不服气的问题了。因为 “服从权威” 的心理只存在于从属关系中而很少出现在合作关系中。简单来说，就是外行的领导要懂得放权。</p>]]></content>
  </entry>
  <entry>
    <title>区块链技术面试题</title>
    <link href="https://smallyu.net/2023/07/12/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E9%9D%A2%E8%AF%95%E9%A2%98/"/>
    <id>blog:https://smallyu.net/2023/07/12/%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF%E9%9D%A2%E8%AF%95%E9%A2%98/</id>
    <published>2023-07-11T17:01:09.000Z</published>
    <updated>2025-11-09T09:22:13.316Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>最近找工作也经历过很多次面试，这几次面试比较大的感受到一个共同的现象，就是和面试官聊不到一块儿，因为一般面试官也只是问他自己会的、关心的技术，很多东西我平时不怎么关心，而我简历上写的东西，对方也不怎么问。举例来说，我简历上有提到 State channels]]></summary>
    <content type="html"><![CDATA[<p>最近找工作也经历过很多次面试，这几次面试比较大的感受到一个共同的现象，就是和面试官聊不到一块儿，因为一般面试官也只是问他自己会的、关心的技术，很多东西我平时不怎么关心，而我简历上写的东西，对方也不怎么问。举例来说，我简历上有提到 State channels 相关的工作内容，我想但凡面试官知道 State channels 是什么，看到这部分简历，一定会多少问一句 HTLC 的原理是什么这种问题。然而我经历过的面试中，只有一家公司的面试官问到了这个，他们也确实是专业做区块链项目的团队。然后人家没要我。</p><p>虽然我面试了很多次，也不通过面试很多次，但是大多数情况是问我一些 web2 风格很重的技术细节，很少有人在区块链方面把我问住，尤其是我简历上提到的工作相关的内容，所以并没有太多挫败的感觉，更多时候是在抱怨，为什么那些人都在关心那些，我觉得不重要的东西，我能把某种需要两三个月才能搞明白的区块链技术理解清楚，半个小时就能看懂的某个关于编程语言的问题还能学不会吗？</p><p>所以就想到，如果我是面试官，面对在应聘区块链开发职位的求职者，我可能会提问哪些问题，然后根据这些问题来判断候选人的水平。这些问题是基本上通用的，其中一些问题能深入和扩展：</p><ol><li>比特币的共识是什么，UTXO 是怎么回事</li><li>以太坊的共识是什么，如何选定出块节点的</li><li>你还知道哪些链，这些链有什么技术特点</li><li>PBFT 的流程是什么，国内有哪些联盟链</li><li>PBFT 有哪些变体，哪些链在用</li><li>Layer 2 有哪几种技术类型</li><li>State channels 的原理是什么，Rollups 的原理是什么</li><li>账户钱包是怎么生成的，keystore 文件是什么</li><li>存储类区块链有哪些，其中的难点是什么</li><li>Solidity 语言有哪些限制，和 Go 语言的不同</li><li>面向对象了解吗，写过 Java 吗</li><li>区块链里有随机数吗，怎么使用</li><li>合约交易是怎么经过虚拟机处理的，怎么增加对另一种语言的支持</li><li>日蚀攻击和女巫攻击分别是什么</li><li>了解过资产跨链吗，大概是什么流程</li></ol><p>这些问题没有明确的先后顺序，也比较浅，抛砖引玉吧。突然想起来我面试还被问到过，区块链里面的区块是怎么连接起来的？答案是下一个区块会存上一个区块的块哈希，这种问题就属于没入门系列，还是问点门里面的问题吧。</p>]]></content>
  </entry>
  <entry>
    <title>如何区分公有链和联盟链</title>
    <link href="https://smallyu.net/2023/07/12/%E5%A6%82%E4%BD%95%E5%8C%BA%E5%88%86%E5%85%AC%E6%9C%89%E9%93%BE%E5%92%8C%E8%81%94%E7%9B%9F%E9%93%BE/"/>
    <id>blog:https://smallyu.net/2023/07/12/%E5%A6%82%E4%BD%95%E5%8C%BA%E5%88%86%E5%85%AC%E6%9C%89%E9%93%BE%E5%92%8C%E8%81%94%E7%9B%9F%E9%93%BE/</id>
    <published>2023-07-11T17:00:58.000Z</published>
    <updated>2025-11-09T09:22:13.424Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="简短版"><a href="#简短版" class="headerlink" title="简短版"></a>简短版</h3><p>发币的就是公链，不发币的就是联盟链。</p>
<h3 id="详细版"><a href="#详细版"]]></summary>
    <content type="html"><![CDATA[<h3 id="简短版"><a href="#简短版" class="headerlink" title="简短版"></a>简短版</h3><p>发币的就是公链，不发币的就是联盟链。</p><h3 id="详细版"><a href="#详细版" class="headerlink" title="详细版"></a>详细版</h3><p>因为我经常否定联盟链，就自然而然产生一个问题：到底什么是联盟链？公链和联盟链的根本区别是什么，分界线在哪儿？本以为这是一个简单的问题，但是仔细想想又没那么简单，不是特别容易去下一个明确的定义，</p><p>简单来说，公开给所有人访问使用的区块链就是公链，在一个小范围内部使用的区块链就是联盟链。这种区别就像是互联网和局域网的区别。但是如果把一条联盟链开放出来，给所有人使用了，它就变成公链了吗？如果这条链使用原始版本的 PBFT 作为共识机制，那它仍然还是联盟链，始终都是联盟链。公链和联盟链的区分，不能仅仅根据使用人群范围的大小。</p><p>再比如存在一个主观的问题，什么是所有人？多大范围算是所有人？如果一共有 100 个人，100 个人就是所有人，那么 99 个人算不算？在现实生活中，似乎也算，99 个人在使用的链，不可能说它是一条联盟链。那 80 个人算不算？好像也算，已经是大多数人了，比起 20 个人的小部分，80 个人不至于认为是一个联盟。60 个人呢？已经超过半数了，能代表所有人吗？</p><p>所以如何判断一条链是公链还是联盟链？经过一段时间的思考，从技术特点的角度去考量，我认为要同时满足这三个条件，才算是公链：</p><ol><li>节点之间网络互联互通</li><li>每个节点平等地拥有成为出块节点的机会</li><li>成为出块节点的门槛是合理的</li></ol><p>你可能注意到，在简短版中，把有没有加密货币作为了区分公链和联盟链的唯一指标，而在详细版里却没有提加密货币。主要是判断的维度不一样，有没有发币是整个系统体现出来的使用方式，上面列举的三个条件要更通用一点，是技术方面的特性。满足三个条件而没有发币仍然能认为是公有链，只不过加密货币对于矿工是很重要的激励手段，是整个系统的一部分，一般是不可或缺的，项目方通常会把加密货币设计进去。</p><h4 id="节点之间网络互联互通"><a href="#节点之间网络互联互通" class="headerlink" title="节点之间网络互联互通"></a>节点之间网络互联互通</h4><p>这一点要求节点不能从网络层面设置访问权限，任何人都能通过互联网访问节点。如果节点没有部署在公网上，而是运行在局域网中，这个节点就不属于公链的节点。如果节点部署在公网上，但是仅限指定的 IP 访问和使用，那这个节点就属于设置了访问权限，是不够开放的行为，如果所有节点都存在类似的设置，整条链就不算是公链。</p><h4 id="每个节点平等地拥有成为出块节点的机会"><a href="#每个节点平等地拥有成为出块节点的机会" class="headerlink" title="每个节点平等地拥有成为出块节点的机会"></a>每个节点平等地拥有成为出块节点的机会</h4><p>比如 PoW，只要算力足够，就会被认可成为出块节点。比如 PoS，只要质押 32 ETH，就有机会成为出块节点。这种属于典型的公链的例子。像是原始版本的 PBFT，出块节点是固定的，还不能更换，就属于联盟链。有一些链在 PBFT 的基础上加入了随机更换共识组的功能，每隔一段时间就会随机选择一些节点作为共识节点负责出块，包含这种设计的区块链是属于公链的，不过项目方需要考量这样的做法是否安全，容错能力怎么样，是否面临女巫攻击的风险。</p><h4 id="成为出块节点的门槛是合理的"><a href="#成为出块节点的门槛是合理的" class="headerlink" title="成为出块节点的门槛是合理的"></a>成为出块节点的门槛是合理的</h4><p>合理是一种主观的感受，因为不好量化，需要项目在设计上去权衡。比如 PoW，获得足够算力去出块是有很高成本的，这个成本就是门槛，如果门槛太低，所有节点都轻易出块，网络会乱，如果门槛太高，没有人能达到，出不了块，都是不合适的。这个门槛需要一个折中的、合适的位置。再比如有些 PBFT 联盟链中，成为出块节点需要 CA 发行的证书，而这个 CA 是由项目方控制的，需要线下通过一系列认证，才能够加入联盟获得证书，这种属于典型的联盟链。</p><h3 id="为什么喜欢区块链"><a href="#为什么喜欢区块链" class="headerlink" title="为什么喜欢区块链"></a>为什么喜欢区块链</h3><p>技术属性上，区块链有一种反叛的精神在里面，区块链主张去中心化的技术理念，自成一套体系，既然你中心化的机构靠不住，那我们就各自为营，我们首先相信自己，其次才相信别人，在这样的模式下，历史记录的准确性非常高。目前能在全世界范围达成数据一致的系统，也就只有区块链才能做到。</p><p>资产属性上，加密货币抵抗地缘政治变化的能力非常强，你可以轻易地持有和世界货币锚定的货币资产，不会因为世界局部的货币价值波动而受到影响。</p><h3 id="为什么不喜欢联盟链"><a href="#为什么不喜欢联盟链" class="headerlink" title="为什么不喜欢联盟链"></a>为什么不喜欢联盟链</h3><p>国内的联盟链项目，很多是政府机构搞信息化建设，最后都是政府出钱。假如雄安新区一个信息平台的项目 2000 W，其中会包含各种技术领域像人工智能、大数据、物联网，区块链是其中一项，具体到这一个区块链类目上，可能 300 W，这 300 W 也不是一般小公司能拿下的，至少得有点强硬的关系，比如外包大厂。然后这个区块链类目又包含很多小的部分，比如某个部门的数据管理平台，要接入区块链进行数据上链，如果这家外包大厂不具备区块链的研发能力，就会从 300 W 中分出 30 W，找一家专门开发区块链的公司，把这部分功能完成了。最终开发联盟链的公司，挣个辛苦钱，同时指望一年能多做几个项目，多挣点钱。</p><p>这种项目大都会走招投标的流程，可以想象一下，光是能不能把项目揽下来就会牵扯到多方的利益纠缠，投标的时候人家会给你公司的整体实力打分，包括申请过多少专利、企业过往的营收能力之类。而且这种项目和区块链的理念没有半点关系，换一个名头比如 5G 技术，还是一模一样的项目流程，招标投标做项目交付，只是其中用到的具体技术不一样而已。所以我说联盟链不是真正的区块链，联盟链是在用金锄头锄地。</p>]]></content>
  </entry>
  <entry>
    <title>对 Layer 2 项目创业想法的回复</title>
    <link href="https://smallyu.net/2023/07/08/%E5%AF%B9Layer-2%E9%A1%B9%E7%9B%AE%E5%88%9B%E4%B8%9A%E6%83%B3%E6%B3%95%E7%9A%84%E5%9B%9E%E5%A4%8D/"/>
    <id>blog:https://smallyu.net/2023/07/08/%E5%AF%B9Layer-2%E9%A1%B9%E7%9B%AE%E5%88%9B%E4%B8%9A%E6%83%B3%E6%B3%95%E7%9A%84%E5%9B%9E%E5%A4%8D/</id>
    <published>2023-07-08T05:25:31.000Z</published>
    <updated>2025-11-09T09:22:13.439Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<blockquote>
<p>说明：没有任何不尊重来信的意思，邮件中对于 L2 的观点带给我很多启发，因为其中有一些内容和我认知不完全一致，我认真理解和思考了来信的含义，所以想借此表达一下我对 L2 的看法。博客中 L2]]></summary>
    <content type="html"><![CDATA[<blockquote><p>说明：没有任何不尊重来信的意思，邮件中对于 L2 的观点带给我很多启发，因为其中有一些内容和我认知不完全一致，我认真理解和思考了来信的含义，所以想借此表达一下我对 L2 的看法。博客中 L2 相关的内容比较少，就放到博客上来了，这里只是单纯作为技术问题讨论一下</p></blockquote><h3 id="来信"><a href="#来信" class="headerlink" title="来信"></a>来信</h3><pre><code>你好，还在找工作吗？Jul 6, 2023, 5:39 PM (2 days ago)to mewangyu 你好！无意间看到了你的博客，也不知道这个邮箱能不能收到。今年开始 L2 开始火起来了。各种大公司，只要有点钱的，都开始怼 L2从 L2beat 来看，还有不少 L2 即将上线 https://l2beat.com/scaling/tvl#upcoming也不清楚是不是天下 L2 一大抄。但总感觉目前的 L2 技术都差不多来源于几家头部公司的开源代码。如果真的是这样，是不是就可以意味着阿猫阿狗都可以自己 Fork 出一个版本来了呢？如果是的话，那么我们就是那个&quot;阿猫阿狗&quot; :)我们创业团队挺有兴趣蹭蹭 L2 公链&quot;热潮&quot;的，感觉您在这块应该是一把好手。如果你也有兴趣，我们可以进一步聊聊合作方式？我大概的想法是远程、由你自由主导的链演化路线PS: 我的 telegram 是 @****** 欢迎在线联系我。</code></pre><h3 id="回复"><a href="#回复" class="headerlink" title="回复"></a>回复</h3><p>您好！</p><p>非常高兴收到您的邮件，也很抱歉没有太及时回复。</p><p>我尝试认真理解您来信的内容，对于其中提到一些关于 L2 的观点，我想描述一下我的理解。</p><h4 id="1-“技术类型”-和-“项目”-的区别"><a href="#1-“技术类型”-和-“项目”-的区别" class="headerlink" title="1. “技术类型” 和 “项目” 的区别"></a>1. “技术类型” 和 “项目” 的区别</h4><p>Layer 2 有 4 种技术类型，State channels、Sidechains、Optimistic rollups、ZK rollups，所有的项目都属于这 4 种类型内，在即将上线的项目中，大多数是 rollups 类型，但是没有信息他们的代码是不是 fork 已有项目的。</p><img src="a.png" width="50%" /><p>具体项目的话是有这 4 个：</p><img src="b.png" width="30%" /><p>但是从已上线的项目列表看，即使是 fork 相同的项目，他们的应用场景也是有很大差异、高度定制化的:</p><img src="c.png" width="50%" /><h4 id="2-现有的项目不是简单的-fork"><a href="#2-现有的项目不是简单的-fork" class="headerlink" title="2. 现有的项目不是简单的 fork"></a>2. 现有的项目不是简单的 fork</h4><p>以 zkSync 为例，在列表上能看到 3 个项目有这个标识：</p><img src="d.png" width="30%" /><p>分别是 zkSync Era、zkSync Lite 和 ZKSpace，其中 zkSync Era 和 zkSync Lite 是同一家。</p><p>再具体看 ZKSpace，他确实是用了 zkSync 的合约，但并不是单纯的 fork 整个项目，而是使用了 zkSync 的合约代码，在其基础上做一些修改适配自己的业务。同时，ZKSpace 也使用了其他项目的代码。</p><img src="e.png" width="50%" /><p>从 ZKSpace（以前是 ZKSwap）的白皮书能看到，ZKSpace 想做的事情是 Layer 2 上的 Uniswap，包含了 AMM 的功能，也就是交易所市商的那些东西。</p><img src="f.png" width="60%" /><p>zkSync 是一个通用的 Layer 2 项目，本身不提供太具体的功能，ZKSpace 使用了一些 zkSync 的合约代码，在那个基础上做一些事情，而且是业务强相关、有具体目标的事情。他并不和 zkSync 本身抢市场。</p><p>再看比如有 OP 标的项目，也就是基于 OP 项目 fork 的。</p><ul><li>Arbitrum 一开始是 fork OP 的，然后改了一些经济模型方面的东西，后来做大了又重构项目。而且 arb 的运营能力很强，举办过几次奥德赛。</li><li>Boba 的特点是 withdraw 余额不需要等 7 天，马上提取，另外通过他自己叫做混合计算的技术，把 web2 的网页能力带到区块链上。</li><li>Zora 是一个专做 NFT 领域的 layer2.</li><li>Mantle 提供了去中心化的序列器之类。</li></ul><p>总的来说，这些项目都是有具体的目的，想要实现某一种功能，然后把现成的代码拿过来，复用一下，重点可能比较在于这些项目的目标，也就是想干什么样的事情。他们都是结合了自己的业务场景，而不是简单的 fork 下来就能运行。</p><h4 id="3-L2-不是链"><a href="#3-L2-不是链" class="headerlink" title="3. L2 不是链"></a>3. L2 不是链</h4><p>目前的 rollups 项目都是中心化的，本身不是一条链，没有共识之类的东西，主要是项目方在运营。</p><h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><p>所以关于您提到的想做 L2 方向的项目，我的意思是，从您的描述来看，可能没有您想的那么简单，其中会很涉及到一些具体问题。也许需要应用场景上的创新，和 defi 或者 gamefi 场景结合之类，或者技术特点上的创新，能够改善某种痛点。</p><p>我也很想蹭热点，也希望能有合适的创业机会，我现在也是在找工作，不过从我的角度看还是挺迷茫的，我本身没有太直接的想法，一个项目该往什么样的方向做之类，我觉得那些都涉及到挺市场化的东西，需要很大的资本力量。</p><p>不知道您具体是什么样的想法。由于内容比较多，就以邮件的方式回复了。有问题您随时联系我。</p><h3 id="补充"><a href="#补充" class="headerlink" title="补充"></a>补充</h3><p>有一些在回复中没有提到的话题，顺便展开聊一聊。</p><p>首先是 Layer 2 为什么火？因为 Vitalik 在最近的博客中频繁提到 zkEVM，比如在文章 <a href="https://vitalik.ca/general/2021/12/06/endgame.html">Endgame</a> 中，把支持 ZK-rollup 认为是以太坊未来的重要工作之一。有些问题没办法在 Layer 1 直接解决，就希望通过 Layer 2 解决。有 Vitalik 这样的备受关注的开发者引领生态上的技术方向，Layer 2 就成为了以太坊的发展热点。</p><p>Vitalik 比较看好 ZK-SNARKs 类的 zkEVM，从技术角度，ZK-rollups 将是所谓的 Endgame。但是 ZK 的开发成本非常高，目前还处于研究开发，小体量的资本玩不起，太贵了。</p><p>Dapp-learning 社区在 Youtube 上有一个 Scroll 的技术分享<a href="https://www.youtube.com/watch?v=SEp5SFaYQHY">视频</a>，内容挺好的。Scroll 的整个技术团队都在国内，从视频的讲解中感觉似乎 Scroll 的技术方案是有一些暴力成分在里面的，就是既然写 circuits 不容易，那就把某一类型的 circuits 结果作为一张表，用的时候查表，然后去不断扩充出各种表以支持整个 EVM。这是 Scroll 对比了各 ZK 项目实现 EVM 完备的方式：</p><img src="g.png" width="80%" /><p>Vitalik 的博客文章 <a href="https://vitalik.ca/general/2022/08/04/zkevm.html">The different types of ZK-EVMs</a> 也提到了对 zkEVM 的分类。不管怎么说，Layer 2 的火热应该是指基于 ZK-rollup 的项目打得火热。</p><p>Optimistic rollups 更像是 L2 的一种过渡方案，相信 ZK 出来后 OP 类的项目都会受到打击，因为 OP 并不依赖于加密技术的可靠性，从命名上就能看出来他是乐观主义，先认为一笔交易没有问题，然后给 7 天的挑战期，如果交易有问题，需要用户自主发起挑战，或者由第三方验证者来完整挑战，有很大程度的人为干预在里面。</p><p>再一个是 L2 项目中心化的问题。除了 Sidechains 的项目，L2 一定是中心化的，因为共识交给 L1 去做，L2 本身不管这个，从动机上，L2 起到的作用是快速地把交易收集起来打包发到 L1 上，一笔交易最终的信任是落到 L1 上的，用户相信的不是 L2 而是 L1 上的交易记录，所以 L2 不需要去中心化，用户不需要，项目方也没有必要。L2 一般是有项目方在发行和运营，用户信任项目的技术方案，才愿意到项目上玩，把资产质押进去。</p><p>还有 L2 使用体验的问题，目前很少有用户会把 OP 或者 ARB 作为低成本资产转移的方案，宁愿用 BNB 或者 TRX 来实现匿名场景的支付，使用比较多的还是治理 token 的投资或者 DApp 项目形式的交互。OP 赎回资产需要 7 天的等待期这一点就挺难用的，L2 链之间的资产转移也是个问题，比如在 OP 上的 USDT 能不能转移到 ARB 上，不然我用 OP，另一个人用 ARB，我们就没法交易了。在这个方面还有很大的提升空间。</p><p>L2 是很有前景的技术方向，期待它能带给我们更好的使用体验，至于其中有没有低成本的获利空间，就不太清楚了。</p>]]></content>
  </entry>
  <entry>
    <title>对区块链共识机制的理解</title>
    <link href="https://smallyu.net/2023/07/01/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E5%85%B1%E8%AF%86%E6%9C%BA%E5%88%B6%E7%9A%84%E7%90%86%E8%A7%A3/"/>
    <id>blog:https://smallyu.net/2023/07/01/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E5%85%B1%E8%AF%86%E6%9C%BA%E5%88%B6%E7%9A%84%E7%90%86%E8%A7%A3/</id>
    <published>2023-07-01T09:19:29.000Z</published>
    <updated>2025-11-09T09:22:13.447Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>共识机制的作用，是让大多数节点的数据能够保持一致。共识机制有两种大的类型，一种是 PoW 风格的，一种是 PBFT]]></summary>
    <content type="html"><![CDATA[<p>共识机制的作用，是让大多数节点的数据能够保持一致。共识机制有两种大的类型，一种是 PoW 风格的，一种是 PBFT 风格的。几乎所有的共识都在这两种风格之下。</p><p>可以从头思考一下，如果是一个人类的群体，怎么样才能让大多数人保持一致呢？一种方法是选出一个领袖，大家都听领袖的意见，再一种方法是大家一起商量进行决策，达成统一的意见。</p><p>对于第一种方法，问题在于如何选出领袖，依据什么样的标准选出，或者怎么样的人才能够成为领袖。对于第二种方法，问题在于哪些人可以参与商量，如何做出决策。</p><p>先看第一种方法，流程上主要有 3 个步骤：</p><ol><li>通过某种方式选出领袖</li><li>所有人在时间单位内都听领袖的</li><li>所有人在时间单位内将会达成一致</li></ol><p>PoW 的过程就是这样：</p><ol><li>解出哈希难题的矿工成为出块节点</li><li>所有节点接收并验证矿工的块</li><li>所有节点的块数据达成一致</li></ol><p>在这种 PoW 风格的共识过程中，最大的变数是第 1 步，也就是如何选出出块的节点，也因此有了很多 PoW 共识的变种。</p><ul><li><p>Proof of Stake (PoS)：以太坊在使用的共识机制，币种名称为 ETH。质押一定量资产的节点会随机成为出块节点，随机的过程由在信标链上运行 VRF 函数完成，并且质押的资产越多，成为出块节点的可能性越大。</p></li><li><p>Proof of Authority (PoA)：以太坊测试网支持的共识机制。在网络的初始化阶段就已经确定哪些节点可以出块，之后按照顺序依次出块。确认验证者的过程是线下完成的，网络本身不具备对验证节点的纠正能力，比较中心化的一种共识。</p></li><li><p>Proof of Importance (PoI)：Nem 在使用的共识机制，币种名称为 XEM。制定了一些给节点打分的机制，在多少天内交易多少次、交易额度是多少之类，以根据分数对节点进行排名，分数高于指定标准的节点，随机成为出块节点。</p></li><li><p>Proof os Elapsed Time (PoET)：Hyperledger Sawtooth 项目使用的共识机制，是英特尔开发的一个项目。每个节点随机生成一个等待时间，等待时间最短的节点成为出块节点。出块节点需要提供一个最短时间的证明，这个证明和硬件设备相结合，达到无法伪造的效果。</p></li><li><p>Proof of Burn (PoB)：Slimcoin 在使用的共识机制，币种名称为 SLM。节点通过销毁资产的交易获得销毁哈希，销毁哈希的计算包含了销毁的金额以及节点在一段时间内销毁的频率等信息，然后系统对每个节点提交的哈希值进行比较，哈希值最小的节点将进行本轮的出块。</p></li><li><p>Proof of Capacity (PoC)：Burst 在使用的共识机制，币种名称为 Burst。节点使用 hard-to-pebble graph 的数据结构，在磁盘上进行文件的写入，这个步骤需要足够多的磁盘空间，写入完成后节点随机打开文件的某个位置，计算对应的哈希值，直到找到满足要求的哈希值，节点就可以进行出块。</p></li><li><p>Proof of History (PoH)：Solana 在使用的共识机制，币种名称为 SOL。这种共识机制的创新之处在于，每一笔交易或者其他链上的操作，都会对应一个哈希值，然后 PoH 生成器生成块，这个块由一系列连续的哈希值，也就是一系列链上操作组成，从而保证链上数据的一致。这里的 PoH 生成器就是出块节点，PoH 生成器的选择标准则是质押金额最多的节点。</p></li></ul><p>这些是 PoW 风格共识的例子，可以看出它们在想方设法改变选择出块节点的方式，但不管具体使用怎么样的机制，这些区块链都符合 3 个步骤的流程。</p><p>再看第二种方法，流程上也是 3 个步骤：</p><ol><li>通过某种方式选出参与决策的人</li><li>参与决策者进行交流、达成一致</li><li>其余所有人都依照决策结果，达成一致</li></ol><p>PBFT 的过程类似这样：</p><ol><li>从所有节点中选出共识节点，然后共识节点依次作为提案节点</li><li>参与共识的节点经过两轮投票，对提案内容进行决策</li><li>共识节点达成一致，其余节点跟风达成一致</li></ol><p>可以看出和第一种方法相比，由单一的领袖变为了多个决策者。在这种 PBFT 风格的共识过程中，最大的变数也是第 1 步，如何从所有节点中选出共识节点，以及共识节点成为提案节点的顺序。这是一些变种：</p><ul><li><p>Delegated Byzantine Fault Talerance (DBFT)：Neo 在使用的共识机制，币种名称为 NEO。每个持有资产的节点都可以进行共识节点的选举，将自己的资产委托给共识节点。拥有委托资产的共识节点进行排名，前几名将依次作为提案节点。</p></li><li><p>Federated Byzantine Agreement (FBA)：Stellar 在使用的共识机制，币种名称为 Stellar。网络中的所有节点都是共识节点，都可以参与两轮投票。为了减少网络的拥堵，节点也可以委托自己的投票权给另一个节点，使用切片或者子网络的方式提高共识效率。</p></li><li><p>HoneyBadgerBFT：一种支持完全异步网络的 BFT 类共识，不依赖于同步的时间顺序，这是 PBFT 不具备的能力。不过异步网络的共识效率相对低一点。</p></li><li><p>HotStuff：一个允许部分网络异步的 BFT 类共识。它的特点是，网络中可以同时存在多个提案，提案节点将选择最好的一个提案，进行后续的流程。这样的方式相当于产生提案的过程是并行进行的，提高了整个共识的效率。</p></li><li><p>VBFT：Ontology 在使用的共识，币种是 ONT。使用 VRF 随机函数进行提案节点的选择，每一轮的提案节点都是随机、不可预测的。</p></li></ul><p>总体而言，PoW 风格和 PBFT 风格都是通过某种方式，筛选出最终能达成一致的内容，但是在选择内容的方式上存在根本区别。PoW 中其余节点将无条件接受来源的块，只要来源的块是符合某种条件的。而 PBFT 中，其余节点先收到块的内容，然后对这个块的去留进行决策，在接受块之前有一个投票的过程。</p><p>现在也有一些创新类型的共识出现，或者是结合多种共识的混合共识等形式，不管是对节点进行信誉评估、根据历史交易质量之类打分，还是根据手机、物联网等硬件设备进行数据的验证，还是对 PBFT 做某个阶段上并行、容错能力和网络效率之类的优化，共识机制终究还是在 PoW 风格和 PBFT 风格的体系之下。</p><p>因此你可以大胆的说，共识机制也就这么回事，只是在具体的设计和实现上有差异而已。</p>]]></content>
  </entry>
  <entry>
    <title>最近找工作的记录（6月份）</title>
    <link href="https://b.smallyu.net/2023/06/29/%E6%9C%80%E8%BF%91%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%886%E6%9C%88%E4%BB%BD%EF%BC%89/"/>
    <id>blog-b:https://b.smallyu.net/2023/06/29/%E6%9C%80%E8%BF%91%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%886%E6%9C%88%E4%BB%BD%EF%BC%89/</id>
    <published>2023-06-28T18:00:00.000Z</published>
    <updated>2025-12-03T09:25:54.164Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>一共面试 15 家公司，一共参加 20 次面试</p>
<h3 id="前期"><a href="#前期" class="headerlink" title="前期"></a>前期</h3><ul>
<li>被优化第 1]]></summary>
    <content type="html"><![CDATA[<p>一共面试 15 家公司，一共参加 20 次面试</p><h3 id="前期"><a href="#前期" class="headerlink" title="前期"></a>前期</h3><ul><li>被优化第 1 天（周四）：签字，收拾东西，走人</li><li>被优化第 2 天（周五）：清理电脑中工作相关的代码</li><li>被优化第 3 天（周六）：找房子</li><li>被优化第 4 天（周日）：搬家</li><li>被优化第 5 天（周一）：写好了简历，开始投简历</li></ul><h3 id="被优化第-6-天（周二）"><a href="#被优化第-6-天（周二）" class="headerlink" title="被优化第 6 天（周二）"></a>被优化第 6 天（周二）</h3><p><strong>北京思物物联科技有限公司</strong>    </p><ul><li>面试形式：现场</li><li>面试时长：20 分钟</li><li>招聘职位：Solidity 合约开发</li><li>公司业务：公司主体在海外，面向海外用户。DeFi 产品，内容是 NFT 质押，模仿 AAVE 协议。整个产品不涉及法币交易，全走 token，所以规避法律风险。</li><li>面试结论：方向不匹配，对方认为 Filecoin 是老旧的技术，或者存储相关的经历更偏向基础设施，而对方是做应用层的 DAPP。对方需要专业写合约的开发。</li></ul><p><strong>最右</strong></p><ul><li>面试形式：线上视频</li><li>面试时长：50 分钟</li><li>招聘职位：区块链开发</li><li>公司业务：对方保密，说是创新业务，自己开发了公链</li><li>面试结论：对方比较重视 BFT 的技术细节，但是也聊 Optimistic Rollup 的技术实现。从自己开发公链这一点，以及比较关注 Tendermint 共识、Cosmos SDK 的使用方法来看，猜测是联盟链类型的业务，面试官本人可能关注的技术面更广泛一点。</li></ul><h3 id="被优化第-7-天（周三）"><a href="#被优化第-7-天（周三）" class="headerlink" title="被优化第 7 天（周三）"></a>被优化第 7 天（周三）</h3><p><strong>Gate.io</strong>    </p><ul><li>面试形式：线上视频</li><li>面试时长：1 小时 20 分钟</li><li>招聘职位：Golang 后端开发</li><li>公司业务：链上数据分析、数据安全、交易数据验证</li><li>面试结论：对方认为方向不匹配，我的经历偏向链开发，而对方的岗位需要更纯粹的后端开发。说我对自己工作内容的了解是 OK 的，然后出了一道反转链表的题目。对方不懂 IPFS 和 Filecoin 之类，更加关心 Web 后端的内容，比如 Node.js 做后端服务的优势、TiDB 的原理、HTTP 3 和 HTTP 2 的区别等等。</li></ul><h3 id="被优化第-8-天（周四）"><a href="#被优化第-8-天（周四）" class="headerlink" title="被优化第 8 天（周四）"></a>被优化第 8 天（周四）</h3><p><strong>KuCoin</strong>    </p><ul><li>面试形式：线上视频</li><li>面试时长：20 分钟</li><li>招聘职位：区块链钱包开发</li><li>公司业务：去中心化钱包</li><li>面试结论：对方岗位需要比较精通 Go 语言的人，懂区块链最好，但是不懂也没关系，所以更加关注 Go 语言基础一点。还问我区块链中用的签名算法是什么，我说 ECC，接着问我 ECC 的参数 r、s、v 中，v 的作用是什么，为什么需要 v，我不知道。然后问我区块链节点收到交易后，如果收到很多笔交易，是怎么挑选交易的，我也不知道。整个流程上他提的问题，大多数我都不知道。然后就不合适了。</li></ul><p><strong>米哒元界（北京）网络科技有限公司</strong>    </p><ul><li>面试形式：线上语音</li><li>面试时长：20 分钟</li><li>招聘职位：Golang 后端开发</li><li>公司业务：GameFi 的后端，会涉及 ERC-721 之类的 NFT 合约</li><li>面试结论：方向不匹配。对方问了一堆语言基础，比如 Go 语言的逃逸分析，Go 语言如何控制协程的数量（CPU 层面），Java 语言中匿名类能否继承接口，等等，或者问是否熟悉 ERC 类的合约规范。我都不知道。后端岗位似乎大多不要求对区块链的了解，更关注纯后端或者语言本身。</li></ul><h3 id="被优化第-9-天（周五）"><a href="#被优化第-9-天（周五）" class="headerlink" title="被优化第 9 天（周五）"></a>被优化第 9 天（周五）</h3><p><strong>零鉴科技</strong>    </p><ul><li>面试形式：线上语音</li><li>面试时长：30 分钟</li><li>招聘职位：区块链研究员、区块链数据收集</li><li>公司业务：MEV、量化交易</li><li>面试结论：不是很匹配，对方更关心 EVM 的原理，比如 storage 的存储结构是什么，我不知道。或者是对 DeFi 项目的了解，因为是要做 MEV 的项目。还问了一下 Python 的深拷贝和浅拷贝的区别，我也没答上来。</li></ul><p><strong>零鉴科技</strong>（第二次）</p><ul><li>面试形式：机试</li><li>机试时长：1 小时 30 分钟</li><li>机试说明：在 2 小时内，完成 4 道基础的计算机技术题目</li><li>题目原文：<a href="机试题目-零鉴科技.html">机试题目-零鉴科技.html</a></li><li>机试感受：除了二分搜索稍微费点功夫，其他题目都太简单了，做起来甚至感觉没意思</li></ul><h3 id="被优化第-10-天（周六）"><a href="#被优化第-10-天（周六）" class="headerlink" title="被优化第 10 天（周六）"></a>被优化第 10 天（周六）</h3><p>–</p><h3 id="被优化第-11-天（周日）"><a href="#被优化第-11-天（周日）" class="headerlink" title="被优化第 11 天（周日）"></a>被优化第 11 天（周日）</h3><p><strong>米哒元界（北京）网络科技有限公司</strong>（第二次）</p><ul><li>面试形式：线上语音</li><li>面试时长：30 分钟</li><li>面试结论：对方是老板，不怎么懂区块链。应该是很小的公司，公司内没有能扛事的区块链技术人员，甚至提到了需要对链选型做决策等事情。我没什么意向。</li></ul><h3 id="被优化第-12-天（周一）"><a href="#被优化第-12-天（周一）" class="headerlink" title="被优化第 12 天（周一）"></a>被优化第 12 天（周一）</h3><p><strong>北京四合天地科技有限公司</strong></p><ul><li>面试形式：现场</li><li>面试时长：1 小时 20 分钟</li><li>招聘职位：区块链平台开发</li><li>公司业务：为大专学校开发区块链教学平台</li><li>面试结论：一共 4 轮面试，普通技术、技术负责人、HR、管理层。对方的技术人员不懂区块链，所以问的问题比较基础。对方公司目前正在组建区块链团队，预计两三个人，目前还没有人，也没有区块链。最后面试的管理层是一个头发花白但是精干的女人，说话声音比较小，语速特别快，老打哈欠，还是挺有气场的，给人一种压迫感。不管对方怎么想，我是对那种业务一点兴趣都没有。</li></ul><h3 id="被优化第-13-天（周二）"><a href="#被优化第-13-天（周二）" class="headerlink" title="被优化第 13 天（周二）"></a>被优化第 13 天（周二）</h3><p><strong>Pionex 派网</strong></p><ul><li>面试形式：线上视频</li><li>面试时长：50 分钟</li><li>招聘职位：数据收集开发</li><li>公司业务：NFT 数据追踪、加密货币交易数据追踪</li><li>面试结论：HR 挺能说的，面试之前就详细介绍了公司的背景和业务详情。面试过程正常聊天，没有提问太多内容。</li></ul><h3 id="被优化第-14-天（周三）"><a href="#被优化第-14-天（周三）" class="headerlink" title="被优化第 14 天（周三）"></a>被优化第 14 天（周三）</h3><p>今天干的三件事：</p><ol><li>拒绝了四合天地的 offer</li><li>和 imToken 的 HR 聊了 40 分钟，然后人家那边不怎么招人</li><li>和一家公司的 HR 聊天并约了明天的面试</li></ol><h3 id="被优化第-15-天（周四）"><a href="#被优化第-15-天（周四）" class="headerlink" title="被优化第 15 天（周四）"></a>被优化第 15 天（周四）</h3><p><strong>北京卷易科技有限责任公司</strong></p><ul><li>面试形式：线上视频</li><li>面试时长：1 小时</li><li>招聘职位：区块链开发</li><li>公司业务：Layer 2.5</li><li>面试结论：技术 1 面，日常面试。找工作以来第一次遇到公链开发的职位，也是第一次比较想去的公司。不过之前 HR 有提到，公司比较需要在招的是资深开发，经验少的需要带。结果可能不太好。</li></ul><h3 id="gap-第-16-天（周五）"><a href="#gap-第-16-天（周五）" class="headerlink" title="gap 第 16 天（周五）"></a>gap 第 16 天（周五）</h3><p>–</p><h3 id="gap-第-17-天（周六）"><a href="#gap-第-17-天（周六）" class="headerlink" title="gap 第 17 天（周六）"></a>gap 第 17 天（周六）</h3><p><strong>北京卷易科技有限责任公司</strong>（第二次）</p><ul><li>面试形式：线上视频</li><li>面试时长：1 小时 50 分钟</li><li>招聘职位：区块链开发</li><li>公司业务：Layer 2.5</li><li>面试结论：技术 2 面，日常面试。了解到是创业团队，刚拿到种子轮融资，在做一个试图同时兼容主流链的 Layer 2 项目，正在组建前期的技术团队，预期今年年底让项目达到能上线的进度。面试官谈到一些创业团队招人的思路，说技术是一方面，另一方面也是看性格，不适合追求稳定或轻易离开团队的人之类。对于这家公司、这种项目形式，我倒是很有意向，不过因为是技术面也没有多说什么。</li></ul><h3 id="gap-第-18-天（周日）"><a href="#gap-第-18-天（周日）" class="headerlink" title="gap 第 18 天（周日）"></a>gap 第 18 天（周日）</h3><p>–</p><h3 id="gap-第-19-天（周一）"><a href="#gap-第-19-天（周一）" class="headerlink" title="gap 第 19 天（周一）"></a>gap 第 19 天（周一）</h3><p>–</p><h3 id="gap-第-20-天（周二）"><a href="#gap-第-20-天（周二）" class="headerlink" title="gap 第 20 天（周二）"></a>gap 第 20 天（周二）</h3><p>–</p><h3 id="gap-第-21-天（周三）"><a href="#gap-第-21-天（周三）" class="headerlink" title="gap 第 21 天（周三）"></a>gap 第 21 天（周三）</h3><p>–</p><h3 id="gap-第-22-天（周四）（端午节）"><a href="#gap-第-22-天（周四）（端午节）" class="headerlink" title="gap 第 22 天（周四）（端午节）"></a>gap 第 22 天（周四）（端午节）</h3><p>–</p><h3 id="gap-第-23-天（周五）（端午节）"><a href="#gap-第-23-天（周五）（端午节）" class="headerlink" title="gap 第 23 天（周五）（端午节）"></a>gap 第 23 天（周五）（端午节）</h3><p>–</p><h3 id="gap-第-24-天（周六）（端午节）"><a href="#gap-第-24-天（周六）（端午节）" class="headerlink" title="gap 第 24 天（周六）（端午节）"></a>gap 第 24 天（周六）（端午节）</h3><p>–</p><h3 id="gap-第-25-天（周日）"><a href="#gap-第-25-天（周日）" class="headerlink" title="gap 第 25 天（周日）"></a>gap 第 25 天（周日）</h3><p>–</p><h3 id="gap-第-26-天（周一）"><a href="#gap-第-26-天（周一）" class="headerlink" title="gap 第 26 天（周一）"></a>gap 第 26 天（周一）</h3><p><strong>聚义岩（趣链子公司）</strong></p><ul><li>面试形式：线上语音</li><li>面试时长：30 分钟</li><li>招聘职位：区块链开发</li><li>公司业务：军工项目，联盟链交付</li><li>面试结论：联系我的 HR 竟然是一家外包公司，不知道简历是怎么到她手里的。面试官上来直接拿错简历了，说是同名同姓，然后开始找我的简历。随便聊了聊。面试官不怎么懂区块链，做联盟链的都那样。</li></ul><h3 id="gap-第-27-天（周二）"><a href="#gap-第-27-天（周二）" class="headerlink" title="gap 第 27 天（周二）"></a>gap 第 27 天（周二）</h3><p><strong>北京知知丫丫科技有限公司</strong></p><ul><li>面试形式：线下</li><li>面试时长：30 分钟</li><li>招聘职位：Golang 开发</li><li>公司业务：初创公司，要做类似于 Notion 的 to T 产品，理念是本地保留完整的数据，然后数据同步到线上</li><li>面试结论：全程注重 Go 语言基础。面试官问写过多少行代码，说这是判断一个人编程能力的指标之一。还说对于程序员来说，开发什么都一样，不管是他们那种产品还是区块链，主要是得基础好。</li></ul><p><strong>FAMEEX 交易所</strong></p><ul><li>面试形式：线上语音</li><li>面试时长：15 分钟</li><li>招聘职位：Golang 后端开发</li><li>公司业务：交易所，分布式办公</li><li>面试结论：面试十来分钟也是挺少见的，问了一些语言基础</li></ul><h3 id="gap-第-28-天（周三）"><a href="#gap-第-28-天（周三）" class="headerlink" title="gap 第 28 天（周三）"></a>gap 第 28 天（周三）</h3><p><strong>北京梓茂科技</strong></p><ul><li>面试形式：线上语音</li><li>面试时长：40 分钟</li><li>招聘职位：钱包开发，分布式办公</li><li>公司业务：交易所钱包，资产托管</li><li>面试结论：常规面试，随便问问。问三色树的内容，我没了解过。</li></ul><p><strong>FAMEEX 交易所</strong>（第二次）</p><ul><li>面试形式：线上语音</li><li>面试时长：10 分钟</li><li>招聘职位：Golang 后端开发</li><li>公司业务：交易所，分布式办公</li><li>面试结论：二面，复试。好家伙也是十来分钟，随便问了问。对方是业务负责人</li></ul><p><strong>鹰飞无限科技有限公司</strong></p><ul><li>面试形式：线上视频</li><li>面试时长：15 分钟</li><li>招聘职位：Golang 后端开发</li><li>公司业务：不知道</li><li>面试结论：水平很差的公司</li></ul><h3 id="gap-第-29-天（周四）"><a href="#gap-第-29-天（周四）" class="headerlink" title="gap 第 29 天（周四）"></a>gap 第 29 天（周四）</h3><p><strong>元界元芥</strong></p><ul><li>面试形式：线下</li><li>面试时长：20 分钟</li><li>招聘职位：智能合约开发</li><li>公司业务：不知道</li><li>面试结论：面试官是一个岁数不太小的男人，有点迷之自信。问在 4 位机上怎么计算 1000x1000，我反复确认才听懂 4 位机这个词，答案自然也是不知道。还问我，只用 + 法，计算 999x999 的结果，最少需要多少次 + 法，我只能想到 log<sub>2</sub>999，对方说这是一道小学的题，就是数字的每一位都加 9 次，一共需要 3x9+1&#x3D;28 次，简直了。我说我们项目里的零知识证明是用 Go 语言写的，对方说不可能，一定是用 Rust 写的。我说我们项目的扇区不需要封装，对方说不可能，一定需要。好家伙。算是一次奇葩的面试经历吧。</li></ul><p><strong>北京梓茂科技</strong>（第二次）</p><ul><li>面试形式：线上视频</li><li>面试时长：20 分钟</li><li>招聘职位：钱包开发，分布式办公</li><li>公司业务：交易所钱包，资产托管</li><li>面试结论：面试官人不错，说话挺温柔，随便聊一聊</li></ul><h3 id="补充（7月份）"><a href="#补充（7月份）" class="headerlink" title="补充（7月份）"></a>补充（7月份）</h3><h4 id="3-日"><a href="#3-日" class="headerlink" title="3 日"></a>3 日</h4><p><strong>并集科技</strong></p><ul><li>面试形式：线下</li><li>面试时长：10 分钟</li><li>招聘职位：Solidity 开发</li><li>公司业务：说什么赛道的项目都有</li><li>面试结论：白跑一趟，要求有上线项目的经历</li></ul><div style="display:none"><h4 id="6-日"><a href="#6-日" class="headerlink" title="6 日"></a>6 日</h4><p><strong>均衡哈希</strong></p><ul><li>面试形式：线下</li><li>面试时长：2 小时</li><li>招聘职位：区块链开发</li><li>公司业务：公司只有老板一个人，老板是创业者，和一个央行的经济学家签了合同，根据经济学家写的一本书，书中提出了创新类型的区块链系统设计，主要是共识方面的改进。公司要进行 MVP 产品的开发，然后保留知识产权卖给华夏。</li><li>面试结论：面试官是老板，字节出来的创业者，年龄不大 30 岁。由于对方不是技术出身，也不怎么懂区块链，所以并不清楚经济学家的区块链系统是怎么个创新法，里面到底有没有东西，在技术上靠不靠谱。华夏的目标是在国内面向省市做推广。公司预期在 Cosmos 的基础上开发，然后自己实现共识方面的东西。</li></ul><h4 id="7-日"><a href="#7-日" class="headerlink" title="7 日"></a>7 日</h4><p><strong>均衡哈希</strong>（第二次）</p><ul><li>面试形式：线上视频</li><li>面试时长：40 分钟</li><li>招聘职位：区块链开发</li><li>面试结论：估计是交叉面的意思，面试官是一个后端开发。</li></ul></div>]]></content>
  </entry>
  <entry>
    <title>没找到工作</title>
    <link href="https://b.smallyu.net/2023/06/24/%E6%B2%A1%E6%89%BE%E5%88%B0%E5%B7%A5%E4%BD%9C/"/>
    <id>blog-b:https://b.smallyu.net/2023/06/24/%E6%B2%A1%E6%89%BE%E5%88%B0%E5%B7%A5%E4%BD%9C/</id>
    <published>2023-06-23T18:43:45.000Z</published>
    <updated>2025-12-03T10:02:00.868Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>区块链最近一两年都没什么热点，自从 ETH 从 3400 跌到 1200，也是美联储加息最用力的一段时间，市场就一直处于冷淡的状态，后来又发生了 Luna 归零、FTX]]></summary>
    <content type="html"><![CDATA[<p>区块链最近一两年都没什么热点，自从 ETH 从 3400 跌到 1200，也是美联储加息最用力的一段时间，市场就一直处于冷淡的状态，后来又发生了 Luna 归零、FTX 破产之类的事情。</p><p>目前来看市场上的工作需求大概有两类，一类是后端开发，一类是智能合约开发。</p><p>先说智能合约开发，也就是 Solidity 合约开发，主要的工作内容是开发 DAPP，工作的要求是熟悉 ERC 标准，熟悉至少一个线上项目比如 Uniswap，关键要对合约安全有经验，最好有线上项目的经历。如果符合这些技能要求，国内工作需求还是比较多的。</p><p>这样的方向我不太适合，一方面缺少相关的经验，另一方面我也不太有兴趣专职搞 DAPP。</p><p>缺少经验好理解，虽然我熟悉 Solidity 的语法和合约的写法，但是并没有资产安全方面的经验，因为项目没有上线，也没有到安全审计那一步。由于工作不相关，对于 DeFi 的机制也了解比较少。</p><p>至于兴趣方面，我知道有一大批人是在学习 DAPP 开发，也就是 Solidity 的开发，有一个专门的学习社区叫 Dapp-Learning，成员还挺多的，集中了不少国内的开发者和学习者，在主流网站上都有账号。从他们的技术分享来看，也有不少人在研究已经上线的项目的论文，主要集中在 DeFi 领域，分享的内容主要是对经济模型的解读，为什么质押多少钱就能获得多少收益，项目方是怎么设计的，这种。</p><p>其实挺没意思的，从我的角度看，如果作为项目方去搞这么一个项目，还是有利可图的，好听点叫割韭菜，难听点叫骗人。如果作为个人，想要撸羊毛，从项目的机制中获利，就属于有钱的傻子。记得很久以前有个项目，开头一句话就是，越早参与进项目的人获得回报越多，简直妥妥的传销模式，但还是有很多人参与，也是有人从中能挣到钱。如果作为学习者，想要学习技术，就得搞清楚到底是学什么技术，是计算机编程的技术，还是骗人的技术。</p><p>另外，Solidity 其实是一种难用的语言，从编程语言的角度，虽然是图灵完备的，但是写法受限制非常大。我甚至难以想象，智能合约工程师的职位，到底是给什么样的求职者准备的，专职写 Solidity 吗？会写其他语言的人不愿意，不会其他语言的人又不可能会 Solidity，什么样的学习和成长路线，才能出来专职写合约的人，搞不懂。</p><p>再说后端开发，和区块链相关的后端职位有两种，一种是钱包的后端开发，另一种是链上数据的量化。这两种职位都有一个特点，就是不懂区块链也能做，只不过是它们处于区块链的业务中，所以就叫区块链后端开发，但是和区块链本身的功能无关。我不止一次听到面试官类似这样的说话，我们要招的就是纯粹的后端开发，懂区块链最好，不懂也无所谓。</p><p>这就涉及到职业规划的问题。我刚毕业的时候做过一年多区块链的应用层开发，后来转到了联盟链的底层开发，再后来跳槽到一个公链的项目，基本上是有路径的。要是现在说放弃区块链的道路，再回头做普通的后端开发，就有一个沉没成本在里面。</p><p>再者是现在的行业趋势，互联网和区块链是两个不同的行业，一般说互联网是 web2，区块链是 web3，哪有从 3 往 2 走的道理。何况互联网已经寒冬好几年了，虽然区块链行业处于熊市，但是互联网不但冷，还处于没落的路上，尤其是国内的互联网大厂，看看有哪家好过的？</p><p>这是一个两难的问题，现在区块链也不好过。其实各行各业都不好过。17 年左右是公链爆发的一段时间，对于区块链开发的需求比较多一点，后来因为比特币和以太坊两座大山，再搞新的 Layer1 链难度太大，现在的区块链开发需求就很少了。除去技术上的市场环境，之前还在职的时候，无意间听到说，国内的投资机构，最近一年没有投过一个 web3 相关的项目。也就是说国内的创业团队是融不到钱、拿不到投资的。</p><p>在国内还招人的，除非是老牌的区块链公司，屈指可数的那几家，扑克牌名下的。再或者就是从国外拉投资，回国内招人开发，主要目的也是为了降低成本，否则没有理由回国，因为目标用户至少要在国外。想在国内融资、面向国内用户、挣国内用户的钱，目前是不可能是事情。也因此，国内区块链开发的职位应该是少之又少。也不一定是开发 Layer 1，哪怕是 Layer 2、链下节点，只要是在公链生态内的呢，同样也很少。</p><p>这里再强调一下公链和联盟链的区别，我是从联盟链走到公链的，就像是从 web2 走到 web3，国内是有不少联盟链的职位需求的，但是我不能回头，至少不能轻易回头。技术上，联盟链不是真正的区块链，市场上，联盟链没有真正的用户需求，价值上，联盟链不值钱、挣不了钱，搞联盟链的公司都没什么钱。</p><p>提到成长空间，当我们要去一家公司的时候，肯定是看中在公司的发展前景，不管是回报上的提升空间，还是技术方面的提升机会，总得占一样吧，要是两样都没有，整个职业生涯不就走下坡路、没有希望了吗？多少得有点盼头的机会才行。</p><p>再讨论一下技术能力的问题。我们经常说一个人的技术能力好或者坏，或者一种技术难或者不难，那么有什么评价的标准吗。我认为可以从一个角度，就是学习成本。如果一个知识点看一眼就能明白，或者半个小时就能理解，或者一两天就能搞清楚，就属于比较简单的，这种东西，在面试之前学会和面试之后学会，有什么区别呢？还有一些东西是学习成本比较高的，比如对行业的理解，对某种技术类型和项目的了解，可能需要至少两三个月或者半年以上，才能够切实的明白，这种就偏难，成本高一点。</p><p>所以面试更多是方向性的面试，面试过程中，面试官可能会问你各种各样的小问题，大多也是捡着他自己会的问，对于有水平的面试官，肯定不会因为学习成本低的问题，就给你不通过的结果。甚至夸张的说，在看到简历的一瞬间，就基本上能确定是不是要招的人了，其余流程都是走个过场。除非简历作假，在面试过程中体现出的能力达不到简历描述的水平。</p><p>我在脉脉上发起过一个投票，统计大家的待业时间都是多长，参与人数还不少：</p><img src="gap.png" width="50%"><p>有一半以上的人，待业时间都超过三个月。现在的市场环境比较差，也许发生什么都不稀奇。</p>]]></content>
  </entry>
  <entry>
    <title>公司解散了</title>
    <link href="https://b.smallyu.net/2023/06/04/%E5%85%AC%E5%8F%B8%E8%A7%A3%E6%95%A3%E4%BA%86/"/>
    <id>blog-b:https://b.smallyu.net/2023/06/04/%E5%85%AC%E5%8F%B8%E8%A7%A3%E6%95%A3%E4%BA%86/</id>
    <published>2023-06-04T09:46:24.000Z</published>
    <updated>2026-03-02T09:13:07.176Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>我们大老板是扑克牌之一，在香港开了一家新公司，在上海的总公司和在北京的分公司都不再保留员工了。整件事情发生在一个星期之内，并没有太多缓冲的时间。</p>
<p>本来是提供了两种方案，可以拿 n+1]]></summary>
    <content type="html"><![CDATA[<p>我们大老板是扑克牌之一，在香港开了一家新公司，在上海的总公司和在北京的分公司都不再保留员工了。整件事情发生在一个星期之内，并没有太多缓冲的时间。</p><p>本来是提供了两种方案，可以拿 n+1 走人，也可以和香港新公司签一种社区形式的“共建协议”，继续工作，但是由于北京分公司大多数人选择离开，剩下的人也撑不起整个项目，大老板就让北京这边的所有人都离开了。</p><p>我是为数不多一开始愿意留下来的人之一，所以离职对我来说更加突然。早上还做好了继续上班的准备，上午告知离开、签字，中午就走人了。很快。不过公司给钱还是比较大方，HR 按照最高标准计算了赔偿，所以也不至于有失落的感觉。</p><p>按理在离开一家公司后，应该说一些在职期间不方便说的东西，比如公司的坏话，但是我并没有怀着恨意离开，也不是因为不满而主动离开，就暂时没有太多想说的。</p><p>至于为什么一开始选择留下，也是有多方面的原因。比如，国内真的很难搞区块链。</p><p>接下来一段时间，可能得接触很多公司了，还不一定能找到合适的工作。这次比较奇怪的感觉是，稍微有点不知道简历该怎么写，也没有复盘一下这两年工作的冲动。这两年的工作不至于达到理想的地步，但是我也没闲着，倒不是在技术方面的心虚。</p><p>因为我平时已经时刻关注区块链行业的动态了，并且我其实长期处于迷茫的状态，所以对于接下来要找的工作，也是充满迷茫的。也许是我不知道，也许国内真的不存在，在区块链方向上靠谱的项目。就各种赛道哪个靠谱啊，即使放在整个行业新闻的角度，我也看不到，所以对于真实要找的工作，就更是一点儿都没底了。</p>]]></content>
  </entry>
  <entry>
    <title>为区块链革命指明方向</title>
    <link href="https://crazy.smallyu.net/2023/05/29/%E4%B8%BA%E5%8C%BA%E5%9D%97%E9%93%BE%E9%9D%A9%E5%91%BD%E6%8C%87%E6%98%8E%E6%96%B9%E5%90%91/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2023/05/29/%E4%B8%BA%E5%8C%BA%E5%9D%97%E9%93%BE%E9%9D%A9%E5%91%BD%E6%8C%87%E6%98%8E%E6%96%B9%E5%90%91/</id>
    <published>2023-05-29T08:10:48.000Z</published>
    <updated>2025-08-16T03:27:11.465Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>为区块链革命指明方向：基于 Web 3.0 的人工智能</p>
<p>Web 3.0 把 Web 2.0]]></summary>
    <content type="html"><![CDATA[<p>为区块链革命指明方向：基于 Web 3.0 的人工智能</p><p>Web 3.0 把 Web 2.0 的数据都迁移到区块链上，作为训练数据在区块链上创建人工智能模型。</p>]]></content>
  </entry>
  <entry>
    <title>prompt 工程的存在，主要原因是 AI 的语义理解能力不够，所以 prompt 工程只是暂时的</title>
    <link href="https://t.smallyu.net/#2023-20"/>
    <id>micro:1558469174</id>
    <published>2023-05-23T03:46:29Z</published>
    <updated>2023-05-23T03:46:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>prompt 工程的存在，主要原因是 AI 的语义理解能力不够，所以 prompt 工程只是暂时的</p>]]></summary>
    <content type="html"><![CDATA[<p>prompt 工程的存在，主要原因是 AI 的语义理解能力不够，所以 prompt 工程只是暂时的</p>
]]></content>
  </entry>
  <entry>
    <title>Pebbling Game 鹅卵石游戏</title>
    <link href="https://smallyu.net/2023/05/18/Pebbling-Game-%E9%B9%85%E5%8D%B5%E7%9F%B3%E6%B8%B8%E6%88%8F/"/>
    <id>blog:https://smallyu.net/2023/05/18/Pebbling-Game-%E9%B9%85%E5%8D%B5%E7%9F%B3%E6%B8%B8%E6%88%8F/</id>
    <published>2023-05-18T08:36:33.000Z</published>
    <updated>2025-11-09T09:22:13.308Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>这是一个在线的网页游戏：<a href="https://smallyunet.github.io/pebbling-game/" target="_blank">Pebbling Game</a>。可以看这个嵌入进来的网页：</p>
<div>
<iframe]]></summary>
    <content type="html"><![CDATA[<p>这是一个在线的网页游戏：<a href="https://smallyunet.github.io/pebbling-game/" target="_blank">Pebbling Game</a>。可以看这个嵌入进来的网页：</p><div><iframe src="https://smallyunet.github.io/pebbling-game/" width="900px" height="580px" frameborder="0" scrolling="yes" style="border: 5px double #e4e4e4;"> </iframe></div><p>为了直观展示 Pebbling Game 的游戏规则，经过几十次调整，GPT-4 完成了这个在线的游戏页面。</p><p>游戏的规则是：</p><ol><li>点击节点的圆圈，可以在节点中放入鹅卵石</li><li>只有指向当前节点的所有节点，都已经放置了鹅卵石，当前节点才能够放置鹅卵石</li><li>游戏目的是在节点 0 放置鹅卵石</li><li>任何时间都能够从任意节点取走鹅卵石</li></ol><p>如果直接点击节点 0，可以看到两个红色闪烁圆圈的提醒，意思是节点 1 和 2 都还没有放入鹅卵石，所以节点 0 不能放入鹅卵石。</p><p>节点 7 没有来源节点，所以可以直接放入鹅卵石。点击节点 7，能看到节点内出现了黑色的实心圆。此时如果想把鹅卵石放入节点 3，会提示因为节点 6 还空着，放入失败。节点 3 的来源节点是 6 和 7.</p><p>那么在这样的游戏规则下，问：最少需要多少颗鹅卵石？</p><p>如果鹅卵石足够多，这个图中一共有 10 个节点，手里有 10 个鹅卵石，就不需要取走鹅卵石的操作，直接按照顺序把节点填满就行。</p><p>如果鹅卵石有限，寻求鹅卵石数量最少的解法，这个图应该至少需要 5 个鹅卵石。</p><p>鹅卵石游戏的特点就是，总会存在一个最小值，如果鹅卵石的数量少于这个值，游戏将不能完成，因为最终的节点依赖于下层节点，而下层节点依次依赖于更下层的节点。如果中间节点的鹅卵石被取走，还需要从最下层开始重新放置。</p><p>鹅卵石游戏对于 Hard-to-pebble graphs 的数据结构具有启发意义，理解了游戏的规则，就理解了区块链如何证明磁盘空间的大小。</p><h3 id="空间证明"><a href="#空间证明" class="headerlink" title="空间证明"></a>空间证明</h3><p>Hard-to-pebble graphs 是一种结合了 Merkle 树的 DAG，特点就是需要一定数量的储存空间才能够完成最顶点的计算。就像是鹅卵石不够就无法完成游戏，储存空间不够就无法完成挑战。</p><p>由于图的多种多样，需要鹅卵石的数量没有通用的最优解，只能是针对某一种类型的图，去计算空间复杂度。</p><p>区块链场景的需求是既要占用空间大，又要验证速度快。Stack expender graph 的图结构在 Proof of Space 中使用比较广泛。在验证阶段，只需要按照 Merkle 树的特点，验证图中的某些节点，就可以确认图的完整性了，同时也能根据图的深度，推算出占用了多大的磁盘空间。</p><p>如果既要验证空间大小，又要验证空间占用的持续性，就在空间证明的基础上加上对时间的证明，比如 Chia 就用了 Delay Verifiable Function 的方式，先验一遍空间证明，等一段时间后，用 VDF 验证确实经过了足够多的时间，然后再验一遍空间证明，就达到了 Proof of Space-Time 的效果。</p>]]></content>
  </entry>
  <entry>
    <title>PDP 文件证明的局限性</title>
    <link href="https://smallyu.net/2023/05/17/PDP%E6%96%87%E4%BB%B6%E8%AF%81%E6%98%8E%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7/"/>
    <id>blog:https://smallyu.net/2023/05/17/PDP%E6%96%87%E4%BB%B6%E8%AF%81%E6%98%8E%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7/</id>
    <published>2023-05-17T07:53:06.000Z</published>
    <updated>2025-11-09T09:22:13.308Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="存储证明"><a href="#存储证明" class="headerlink" title="存储证明"></a>存储证明</h3><p>对于一个文件来说，PDP 最基础的用法，就是根据文件内容生成对应的 TAG，然后把文件发送到另一个环境里。接着用保存下来的]]></summary>
    <content type="html"><![CDATA[<h3 id="存储证明"><a href="#存储证明" class="headerlink" title="存储证明"></a>存储证明</h3><p>对于一个文件来说，PDP 最基础的用法，就是根据文件内容生成对应的 TAG，然后把文件发送到另一个环境里。接着用保存下来的 TAG 验证对方是否真的储存了文件。如果对方没有储存文件，是不可能通过第一次验证的。在接下来的验证中。因为挑战是随机生成的，会选择文件不同位置的片段，能在概率上提高验证的可靠性。</p><p>所以这样的用法，至少能够证明文件储存在对方环境中过。但是这样的证明方式存在疏漏，就是文件不需要完整，或者说缺少对文件完整性的证明。如果文件非常大，而挑战的数量一般是固定的，文件越大，挑战越不全面。虽然挑战的文件片段是随机的，仍然存在可能性，对方不需要完整的文件，而只需要文件的一部分，2&#x2F;3、1&#x2F;2、1&#x2F;3，就足以完成挑战了。</p><h3 id="文件完整性证明"><a href="#文件完整性证明" class="headerlink" title="文件完整性证明"></a>文件完整性证明</h3><p>要让 PDP 能够证明文件的完整性，可以把 PDP 证明和 Merkle 树的数据结构结合起来。PDP 证明一般需要把文件拆分成数据片段，根据数据片段生成 TAG，并不强调数据片段的序列化方式。</p><p>和 Merkle 树结合的地方，就是在把文件拆分为数据片段之后，把数据片段序列化到 Merkle 树中。由于 Merkle 树的特性，父节点的值需要依赖子节点的值才能够推算出来，如果验证了父节点是正确的，就足以说明子节点是全部存在的，也就间接证明了文件的完整性。</p><p>在实际的使用中，往往抽取 Merkle 树的一些节点，对 Merkle 节点的路径进行验证。也是验证 Merkle 树完整性的一般方法。在使用了 Merkle 树作为文件的数据结构，并且在验证 PDP 证明的同时验证 Merkle 树的完整性，就能确保文件是完整存在了。</p><p>Merkle 树的验证覆盖率也不可能 100%，但通常认为，伪造 Merkle 树节点的成本比真正保留了完整数据的成本还要高。</p><h3 id="文件大小证明"><a href="#文件大小证明" class="headerlink" title="文件大小证明"></a>文件大小证明</h3><p>PDP 证明本身不包含文件的元信息，它只能证明文件是存在的、文件是完整的，至于是什么样的文件，文件名是什么、文件类型是什么、文件有多大，一概不知。PDP 的证明信息里不包含文件的元信息，而元信息中比较有用的是文件的大小信息。PDP 不是区块链时代的技术，也就没怎么关心这个问题。</p><p>有的区块链用磁盘空间的大小来描述节点的算力，或者根据文件大小来让使用者付费，或者根据储存的文件大小来给予存储节点奖励，这些都意味着文件大小的信息至关重要。</p><p>那么，对于文件的元信息缺失的问题，一种做法是在 PDP 证明系统之外，将元信息与文件数据关联起来。另一种做法是，对文件进行修改，将元信息附加到文件数据里，只要证明文件数据的完整，就能够确认文件元信息的准确。</p><p>然而，无论哪种方式，都不能保证文件元信息的可靠。在区块链的场景下，信任模型发生了一些变化，和 PDP 要解决的问题存在差异。以前的 PDP 是让用户相信存储节点，而现在，是让区块链来相信存储节点。</p><p>第一种方式需要额外的机制保证元信息和文件数据之间的映射关系，这会带来很大的开销。第二种方式在实现上是简便的，问题在于将元信息附加到文件数据的步骤，由谁来完成？是可信的吗？如果恶意附加了错误的信息呢？另外，怎么读取这些元信息？要把文件数据或者一部分文件数据下载下来？下载的信息还不能保证是正确的？</p><p>总之，在加密学的范畴里，PDP 并不能解决对文件大小的证明。</p><h3 id="文件持续性证明"><a href="#文件持续性证明" class="headerlink" title="文件持续性证明"></a>文件持续性证明</h3><p>PDP 证明需要不断地发起挑战请求，对方能够完成挑战则说明文件安好。比如现在发起一次挑战，一个小时之后又发起一次挑战，至少能够说明对方在完成挑战的时刻，文件是完整存在的。那在没有进行挑战的时间呢？没有限制。</p><p>如果在第一次完成挑战后，就把文件转移到了另外一个地方，等第二次挑战的时候，再把文件拿过来完成挑战，这完全是可以的。PDP 并不也没有能力阻止这样的情况。PDP 无法对文件的持续性提供证明。</p><p>这样的能力限制会对区块链造成什么样的影响呢，首先能想到的就是算力换空间。因为在有些区块链的规则里，文件越大，矿工的收益越高。矿工完全可以利用 PDP 的证明间隔，把空间腾给其他文件用，用磁盘的 IO 换取磁盘空间大小。</p><p>再就是证明成本的提高。挑战越频繁，文件越安全，这对寻求证明的一方是一种压力。</p><h3 id="文件多副本证明"><a href="#文件多副本证明" class="headerlink" title="文件多副本证明"></a>文件多副本证明</h3><p>PDP 自然也不具备证明文件有多个副本的能力。如果需要对方存 2 个副本，而对方实际上只存了 1 份，对于 PDP 是没有任何感知的，这很容易理解。</p><p>如果想分散文件损失的风险，把文件存到了不同地方，在使用 PDP 作为验证手段的情况下，是无法达到目的的。</p>]]></content>
  </entry>
  <entry>
    <title>不要去撸宠店</title>
    <link href="https://crazy.smallyu.net/2023/05/11/%E4%B8%8D%E8%A6%81%E5%8E%BB%E6%92%B8%E5%AE%A0%E5%BA%97/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2023/05/11/%E4%B8%8D%E8%A6%81%E5%8E%BB%E6%92%B8%E5%AE%A0%E5%BA%97/</id>
    <published>2023-05-11T10:04:23.000Z</published>
    <updated>2026-07-04T17:36:19.119Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>以前看到一个段子，原图找了好久没找着，大概内容是，有个网友试着花钱买爱情，4000]]></summary>
    <content type="html"><![CDATA[<p>以前看到一个段子，原图找了好久没找着，大概内容是，有个网友试着花钱买爱情，4000 块钱，质量比较高的那种。然后网友发现，虽然小姐姐本人和照片里一样漂亮，身材也好，但满满的科技感。脸上、腿上，捏不起一点肉。如果让她跟你互动，她虽然会很配合你的要求，说一些话之类，但是言语之间、表情上都觉得，她有一些不耐烦，想要赶紧完事的感觉，然后这个网友就感慨说，她是没有感情的，不像活生生的人，更像是一种工具,不是一段太好的体验。</p><p>然后下面还有评论打趣说，你给我 4000 块钱，我保证像个活生生的人 :P</p><p>这让我想到去撸宠店的经历，凡是做买卖的，似乎都会出现这样的情况。平时在各种小视频里看到小奶猫、小柴犬，觉得这些宠物怎么这么可爱啊！然后实际上去了猫舍、狗屋，就会发现这些宠物根本不搭理你，因为你是陌生人。</p><p>第一次去猫舍就感觉被坑了，因为猫不让抱，店员说以前的客人对猫太凶了，导致很多猫脾气都不好，容易生气。然后再仔细一看，每只猫都哭丧着脸，一副被迫营业的表情，不是在睡觉就是躲得人远远的。</p><p>你可以给猫喂吃的，它们就会过来吃，也可以拿逗猫棒勾引它们，但是你会发现，它们的眼睛不会看你，因为不认识你，它们看着的是你手里的食物。它们不会钻到你手里让你摸头，更不会对着你笑。虽然各种猫都有，都是纯种，都很好看，但是没有感情。</p><p>让人意外的是店里的羊驼特别温顺，看起来没有脾气，亲近人，还吃我的鞋带。</p><img src="1.jpg" width="50%"><p>不过这玩意儿就怕它跟你面对面的时候，它吐口水。羊驼生气了会吐口水，看过那样的视频，总是有那样的阴影在，就也不敢多看羊驼。</p><p>狗屋也是类似的感觉，纯种柴犬，长得很英俊，会自己找你手上拿的食物，但是不多看你一眼。小柴犬很活泼，满地打架。</p><img src="2.jpg" width="50%">]]></content>
  </entry>
  <entry>
    <title>半年的工作回顾</title>
    <link href="https://b.smallyu.net/2023/05/06/%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/"/>
    <id>blog-b:https://b.smallyu.net/2023/05/06/%E5%8D%8A%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/</id>
    <published>2023-05-06T11:24:50.000Z</published>
    <updated>2026-05-27T07:32:32.132Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<blockquote>
<p>前几年关于工作内容方面的回顾：</p>
<ul>
<li>2022 年：《<a]]></summary>
    <content type="html"><![CDATA[<blockquote><p>前几年关于工作内容方面的回顾：</p><ul><li>2022 年：《<a href="/2022/08/27/%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">一年的工作回顾</a>》</li></ul></blockquote><p>回顾一下最近半年的工作。从半年前开始，我就迷茫了，因为知道 Filecoin 在做 EVM 的适配，存储赛道已经倒向计算赛道的一边。我们又无法超越 Filecoin。</p><p>不过我还是有收获的，主要集中在对文件证明的进一步理解，以及对项目中代码细节的进一步熟悉，这一块是我之前没了解的。</p><h3 id="扇区证明"><a href="#扇区证明" class="headerlink" title="扇区证明"></a>扇区证明</h3><p>扇区证明一直存在个问题，就是证明会失败。一开始认为是合约进行证明检查的时候，根本没有带上文件列表的信息，导致过期文件没有被删掉。后来发现不止这一个问题，因为在修复代码后，如果文件只存到一个存储节点，是正常的，如果有多个存储节点，证明仍然会失败。</p><p>最后查到的原因是，当一个文件被存到多个节点，其他节点提交证明到合约，如果发现文件过期了，就会在合约里删掉节点对应的文件信息，同时广播给其他节点，要删掉这个文件。而其他节点收到通知后，只删除了本地的问题，没有删除合约里的文件信息，就导致本地的文件经常会少于合约里记录的文件，证明就失败了。</p><p>这个问题解决的过程中，相当于把证明相关的代码看了一遍。</p><h3 id="EVM-合约"><a href="#EVM-合约" class="headerlink" title="EVM 合约"></a>EVM 合约</h3><p>在去年 <a href="/2022/08/27/%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/">一年的工作回顾</a> 中提到，我在做一件把 Go 语言合约用 Solidity 重写的事情，也就是把原有的合约移植到以太坊上运行。</p><p>其中让项目支持以太坊账户的事情早就完成了，存储节点可以顺利地使用以太坊节点，通过以太坊的智能合约实现文件的上传下载。但是合约对文件的证明一直空着，因为项目使用了 Bulletproof 的零知识证明，用 Solidity 写一遍 Bulletproof 的证明太费力了。</p><p>现在的做法是 POA 的方式，在合约里本该进行证明的地方，换成提交证明参数，把证明参数记录到合约中。然后验证节点从合约里把证明参数拿下来，在本地进行零知识证明的验证，再把证明结果提交回合约里。</p><p>因为把证明相关的代码看了一遍，所以现在能够完成 EVM 合约中，证明相关的这一部分。</p><h3 id="为什么忽略-Layer2"><a href="#为什么忽略-Layer2" class="headerlink" title="为什么忽略 Layer2"></a>为什么忽略 Layer2</h3><p>之前有一个想法是，把证明放到 Layer2 的节点上做。我在这个方向上没什么进度，有两个原因：</p><ol><li>Layer2 的定位是 EVM 完备，本身不具备额外的功能</li><li>Layer2 也很难进行验证</li></ol><p>第一点的意思是，对于用户或者开发者来说，Layer2 存在的意义是降低手续费，如果能在使用效果上和 Layer1 一模一样，那就了不得了。给 Layer2 增加一些额外的功能，是不是 Layer2 这种项目的本意呢？</p><p>第二点的意思是，Layer2 的项目也是拿着 Layer1 的节点改了改区块的头信息之类。想要实现文件的验证，需要在虚拟机的字节码层面，识别出一笔交易是调用了某个合约的某个函数，然后把这个函数要操作的变量拿出来，对参数进行一次零知识证明的验证，再把验证结果在字节码层面写入回变量中。这样做的难度很大。不过要真的能搞成，相当于搞了一个业务专用的 EVM 虚拟机，技术门槛挺高，挺能用来炫耀的。</p><p>与之相比，相对简单的做法就是，用一个客户端对证明参数做验证，再把结果提交回去。如果是这样，那就无所谓客户端在 Layer2 的节点上还是其他什么节点上了。 我就选择了这种简单的方式去做，虽然不够酷，但是有生之年能完成，能看到结果，现在确实完成了。</p><h3 id="Solidity-合约"><a href="#Solidity-合约" class="headerlink" title="Solidity 合约"></a>Solidity 合约</h3><p>稍微总结一下 Go 合约迁移到 Solidity 合约遇到的问题。</p><p>合约大小不能超过 24 KB，否则会编译失败。对于业务型的合约，24 KB 是不够用的，需要拆分为两个甚至多个合约，合约之间再通过调用完成相应的功能。拆起来也不难，就是注意在功能上拆明白，哪些是对外的，哪些是内部的。</p><p>storage 的结构体不能包含列表，因为列表不是固定长度的。合约不好计算占用了多少空间。这就需要把原先结构体里面的列表拆出来，用的时候单独用。当然如果对业务逻辑熟悉，这一点不是什么问题，如果对业务逻辑不熟悉，看到一堆陌生的变量名称，还是挺烦的。我就因为当时偷懒，合约里没把逻辑写全，查了两天才查明白问题。</p><p>mapping 不能迭代。原先简单的写法，需要用 library 改为挺复杂的写法。</p><p>mapping 元素不存在会返回默认值。无法判断 mapping 是否包含某个 key，如果业务中类型的默认值有含义，可能会出现意想不到的情况。</p><p>这几点不算什么大问题，但可能会给写代码的过程带来一点麻烦，因为需要用不一样的写法，写出完全一样的逻辑。</p>]]></content>
  </entry>
  <entry>
    <title>在币圈挣钱： 一流的钱：作为项目方发币，无中生有。 二流的钱：空投、漏洞、抽奖、挖矿，无中生有 三流的钱：炒币，自负盈亏...</title>
    <link href="https://t.smallyu.net/#2023-19"/>
    <id>micro:1514146548</id>
    <published>2023-04-19T05:18:59Z</published>
    <updated>2023-04-19T05:18:59Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>在币圈挣钱： 一流的钱：作为项目方发币，无中生有。 二流的钱：空投、漏洞、抽奖、挖矿，无中生有 三流的钱：炒币，自负盈亏 四流的钱：打工，给别人挣钱</p>]]></summary>
    <content type="html"><![CDATA[<p>在币圈挣钱：<br>一流的钱：作为项目方发币，无中生有。<br>二流的钱：空投、漏洞、抽奖、挖矿，无中生有<br>三流的钱：炒币，自负盈亏<br>四流的钱：打工，给别人挣钱    </p>
]]></content>
  </entry>
  <entry>
    <title>no more opportunities</title>
    <link href="https://t.smallyu.net/#2023-18"/>
    <id>micro:1501135000</id>
    <published>2023-04-09T13:57:04Z</published>
    <updated>2023-04-09T13:57:04Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>no more opportunities</p>]]></summary>
    <content type="html"><![CDATA[<p>no more opportunities</p>
]]></content>
  </entry>
  <entry>
    <title>不要小瞧 ChatGPT</title>
    <link href="https://smallyu.net/2023/03/30/%E4%B8%8D%E8%A6%81%E5%B0%8F%E7%9E%A7-ChatGPT/"/>
    <id>blog:https://smallyu.net/2023/03/30/%E4%B8%8D%E8%A6%81%E5%B0%8F%E7%9E%A7-ChatGPT/</id>
    <published>2023-03-30T09:09:36.000Z</published>
    <updated>2026-08-04T11:43:17.182Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>之前我不了解 Filecoin 是如何管理磁盘空间的，既然它使用了 Proof of Space，那么 Sector 在创建的时候就一定会占用掉磁盘空间，当有用户的文件存入 Sector，Filecoin]]></summary>
    <content type="html"><![CDATA[<p>之前我不了解 Filecoin 是如何管理磁盘空间的，既然它使用了 Proof of Space，那么 Sector 在创建的时候就一定会占用掉磁盘空间，当有用户的文件存入 Sector，Filecoin 是如何及时把占用的空间释放出来的？每写入一次文件，就释放一次占用的空间，这种做法太生硬了。</p><p>我看了 Filecoin 的 <a href="https://docs.filecoin.io/basics/what-is-filecoin/storage-model/">文档</a> 和 <a href="https://spec.filecoin.io/systems/filecoin_mining/sector/">Spec</a>，都没能很直接地找到答案。运行 Filecoin 节点的成本又比较高，不但对硬件需求高，而且还得在实际的操作过程中去观察磁盘容量的变化。</p><p>后来无意间问了 ChatGPT 一句，没想到它给出了很详细的解释，让我对 ChatGPT 刮目相看。Filecoin 不会实时释放磁盘空间，只在 Sector 存满文件之后有一个 Sealing 的过程，这个过程会把 Sector 封存起来，然后用真实的数据替换到之前随机生成的用来占用空间的文件，用真实数据进行挖矿并获得收益。</p><p>以前在一个视频上听到过 Filecoin 的磁盘利用率只有 50% 的说法，但没有很理解为什么那么说。现在才算是明白，Sealing 之前 Sector 会占用两倍磁盘空间的含义。</p><p>在这件事情上，最令人惊讶的是 ChatGPT 的能力，其实回头想想，如果有一个经验丰富的 Filecoin 研究者，他很轻易就能够解答我的疑惑。但我经常面临的问题是，找不到那样资深的研究者，我向他咨询问题，他还乐意给我解答。现在我找到了。</p><p>2020年12月21日，我在<a href="/micro-blog/#2020-32">微博</a>上写下这样一句话：</p><blockquote><p>单纯的记忆是没有意义的，把书本和网络上的内容背下来，只能“显得”厉害，欺骗愚昧的人。如果把计算机和互联网理解成另一种形式的生物，它将比任何人类都博学。</p></blockquote><p>没想到，事到如今，这样的 “生物” 真的出现了，ChatGPT 集成了各个领域的专业知识，并且能够以人类的语言进行对话。我以前就知道，单纯提高自己 “死知识” 的储备没有用，总有你无法超越的人，甚至对方不是人。</p><p>最近有一个 ChatGPT 超越人类案例：<a href="https://www.zhihu.com/question/592511373">如何看待一男子宠物狗患病兽医难断病因，询问 GPT-4 后获救？</a>内容大意是，由于兽医经验有限，对于狗狗的病因，兽医只冲着 A 方向去诊断。后来主人把狗狗的各项身体指标让 ChatGPT 分析，ChatGPT 给出了 A、B 两种可能，去医院一查，果然是 B。由于 ChatGPT 不像兽医一样受到过往阅历的限制，ChatGPT 显得比兽医更加博学。</p><p>随着年龄的增长，我们必须学会抛弃极端的思维方式。我们不能相信 AI 会替代人类，因为现在的 AI 没有智能。我们也不能否认 AI 在某一些方面强过人类，可以作为人类很好的助手。</p><p>现在最先进的大语言模型是 GPT-4，需要在 ChatGPT 的网站上花 20 美元一个月开订阅才能用到。免费使用的预览版本是 GPT-3.5，不过 GPT-3.5 也很厉害。当人们以为 AI 聊天只停留在微软小冰和苹果 Siri 那样水平的时候，GPT-3.5 横空出世，广为流传。我以前用 GPT-3.5 也做过一些事情，帮朋友生成播客的好评评论、帮朋友完成专科学校的编程习题作业，等等。</p><p>ChatGPT 的翻译能力也是很强的，个别词汇的翻译比谷歌翻译要厉害。比如 “兜底机制” 这个词，谷歌翻译会翻译成 “Pocket Mechanism”，而 ChatGPT 会翻译成 “fallback mechanism”，显然谷歌翻译是直译，ChatGPT 是在理解词汇含义之后再翻译的。再比如 “布偶猫”，谷歌翻译为 “cat plush”，ChatGPT 翻译为 “Ragdoll cat”，高下立判。</p><p>不过 GPT-3.5 自诞生就存在一个广为诟病的问题，就是 “一本正经地胡说八道”。作为一个语言模型，程序员应该能比较容易理解，为什么会出现这样的现象，像是套模板，从一堆现成的语言模板里挑出比较好的回答。GPT-3.5 似乎就是这样。也就是说，想靠 GPT-3.5 来获取知识，是有很大风险的，它能告诉你正确的内容，也能把编造的内容当作知识讲出来。</p><p>谷歌的大语言模型 <a href="https://bard.google.com/">Bard</a> 不但综合能力比 ChatGPT 差，对代码的处理能力很弱，而且同样存在 “一本正经地胡说八道” 的情况，还经常 “答非所问”。中国的产品就更不用比了。</p><p>与 GPT-3.5 相比，GPT-4 在各方面应该都有所改善，不是很清楚在信息的准确性上具体有多大程度的改善，但对语言的理解能力确实超过 GPT-3.5，比如这里的<a href="https://v2ex.com/t/927744">讨论</a>。GPT-4 用了和 GPT-3.5 不一样的训练模型架构，微软发布过关于 GPT-4 的<a href="https://arxiv.org/abs/2303.12712">技术论文</a>。从论文看， GPT-4 是支持多模态的，也就是支持根据输入数据生成统计图之类，可能现在还没有开放出来给公众使用。</p><p>GPT-4 的能力过分强大也引来很多人的担忧，甚至马斯克都签署了<a href="https://futureoflife.org/open-letter/pause-giant-ai-experiments/">暂停训练比 GPT-4 更强大 AI 的公开信</a>。没有人知道 GPT-4 的出现，会给人类社会带来有益的还是有害的影响。</p><p>目前已经有很多产品接入了 GPT 的能力，微软的 Office 办公套件是首先支持的，毕竟是自家产品。不知道实际使用效果怎么样，也许会带来翻天覆地的变化，很多重复性的工作，GPT 完全具备更出色的处理能力。你不需要知道 Excel 里的某个函数怎么写，那些函数也许专业的程序员都用不来，何况几乎不懂计算机的文员，有了 GPT，用自然语言描述就可以了。以后的计算机教育也许会增加一个门类：如何与 ChatGPTG 高效沟通。</p><p>微软的 Bing 搜索引擎也引入了 GPT 的能力，没有 GPT 的 Bing 在搜索结果上是无法和 Google 相比的，有了 GPT，Bing 就有了使用自然语言搜索的能力。New Bing 的方式是，根据用户要搜索的内容，GPT 去搜索一遍，然后归纳总结，再用自然语言描述出来。这样做的好处是，GPT 说的都是正确的内容，缺点是处理过程比较慢。尝鲜可以，对于程序员来说，快速解决问题还得是 Google。</p><p>更加值得期待的是 GPT-4 的插件，让 GPT 融入到更多的场景中，比如取代 GitHub Copilot，在生成代码的能力上绰绰有余，只是使用形式上的问题。Copilot 这个东西，一旦用过就回不去了，本以为能够这样自动补全代码已经很先进，没想到 Copilot 发布没多久，GPT 就出来了。Copilot 是面临危险的，也推出了 Copilot X 方案，不过我更看好 GPT 的未来。我已经取消了 Copilot 每月 10 美元的订阅，买了每个月 20 美元的 ChatGPT Plus，相信以后 GPT 能大放异彩。</p><p>现在 ChatGPT 的使用对于美国之外的用户，还有一些门槛。首先需要能够正常访问 ChatGPT 的网站，然后注册账号需要美国的手机号码，最后订阅 Plus 需要美国的银行卡。经过一系列的折腾，我的建议是直接买现成的账号最划算，150 人民币就可以买到一个独立使用的、开通了 Plus 的账号。否则即使付出很高的成本，也未必能把事办成。</p><p>外国的手机号码可以花 300 块钱买 Ultra 实体卡，不需要 KYC，号码是 +1 开头，长期保号，每月 3 美元月租，开了 Wi-Fi Calling 可以免费使用 100 条短信。美国手机号还是比较有用的，可以开美区的 PayPal 账户，美区的 Apple ID 可以用美区的 PayPal 支付。美区的 PayPal 可以绑国内开的 Visa 信用卡。很多 IM 软件也会需要国外的手机号码作为验证。</p><p>国外的银行卡可以试试 Depay 虚拟卡，最近因为 ChatGPT 会员的需要发展速度很快，充值加密货币，然后以美元消费。但是 ChatGPT 的订单有一系列的风控规则，IP 地址、订单地址不一致都有可能触发风控，导致订阅失败。只是开通 ChatGPT Plus 的话，苹果手机访问 ChatGPT 能看到 Apple Pay 的选项，有美区 PayPal 也可以试试。总的来说，直接买账号是最快最省力的办法。</p><p>另外，最近 AI 领域的文字生成图片也比较火。我试用了比较热门的几个产品。</p><ul><li><a href="https://labs.openai.com/">DALL-E</a> 和 GPT 是同一家，都是 OpenAI 的产品，但是 DALL-E 绘制出来的人物经常是畸形的</li><li><a href="https://replicate.com/explore">Replicate</a> 提供了多种模型的试用，比如 <a href="https://replicate.com/stability-ai/stable-diffusion">stable-diffusion</a>，同样的问题，生成的人物总是怪怪的</li><li><a href="https://www.midjourney.com/">Midjourney</a> 是在 Discord 里面交互的一个产品，生成的图片质量不差，但是图片里的场景都比较小</li></ul><p>从我的感受上，目前文字生成图片的效果并不好，而且生成图片的效果很大程度取决于，输入的描述语是不是精确符合模型的规则，希望以后借助 GPT 的自然语言能力，文字生成图片会更加好用。</p><p>拥有 ChatGPT 就相当于有了一个空前强大的知识库，它拥有丰富的文字能力，一心一意为你服务，你难道不应该拥有一个吗？</p>]]></content>
  </entry>
  <entry>
    <title>一个养老金计算器</title>
    <link href="https://crazy.smallyu.net/2023/03/26/%E4%B8%80%E4%B8%AA%E5%85%BB%E8%80%81%E9%87%91%E8%AE%A1%E7%AE%97%E5%99%A8/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2023/03/26/%E4%B8%80%E4%B8%AA%E5%85%BB%E8%80%81%E9%87%91%E8%AE%A1%E7%AE%97%E5%99%A8/</id>
    <published>2023-03-26T14:31:04.000Z</published>
    <updated>2026-07-04T17:36:19.118Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>由于计算机行业特殊的职业规则，假设做一个在最悲观情况下的打算：在 35 岁之前攒出父母全部的养老金。</p>
<p>这种计划的动机涉及到一些严肃但会让人感觉非常消极问题，确实不想展开去讨论了。</p>
<p>我写了一个在线的网页来描述具体的计算过程：<a]]></summary>
    <content type="html"><![CDATA[<p>由于计算机行业特殊的职业规则，假设做一个在最悲观情况下的打算：在 35 岁之前攒出父母全部的养老金。</p><p>这种计划的动机涉及到一些严肃但会让人感觉非常消极问题，确实不想展开去讨论了。</p><p>我写了一个在线的网页来描述具体的计算过程：<a href="/html/pension.html">养老金计算器</a></p><p>有意思的一点是，这个网页的样式是由 ChatGPT 生成的。我懒得写带颜色的 CSS，就把 body 里面的标签代码交给 ChatGPT，让它帮我生成一个清淡色彩风格的样式。</p><h3 id="更新（2025-07-07）"><a href="#更新（2025-07-07）" class="headerlink" title="更新（2025.07.07）"></a>更新（2025.07.07）</h3><p>现在 2 年过去了，可以对比看一下这个经过最新的 ChatGPT o3 模型优化后的版本，页面样式和交互都有了显著提升：<a href="/html/pension2.html">养老金计算器（2025年版）</a></p><h3 id="更新（2025-11-29）"><a href="#更新（2025-11-29）" class="headerlink" title="更新（2025.11.29）"></a>更新（2025.11.29）</h3><p>来看看擅长前端的 Gemini 3 Pro 改进的版本：<a href="/html/pension3.html">养老金计算器（2025年版 v2）</a></p>]]></content>
  </entry>
  <entry>
    <title>为什么炒币不是一个好主意</title>
    <link href="https://smallyu.net/2023/03/15/%E4%B8%BA%E4%BB%80%E4%B9%88%E7%82%92%E5%B8%81%E4%B8%8D%E6%98%AF%E4%B8%80%E4%B8%AA%E5%A5%BD%E4%B8%BB%E6%84%8F/"/>
    <id>blog:https://smallyu.net/2023/03/15/%E4%B8%BA%E4%BB%80%E4%B9%88%E7%82%92%E5%B8%81%E4%B8%8D%E6%98%AF%E4%B8%80%E4%B8%AA%E5%A5%BD%E4%B8%BB%E6%84%8F/</id>
    <published>2023-03-15T10:38:01.000Z</published>
    <updated>2026-06-30T07:16:22.262Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>最近很长时间我都被贫穷的痛苦困扰，但我不认为炒币是一个获得财富的好办法。尤其是短线操作，以及各种加杠杆的合约交易。</p>
<p>币圈就像一个充满金钱诱惑的赌场，各大交易所、各种 DeFi Dapp]]></summary>
    <content type="html"><![CDATA[<p>最近很长时间我都被贫穷的痛苦困扰，但我不认为炒币是一个获得财富的好办法。尤其是短线操作，以及各种加杠杆的合约交易。</p><p>币圈就像一个充满金钱诱惑的赌场，各大交易所、各种 DeFi Dapp 都是赌桌上的游戏。赌徒也许会赚钱也许会赔钱，但最终赚钱的一定是赌场。很少有赌徒可以从赌桌上全身而退。</p><p>比较聪明的人都只是把加密货币作为理财手段，按照投资的性质分配一部分可支配财产进去。长线操作才算是投资，短线就是赌。</p><p>造成这样的现象，最根本的原因是，没有人可以预测市场的走向。</p><p>很多人喜欢在行情发生变化后，有理有据地分析行情为什么会发生，消息面有哪些利好、技术面有哪些趋势、周期上有什么规律。这些分析最大的共同点，就是全都在事后分析，事情发生前，没有人知道会发生什么事情。看看近一年的几次黑天鹅事件，有哪一次是被经济学家、区块链科学家预测到的吗？</p><p>究其原因，没有人可以预测未来。</p><p>再就是最简单的道理，如果那些号称量化大师、预测行情的专业人士，真的掌握着财富密码，为什么要说出来呢？为什么唯恐大家不知道呢？说明他们都只是瞎猜而已，扩大知名度能够带来的收益，比财富密码的收益要高。</p><p>从投资的角度，炒币能带来的收益是比较有限的，却需要承担非常高的风险。当然和传统的基金和股票比起来，变化幅度要大很多，但是加密货币的行情波动还远达不到，让人暴富的程度。10 年前也许可以，回到 10 年前，你真的敢买吗？</p><p>站在历史的高点，看任何事情都轻而易举，可做为历史的亲历者，想超前于时代是很困难的事情，需要过人的眼光和魄力。</p><p>另外，加密货币野蛮发展到现在，已经有一点脱离价值投资的范畴，大盘的涨跌、牛熊市的转换，是因为人们对加密货币本身的认知变化吗？至少最近几年不是，大都因为美联储的货币政策。也就是说，现在加密货币的市场就这么大，除非扩大加密市场的容量，不然新出的链只是在和已有的链争市场份额。</p><p>所以扩大加密市场的机会，在 Web 3.0 和元宇宙上。要让更多的非加密行业内的人，参与到加密市场中去。</p><p>炒币能够稳定获利的方式是老鼠仓，前提要有那种层面的信息源。KOL 在一定程度上是能够影响市场的，如果粉丝数量非常庞大，在 KOL 的言论引导下，粉丝跟风集火到某一个点上，也算是操纵市场的一种方式。这种跟风活动最终获利的肯定也不是后来参与进去的人，自然不靠谱。</p><p>至于说为什么需要关心炒币的问题，因为工作本身并不能让你变得富有。打工可以是一个积累财富的过程，但不会出现让你财富突然增长的情况。思考和寻找能带来更多收益的机会是很有必要的事情。</p><p>关于企业运行的逻辑，一般开始的时候花投资人的钱，有盈利后再把收益还给股东。企业往往会有多个产品线，只要整体上营收大于成本，企业就能够生存下去。</p><p>其实企业在裁员的时候也是充满纠结的，假如因为盈利问题，需要裁掉一个产品线，那么纠结之处在于，如果扛一扛过去这段困难时间，也许未来这个产品能带来更多收益，也许因为没有及时裁掉而带来更多亏损。如果直接裁掉，那么以后再想打造这么一个产品线，又要付出的更多的成本。</p><p>还有一个裁员中让人纠结的问题是，一个人在 A 领域打 60 分，另一个人在 B 领域打 80 分，现在因为 B 领域所在的产品线整个裁掉了，B 领域的所有人都要裁掉，也就是说企业裁掉了更加优秀的人。所以裁员这事不好说，和企业的运行情况和战略方向关系比较大。</p><p>总的来说，炒币不可取，盲目依赖于上班所在的企业也不可取。</p>]]></content>
  </entry>
  <entry>
    <title>在北京吃一顿饭要花多少钱</title>
    <link href="https://b.smallyu.net/2023/03/11/%E5%9C%A8%E5%8C%97%E4%BA%AC%E5%90%83%E4%B8%80%E9%A1%BF%E9%A5%AD%E8%A6%81%E8%8A%B1%E5%A4%9A%E5%B0%91%E9%92%B1/"/>
    <id>blog-b:https://b.smallyu.net/2023/03/11/%E5%9C%A8%E5%8C%97%E4%BA%AC%E5%90%83%E4%B8%80%E9%A1%BF%E9%A5%AD%E8%A6%81%E8%8A%B1%E5%A4%9A%E5%B0%91%E9%92%B1/</id>
    <published>2023-03-11T03:45:57.000Z</published>
    <updated>2026-03-02T08:57:41.563Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>偶然回顾近半年的博客内容，有点太严肃沉重。正好最近半年也吃了很多顿饭，才开始对吃饭这件事情有个大概的了解。</p>
<center style="font-size: 110%;"><strong>中餐</strong></center>

<p>按照北京的消费水平，人均]]></summary>
    <content type="html"><![CDATA[<p>偶然回顾近半年的博客内容，有点太严肃沉重。正好最近半年也吃了很多顿饭，才开始对吃饭这件事情有个大概的了解。</p><center style="font-size: 110%;"><strong>中餐</strong></center><p>按照北京的消费水平，人均 180 人民币就可以吃一顿像样的中餐了。如果低于 ¥180，可能会略显寒酸，即使能够刚刚吃饱，也可能会让坐在对面的女生感觉不尽兴。比较好的状态是，吃饱后桌子上还剩小半盘子菜，坐一坐聊会儿天的功夫，还能再补两口。</p><img src="a.png" width="40%" /><p>这是前几天在望京凯德 MALL 吃的麻辣烤鱼，在一家叫南锣肥猫的店，很好吃。鱼软，刺少，微辣，辣度刚刚好。拍出来的照片颜色鲜艳。锅里加了一些配菜，有午餐肉、腐竹、油条之类，人均 ¥180。</p><img src="j.png" width="50%" /><p>这个是蓝色港湾的一家烤鱼的店，不知道这种在汤里泡着的算不算烤鱼，鱼其实不好吃，没有麻辣烤鱼好吃，不过没刺。中间的腊肠是我硬要点，结果全剩下了，也不是不好吃，实在吃不动了。这顿饭人均 ¥300，算是不便宜，不过很多没吃掉，浪费了。当时也没想着打个包。</p><img src="e.png" width="50%" /><p>北京的烤鸭是有名的地方菜，是很经典的一个菜的种类。这是在合生汇的京华烟云，场地稍微亲民简陋，是那种距离比较近的方形的桌子，价格在烤鸭店里算适中偏低，甜口的虾不太好吃，饮品杯子倒是非常可爱，当时是冬天，还给杯子戴个小帽子，可以带回家收藏了。人均 ¥140 就可以吃饱，多点两个菜尝一尝就要人均 ¥180。</p><img src="c.png" width="50%" /><p>这是在望京的四季民福烤鸭店，一家很火爆的连锁店，饭点去几乎要等位 40 多分钟。这家的烤鸭肯定好吃，不过我觉得最好吃的是那个肉汤，尤其是汤，特别好喝，菜刚端上来会觉得气味奇怪，有点排斥，但是喝两口就喜欢上了。还有那个凉菜，不知道是什么拌什么，又细又凉，口感非常好。对烤鸭的印象不深，只记得菜很多根本吃不完，人均不到 ¥200。</p><p>小大董也是一家有名的连锁店，很多商圈都有分店。三里屯太古里三层有小大董，红烧肉真的很爽，爱大口吃肉千万不能错过。小大董的宫保鸡丁也比四季民福好吃，很有味道。也是人均不到 ¥200，菜多的吃不完，很撑。可惜忘了拍照片。</p><p>比较贵的烤鸭店应该是提督了，公司聚餐吃过一回，环境很小资，菜的样式也挺高级。我没单独吃过，估计人均至少得 ¥300。</p><img src="b.png" width="50%" /><p>这是在五道口购物中心一家叫台巷里的台湾菜馆。台湾菜里的三杯鸡是招牌菜，酱味很重的感觉。烤肉拌饭也值得一吃，下饭管饱。但是蟹黄包的味道一般，有点淡，也可能是三杯鸡的味道太重了，吃过之后就感受不到蟹黄的味道。人均 ¥170 吧。</p><img src="p.png" width="50%" /><p>这个是麻辣香锅，便宜又好吃。火锅的价格也差不多，海底捞人均 ¥150 足够吃饱了，多了吃不完。</p><center style="font-size: 110%;"><strong>西餐</strong></center><p>要说环境高级还得是西餐，氛围好，餐桌间距大，桌子上放着花瓶，还可以让工作人员撒上一些花瓣。价格也要比中餐贵不少，便宜一点的西餐，大概人均要 ¥250，贵一点的，人均 ¥500，再贵一点的，没有吃过。</p><img src="k.png" width="50%" /><p>在三里屯的一家西餐店，当时赶时间没吃牛排，点了披萨意面，10 分钟把所有菜全吃掉。记得这家的意面是吃过最好吃的，但是后来再去吃，意面披萨汉堡全部不一样了，材料也不一样，盘子也不一样，找不到以前的味道。对了西餐为啥要配上日语的标语 😂</p><img src="g.png" width="50%" /><p>这是一家小店，在望京一个小商场的 -1 层，靠窗这个位置拍出来的照片还是挺好的。也是随便吃一顿的晚餐，人均 ¥250。</p><img src="i.png" width="50%" /><img src="m.png" width="40%" /><p>这个是有名的花厨，餐厅里面环境好，餐品样式也好。第二张照片是蓝蝴蝶鸡尾酒，把酒倒进去后会有一个变色的过程，从蓝色变成粉色，挺好玩的。人均不到 ¥300 吧。</p><img src="h.png" width="50%" /><p>这个是我吃过最贵的西餐，在牛排家，惠灵顿牛排套餐，牛排肉很软，很嫩，很好吃。人均 ¥500。</p><center style="font-size: 110%;"><strong>韩餐</strong></center><p>韩餐可以试一下最简单的石锅拌饭，在各种商场里面的简餐，人均 ¥50。或者商场里有的部队火锅，辛拉面最好吃了，也不贵。当然平时也可以买几桶 5 块钱的辛拉面泡面尝一尝味道。</p><img src="n.png" width="40%" /><p>这是一家在望京的店，叫元妈妈的安东鸡，在那个一条街的商圈里面，韩式风味的鸡肉，场地不大，看着比较像家常菜，但是这个鸡肉挺好吃的，带点辣，汤看着颜色重但是可以直接喝，而且我很喜欢这个汤的味道。尤其是把汤浇到米饭上，拌饭吃。人均 ¥120。</p><img src="f.png" width="50%" /><p>更硬菜一点的是韩式烤肉，猪五花最好吃了，必须点两份，还有肥牛，再点个海带拌饭。不过要小心烤肉的时候不要着火，有一次用那种铁丝的网烤肥牛，直接烧起来了，肉全焦了。</p><center style="font-size: 110%;"><strong>墨西哥菜</strong></center><img src="l.png" width="40%" /><p>墨西哥菜不贵而且出其不意地好吃，这个肉看着黑但是并不是焦，上面有一层酱汁。墨西哥菜都是饼里卷着菜的风格，餐桌上会有小卡片，告诉你墨西哥的菜，吃的时候手要抬起来，手捏着饼，小臂和桌面平行，头倾斜 45 度，挺讲究的吃法。当然你要真那种姿势吃可能也挺奇怪的。</p><center style="font-size: 110%;"><strong>日料</strong></center><p>日料价格和西餐差不多，刺身之类的生食比较多，我吃的少，寿喜锅是经常出现的菜品，还有各种小烤串。不过日料的店家场地似乎都不大，很挤的感觉。北京有一家店忘了叫什么，可以换上和服到门口拍和式风格的照片，不过衣服都不新，菜也很一般，贵，量少，主打拍照。</p><center style="font-size: 110%;"><strong>甜品</strong></center><p>如果中午没吃饭，下午两三点就得去吃个下午茶。虽然只是甜品，当个点心吃，但是价格并不便宜。甜品的价格有高有低，由甜品店的风格决定。基本上有两种类型。快餐式的甜品店人均 ¥80，一人一个蛋糕一杯饮料，再多点个蛋糕或者冰激凌。还有一种是网红甜品店，装修华丽，专门给小姑娘拍照准备的，人均 ¥180。</p><img src="d.png" width="40%" /><p>这个是快餐式的甜品，在朝阳大悦城里面。甜品的味道一般不会差，饮品的种类花样也比较多，鸭屎口味的饮料我是真的接受不了。</p><img src="o.png" width="40%" /><p>这个属于看着高大上的甜品店，大众点评上好评多，比较火爆，需要预约那种，中古欧式风格，穿一身 Lolita 在这里拍照，背景氛围各种好看。</p><center style="font-size: 110%;"><strong>小结</strong></center><p>总来来说，各种菜系，人均 ¥150 - ¥200 就妥妥的了。真的是吃了很多次开心的饭。</p>]]></content>
  </entry>
  <entry>
    <title>区块链需要一场技术革命</title>
    <link href="https://crazy.smallyu.net/2023/03/06/%E5%8C%BA%E5%9D%97%E9%93%BE%E9%9C%80%E8%A6%81%E4%B8%80%E5%9C%BA%E6%8A%80%E6%9C%AF%E9%9D%A9%E5%91%BD/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2023/03/06/%E5%8C%BA%E5%9D%97%E9%93%BE%E9%9C%80%E8%A6%81%E4%B8%80%E5%9C%BA%E6%8A%80%E6%9C%AF%E9%9D%A9%E5%91%BD/</id>
    <published>2023-03-06T10:45:05.000Z</published>
    <updated>2025-08-16T03:27:11.475Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>之前偶然看到一个视频，内容是某一年的互联网大会，李彦宏说，百度当年做了一个错误的决定，就是没有抓住移动互联网的机会。以前认为手机短信那么贵，一次要花 1]]></summary>
    <content type="html"><![CDATA[<p>之前偶然看到一个视频，内容是某一年的互联网大会，李彦宏说，百度当年做了一个错误的决定，就是没有抓住移动互联网的机会。以前认为手机短信那么贵，一次要花 1 毛钱，所以不认为手机上的搜索会流行起来，公司也没有在移动端上布局。等到意识到大势所趋，已经来不及了，移动端的搜索不只是把网页尺寸变小那么简单。</p><p>看到这个讲话的内容首先想到，当年 1 毛钱一条的短信，是不是很像现在 10 美元一次的以太坊交易？</p><p>昂贵的短信协议 SMS 按消息次数收费，人们不敢大量使用，结果更廉价的互联网用 TCP 协议，按照流量收费，和消息次数无关，短信就被淘汰了。</p><p>做一个简单的类比，如果以太坊不再按照交易次数收费，而是按照交易金额收费呢？</p><p>这需要改变区块链最基础的运行逻辑。先不考虑如何实现的问题，在 “按照交易金额收费” 的前提下，区块链会怎么样呢？</p><p>按照交易金额收费的含义是，比如设置转账手续费为 1%，转账 100 美元的手续费就是 1 美元。一次性把 100 美元转账给别人，和分 10 次每次转账 10 美元，花费的手续费是一样的。这样最大的好处就是，非常有利于小额交易的流行。</p><p>（然后网络上的交易量暴增，矿工没有能力处理如此庞大的交易量，网络拥堵、瘫痪、混乱，产生了多个分叉……</p><p>小额交易的流行意味着，以太坊不再是理财产品，而成为正真的货币。货币能够更好地承担起价值转移的作用，这也是比特币一开始的愿景。</p><p>也就是说，限制加密货币扩张最根本的因素，是区块链网络处理交易的能力，需要高吞吐量、低手续费。</p><p>在目前的技术框架下，这几乎是不可能的事情。如果比特币是短信，以太坊就是使用短信查资料的服务，闪电网络相当于短信月包，DeFi 提供了短信理财的能力，DAO 是拉了个短信群，GameFi 是用短信玩贪吃蛇，ZK Rollups 给短信做了最安全的加密…… Web 3.0 是融合了各种短信服务的移动时代，元宇宙是使用短信作为 IM 的虚拟世界。</p><p>现在的区块链，始终围绕在 “短信” 上，致力于拓展短信的业务能力。然而正真需要的能引起变革的技术，是互联网。</p><p>再来考虑会引起技术变革的可能性。</p><p>首先是硬件性能的指数级增长，如果网络的传输性能得到非常大的提升，区块链的交易速度也会有明显的提高。</p><p>其次是共识算法的突破性进展，如果共识算法只需要更少的交互次数、更小的网络带宽，也能给交易能力带来提高。</p><p>最后期待主的降临，给地球带来新希望。</p><p>关于区块链的行业现状可以参考一下这篇文章，是 BlockBeats 在今年 ETHDenver 会议的采访记录：<a href="https://www.theblockbeats.info/news/35283">采访 75 位 ETHDenver 参会者，他们在大会中找到了哪些「财富密码」？</a> 我没太仔细看，反正大意是，没有太新的东西，技术发展有阻力，正在期待应用的爆发。</p>]]></content>
  </entry>
  <entry>
    <title>最近没有灵感了 😭</title>
    <link href="https://t.smallyu.net/#2023-17"/>
    <id>micro:1451308091</id>
    <published>2023-03-02T05:07:48Z</published>
    <updated>2023-03-02T05:07:48Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最近没有灵感了 😭</p>]]></summary>
    <content type="html"><![CDATA[<p>最近没有灵感了 😭</p>
]]></content>
  </entry>
  <entry>
    <title>一种在区块链上生成随机数的机制</title>
    <link href="https://smallyu.net/2023/02/22/%E4%B8%80%E7%A7%8D%E5%9C%A8%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%8A%E7%94%9F%E6%88%90%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%9A%84%E6%9C%BA%E5%88%B6/"/>
    <id>blog:https://smallyu.net/2023/02/22/%E4%B8%80%E7%A7%8D%E5%9C%A8%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%8A%E7%94%9F%E6%88%90%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%9A%84%E6%9C%BA%E5%88%B6/</id>
    <published>2023-02-22T10:19:59.000Z</published>
    <updated>2025-06-19T03:30:33.055Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>区块链本身不允许存在随机数，因为全部节点都需要同步计算结果，如果每次运行的结果不一样，整个网络就会混乱。也就是说，在区块链上，如果有一个函数的作用是生成随机数，这个函数需要符合两点要求：1. 返回值是不可预测的；2.]]></summary>
    <content type="html"><![CDATA[<p>区块链本身不允许存在随机数，因为全部节点都需要同步计算结果，如果每次运行的结果不一样，整个网络就会混乱。也就是说，在区块链上，如果有一个函数的作用是生成随机数，这个函数需要符合两点要求：1. 返回值是不可预测的；2. 返回值是确定的。</p><p>这两点要求似乎相悖，但目前已经有解决方案了，Chainlink 的预言机提供了使用 VRF 来生成随机数的方法。由于 VRF 的特性，正好适合在区块链的场景中生成随机数。</p><p>不过现在要讨论的是另一个问题：矿工作恶。可以参考一下这篇文章的内容：<a href="https://hackingdistributed.com/2017/12/24/how-not-to-run-a-blockchain-lottery/">How Not To Run A Blockchain Lottery</a></p><p>假如在区块链上运行一个彩票游戏，而矿工也参与了彩票下注，由于彩票中奖后会获得巨额奖励，只要巨额奖励超过矿工的挖矿所得，矿工就有足够的动机作恶。作恶的方式是，因为一笔交易的执行结果是确定的，而矿工会先知道结果，如果交易结果对自己不利，矿工可以拒绝出块。对于矿工来说，在经济上不一定划算，但是这种情况的存在，不但给彩票游戏增加了不公平的性质，还给了矿工作恶的权利。矿工也有被贿赂的可能性，如果矿工集体作恶，网络就乱套了。</p><p>面对这样的情况，我们需要一种方式来生成随机数，要求矿工不能知道这个数字是什么。等区块确认上链后，随机的数字才被公开。</p><p>有什么是真正的随机、难以预测呢？未来，未来无法预测。</p><p>我们可以尝试使用这样的方式：随机数用本次交易块高度 +2 个块的块哈希作为随机数种子。</p><p>比如发起一笔交易，要生成一个随机数，现在的块高度是 1，这笔交易提交后，得到的随机数是 null，真正的随机数将会在块高度达到 3 时才真正显示。因为这个随机数使用 3 的块哈希作为随机数的种子，在块高度达到 3 之前是不可能有人知道，这个数字将会是什么。</p><p>在彩票的场景中，抽奖结果在块高度为 1 是已经确定了，用户在块高度为 1 的交易中已经参与了抽奖，只是块高度为 3 时才公布抽奖结果。这样几乎能避免矿工作恶的问题，因为在块高度为 1 时，矿工也不知道结果是什么，在块高度为 3 时，参与抽奖的顺序和结果已经确定了。</p><p>那矿工在块高度 3 的时候，不还是可以拒绝出块吗？直接拒绝 1 块或者拒绝 3 块没有差别啊？</p><p>这里就需要区分两个情况：</p><ul><li>在块高度 1 发起的请求，在块高度 3、4、5 去查，得到的都是以块高度 3 的块哈希为种子，计算出的随机数</li><li>在块高度 1 发起的请求，以块高度 3 的块哈希作为种子；在块高度 2 发起的请求，以块高度 4 的块哈希作为种子</li></ul><p>要想达到完全随机的效果，应该使用第二种方式。</p><p>那问题又来了，当前块高度是不断变化的，这个随机值不就成变量了吗？用户在块高度是 3 的时候生成随机数，然后想知道这个随机数具体是多少，结果永远没办法得到这个值，因为等块高度是 5 的时候才真正产生这个数，而块高度是 5 的时候去查询，要等到块高度 7……</p><p>这里还需要区分两个概念：生成随机数和查询随机数。上面两种情况都是按照查询随机数的机制来描述的。</p><p>按照生成随机数的机制来设定，使用第二种方式是必须的，不然随机数就成常量了。那查询呢？不能否认的事实是，只要用户能查到的结果，矿工一定能查到，而且会提前知道。问题回到了一开始的困局，似乎无解了。</p><p>不对不对。</p><p>为什么要设定为使用块高度 +2，而不是 +1 块高度的块哈希呢？是为了避免矿工提前知道结果，如果是 +1，矿工挖出 1 个块就能知道结果，如果是 +2，矿工一般很难领先网络 2 个块。</p><p>所以更好的做法，是在块高度 1 发出生成随机数的请求，然后将块高度 2 和块高度 3 的块哈希，作为随机数种子。在这种情况下，矿工手里的第 3 个块会对随机数产生一定影响，但又不是决定性的影响，有可能第 2 个块就已经确定矿工与中奖无缘了，矿工将没有必要在第 3 个块上进行违规操作。</p><p>那如果第 3 个块也能很大程度决定随机数的内容呢？矿工仍然可以拒绝出块。</p><p>从这个角度来看，延后的块数越多，矿工的影响力越小。假如随机数由 +10 个块的块哈希决定，前 9 个块已经让所有矿工都出局了，矿工就不作恶了。</p><p>还有其他更好的方案吗？好像没有。假如将 +2 个块的块哈希作为对称加密的私钥，在 +2 块产生前随机值已经产生但是无法被解码，问题在于，合约也无法提前把 +2 块作为密钥对随机值进行加密。</p><p>只能降低矿工的影响力了。</p><p>未来无法预测，但当未来来临的时候，总有人能先知先觉。</p>]]></content>
  </entry>
  <entry>
    <title>web3 意味着，区块链将不仅仅围绕 token，而是结合了 NFT、DID，在数字版权、社交、游戏、音乐等场景上发挥实...</title>
    <link href="https://t.smallyu.net/#2023-16"/>
    <id>micro:1437222628</id>
    <published>2023-02-20T15:46:41Z</published>
    <updated>2023-02-20T15:46:41Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>web3 意味着，区块链将不仅仅围绕 token，而是结合了 NFT、DID，在数字版权、社交、游戏、音乐等场景上发挥实际作用。</p>]]></summary>
    <content type="html"><![CDATA[<p>web3 意味着，区块链将不仅仅围绕 token，而是结合了 NFT、DID，在数字版权、社交、游戏、音乐等场景上发挥实际作用。</p>
]]></content>
  </entry>
  <entry>
    <title>为什么以太坊的私钥计算不可逆</title>
    <link href="https://smallyu.net/2023/02/20/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%9A%84%E7%A7%81%E9%92%A5%E8%AE%A1%E7%AE%97%E4%B8%8D%E5%8F%AF%E9%80%86/"/>
    <id>blog:https://smallyu.net/2023/02/20/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%9A%84%E7%A7%81%E9%92%A5%E8%AE%A1%E7%AE%97%E4%B8%8D%E5%8F%AF%E9%80%86/</id>
    <published>2023-02-20T15:42:24.000Z</published>
    <updated>2026-08-04T11:43:16.560Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>你有没有过好奇，为什么以太坊的私钥无法从账户地址逆推算出来？当你拥有一个私钥，想要得到这个私钥对应的账户地址，你可以在 MetaMask 里导入这个账户，或者使用 ether.js 这样的 SDK]]></summary>
    <content type="html"><![CDATA[<p>你有没有过好奇，为什么以太坊的私钥无法从账户地址逆推算出来？当你拥有一个私钥，想要得到这个私钥对应的账户地址，你可以在 MetaMask 里导入这个账户，或者使用 ether.js 这样的 SDK 在代码层面导入一个账户到钱包，然后打印出账户的地址。这个导入账户的过程有没有黑箱操作？</p><p>我前几天无意中在 Medium 上看到一篇文章，作者用很简洁的代码写出了从私钥到地址的计算过程，作者的代码在这里 <a href="https://gist.github.com/RareSkills/eb51623908f348663cd6a241d9dbf115">RareSkills&#x2F;generate-ethereum-address-lower-level.py</a>。</p><p>我把代码复制过来：</p><pre><code class="python">from ecpy.curves import Curvefrom sha3 import keccak_256private_key = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80cv     = Curve.get_curve(&#39;secp256k1&#39;)pu_key = private_key * cv.generator # just multiplying the private key by generator point (EC multiplication)concat_x_y = pu_key.x.to_bytes(32, byteorder=&#39;big&#39;) + pu_key.y.to_bytes(32, byteorder=&#39;big&#39;)eth_addr = &#39;0x&#39; + keccak_256(concat_x_y).digest()[-20:].hex()print(&#39;private key: &#39;, hex(private_key))print(&#39;eth_address: &#39;, eth_addr)</code></pre><p>这段代码只有四五行，计算的关键有两个地方，<code>private_key * cv.generator</code> 和 <code>keccak_256(concat_x_y)</code>。除了这两个地方，其他的部分都是常量计算，乍一看挺复杂，仔细看看拆解一下，都是很简单的字符串拼接。</p><p>其中，<code>private_key * cv.generator</code> 是椭圆曲线的计算，上看定义的私钥 <code>private_key</code> 是一个 16 进制的数字，注意是 <code>int</code> 类型，然后用椭圆曲线的生成器去计算出一个值。这个计算过程是不可逆的，就是在椭圆曲线上绕圈那个过程，可以类比理解为，一个数字取余之后，你无法还原出取余之前的数字。椭圆曲线只是用更复杂的方式，提供了比 RSA 更加安全的计算结果。</p><p>第二个不可逆的计算是 <code>keccak_256(concat_x_y)</code>，这是一个计算哈希值的过程，keccak 是 sha3 的一种。摘要算法不可逆，这也是毫无疑问的事情。</p><p>也就是说，从私钥到地址的计算过程，有两处是不可逆的，所以整体上，无法从以太坊的账户地址，逆推计算出私钥。</p>]]></content>
  </entry>
  <entry>
    <title>李笑来说过一句话：傻逼的共识也是共识。 群众很多时候是盲目的，犹太人群众宁愿放过一个十恶不赦的杀人犯，也要让罗马帝国用酷...</title>
    <link href="https://t.smallyu.net/#2023-15"/>
    <id>micro:1435866727</id>
    <published>2023-02-19T04:27:53Z</published>
    <updated>2023-02-19T04:32:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>李笑来说过一句话：傻逼的共识也是共识。 群众很多时候是盲目的，犹太人群众宁愿放过一个十恶不赦的杀人犯，也要让罗马帝国用酷刑处死耶稣。群众才是罪恶的。 所以区块链可以去中心化，但是 DAO 仍然需要集权。区块链本身只记录数据，不发表意见。</p>]]></summary>
    <content type="html"><![CDATA[<p>李笑来说过一句话：傻逼的共识也是共识。</p>
<p>群众很多时候是盲目的，犹太人群众宁愿放过一个十恶不赦的杀人犯，也要让罗马帝国用酷刑处死耶稣。群众才是罪恶的。</p>
<p>所以区块链可以去中心化，但是 DAO 仍然需要集权。区块链本身只记录数据，不发表意见。</p>
]]></content>
  </entry>
  <entry>
    <title>从今天起，做一个优雅的人， 饿了就吃，困了就睡， 没钱了就挣，有钱了就花， 有时间了就玩，没时间了挤出时间玩， 迟到了就...</title>
    <link href="https://t.smallyu.net/#2023-14"/>
    <id>micro:1435650821</id>
    <published>2023-02-18T11:47:19Z</published>
    <updated>2023-02-18T11:47:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>从今天起，做一个优雅的人， 饿了就吃，困了就睡， 没钱了就挣，有钱了就花， 有时间了就玩，没时间了挤出时间玩， 迟到了就道歉，没迟到就睡一会儿再迟到， 不紧不慢，不慌不忙， 🐶</p>]]></summary>
    <content type="html"><![CDATA[<p>从今天起，做一个优雅的人，<br>饿了就吃，困了就睡，<br>没钱了就挣，有钱了就花，<br>有时间了就玩，没时间了挤出时间玩，<br>迟到了就道歉，没迟到就睡一会儿再迟到，<br>不紧不慢，不慌不忙，<br> 🐶</p>
]]></content>
  </entry>
  <entry>
    <title>元宇宙的概念被限制在 VR、AR、XR 上了，不一定非要 3D 的虚拟空间。如果数字身份 + 数字空间也算元宇宙，那元宇...</title>
    <link href="https://t.smallyu.net/#2023-13"/>
    <id>micro:1435471410</id>
    <published>2023-02-18T03:14:06Z</published>
    <updated>2023-02-18T03:14:06Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>元宇宙的概念被限制在 VR、AR、XR 上了，不一定非要 3D 的虚拟空间。如果数字身份 + 数字空间也算元宇宙，那元宇宙就指日可待了，并且是基于区块链作为基础设施。</p>]]></summary>
    <content type="html"><![CDATA[<p>元宇宙的概念被限制在 VR、AR、XR 上了，不一定非要 3D 的虚拟空间。如果数字身份 + 数字空间也算元宇宙，那元宇宙就指日可待了，并且是基于区块链作为基础设施。</p>
]]></content>
  </entry>
  <entry>
    <title>ChatGPT 有和区块链结合的机会吗？没有。AI 和区块链都属于基础设施。不过元宇宙呢，元宇宙既需要 ChatGPT，...</title>
    <link href="https://t.smallyu.net/#2023-12"/>
    <id>micro:1435471016</id>
    <published>2023-02-18T03:12:02Z</published>
    <updated>2023-02-18T03:14:43Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>ChatGPT 有和区块链结合的机会吗？没有。AI 和区块链都属于基础设施。不过元宇宙呢，元宇宙既需要 ChatGPT，也需要区块链</p>]]></summary>
    <content type="html"><![CDATA[<p>ChatGPT 有和区块链结合的机会吗？没有。AI 和区块链都属于基础设施。不过元宇宙呢，元宇宙既需要 ChatGPT，也需要区块链</p>
]]></content>
  </entry>
  <entry>
    <title>ChatGPT 只是一个语言模型，虽然不是人工，但是也没有任何能力，除了输出文字什么都干不了，更不需要担心它有任何智力。</title>
    <link href="https://t.smallyu.net/#2023-11"/>
    <id>micro:1435470662</id>
    <published>2023-02-18T03:10:04Z</published>
    <updated>2023-02-18T03:11:10Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>ChatGPT 只是一个语言模型，虽然不是人工，但是也没有任何能力，除了输出文字什么都干不了，更不需要担心它有任何智力。</p>]]></summary>
    <content type="html"><![CDATA[<p>ChatGPT 只是一个语言模型，虽然不是人工，但是也没有任何能力，除了输出文字什么都干不了，更不需要担心它有任何智力。</p>
]]></content>
  </entry>
  <entry>
    <title>区块链已经老了，接下来是 Web 3.0，再接下来是元宇宙。</title>
    <link href="https://t.smallyu.net/#2023-10"/>
    <id>micro:1435135455</id>
    <published>2023-02-17T19:27:47Z</published>
    <updated>2023-02-17T19:27:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>区块链已经老了，接下来是 Web 3.0，再接下来是元宇宙。</p>]]></summary>
    <content type="html"><![CDATA[<p>区块链已经老了，接下来是 Web 3.0，再接下来是元宇宙。</p>
]]></content>
  </entry>
  <entry>
    <title>其实区块链很少拼技术，更多的是资本运作。</title>
    <link href="https://t.smallyu.net/#2023-9"/>
    <id>micro:1434050402</id>
    <published>2023-02-17T03:35:25Z</published>
    <updated>2023-02-17T03:35:25Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>其实区块链很少拼技术，更多的是资本运作。</p>]]></summary>
    <content type="html"><![CDATA[<p>其实区块链很少拼技术，更多的是资本运作。</p>
]]></content>
  </entry>
  <entry>
    <title>A make &amp;quot;restart&amp;quot; holiday.</title>
    <link href="https://t.smallyu.net/#2023-8"/>
    <id>micro:1399257728</id>
    <published>2023-01-21T14:04:57Z</published>
    <updated>2023-01-21T14:04:57Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>A make &amp;quot;restart&amp;quot; holiday.</p>]]></summary>
    <content type="html"><![CDATA[<p>A make &quot;restart&quot; holiday.</p>
]]></content>
  </entry>
  <entry>
    <title>关于以太坊的私钥碰撞</title>
    <link href="https://smallyu.net/2023/01/18/%E5%85%B3%E4%BA%8E%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%9A%84%E7%A7%81%E9%92%A5%E7%A2%B0%E6%92%9E/"/>
    <id>blog:https://smallyu.net/2023/01/18/%E5%85%B3%E4%BA%8E%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%9A%84%E7%A7%81%E9%92%A5%E7%A2%B0%E6%92%9E/</id>
    <published>2023-01-18T07:27:25.000Z</published>
    <updated>2026-08-04T11:44:00.456Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>如果你有 1&#x2F;100000000 的机会暴富，你愿意尝试一下吗？</p>
<h3 id="以太坊私钥"><a href="#以太坊私钥" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>如果你有 1&#x2F;100000000 的机会暴富，你愿意尝试一下吗？</p><h3 id="以太坊私钥"><a href="#以太坊私钥" class="headerlink" title="以太坊私钥"></a>以太坊私钥</h3><p>以太坊的账户完全由私钥控制，根据私钥可以推算出账户的地址。私钥是一个 64 位长度的 16 进制字符串，比如：</p><pre><code>0xd110227375ab838e8743192d278c105e30f253c966987c50b754412c9b986fe3</code></pre><p>你可以在任何支持以太坊账户的钱包，用这个私钥导入对应的账户。这个私钥对应的账户地址是：</p><pre><code>0x00000006A3D4DA3A559829B1730603CAeE97cC3D</code></pre><p>你也可以根据这个账户地址，在以太坊浏览器上查询到账户相关的<a href="https://etherscan.io/address/0x00000006A3D4DA3A559829B1730603CAeE97cC3D">交易记录</a>等信息。</p><h3 id="私钥碰撞"><a href="#私钥碰撞" class="headerlink" title="私钥碰撞"></a>私钥碰撞</h3><p>既然私钥只是一个字符串，那么有没有可能，随机生成一个字符串，这个私钥对应的账户地址，正好有钱？因为有了私钥就能够控制账户上的所有资产。以太坊上有钱的账户那么多，有的余额还特别高，万一正好生成了一个私钥，那岂不是直接暴富。</p><p>当然随机生成的字符串，必须是 64 位长度 16 进制。为了避免以太坊的 SDK 存在某些防碰撞的规则，我们可以直接粗暴一点生成，比如这样：</p><pre><code class="javascript">let s = &quot;0123456789abcdef&quot;;let hex = &quot;0x&quot;;for (let i = 0; i &lt; 64; i++) &#123;  hex += s[Math.floor(Math.random() * 16)];&#125;</code></pre><p>这样做足够直观，在字符串层面随机拼接出 64 位长度的。LeetCode 的简单题就是天天搞这种。虽然实际上以太坊并没有防碰撞的机制。</p><h3 id="碰撞概率"><a href="#碰撞概率" class="headerlink" title="碰撞概率"></a>碰撞概率</h3><p>我们来计算一下，随机生成私钥，碰撞到有效账户的概率。假如存在一个地址，我们想要正好随机生成这个地址的私钥，可能性是多大？</p><p>16 进制就代表每一位字符，和目标私钥一致的可能性是 1&#x2F;16，一共 64 位长度，概率就是 (1&#x2F;16)<sup>64</sup>。</p><pre><code>p = (1/16)^64  = 1 / 16^64  = 1 / 115792089237316195423570985008687907853269984665640564039457584007913129639936</code></pre><p>把零头抹掉，只计算数量级的话：</p><pre><code>p = 1 / 115792089237316195423570985008687907853269984665640564039457584007913129639936  = 1 / 100000000000000000000000000000000000000000000000000000000000000000000000000000  = 1 / 10^77</code></pre><p>这是一个非常低的概率，中国中奖率最低的大乐透彩票，中奖概率是千万分之一，也就是 1&#x2F;10^8。以太坊的私钥碰撞，想正好是某一个账户的可能性，相当于连续中 10 次彩票。这是几乎不可能发生的事情。</p><p>不过彩票的中奖是有速度限制的，比如需要 1 天才开奖。加密货币领域的私钥可不是，如果提高随机生成私钥的速度，能不能增加碰撞成功的概率呢？</p><p>目前比特币全网的<a href="https://www.blockchain.com/explorer/charts/hash-rate">哈希率</a>是 270M TH&#x2F;s。比特币挖矿的过程本身就是不断地做哈希计算，直到找到拥有 n 和前导 0 哈希值的字符串，所以比特币的哈希率也可以用来描述私钥的生成速率。做一下<a href="https://en.bitcoinwiki.org/wiki/Hashrate">单位换算</a>：</p><pre><code>r = 270M TH/s  = 270000000 TH/s  = 270000000000 GH/s  = 270000000000000 MH/s  = 270000000000000000 kH/s  = 270000000000000000000 /s  = 100000000000000000000 /s  = 10^20</code></pre><p>这个结果只保留了数量级。假如你拥有全球比特币矿机的算力，去做以太坊的私钥碰撞，每秒钟的概率是：</p><pre><code>ps = p * r   = 1 / 10^57   = 1 / 1000000000000000000000000000000000000000000000000000000000</code></pre><p>这仍然是一个低到遥不可及的可能性。如果碰撞持续尝试 1 年呢？</p><pre><code>py = ps * 60 * 60 * 24 * 365   = ps * 31536000   = ps * 10000000   = ps * 10^7   = 1 / 10^50   = 1 / 100000000000000000000000000000000000000000000000000</code></pre><p>持续运行 1 亿年呢？</p><pre><code>pb = py * 100000000   = py * 10^8   = 1 / 10^42   = 1 / 1000000000000000000000000000000000000000000</code></pre><p>可以看到，时间对于概率的增加幅度，是微乎其微的。计算能力也许有可能成倍增长，比如苹果 M 系列芯片，比 Intel 芯片高几倍速度的提升。但是在 70 个 0 的数量级面前，这样的提升仍然微不足道。</p><p>即使拥有 1 亿个地球的比特币算力，运行 1 亿年，也只是能再减少几个 1 后面的 0，远远达不到碰撞成功的目的。</p><h3 id="尝试一下"><a href="#尝试一下" class="headerlink" title="尝试一下"></a>尝试一下</h3><p>虽然可能性非常小，但我还是想尝试一下。</p><p>我写了一个脚本 <a href="https://github.com/eth-collision/eth-collision-random">eth-collision&#x2F;eth-collision-random</a>，随机生成私钥后，根据私钥的账户地址，自动去 <a href="https://etherscan.io/">etherscan.io</a> 上查询账户余额，如果余额大于 0 会把私钥输出到日志文件里。由于 Etherscan 对 API 的调用次数有限制，脚本会以每秒 20 个地址的速度去查询，也就是一天能尝试 172 万个地址。</p><p>这个速度不够快，有更好的办法吗？凡是第三方服务，大多数会有 API 速率的限制，想不受限制进行查询，只能自己运行一个以太坊节点了。以太坊节点最低的硬件要求，是 4 核 16G 内存 1T 硬盘。这样配置的服务器，在 <a href="https://www.vultr.com/">Vultr</a> 上的价格至少要 300 美元一个月。有点贵。而且运行起节点后，还需要自己写一写程序，根据每个块的交易信息统计出有余额的地址。整个周期会很长。</p><p>我注意到 <a href="https://etherscan.io/accounts/1?ps=100">这个页面</a> 提供了以太坊上余额最多的地址列表，1 页 100 个，总共 100 页。我写了一个爬虫 <a href="https://github.com/eth-collision/eth-address-top-list.git">eth-collision&#x2F;eth-address-top-list</a> 到这个页面上抓取数据，这样就能得到以太坊余额最多的 10000 个账户地址的列表。</p><p>根据抓到的 10000 个地址，程序就可以比较快地运行了，而不需要受到 API 速率的限制，也不需要自己跑全节点。由于不看好 JavaScript 的运行速度，我用 Golang 写了一个程序 <a href="https://github.com/eth-collision/eth-collision-match-address.git">eth-collision&#x2F;eth-collision-match-address</a>，启动 100 个协程来加快生成私钥的速度。程序会把 10000 个地址读到一个 map 里，然后判断随机生成的账户是否在目标列表内。JavaScript 的一个 for 循环也足够把 CPU 跑满，但是直觉上总感觉 Golang 会更快一点。</p><p>对了，Golang 中的 map 记得加互斥锁。因为 map 不是并发安全的。不过加锁会降低速率。为了解决需要加锁的问题，因为只有 10000 个地址，占不了多少内存，所以可以实例化多个 map，有多少个协程就有多少个 map，每个协程在自己的 map 上做验证。这样就能充分保证私钥的生成和验证效率。</p><p>10000 个地址是不是太少了？以太坊一共有那么多个地址。一共有多少个呢？从 Etherscan <a href="https://etherscan.io/chart/address">统计</a>目前有 230M 左右，大概 2 亿多个。</p><p>后来我发现了一个仓库 <a href="https://github.com/eth-collision/Wallet-private-key-collision-brute-force-tool">eth-collision&#x2F;Wallet-private-key-collision-brute-force-tool</a>，这个仓库里提供了一个 OneDrive 文件的下载链接，是一个包含 1.8 亿条账户地址的文件，这些账户都在链上有过交易记录。文件的压缩包有 4.4G 大，解压后 16G 左右，是 pkl 格式的文件，然后我用 Python 解析成了 txt 文件。</p><p>在得到这么多账户地址的列表后，现在的问题就变成了，该怎么利用这些数据。</p><p>首先是像原先一样，把所有数据读到 map 里。这么多的数据读到内存里，占用的内存可能至少 16G，也就是需要 24G 内存的服务器。Vultr 上最便宜的符合要求的服务器，接近 150 美元一个月。况且那么大数据量，Golang 的查询效率也是个疑问，还得加锁，限制比较多。</p><p>有没有好的方案？用数据库的话，MySQL 是支撑不住亿级别的数据查询的，记得之前参与的一个项目，在上亿数据里做最简单的查询要 10 秒以上，还是单次查询。现在的需求是每秒钟查询上千次。Redis 呢？Redis 的查询效率应该是有保证的，可 Redis 还是会把所有数据读到内存里。在 Redis 的<a href="https://redis.io/docs/getting-started/faq/">介绍</a>里，1M 个 key 需要 85M 的内存，换算一下：</p><pre><code>1M   -&gt; 85M180M -&gt; 180 * 85M     = 15300M     = 15G</code></pre><p>Vultr 上，16G 的 Redis 价格很高，比服务器贵多了，需要 480 美元一个月。至于更沉重一点的数据库，像 Elasticsearch 或者更专业一点的 HBase 之类，从数据库搭建到导入数据，然后处理数据，一整套下来确实麻烦了一点。服务器开销也不见得更低。</p><p>再后来，看到有个东西叫布隆过滤器，正好符合这样的使用场景。我试了一下，容量 2 亿条数据的布隆过滤器，容错率 10 亿分之一，在加载完 1.8 亿条数据后，导出的<a href="https://github.com/eth-collision/eth-address-all">二进制文件</a>，只占用 1G 的磁盘空间。加载到内存中，也只需要占用 1G。</p><p>这样的方案其实挺好了。我在服务器上运行碰撞程序，每个月需要 30 美元的 2核 4G 服务器，每个小时可以尝试 60M 个地址。每个月需要 600 人民币的 8核 16G 服务器，每个小时可以尝试 160M 个地址。</p><p>当然，用再好的服务器都没有用，用整个地球上的算力都没用。</p><h3 id="靓号地址"><a href="#靓号地址" class="headerlink" title="靓号地址"></a>靓号地址</h3><p>以太坊的账号地址也有靓号一说，比如地址 <code>0x00000006A3D4DA3A559829B1730603CAeE97cC3D</code> 包含有 6 个前导 0。关于靓号地址可以参考<a href="https://www.theblockbeats.info/news/33808?from=telegram">这篇文章</a>。</p><p>我写了这个程序 <a href="https://github.com/eth-collision/eth-collision-find-address">eth-collision&#x2F;eth-collision-find-address</a> 来寻找靓号地址，一般来说，找到 6 个前导 0 的地址是非常容易的事情，在 Macbook Air M1 上几分钟就可以。包含 7 个前导 0，可能需要半个小时。包含 8 个前导 0，就需要一两天。</p><p>包含有 10 个前导 0 的地址，已经算是非常非常稀有了。不过当然靓号地址没什么用，你一旦知道私钥，这个账号就是你的了，给别人别人也不要。</p><h3 id="在线手动碰撞"><a href="#在线手动碰撞" class="headerlink" title="在线手动碰撞"></a>在线手动碰撞</h3><p>这是一个在线手动进行私钥碰撞的网页，可以根据私钥计算出公钥，也可以生成随机的公私钥对，并且点击链接能够直接跳转到 Etherscan 检查地址对应的余额。</p><p>地址：<a href="http://eag.smallyu.net/">http://eag.smallyu.net</a></p><p>源码：<a href="https://github.com/smallyunet/eth-address-generator">smallyunet&#x2F;eth-address-generator</a></p><p>页面是纯前端实现的，可以离线使用，不会有任何安全问题。</p>]]></content>
  </entry>
  <entry>
    <title>所有人……都在等待……下一轮……牛市……</title>
    <link href="https://t.smallyu.net/#2023-7"/>
    <id>micro:1376932613</id>
    <published>2023-01-10T09:01:13Z</published>
    <updated>2023-01-10T09:01:13Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>所有人……都在等待……下一轮……牛市……</p>]]></summary>
    <content type="html"><![CDATA[<p>所有人……都在等待……下一轮……牛市……</p>
]]></content>
  </entry>
  <entry>
    <title>拔剑四顾</title>
    <link href="https://t.smallyu.net/#2023-6"/>
    <id>micro:1374812251</id>
    <published>2023-01-08T11:35:35Z</published>
    <updated>2023-01-08T11:35:35Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>拔剑四顾</p>]]></summary>
    <content type="html"><![CDATA[<p>拔剑四顾</p>
]]></content>
  </entry>
  <entry>
    <title>无意间在短视频里看到俞敏洪的一句话：如果你实在觉得迷茫，就去读 100 页的书，说不定就有想法了。</title>
    <link href="https://t.smallyu.net/#2023-5"/>
    <id>micro:1374499639</id>
    <published>2023-01-07T14:31:11Z</published>
    <updated>2023-01-07T14:31:11Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>无意间在短视频里看到俞敏洪的一句话：如果你实在觉得迷茫，就去读 100 页的书，说不定就有想法了。</p>]]></summary>
    <content type="html"><![CDATA[<p>无意间在短视频里看到俞敏洪的一句话：如果你实在觉得迷茫，就去读 100 页的书，说不定就有想法了。</p>
]]></content>
  </entry>
  <entry>
    <title>做一个假设，在没有技术限制的情况下，区块链最理想的样子是什么？其实比特币就是最理想的样子，以太坊也是。唯一需要提高的是...</title>
    <link href="https://t.smallyu.net/#2023-4"/>
    <id>micro:1373412017</id>
    <published>2023-01-06T09:51:12Z</published>
    <updated>2023-01-06T09:51:12Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>做一个假设，在没有技术限制的情况下，区块链最理想的样子是什么？其实比特币就是最理想的样子，以太坊也是。唯一需要提高的是 TPS，别的没那么重要。 所以目前限制区块链革命的瓶颈，是网络速度。</p>]]></summary>
    <content type="html"><![CDATA[<p>做一个假设，在没有技术限制的情况下，区块链最理想的样子是什么？其实比特币就是最理想的样子，以太坊也是。唯一需要提高的是 TPS，别的没那么重要。</p>
<p>所以目前限制区块链革命的瓶颈，是网络速度。</p>
]]></content>
  </entry>
  <entry>
    <title>加密资产一个有意思的地方是，一个账户全部资产的控制权，在账户的私钥上，而私钥是一个由 64 位十六进制字符组成的字符串。...</title>
    <link href="https://t.smallyu.net/#2023-3"/>
    <id>micro:1373396515</id>
    <published>2023-01-06T09:33:24Z</published>
    <updated>2023-01-06T09:33:24Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>加密资产一个有意思的地方是，一个账户全部资产的控制权，在账户的私钥上，而私钥是一个由 64 位十六进制字符组成的字符串。任何人都可以尝试去随机生成一个私钥。 问：如果随机生成一个以太坊私钥，账户里有钱的可能性是多大？</p>]]></summary>
    <content type="html"><![CDATA[<p>加密资产一个有意思的地方是，一个账户全部资产的控制权，在账户的私钥上，而私钥是一个由 64 位十六进制字符组成的字符串。任何人都可以尝试去随机生成一个私钥。</p>
<p>问：如果随机生成一个以太坊私钥，账户里有钱的可能性是多大？</p>
]]></content>
  </entry>
  <entry>
    <title>“区块链上没有随机数”。</title>
    <link href="https://t.smallyu.net/#2023-2"/>
    <id>micro:1373350765</id>
    <published>2023-01-06T08:39:05Z</published>
    <updated>2023-01-06T08:39:05Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“区块链上没有随机数”。</p>]]></summary>
    <content type="html"><![CDATA[<p>“区块链上没有随机数”。</p>
]]></content>
  </entry>
  <entry>
    <title>如果你理解不了 NFT 的价值，可以想想之前的邮票、集邮。所以有价值的 NFT，需要有背景的发行方限量发行。</title>
    <link href="https://t.smallyu.net/#2023-1"/>
    <id>micro:1368350487</id>
    <published>2023-01-01T04:35:50Z</published>
    <updated>2023-01-01T04:35:50Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果你理解不了 NFT 的价值，可以想想之前的邮票、集邮。所以有价值的 NFT，需要有背景的发行方限量发行。</p>]]></summary>
    <content type="html"><![CDATA[<p>如果你理解不了 NFT 的价值，可以想想之前的邮票、集邮。所以有价值的 NFT，需要有背景的发行方限量发行。</p>
]]></content>
  </entry>
  <entry>
    <title>新年快乐！</title>
    <link href="https://t.smallyu.net/#2022-44"/>
    <id>micro:1367689292</id>
    <published>2022-12-30T02:25:40Z</published>
    <updated>2022-12-30T02:25:40Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>新年快乐！</p>]]></summary>
    <content type="html"><![CDATA[<p>新年快乐！</p>
]]></content>
  </entry>
  <entry>
    <title>This year (2022)</title>
    <link href="https://crazy.smallyu.net/2022/12/30/This-year-2022/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2022/12/30/This-year-2022/</id>
    <published>2022-12-30T02:20:43.000Z</published>
    <updated>2025-10-01T00:52:59.255Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>I posted the same title article last year, so I want to make this a traditional behavior, just like I write “The Brave” series every]]></summary>
    <content type="html"><![CDATA[<p>I posted the same title article last year, so I want to make this a traditional behavior, just like I write “The Brave” series every China’s National Day, that’s about the topic of dreams, and this is about the topic of life.</p><p>It’s an important point last year in the article that I made a new friend when a similar day as the recent day a year ago. My life is almost around her fully this year, although we are just friends. It’s difficult to say whether it is a lucky thing or unfortunate. It’s good because friends could be forever but other relationships may break quickly. And it’s bad because many things are limited by the relationships named friends.</p><p>I’m confused about this thing many times and argued many times with her. </p><p>Is there exist pure friendship relationship between the different gender? I think there is no… But we should objectively analyze this problem. I separate the problem into two sides. On the idea side, absolutely have not. You may think something even though you just watches a girl in street. But on the action side, it’s possible to have. It’s easy to understand because behavior is limited by morality. So this problem is cleared.</p><p>Actually, we are deeper than friendship already. So I am not too more disappointment about it.</p><p>And… I don’t know what to say now. Ooh, I remembered something she did for me. But… It has not necessary to write it down here.</p>]]></content>
  </entry>
  <entry>
    <title>“猜均值的2/3” dApp 游戏设计</title>
    <link href="https://smallyu.net/2022/12/27/%E2%80%9C%E7%8C%9C%E5%9D%87%E5%80%BC%E7%9A%842-3%E2%80%9DdApp-%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1/"/>
    <id>blog:https://smallyu.net/2022/12/27/%E2%80%9C%E7%8C%9C%E5%9D%87%E5%80%BC%E7%9A%842-3%E2%80%9DdApp-%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1/</id>
    <published>2022-12-27T07:48:46.000Z</published>
    <updated>2025-06-23T14:02:31.685Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p><a href="https://zh.m.wikipedia.org/zh-cn/%E7%8C%9C%E5%9D%87%E5%80%BC%E7%9A%842/3">猜均值的2&#x2F;3</a> 是一个经典的博弈游戏，现在把它改造成运行在区块链上的 dApp]]></summary>
    <content type="html"><![CDATA[<p><a href="https://zh.m.wikipedia.org/zh-cn/%E7%8C%9C%E5%9D%87%E5%80%BC%E7%9A%842/3">猜均值的2&#x2F;3</a> 是一个经典的博弈游戏，现在把它改造成运行在区块链上的 dApp 游戏，这是游戏的基本规则：</p><ol><li>玩家支付 <code>任意金额</code> 参与游戏</li><li>计算所有用户支付的 <code>金额总和</code></li><li>计算 <code>金额总和</code> 平均值的 2&#x2F;3 作为 <code>胜利数字</code></li><li>玩家支付的 <code>任意金额</code> 最接近 <code>胜利数字</code> 则获胜</li></ol><p>游戏的奖励规则是：</p><ol start="5"><li>获胜者获得本轮游戏所有用户支付的 <code>金额总和</code></li><li>合约在每轮游戏抽取 <code>金额总和</code> 的 1% 作为服务费</li></ol><p>一个重要的问题是，每轮游戏多少玩家参与？或者说每轮游戏什么时候结束？关于游戏结束的规则是这样：</p><ol start="7"><li>每一轮游戏，当玩家参与的时候，可以知道玩家是第 <code>n</code> 个参与的</li><li>生成一个随机数 <code>x</code>（10&lt;&#x3D;x&lt;&#x3D;100）</li><li>根据 <code>n</code> 和 <code>x</code>，生成一个随机数的边界 <code>l, r = n-x, n+x</code></li><li>在 <code>[l, r]</code> 的区间内生成一个随机数 <code>y</code></li><li>如果 <code>y == n</code>，本轮游戏结束</li></ol><p>还有一点补充规则：</p><ol start="12"><li>如果一个用户多次参与游戏，以第一次参与结果为准</li><li>如果多个用户支付的 <code>任意金额</code> 相同，第一个参与的用户获胜</li></ol><p>上面是这个游戏的全部规则。</p><p>结束游戏的规则有点复杂，举一个具体的数值，比如有一个玩家，是第 <code>n=50</code> 个参与进游戏的，然后生成了一个随机数 <code>x=10</code>，那么生成的随机数边界就是 <code>l, r = 45, 55</code>。在范围 [45, 55] 中再生成一个随机数，如果正好是 50，本轮游戏结束。</p><p>为什么要这样做？因为区块链上的数据是公开的。在原版的“猜均值的2&#x2F;3”游戏中，玩家选择的数字，相互是保密的。但在区块链上很难做到这一点。所以这里提出的 dApp 版本游戏规则，至少有两点和原版规则不同：</p><ul><li>玩家参与游戏支付的金额是无限制的，可以是 0，也可以无限大，而原版规则有上限</li><li>玩家数量是不确定的，原版规则是知道有几名玩家参与</li></ul><p>这样差异的设计都是因为，区块链上的数据是公开的，所以要引入一些随机的机制。如果没有随机结束的机制，在玩家数量确定的情况下，越是后面参与的玩家，越有优势，因为可以根据前面参与玩家的记录，推算出自己用哪个数字参与更有可能获胜。</p><p>当然，最后参与的玩家并不一定有能力扭转局势，尤其是在参与数值有上限的情况下。但如果玩家数量是随机的，就不存在“后面参与的玩家”一说，因为谁都不知道游戏什么时候结束，谁是最后一个玩家。所以即使玩家能够支付出扭转局势的金额，也会被后面的玩家拉下来。</p><p>至于原版游戏要求参与数值为整数，dApp 版本的参与数值可以没有限制，可以是小数。是因为原版游戏是人为给出参与数值，而 dApp 版本可以在计算机上自由输入，并且结果是智能合约计算的，不限制精度也没有影响。</p><p>然后解释一下游戏结束的规则。这个规则的效果是，能在大多数情况下，让游戏在参与人数为 [10, 100] 的区间内结束。这个区间对应 <code>规则 9</code> 中 <code>x</code> 的范围。</p><p>这个规则可以这样理解，每个用户都拥有能力结束游戏，但是能力是随机的，最高 1&#x2F;10，最低 1&#x2F;100。如果拥有 1&#x2F;10 的能力，就是有 1&#x2F;10 的可能性让游戏结束。</p><p>假设所有用户都拥有最高的能力 1&#x2F;10，那么游戏大概率会在 10 个人参与后结束。每个人触发“游戏结束”这个事件的概率是独立的，不管多少人参与都是 1&#x2F;10。参与的人数越多，结束的可能性越大，因为不结束的可能性是 9&#x2F;10 的人数次方。</p><p>假设所有用户都拥有最低的能力 1&#x2F;100，那么游戏大概率会在 100 个人参与后结束。</p><p>所以 <code>规则 9</code> 中 <code>x</code> 的范围大概就限定了参与人数的范围。当然，这里的人数范围 [10, 100] 不是严格的概率计算。</p><p>按照上面定义的游戏结束规则，这里模拟了 10 万次运行的结果，记录下游戏会在“有多少个玩家参与”的时候结束，代码在这里：<a href="https://github.com/guessavg/emulate_tool">guessavg&#x2F;emulate_tool</a></p><img src="chart1.png" width="60%"><p>这个图的横坐标是参与游戏的玩家数量，纵坐标是在对应的数量上，游戏结束的次数。比如在接近 1 的位置上，有 2500 次，说明在 10 万次游戏中，有 2500 次 1 个玩家参与就结束了。</p><img src="chart2.png" width="60%"><p>如果次数不够直观的话，可以看这个比例的图，每个数字上结束的比例不超过 2.5%。越靠前的位置，游戏结束的可能性越大，因为每次都是从 0 开始，前面的位置结束游戏的机会更多一点。</p><img src="chart3.png" width="60%"><p>这个比例统计图更能够说明结果，游戏有接近 20% 的概率在参与人数小于 10 的情况下结束，有接近 70% 的概率在参与人数为 [10, 100] 的范围内结束。参与人数大于 300 才结束游戏的概率，只有 0.07%。</p><p>虽然这个规则形成的结果，概率上不是完整的正态分布，但是基本上能够满足一开始的需求，也就是让游戏在随机的时间点结束，并且结束的时间不会很离谱，不会导致参与人数太少或者太多，而且还提供了一定的小概率，允许参与人数达到 500 左右。</p><p>相信这会是一个合理的设计。</p><p><br/><br/></p><h3 id="更新（2025-04-22）"><a href="#更新（2025-04-22）" class="headerlink" title="更新（2025.04.22）"></a>更新（2025.04.22）</h3><p>一年多前，我写过一个 《<a href="/2022/12/27/%E2%80%9C%E7%8C%9C%E5%9D%87%E5%80%BC%E7%9A%842-3%E2%80%9DdApp-%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1/">“猜均值的2&#x2F;3” dApp 游戏设计</a>》的设想。</p><p>偶然想起来，现在有了功能强大的 ChatGPT 的帮助，让这个游戏在实现上变得简单，合约和前端页面都可以轻松完成。今天只用了 2 个小时，就完成了这个网页的 Demo。</p><p>可以通过这个页面访问游戏：<a href="https://guessavg.oiia.network/">https://guessavg.oiia.network/</a></p><p>有几点需要说明：</p><ol><li>目前这个 dApp 小游戏运行在 Oiia Network 上，合约地址 <a href="https://explorer.oiia.network/account/0x6eb079C9D3005Bd596E8a0E5065fA33C80aBA8F1"><code>0x6eb07...BA8F1</code></a></li><li>参加游戏实际上就是调用合约的函数，同时给合约转账一笔钱，例如交易 <a href="https://explorer.oiia.network/tx/0x1bfb286c9ed796e16870cc36488bd3c11db6eef43e34c425e58ac76715010936"><code>0x1bfb2...10936</code></a></li><li>合约代码在仓库 <a href="https://github.com/guessavg/contract">guessavg&#x2F;contract</a>，理论上可以部署到任意网络，因为 OIIA 不要钱，我就拿来用了。</li><li>前端代码仓库在 <a href="https://github.com/guessavg/game">guessavg&#x2F;game</a>，和合约代码配合使用。</li><li>OIIA 可以在 faucet 领到一些 <a href="https://faucet.oiia.network/">https://faucet.oiia.network/</a></li><li>这个私钥有 10 个 OIIA，也能拿来玩一下。但是从游戏机制上，是不允许相同地址重复参与的，需要先把 OIIA 转到陌生地址才行。 <code>fdf0aec857f3ac4fe146e0d00fb3a7a729646a081719df3f4e168a541a21893b</code></li><li>前端网页在添加 Oiia 网络到 Metamask 的时候，会报错，但实际上成功了，我没有深入排查原因。一个月前相同的代码还没报错来着。</li><li>Oiia Network 随时会消失。</li><li>只是玩玩……</li></ol><br><h3 id="更新（2025-05-06）"><a href="#更新（2025-05-06）" class="headerlink" title="更新（2025.05.06）"></a>更新（2025.05.06）</h3><p>Oiia Network 今天起就完全停止运行了，因为我不想为没有人用的网络付服务器费用了。现在这个猜均值的游戏 Demo 已经转移部署到 Base 网络上。</p><ol><li>游戏 Demo 地址：<a href="https://guessavg.github.io/game/">https://guessavg.github.io/game/   </a></li><li>Base 上的合约地址：<a href="https://basescan.org/address/0x4BbeE9F876ff56832E724DC9a7bD06538C8868D2"><code>0x4BbeE...868D2</code></a></li><li>需要 Base 网络上的 ETH 参与游戏。</li><li>游戏降低了难度，只需要两三个玩家就会结束一轮游戏。</li></ol>]]></content>
  </entry>
  <entry>
    <title>朋友说我老是胡思乱想（生活上），就搞得事情很烦。可以我的某些能力正是来自胡思乱想……</title>
    <link href="https://t.smallyu.net/#2022-43"/>
    <id>micro:1363556196</id>
    <published>2022-12-23T02:38:45Z</published>
    <updated>2022-12-23T02:38:45Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>朋友说我老是胡思乱想（生活上），就搞得事情很烦。可以我的某些能力正是来自胡思乱想……</p>]]></summary>
    <content type="html"><![CDATA[<p>朋友说我老是胡思乱想（生活上），就搞得事情很烦。可以我的某些能力正是来自胡思乱想……</p>
]]></content>
  </entry>
  <entry>
    <title>Proof of Storage/Space/Replication 的区别</title>
    <link href="https://smallyu.net/2022/12/20/Proof-of-Storage-Space-Replication-%E7%9A%84%E5%8C%BA%E5%88%AB/"/>
    <id>blog:https://smallyu.net/2022/12/20/Proof-of-Storage-Space-Replication-%E7%9A%84%E5%8C%BA%E5%88%AB/</id>
    <published>2022-12-20T09:58:48.000Z</published>
    <updated>2025-11-09T09:22:13.309Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="时间线"><a href="#时间线" class="headerlink" title="时间线"></a>时间线</h3><style>
table {
    display:]]></summary>
    <content type="html"><![CDATA[<h3 id="时间线"><a href="#时间线" class="headerlink" title="时间线"></a>时间线</h3><style>table {    display: inline;}</style><center><table><thead><tr><th>简称</th><th>全称</th><th>年份</th></tr></thead><tbody><tr><td>PDP</td><td>Provable Data Possession</td><td>2007</td></tr><tr><td>PORs</td><td>Proofs of Retrievability</td><td>2007</td></tr><tr><td>PoS</td><td>Proofs of Storage</td><td>2009</td></tr><tr><td>PoS</td><td>Proofs of Space</td><td>2013</td></tr><tr><td>PoST</td><td>Proofs of Space-Time</td><td>2016</td></tr><tr><td>PoRep</td><td>Proof of Replication</td><td>2017</td></tr><tr><td>PoC</td><td>Proof of Capacity</td><td>2017</td></tr></tbody></table></center><h3 id="Proofs-of-Storage"><a href="#Proofs-of-Storage" class="headerlink" title="Proofs of Storage"></a>Proofs of Storage</h3><p>PDP 和 PORs 在 2007 年各自独立地发表，在文件证明的方式上各有优劣，是对同一类问题不同分支的解决方案。</p><p>PoS（Proofs of Storage）的概念至少在 2009 年就已经出现，是一种统称，指客户端对服务端上文件进行验证的交互式协议，同时包含了 PDP 和 PORs 的范畴。比如论文《Proofs of Storage from HomomorphicIdentification Protocols》，第一作者是 Giuseppe Ateniese。</p><p>由于 2009 年区块链还没什么发展，所以 PoS（Proofs of Storage）和共识机制没有关系，和 PoS（Proof of Stack）也仅仅只是简称撞了，没什么联系。</p><p>PDP 和 PORs 属于 PoS 的前身，PoS 把它们用一个名字统一起来了。</p><h3 id="Proofs-of-Space"><a href="#Proofs-of-Space" class="headerlink" title="Proofs of Space"></a>Proofs of Space</h3><p>PoS（Proofs of Space）开始于 2013 年的论文《Proofs of Space》，第一作者是 Stefan Dziembowski。</p><p>也是巧合，PoS（Proofs of Space）和 PoS（Proofs of Storage）的简称一样，有时候可能会引起混淆。这个小节的 PoS 指 Proofs of Space。</p><p>PoS 的理念是，对标 PoW（Proof of Work）。所以从 PoS 开始，就是区块链中的概念了，它是一种共识机制。</p><p>PoW 是用 CPU 的算力进行挖矿，PoS 的想法是用磁盘的容量进行挖矿，想办法证明服务器上有某个数值的磁盘空间。</p><p>最基础的办法，是客户端生成一个文件，比如 1G，然后发送到服务器上，接着只要验证服务器上保存了那个文件，就能证明服务器确实有 1G 的磁盘空间了。不过这个办法太笨了，不但消耗客户端的磁盘空间，还会给网络传输带来非常大的压力。</p><p>PoS 提供的办法是，使用一种 hard to pebble graphs 的数据结构，比如 Merkle hash tree。这种数据结构的特点是，生成上层的数据必须要依赖于下一层的数据。</p><p>比如在使用了 Merkle hash tree 的系统里，客户端可以要求服务端，返回某一个上层节点的整条链路，然后自行验算路径是否正确。可以交叉验证多条链路，基本上就能保证服务端的可信了。</p><h3 id="Proofs-of-Space-Time"><a href="#Proofs-of-Space-Time" class="headerlink" title="Proofs of Space-Time"></a>Proofs of Space-Time</h3><p>PoST（Proofs of Space-Time）出现于 2016 年，论文标题《Simple Proofs of Space-Time and Rational Proofs of Storage》，第一作者是 Tal Moran。</p><p>PoST 是基于 PoS（Proofs of Space）的方案，因为 PoS 可以证明服务器端拥有一定量的磁盘空间，但是不能证明，服务器端的空间容量一直保持在期望的水平。比如，在进行验证的时候，服务器的磁盘空间是 1G，一旦验证结束，服务器就把空间用到别的地方了。再验证的时候，就再生成一遍 1G 的文件，用于验证。</p><p>所以 PoS 提议每 1 分钟都进行一次验证，以保证服务器的诚实。这显然不是很聪明的做法。</p><p>PoST 期望解决这个问题。PoST 提供的方法是，加大初始化阶段的难度，也就是 PoS 生成文件的阶段，想办法让服务器，必须要足够多的时间，才能够生成文件。</p><p>怎么保证需要足够多的时间呢，PoW（Proof of Work）就能够做到，比如计算 2^30 次哈希值，就意味着花费了那么多的时间。</p><p>PoST 就把 PoW 和 PoS 结合了起来，在初始化的阶段，让服务器必须消耗足够多的时间，才能够生成文件，然后在证明的阶段，去验证初始化阶段生成的文件。</p><h3 id="Proof-of-Replication"><a href="#Proof-of-Replication" class="headerlink" title="Proof of Replication"></a>Proof of Replication</h3><p>PoRep（Proof of Replication）源自 2017 年的论文《Proof of Replication》，第一作者是 Juan Bene。</p><p>PoRep 属于 Proofs of Storage 的一种，是 Protocol Labs 的研究成果，Protocol Labs 还开发了 IPFS 和 Filecoin。PoRep 也是 Filecoin 在使用的共识机制。</p><p>PoRep 基于 Proofs of Space 和 Proofs of Retrievability，在其基础上增加了一种能力，就是可以区分出服务器端的副本数量。做法也相对简单，就是在生成 Tags 的阶段，给每个副本都带一个唯一标识，让每一份副本都变得独一无二。</p><p>因为是去中心化的网络，Filecoin 需要保证整个网络中存在多个副本，如果节点联合起来作恶，之前的证明方式是无法应对的，所以 Filecoin 使用了 PoRep 的共识机制。</p><p>2017 版的 PoRep 相对简单，在 2018 版的 PoRep 里，才开始提到使用 Depth Robust Graphs 的数据结构。论文标题是《PoReps:  Proofs of Space on Useful Data》，第一作者是 Ben Fisch。</p><h3 id="Proof-of-Capacity"><a href="#Proof-of-Capacity" class="headerlink" title="Proof of Capacity"></a>Proof of Capacity</h3><p>PoC（Proof of Capacity）是 2017 年 Burstcoin 区块链使用的一种共识机制，</p><p>PoC 提供了一种挖矿的方式，产生新的区块需要一个 nonce 值：</p><pre><code>1 nonce = 8192 hash value = 4095 scoops</code></pre><p>其中 hash value 是使用 Shabal 作为哈希函数计算出的哈希值，每两个哈希值为一个 scoops。</p><p>在 0 到 4095 个 scoop nubmer 中随机选出一个，然后和相应的 nonce 结合，去计算出一个 <code>deadline</code> 值。和其他所有节点相比，谁的 deadline 值最小，谁就可以产生新的区块。</p><p>PoC 更倾向于一种纯粹的共识机制。</p>]]></content>
  </entry>
  <entry>
    <title>Proofs of Retrievability 文件证明的含义</title>
    <link href="https://smallyu.net/2022/12/16/Proofs-of-Retrievability-%E6%96%87%E4%BB%B6%E8%AF%81%E6%98%8E%E7%9A%84%E5%90%AB%E4%B9%89/"/>
    <id>blog:https://smallyu.net/2022/12/16/Proofs-of-Retrievability-%E6%96%87%E4%BB%B6%E8%AF%81%E6%98%8E%E7%9A%84%E5%90%AB%E4%B9%89/</id>
    <published>2022-12-16T09:22:05.000Z</published>
    <updated>2025-11-09T09:22:13.309Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>PORs（Proofs of Retrievability）的论文和 PDP 在同一年 2007 年发表，论文题目是《PORs: Proofs of Retrievability for Large Files》，第一作者是 Ari Juels。</p>
<p>PORs]]></summary>
    <content type="html"><![CDATA[<p>PORs（Proofs of Retrievability）的论文和 PDP 在同一年 2007 年发表，论文题目是《PORs: Proofs of Retrievability for Large Files》，第一作者是 Ari Juels。</p><p>PORs 不但可以证明文件确实被保存在服务端，而且可以知道文件有没有被修改、删除，这是 PDP 不具备的能力。不过 PORs 的局限性在于，只能用于加密文件，或者说必须对文件进行加密。PORs 实现的关键在于复杂的 setup 阶段。</p><p>PORs 的思路是，客户端生成一些随机的编码记录在数组中，这些编码被称为哨兵。比如 <code>[6, 4, 0]</code> 是三个哨兵。</p><p>先对客户端的文件进行对称加密，而且必须使用 block cipher 的方式。在加密过程中，把哨兵加入到文件随机的位置。两个哨兵之间，可能隔着 1 个 block 或者无数个 block，哨兵的位置是随机的。</p><p>然后把加密后的文件发送到服务端保存。</p><p>客户端发起挑战的内容，就是要服务端返回，文件在随机 n 个位置上的编码。挑战中包含哨兵所在的位置。</p><p>由于文件是加密的，服务端并不能判断，挑战的位置是原始文件的数据，还是哨兵位置的数据，服务端是难以推测出哨兵位置的。</p><p>对于客户端来说，只需要验证哨兵所在位置对应的编码，就可以判断文件是否存在以及完好无损。如果文件被修改或者中间的某些数据丢失，哨兵所在位置的编码一定是大相径庭的，挑战无法完成。</p><p>Retrievability 是可检索的意思，在 PORs 中的含义是，对于客户端来说，我可以通过指定哨兵位置的方式，对文件的某个部分验证，比如想验证第 1 个哨兵到第 3 个哨兵之间的文件是否完好，或者去验证第 5 个哨兵到第 9 个哨兵之间的文件，指哪打哪。</p><p>至于说为什么一定要对文件进行加密，应该一方面 PORs 依赖于对称加密的 block cipher，另一方面，对于不加密的文件，服务端比较容易推测出哨兵的位置。所以 PORs 只能用于加密文件。</p><p>论文中还通过引入纠错码的方式，来增加文件的容错能力。在 setup 阶段，先对 block 加入纠错码，再进行对称加密。引入纠错码的好处，就是在两个哨兵之间，在一定的错误范围内，如果文件有损坏，可以去修复文件。</p><p>为什么在 PORs 的机制中，纠错码开始显得重要？因为要和 PORs 的特点 Retrievability 结合。如果文件被储存在多个服务器环境，遭到了不同程度的损坏，因为有哨兵的存在，比较容易从其他服务器中恢复文件的一部分。在这样的背景下，引入纠错码就是对文件容错能力的进一步加强了。</p>]]></content>
  </entry>
  <entry>
    <title>对 S-PDP 文件证明的示例和解释</title>
    <link href="https://smallyu.net/2022/12/14/%E5%AF%B9S-PDP%E6%96%87%E4%BB%B6%E8%AF%81%E6%98%8E%E7%9A%84%E7%A4%BA%E4%BE%8B%E5%92%8C%E8%A7%A3%E9%87%8A/"/>
    <id>blog:https://smallyu.net/2022/12/14/%E5%AF%B9S-PDP%E6%96%87%E4%BB%B6%E8%AF%81%E6%98%8E%E7%9A%84%E7%A4%BA%E4%BE%8B%E5%92%8C%E8%A7%A3%E9%87%8A/</id>
    <published>2022-12-14T13:39:59.000Z</published>
    <updated>2025-11-09T09:22:13.447Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>我们现在说的 PDP，一般指发表于 2007 年论文《Provable Data Possession at Untrusted Stores》里的 PDP，第一作者是 Giuseppe Ateniese。这篇论文之前，已经有一些文件证明的概念，比如]]></summary>
    <content type="html"><![CDATA[<p>我们现在说的 PDP，一般指发表于 2007 年论文《Provable Data Possession at Untrusted Stores》里的 PDP，第一作者是 Giuseppe Ateniese。这篇论文之前，已经有一些文件证明的概念，比如 B-PDP，但是都没有做到，能够保证服务器端保存了文件。</p><p>S-PDP 是论文中首次提出的一种 scheme，可以用于客户端确认，某个文件确实被保存到了服务器环境上，这个服务器环境是不受信任的。</p><p>PDP 在解决的问题，就是我把一个文件保存到服务器上，不是说服务器告诉我它保存了，我就相信它真的保存了，我需要一种机制，确认文件真的在服务器上了。</p><p>PDP 也有很多种类型，有公开的、私有的、静态的、动态的。S-PDP 是比较基础的一种公开验证的 PDP。</p><p>同态加密是实现 S-PDP 的关键。</p><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><p>我想举一个简单的例子来说明 S-PDP 的过程。因为论文中不着边的东西比较多，概括性的定义比较多，而且语焉不详，没有提供太具体的实现方式。我是按照自己的理解来解释。</p><p>现在客户端有一个原始的文件，内容是：</p><pre><code>F = 12345</code></pre><p>把这个文件分割成小的 block，比如分成 5 份：</p><pre><code>F = [1, 2, 3, 4, 5]</code></pre><p>在客户端这边生成一个随机数组成的数组 W，数组的长度和文件的 block 数量一致。W 的内容一定要是不可预测的：</p><pre><code>W = [8, 1, 7, 3, 6]</code></pre><p>生成同态加密标签分 2 步，首先，我们对 F 和 W 使用加法同态加密，接着，使用客户端公钥对同态加密后的数组，进行非对称加密：</p><pre><code>T = r[ h(9),  h(3),  h(10),  h(7),  h(11)]  =  [rh(9)) rh(3), rh(10), rh(7), rh(11)]</code></pre><p>客户端将会把原始文件 F、同态加密标签 T 一起发送到服务端进行保存，客户端只保留本地生成的随机数组 W，W 是唯一私密不能泄漏的内容。客户端发送完毕后，就可以把本地的原始文件 F 和同态加密标签 T 都删掉了。</p><p>当客户端想要验证服务端的文件，由客户端生成一个挑战，比如随机验证第 1 个和第 3 个 block：</p><pre><code>chal = [1, 3]</code></pre><p>服务端在收到挑战后，生成证明也分 2 步，首先，使用客户端的公钥对原始文件 F 的第 1 个和第 3 个 block 进行非对称加密，接着，使用同态加密标签 T 去做减法同态加密：</p><pre><code>V = [rh(9), rh(10)] - r[h(1),  h(3)]  = [rh(9), rh(10)] - [rh(1), rh(3)]  = [rh(8), rh(7)]</code></pre><p>客户端拿到证明 V 后，使用私钥对证明进行非对称解密：</p><pre><code>sW = r&#39;[rh(8), rh(7)]   =   [ h(8),  h(7)]</code></pre><p>可以验证，证明经过解密后的 sW 正对应随机数组 W 第 1 个和第 3 个索引的值。由于同态加密的使用，整个过程中，W 的内容都没有泄漏。</p><p>用户只要手里有一开始生成的随机数组 W，在没有原始文件的情况下，就可以验证服务端的文件确实存在。这个随机数组 W 的数据占用是非常少的。而且过程中由于非对称加密的使用，服务端必须同时拥有同态加密标签 T 和原始文件 F，才能够完成挑战。因为 T 是公钥加密的，如果服务端作恶，客户端会解密不出来，服务端挑战失败。</p><h3 id="局限性"><a href="#局限性" class="headerlink" title="局限性"></a>局限性</h3><p>在 PDP 的过程中，存在个问题：既然 V &#x3D; T - F，如果服务端事先把整个 V 保存下来，即使删掉 T 和 F，也是可以通过挑战的，而且客户端并不会发现？</p><p>这是 PDP 的局限性，PDP 只能保证服务器至少保存了这个文件 1 次（如果一次都不保存，是不能生成 V 的），但是无法保证文件持续保存在服务器上，也无法反复验证证明的有效性。</p><p>假如第一次挑战是 [1, 3]，服务器通过了挑战并且保存了挑战为 [1, 3] 的证明，那么之后只要是 [1, 3] 的挑战，服务器都可以直接返回已经通过挑战的证明，而不需要对文件进行计算。客户端无法知晓，证明是立即生成的，还是早已生成的。这是所有 PDP 证明的局限性。</p>]]></content>
  </entry>
  <entry>
    <title>区块链有两个领域，金融领域和其他领域，国外大多数的区块链应用还是聚焦在金融领域上，包括交易所。国内试图在其他领域找到方向...</title>
    <link href="https://t.smallyu.net/#2022-42"/>
    <id>micro:1338646393</id>
    <published>2022-12-06T02:37:03Z</published>
    <updated>2022-12-06T02:37:03Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>区块链有两个领域，金融领域和其他领域，国外大多数的区块链应用还是聚焦在金融领域上，包括交易所。国内试图在其他领域找到方向，但是一直没有找到。 对于开发者，金融领域更多和基金公司、量化交易等相关，但是门槛比较高。其他领域上，还没有能走出来的。</p>]]></summary>
    <content type="html"><![CDATA[<p>区块链有两个领域，金融领域和其他领域，国外大多数的区块链应用还是聚焦在金融领域上，包括交易所。国内试图在其他领域找到方向，但是一直没有找到。</p>
<p>对于开发者，金融领域更多和基金公司、量化交易等相关，但是门槛比较高。其他领域上，还没有能走出来的。</p>
]]></content>
  </entry>
  <entry>
    <title>我的加密货币交易机器人</title>
    <link href="https://smallyu.net/2022/12/03/%E6%88%91%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E4%BA%A4%E6%98%93%E6%9C%BA%E5%99%A8%E4%BA%BA/"/>
    <id>blog:https://smallyu.net/2022/12/03/%E6%88%91%E7%9A%84%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E4%BA%A4%E6%98%93%E6%9C%BA%E5%99%A8%E4%BA%BA/</id>
    <published>2022-12-03T07:29:27.000Z</published>
    <updated>2025-06-19T03:30:33.051Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>当然不是什么机器人，只是一个简单的脚本。不过值得一说的是，它确实能带来收益。</p>
<p>目前运行了 10 天左右，收益约 5%，在我看来已经是很好的结果，比自己操作要靠谱很多，反正我手动炒币只有亏钱的份。</p>
<p>如果本金是 $100，那么按照 5%]]></summary>
    <content type="html"><![CDATA[<p>当然不是什么机器人，只是一个简单的脚本。不过值得一说的是，它确实能带来收益。</p><p>目前运行了 10 天左右，收益约 5%，在我看来已经是很好的结果，比自己操作要靠谱很多，反正我手动炒币只有亏钱的份。</p><p>如果本金是 $100，那么按照 5% 的收益率，一个月可以赚 $15，至少能把开服务器的钱挣回来。能平衡开支也是一件值得开心的事情。</p><p>换个角度想，10 天 5%，一个月 15%，一年 150% ……这收益率简直逆天。这还只是用 spot 交易，如果加上杠杆，收益会高很多。</p><p>经过最近几天的运行调试，解决了一些常见的错误情况，程序已经基本上稳定了。</p><h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p><a href="https://www.bi123.co/">https://www.bi123.co/</a> 这个网站提供了各种加密货币的信号，会在整点的时候，通过邮件发送过去，某一种加密货币是看涨还是看跌。经过很长时间的人为观察，这个信号挺准的，至少在大方向上没有错。</p><p>那么脚本在收到邮件后，就根据信号，自动在 Binance 上进行交易。Binance 提供了完善的 API。</p><p>脚本会实时推动消息到 Telegram 的机器人，方便查看和关注交易结果。</p><h3 id="收益分析"><a href="#收益分析" class="headerlink" title="收益分析"></a>收益分析</h3><p>在一个价格波动的周期中，如果能做到低点买、高点卖，那么每一个上升的波段都是收益。无所谓价格最终有没有变高，只要有波动，就能有收益。</p><p>bi123 的信号是整点发的，也许会感觉不及时，会错过收益的机会或者带来更大的损失，不过以至少一个小时为周期，也可以防止太小幅度的波动，带来不必要的买卖。</p><p>由于各种加密货币的价格涨跌不一致，脚本支持配置多种不同的加密货币，随个人喜好选择。</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>也没什么技术含量，代码在这里：<a href="https://github.com/smallyunet/txbot">smallyunet&#x2F;txbot</a></p><h3 id="2023-01-12"><a href="#2023-01-12" class="headerlink" title="2023.01.12"></a>2023.01.12</h3><p>现在已经过去了一个多月的时间，来总结一下我实际的使用情况和结论。</p><p>首先是由于犯了很多错误，导致我最近一个月的余额是亏损的，大概亏损 3% 左右。一开始我没有留意，信号是分级别的，有 1 小时级别、4 小时级别、1 天的级别。不同的级别对市场的响应速度不一样。bi123.co 的 “信号趋势” 这个种类的信号，原理是对比收盘价，比如现在的价格是 1500 美元， 4 个小时之前是 1300 美元，那么就发出看涨的信号，就这么简单，就这么暴力。所以不同级别强度的信号，差异很大。一般来说，不推荐使用 1 小时的信号，我也确实在使用 1 小时信号的情况下，亏损率比较高。后来换成 4小时级别的信号，效果好多了。我推荐用 4 小时的信号。</p><p>再一个是信号种类。bi123.co 提供了 “信号趋势”、“RSI 背离”、“MD5 短线”、“多空头排列” 等多种信号，我之前只用了 “信号趋势” 一种，比较容易导致对市场的反应不及时。我推荐所有种类的信号一起用。</p><p>现在交易机器人脚本是支持配置使用，不同级别的信号强度以及信号种类的，默认配置是我感觉比较好的一种配置。</p><p>再看机器人的效果，目前机器人是无法逆市场而为的，也就是说很难在熊市的情况下获利，因为目前机器人只支持 spot 交易，没有添加做空或者倍率的交易方式，后期可以考虑加入。而且机器人会在市场短期震荡的情况下，发生亏损，也就是横盘的情况，机器人不但无法获利，而且会有少量亏损。从这个角度看，机器人似乎很肋助。</p><p>但机器人也不是毫无用处，机器人可以帮助你顺应市场，在跌的时候及时卖出，涨的时候及时买入，而不至于发生，跌的时候继续持有、涨的时候没有买入等情况。而这些操作都不需要手动完成，你甚至不需要关心这笔资产的情况，一切都会自动发生，它可以帮助你，不错过任何时候市场的机会。市场下跌及时止损，市场上涨及时跟进，就是这样。</p><p>机器人的另一个用处是，支持多币种的配置，可以让你不错过某个币种疯狂上涨的获利机会。市场上经常出现，某一个币种逆势上涨的情况，其他币都没怎么动，某个币拉疯了。如果是手动操作资产，很难不错过这样的机会，但如果是机器人自动批量操作，似乎很容易，也很自然而然可以抓住这样的机会。</p><h3 id="2023-01-15"><a href="#2023-01-15" class="headerlink" title="2023.01.15"></a>2023.01.15</h3><p>短短两天，市场疯涨，机器人的表现也符合预期，市场拉升，机器人会自动买入，及时跟上收益。这是最近一整个月，在机器人的控制下，我的资产变动情况（纵坐标的单位不重要）：</p><img src="balance.png" width="100%"><p>在一段时间的实践之后，我仍然推荐使用这样的机器人。</p><h3 id="2023-03-16"><a href="#2023-03-16" class="headerlink" title="2023.03.16"></a>2023.03.16</h3><p>经过最近一段时间对机器人的试用，我决定放弃并停止使用这样的机器人。我一共标的了 56 种加密货币，接受它们的信号，并且根据信号自动进行交易，这是最近一个月的资产变动情况：</p><img src="balance2.png" width="100%"><p>也许是标的货币的种类太多，导致单种货币投入的金额太小，又或者是其他什么原因，总之由于机器人实际效果的不理想，以及现在我对炒币这件事情的不认可，不再推荐使用这样的机器人。</p>]]></content>
  </entry>
  <entry>
    <title>国内所有的区块链，只有 Tron 是支持 USDT 的。</title>
    <link href="https://t.smallyu.net/#2022-41"/>
    <id>micro:1328670390</id>
    <published>2022-11-28T07:50:59Z</published>
    <updated>2022-11-28T07:50:59Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>国内所有的区块链，只有 Tron 是支持 USDT 的。</p>]]></summary>
    <content type="html"><![CDATA[<p>国内所有的区块链，只有 Tron 是支持 USDT 的。</p>
]]></content>
  </entry>
  <entry>
    <title>如果某个 layer 2 一家独大，用户会不会都跑到 layer 2 上玩？layer 1 是不是就没有存在的意义了？l...</title>
    <link href="https://t.smallyu.net/#2022-40"/>
    <id>micro:1324593810</id>
    <published>2022-11-23T06:05:08Z</published>
    <updated>2022-11-23T06:05:08Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果某个 layer 2 一家独大，用户会不会都跑到 layer 2 上玩？layer 1 是不是就没有存在的意义了？layer 2 是不可能超越 layer 1 的。</p>]]></summary>
    <content type="html"><![CDATA[<p>如果某个 layer 2 一家独大，用户会不会都跑到 layer 2 上玩？layer 1 是不是就没有存在的意义了？layer 2 是不可能超越 layer 1 的。</p>
]]></content>
  </entry>
  <entry>
    <title>对区块链行业的见闻</title>
    <link href="https://smallyu.net/2022/11/15/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E8%A1%8C%E4%B8%9A%E7%9A%84%E8%A7%81%E9%97%BB/"/>
    <id>blog:https://smallyu.net/2022/11/15/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E8%A1%8C%E4%B8%9A%E7%9A%84%E8%A7%81%E9%97%BB/</id>
    <published>2022-11-15T09:05:50.000Z</published>
    <updated>2025-11-09T09:22:13.448Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>最近有点迷茫，随便写写，可能比较乱。之前只写过工作方面的回顾，没有概念方面的内容。这一年过的很快，发生了很多事情，又没什么大的变化。</p>
<p>最近一年都是熊市，尤其是五月份之后，区块链行业进入严重的寒冬，没有像之前各种概念层出不穷，似乎没有大事发生，大家都还在想，下一]]></summary>
    <content type="html"><![CDATA[<p>最近有点迷茫，随便写写，可能比较乱。之前只写过工作方面的回顾，没有概念方面的内容。这一年过的很快，发生了很多事情，又没什么大的变化。</p><p>最近一年都是熊市，尤其是五月份之后，区块链行业进入严重的寒冬，没有像之前各种概念层出不穷，似乎没有大事发生，大家都还在想，下一轮加密货币行业的叙事会是什么？</p><h3 id="ETH"><a href="#ETH" class="headerlink" title="ETH"></a>ETH</h3><p>以太坊是加密行业的半壁江山，很多项目都是基于以太坊构建的，很多 token 都在以太坊的合约里，很多概念也都是以太坊提出来的，比如 DAO，这样的体量是不会轻易倒下的，如果倒下那些项目要跟着死。比特币的价值在于开创了整个行业，但未来区块链拓展应用场景和生态，还得是以太坊，以太坊能玩得起来。</p><p>再一个是公链的开发周期长，当年以太坊也是苦苦拉投资，“2017 年 Vitalik 来中国学中文”，后来回西方国家开发了两年，EVM 才成型，并且现在几乎已经成为智能合约的标准，各种链都开始试图兼容 EVM，因为智能合约的虚拟机和生态，没有完成度比 EVM 高的。以太坊一开始发布的白皮书，也是以智能合约为卖点，PoS 是后来版本的白皮书才有的。</p><p>2017 年到 2019 年是公链爆发的时间段，在共识机制上创新，或者应用场景上创新，现在的很多链都是那个时候留下的，投资人也愿意往底层链上投资。现在发链的比较少，因为竞争力不大，回报周期也比较长。今年的 Aptos 和 Sui 主打 Move 编程语言，共识机制上没有太大创新，我觉得 Move 编程语言也不会很流行。</p><p>号称历史上最大升级的以太坊 merge，其实啥事都没有，对于普通用户来说，发生了和没发生一样，一点感觉都没有。合并之后，币价从 1700 跌到了 1400。说好的发行量减少、会通缩、价格会涨，都没有。</p><p>不过以太坊合并之后价格没崩，说明以太坊的价值不来源于挖矿。有的人认为挖矿是币价的保障，因为有一个成本在里面。以太坊的事情说明，不用算力挖矿、没有硬件设备做抵押，也能行。</p><h3 id="CEX"><a href="#CEX" class="headerlink" title="CEX"></a>CEX</h3><p>加密货币的价格和美股关联性很强，涨跌全看美联储的加息幅度和 CPI 之类的指标。不过也有不那么相关的时候，如果用户对美股失去信心，资金就会进入加密货币，如果对加密货币失去信心，资金就会进入美股。</p><p>加密货币行业的盘子比较小，好像全部只有几千亿美元，和美股几十万亿的盘子比起来，影响不会很大。有的阴谋论会说，加密货币是美国货币的蓄水池，为了缓解通胀。</p><p>这两天 FTX 暴雷，挪用用户的加密货币资产，导致用户对加密货币尤其是 CEX 失去信心，加密货币进入新一轮熊市，以太坊价格好不容易回到 1700 左右，一下打回 1300。各大交易所开始公布资产证明。</p><p>交易所里面的交易真的是赌博，我玩不来。我曾经也有一个暴富的梦，拿着 100 美元，开了 125 倍的杠杆，做空 Mask，几秒钟被拉爆仓。后来又拿着 100 美元，做多 Sol，只剩下一半左右。不敢玩了，币圈都是赌狗，涨跌全靠消息，doge coin 全靠 Musk 喊单。FTX 拿的 SHIB 都比 ETH 多。</p><p>顺便说一句，凉兮素质很低，马一龙没啥文化，KOL 都是跳梁小丑。孙宇晨其实是看不起这些人的，只是借助他们的流量和噱头。</p><h3 id="Finance"><a href="#Finance" class="headerlink" title="Finance"></a>Finance</h3><p>NFT 的出圈挺突然的，但是现在热度也下来了。看到一篇文章里说，区块链的场景有两种，一种是 web 2 转移到 web 3，那不叫创新，叫链改，另一种是 web 3 原生。本来想着用 NFT 作为艺术品的链上存证，没起来，结果蓝筹 NFT 在链上搞原创，链下搞周边，火了。现在的 NFT 还是投资的属性多一点，靠品牌大和稀有度。</p><p>各种 Fi 其实最终都落在 Finance 上，SoicalFi、GameFi、DeFi，都在金融的圈子里。目前还没有靠谱的场景能行得通，最大的 web 3.0 和元宇宙都是概念阶段。国外都没玩通，国内就更不行了，天然抵制 Fi。在这样的背景下，你说绝望吧。</p><p>有聊天室和邮箱基于 ENS 的，问题是谁用啊。有小游戏结合链上资产的，玩家挣不到钱，项目方也挣不到钱，那怎么办。</p><p>在一些一线机场买 VPN 的时候，发现支持 TRC-20，还挺意外的，原来 Tron 还活着，还有商家在用，倒是给了我下载 Trx 钱包的理由，它真的能用来买东西，不用担心国内的支付方式有问题了。不过遗憾的是，依然是 Finance 场景。</p><h3 id="DSN"><a href="#DSN" class="headerlink" title="DSN"></a>DSN</h3><p>分布式储存网络有两个头部，Filecoin 和 Arweave。</p><p>Filecoin 是链下储存的典型，或者说基于合约的 DSN，链下用 IPFS 存数据，链上做存证、结算、挑战。Filecoin 的学术能力很强，先是做出了 IPFS，在 PoC 方面也基本上是老大，在文件证明的方向有很多创新，超越了基础的 PDP、Proof of Retrivailiabily。在链式的文件证明上都是发顶会的论文。</p><p>链下储存的优点是文件可以很大，不会影响到链的效率，但是 Filecoin 广为人知的问题是，数据有丢失的风险，数据没了就真的没了。而且 Filecoin 的节点和 SDK 真的不怎么好用，至少不亲民，据说因为要根据磁盘空间计算算力，故意控制文件的编码速度到一个频率，导致用户的体验非常差，可能要一两个小时才能知道，文件有没有成功储存。现在也少有项目是用 Filecoin 构建项目。</p><p>Arweave 是链上储存的典型，或者说基于链的 DSN。Arweave 的创新能力比起 Filecoin 差很多，块结构和 Filecoin 类似，会在块中记录一个 calldata，随机验证上一个块 calldata 前 10% 的内容。Filecoin 的 PoC 共识比较纯粹一点，Arweave 还是要依赖 PoW 挖矿，先做文件的校验，然后 randomX 挖矿。</p><p>Arweave 利用经济模型，文件越稀有，挖矿的几率越高，用这样的方式达到文件永久储存的效果，以区别于 Filecoin 的临时储存。Arweave 和 Meta 合作也让 Ar 的价格涨了很多。</p><p>链上储存的好处就是，文件永远不会丢。问题是数据膨胀量也比较大，对于大文件的储存可能不是很友好，比较适合存 NFT 之类的数据。以太坊也早就有结合 IPFS 做链下储存 NFT 的方案。</p><p>我理解链上储存和链下储存，或者基于链的储存和基于合约的储存，简单的区分方式是，看生成新的块要不要依赖上一个块的文件数据。</p><p>有人认为目前的区块链，基本方向还在于分布式计算，至于分布式储存，可能路径不是特别明确。Filecoin 也是在搞一种 actor 的节点，支持 EVM 的执行环境。其实早在多年前《硅谷》的电视剧里，就已经畅想过分布式储存的前景了。</p><p>参考之前的思维方式，分布式储存是要做链改，替换掉 web 2 的云服务器市场呢，还是在 web 3 上搞创新呢。</p><h3 id="Layer-2"><a href="#Layer-2" class="headerlink" title="Layer 2"></a>Layer 2</h3><p>首先 layer 2 还在 Finance 的范畴里。以太坊计划把 layer 2 发扬光大，提高主网的性能，分散主网的计算压力。</p><p>目前 layer 2 还没有真正的头部，各个 layer 2 项目是割裂的，相互之间不能交互，对用户的体验是很大的问题。用户需要选一个 layer 2 站队，那么只有一些小项目会放到 layer 2 上。layer 1 的大合约不太可能会放到 layer 2 上。</p><p>layer 2 的技术设施也不完善，zk 就不用想了，op 和 arb 相对能用，但是比较中心化，和 layer 1 的交互也比较慢。arb 今年在奥德赛的时候，由于用户的突然增加，gas 费接近主网的 3 倍，属于世界名画了，问题也一时难以修复。</p><p>op 的挑战周期比较长，据说是一到两周，对于普通用户有点不能接受，而且问题在于，谁来验证主网上的交易。用户自己肯定不干，交给第三方的话，又要把信任放到第三方上。</p><p>state channels 和侧链的局限性都比 rollups 要大，更加不那么安全，op 似乎是从 plamsa 演进来的。</p><p>以太坊对 layer 和 sharding 都有很多蓝图，但是就像不知道谁说的，“以太坊啥都好，就是啥都慢”，我们对以太坊的期待要等很久。</p><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>DID 几年前就有了，没有项目真正做起来。现在阶段，还是认为小狐狸或者钱包是 web 3 的入口，如果要搞 DID，可能还需要一大波市场的清洗。</p><p>Solana 的价格在 FTX 的事件中跌的厉害，Solana 的特点是 PoH 共识，因为经历过之前的几次宕机，大家不是特别看好。</p><p>Polkadot 主要是它不好用啊。</p><p>DeFinity 看起来挺好用的，理念上也结合了各种链的优点，号称无限扩容，全部数据上链。问题是他没有太大创新，更多的是把各种东西整合到一起。</p><p>Conflux 是国内的链，从大学实验室里开始的，在国内根本做不起来，啥场景都没有。</p><p>比特币由于耗费大量算力的问题，长期看会被淘汰，也会被历史记住。它最稳，也最不稳。</p><p>其他的我也不知道了。</p>]]></content>
  </entry>
  <entry>
    <title>好像没有完美的编程语言，因为仔细想想，各种语言都不是特别干净，lisp 简洁、完整，有的人很推崇 lisp，但是它不好用...</title>
    <link href="https://t.smallyu.net/#2022-39"/>
    <id>micro:1295749209</id>
    <published>2022-10-29T06:26:45Z</published>
    <updated>2022-10-29T06:26:45Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>好像没有完美的编程语言，因为仔细想想，各种语言都不是特别干净，lisp 简洁、完整，有的人很推崇 lisp，但是它不好用啊，不直观。看到 Youtube 上的一个 视频 ，采访很多人，你最喜欢的编程语言是什么？甚至有人说 basic、matlab、labview 之类，谁能说它们不是编程语言呢。</p>]]></summary>
    <content type="html"><![CDATA[<p>好像没有完美的编程语言，因为仔细想想，各种语言都不是特别干净，lisp 简洁、完整，有的人很推崇 lisp，但是它不好用啊，不直观。看到 Youtube 上的一个<a href="https://youtu.be/p8-rZOCn5rQ">视频</a>，采访很多人，你最喜欢的编程语言是什么？甚至有人说 basic、matlab、labview 之类，谁能说它们不是编程语言呢。</p>
]]></content>
  </entry>
  <entry>
    <title>开发软件真是需要很多投入的事情，即使是 Bitcoin 非常初期版本的 代码 ，也是花了很多时间打磨，EVM 能够几乎没...</title>
    <link href="https://t.smallyu.net/#2022-38"/>
    <id>micro:1295744958</id>
    <published>2022-10-29T05:59:26Z</published>
    <updated>2022-10-29T05:59:26Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>开发软件真是需要很多投入的事情，即使是 Bitcoin 非常初期版本的 代码 ，也是花了很多时间打磨，EVM 能够几乎没有对手，也是经历了很长的开发周期。 tmb-golang 已经很久没有更新了。我得开始新的、其他计划。</p>]]></summary>
    <content type="html"><![CDATA[<p>开发软件真是需要很多投入的事情，即使是 Bitcoin 非常初期版本的<a href="https://github.com/smallyunet/bitcoin-code.git">代码</a>，也是花了很多时间打磨，EVM 能够几乎没有对手，也是经历了很长的开发周期。<a href="https://github.com/the-minimal-blockchain/tmb-golang">tmb-golang</a> 已经很久没有更新了。我得开始新的、其他计划。</p>
]]></content>
  </entry>
  <entry>
    <title>试着看了排名前 30 的 coin 的 白皮书 ，感觉越后面的越不想仔细看，没有太多新意。现在已经不是 2017 到 2...</title>
    <link href="https://t.smallyu.net/#2022-37"/>
    <id>micro:1295743795</id>
    <published>2022-10-29T05:51:27Z</published>
    <updated>2022-10-29T05:51:27Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>试着看了排名前 30 的 coin 的 白皮书 ，感觉越后面的越不想仔细看，没有太多新意。现在已经不是 2017 到 2019 年那种，发行 Layer 1 公链、打差异化的时代了。今年有什么新出的概念吗，好像没有。 前段时间 Aptos 上线，主要的特点是 move 语言。真的有那么多人，在乎合约语言吗？$10 的...</p>]]></summary>
    <content type="html"><![CDATA[<p>试着看了排名前 30 的 coin 的<a href="https://whitepaper.io/coins">白皮书</a>，感觉越后面的越不想仔细看，没有太多新意。现在已经不是 2017 到 2019 年那种，发行 Layer 1 公链、打差异化的时代了。今年有什么新出的概念吗，好像没有。</p>
<p>前段时间 Aptos 上线，主要的特点是 move 语言。真的有那么多人，在乎合约语言吗？$10 的 APT 上线后，现在也只剩 $8 左右了。</p>
<p>我觉得 Aptos 的市场比较大，不会倒，但是也很难发展太好。不管技术上多可靠，至少要好用，Polkdot 用 Rust 语言再各种先进，也是起不来的，因为用户，不会用。Ethereum 的 SDK 主要是 Javascript，Solidity 的语法也精简，才能有很多人能用的起来。</p>
]]></content>
  </entry>
  <entry>
    <title>迷宫</title>
    <link href="https://crazy.smallyu.net/2022/10/05/%E8%BF%B7%E5%AE%AB/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2022/10/05/%E8%BF%B7%E5%AE%AB/</id>
    <published>2022-10-05T03:49:57.000Z</published>
    <updated>2025-10-01T00:53:50.006Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>勇者做了一个梦<br>他生活在远方的田野<br>没有铠甲 没有宝剑<br>父母在身边 亲人康健<br>没有繁华 没有魔法<br>朋友会呼唤 成群结伴<br>没有梦想 没有远方<br>每天都劳作 辛苦平淡<br>没有怪兽 没有恶龙<br>有温馨的家 和温柔的她<br>有人问]]></summary>
    <content type="html"><![CDATA[<p>勇者做了一个梦<br>他生活在远方的田野<br>没有铠甲 没有宝剑<br>父母在身边 亲人康健<br>没有繁华 没有魔法<br>朋友会呼唤 成群结伴<br>没有梦想 没有远方<br>每天都劳作 辛苦平淡<br>没有怪兽 没有恶龙<br>有温馨的家 和温柔的她<br>有人问 幸福是什么<br>他说 铃声一响 就知道是谁的来信<br>一定是她  </p><p>勇者在黄昏的洞穴醒来<br>对梦中的生活感到迷茫<br>分明是宁静和睦的幸福<br>却让人感觉到充满绝望<br>一成不变的枯燥和无聊<br>掩埋了多少绚烂的祷告<br>眼前是高大的树 崎岖的路<br>认不清的方向 说不出的苦<br>太阳升起到落下 反反复复<br>周而复始 总是同样的迷途<br>有人问 孤独是什么<br>他说 铃声一响 就知道是谁的来信<br>只有她  </p><p>他回到了没有梦的地方<br>却忽然分不清 哪里是梦  </p><p>当时<br>他遇到了路过的牧师 事情从那里开始<br>他丢掉曾经的魔法书 去寻找更多宝物<br>他开始觉得 旅途未必独自前进<br>以前面对的危险折磨 属于自己的修行<br>有牧师的治疗和祝福 一切都变得容易  </p><p>可是<br>世上没有出其不意的惊喜<br>也许不止是逢场作戏<br>但终究只是过客而已<br>拥有短暂时光的相互扶持<br>已经足够凑齐未来的回忆<br>等到时光流动到无法停止<br>还能再书写不单调的历史  </p><p>所以<br>他很多次想放弃<br>但每当转身离开<br>又看到她的神情<br>是放不下的感慨  </p><p>这是一个破不掉的局<br>陷入其中就一败涂地  </p><p>此时<br>城镇的内外都不太平<br>彼岸的国度战火纷飞<br>墙内的居民像是傀儡<br>行尸走肉尚可以同仇敌忾<br>好过作茧自缚的酒囊饭袋<br>来自地狱的恶魔举着招牌<br>为了幻想的王国胡乱修改<br>破坏已建立的秩序和心态  </p><p>他不能改变什么<br>他不是唯一的勇者<br>也不是唯一的失败者<br>没有出奇的天赋<br>也没有天降的神喻<br>只是一出不意外的戏  </p><p>戏还在演<br>场还没散<br>人还在看  </p>]]></content>
  </entry>
  <entry>
    <title>随机确认块的共识机制</title>
    <link href="https://smallyu.net/2022/09/25/%E9%9A%8F%E6%9C%BA%E7%A1%AE%E8%AE%A4%E5%9D%97%E7%9A%84%E5%85%B1%E8%AF%86%E6%9C%BA%E5%88%B6/"/>
    <id>blog:https://smallyu.net/2022/09/25/%E9%9A%8F%E6%9C%BA%E7%A1%AE%E8%AE%A4%E5%9D%97%E7%9A%84%E5%85%B1%E8%AF%86%E6%9C%BA%E5%88%B6/</id>
    <published>2022-09-25T09:43:28.000Z</published>
    <updated>2025-11-09T09:22:13.556Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="步骤"><a href="#步骤" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<h3 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h3><ol><li><p>在一个时间窗口内，一个节点会收到多个通过验证的块，在这些块中随机选取一个作为自己的下一个块。</p></li><li><p>在下一个时间窗口，节点如果没有收到块，同时发现网络整体的块高度已经高于自己，将丢弃掉上一个确认的块。</p></li><li><p>如果块高度相同，少数服从多数。</p></li></ol><h3 id="为什么要这样"><a href="#为什么要这样" class="headerlink" title="为什么要这样"></a>为什么要这样</h3><ul><li>收到多个通过验证的块</li></ul><p>Proof of work 的思路是，在一个时间窗口内，只有一个正确答案，这样就保证了整个网络的一致。换个思路的话，为什么不能在同一个时间窗口内，产生多个正确答案呢？</p><ul><li>随机选取一个块</li></ul><p>由于网络中同时存在多个正确的块，那么就需要一种机制来从中选取一个，公平起见，就用完全随机的方式。</p><ul><li>丢弃上一个块</li></ul><p>丢弃块的机制是为了给系统提供自我纠错的能力。Ethereum 的 DAO 攻击事件，需要开发者带领社区对区块链进行硬分叉，说明系统本身是没有纠错能力的，需要人为干预，似乎目前所有区块链系统都是这样。</p><ul><li>少数服从多数</li></ul><p>在没有交易发生的情况下，有可能所有节点都处于等待的状态，此时因为块高度相同，没有节点愿意丢弃自己的块，整个网络是割裂的。这是一种博弈的状态，所以要按照少数服从多数的原则打破平衡。</p><h3 id="一些问题"><a href="#一些问题" class="headerlink" title="一些问题"></a>一些问题</h3><ul><li>为什么要随机？</li></ul><p>为了避免富有的人越富有，有算力的节点更富有，有财产的节点更富有，公平地给予每个参与到网络中的节点，获取块奖励的机会。</p><ul><li>谁来随机？</li></ul><p>每个节点各自随机，选取一个块。而不是使用类似 Varifiable random function 的方式，让每个节点都使用确认的结果。</p><ul><li>完全随机还是有限制的随机？</li></ul><p>完全随机。</p><p>完全随机是指，节点收到 100 个块，选中某个块的概率就是 1%。有限制的随机是指，例如，上一个块已经是某个节点提供的，下一个块就不再使用它的块。相应的，块奖励也不会给它。</p><p>如果是有限制的随机，已经产生过块的节点，和没有产生过块的节点，就有了不一样的权重，无论权重侧重于哪一边，都不是合理的方式。如果产生过块的节点更有权重，依然会存在富有的人越富有的问题。如果没有产生过块的节点更有权重，网络中的参与者就会疯狂创建新的账户，使用没有获得过块奖励的节点产出块。</p><ul><li>随机会带来分叉？</li></ul><p>一定会，但分叉是小范围的。如果网络效率很高，那么只有最新的一两个块会处于不确定的状态，等大多数节点确认下来，就成为主流的一条链了。</p><ul><li>分叉会一直存在吗？</li></ul><p>不会，因为分叉会被淘汰。新加入网络的节点，肯定要选择某一个节点同步数据。对于其他节点，随机选择是指从通过验证的块中选择，通过验证的含义是，历史数据和自己一样。那么当某一条分叉链没有交易产生，由于纠错机制的存在，分叉链会不断丢弃掉自己的块，直到和主网络一致。</p><ul><li>如果新节点不同步数据呢？</li></ul><p>如果新加入的节点不同步已有数据，而是另起炉灶，那么它需要拉拢超过整个网络大多数节点规模的追随者。比如有 1000 个节点，由于完全随机的机制，它需要另外 1000 个节点，自己的链才会变为网络中的主流。这种做法可以视为攻击网络的一种方式。难度似乎比 51% 攻击还要高。</p><ul><li>存在 51% 攻击？</li></ul><p>由于块高度优先的方式加上少数服从多数的原则，可能会认为，攻击者甚至不需要 51%，只需要掌控块高度最高节点数的 51%，就可以形成攻击。</p><p>这里也许存在概念上的误区，攻击是指颠覆原有的数据而不是产生新的数据。51% 是不存在的。</p><ul><li>回滚会带来不确定性？</li></ul><p>对于用户来说，确实是不好的体验，可能上一分钟交易已经成功了，下一分钟节点丢弃了块，交易撤销了。</p><p>不过好在这种不确定是短暂的，可以认为确认一个块需要两个时间窗口或者更多个。因为即时网络中存在小范围的分叉，最终也会趋于大多数一致。</p><p>所以问题变成了客户端确认一笔交易的时机。</p><ul><li>未确认的块会造成资源浪费？</li></ul><p>一个节点收到 10 个块，确认 1 个，其他的块就浪费掉了。包括反复的纠错，也属于资源的浪费。</p><p>PoW 浪费的是算力资源，这种随机确认块的方式，浪费的是网络传输的资源，因为如果一个节点想要自己的块被确认，它首先要让其他节点接收到它的块。那么假如网络中有 1000 个节点，就需要每一轮都把块广播给 1000 个节点。</p><p>好在网络传输资源的浪费是有上限的，区块链网络本身就需要把每一笔交易广播到网络中，与其相比，现在只是需要多广播一个块的内容，算不上太大的负担。而且由于是完全随机地选择块，节点试图通过更高的网络配置来多次广播块也是没有意义的。</p><ul><li>如果网络异常，节点会丢弃所有块？</li></ul><p>如果节点获取到网络中块高度非常低，按照规则 2，是不是就会逐渐丢弃掉所有块？</p><p>不会。要区分清楚，从网络中获取到异常信息，和连接不到网络、无法从网络总获取信息，是两回事。假如一个节点的路由表中有 1000 个节点的连接记录，由于网络状况异常，只能连接到 10 个，此时就属于异常情况，节点不应该按照正常的共识流程丢弃块。</p><ul><li>有哪些已有的提案？</li></ul><p>在这篇论文《<a href="https://arxiv.org/abs/2001.07091">Blockchain Consensus Algorithms: A Survey</a>》的第 16-17 页，提到了随机选择出块节点的共识方式，以及基于 coin-age 的选择方式。这确实是一个随机的概念，但论文描述的是随机是指随机选择节点，而不是针对块，并且是在 PoS 的语境下讨论的，出块节点有被选定、被内定的意味。</p>]]></content>
  </entry>
  <entry>
    <title>“你赚不到自己认知范围外的钱。”</title>
    <link href="https://t.smallyu.net/#2022-36"/>
    <id>micro:1256918985</id>
    <published>2022-09-24T09:14:51Z</published>
    <updated>2022-09-24T09:14:51Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“你赚不到自己认知范围外的钱。”</p>]]></summary>
    <content type="html"><![CDATA[<p>“你赚不到自己认知范围外的钱。”</p>
]]></content>
  </entry>
  <entry>
    <title>按照正常的进度，还需要一年零两个月。</title>
    <link href="https://t.smallyu.net/#2022-35"/>
    <id>micro:1256876264</id>
    <published>2022-09-24T06:07:49Z</published>
    <updated>2022-09-24T06:07:49Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>按照正常的进度，还需要一年零两个月。</p>]]></summary>
    <content type="html"><![CDATA[<p>按照正常的进度，还需要一年零两个月。</p>
]]></content>
  </entry>
  <entry>
    <title>为什么不把 USDT 拿住而是换成 ETH，因为本身就是想要长期持有的。像 USDT 这种放在合约里的资产多少会有不靠谱...</title>
    <link href="https://t.smallyu.net/#2022-34"/>
    <id>micro:1256868310</id>
    <published>2022-09-24T05:33:19Z</published>
    <updated>2022-09-24T05:45:46Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>为什么不把 USDT 拿住而是换成 ETH，因为本身就是想要长期持有的。像 USDT 这种放在合约里的资产多少会有不靠谱的感觉，它的价值来自于 Tether 的背书，随着时间的推移，不知道会发生什么样的变化，短时间可能不会，但是长期持有的含义，就是去几乎忘记这件事情，不用操心市场发生了什么样的变化。 ETH 作为原生...</p>]]></summary>
    <content type="html"><![CDATA[<p>为什么不把 USDT 拿住而是换成 ETH，因为本身就是想要长期持有的。像 USDT 这种放在合约里的资产多少会有不靠谱的感觉，它的价值来自于 Tether 的背书，随着时间的推移，不知道会发生什么样的变化，短时间可能不会，但是长期持有的含义，就是去几乎忘记这件事情，不用操心市场发生了什么样的变化。</p>
<p>ETH 作为原生 token，即使没有交易价值了，也可以拿来用，虽然成本高了一点。除非 Ethereum 砸了。</p>
<p>另一方面，USDT 多没意思，ETH 价格波动那么大，就是得玩一玩。</p>
]]></content>
  </entry>
  <entry>
    <title>我只买过两次 ETH，一次是在 3400 的时候，一次是在 1700 的时候 😂 3400 那一次遇到了大熊市，跌到了...</title>
    <link href="https://t.smallyu.net/#2022-33"/>
    <id>micro:1256867562</id>
    <published>2022-09-24T05:29:48Z</published>
    <updated>2022-09-24T05:35:08Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>我只买过两次 ETH，一次是在 3400 的时候，一次是在 1700 的时候 😂 3400 那一次遇到了大熊市，跌到了 1000 附近； 1700 这一次是在 merge 前，虽然知道因为分叉会带走一点价格、缺少了矿工的硬性支撑会跌，但是长期还是看好 ETH 的生态。 没想到美联储一直加息，ETH 都 1300 了，...</p>]]></summary>
    <content type="html"><![CDATA[<p>我只买过两次 ETH，一次是在 3400 的时候，一次是在 1700 的时候 😂   </p>
<p>3400 那一次遇到了大熊市，跌到了 1000 附近；</p>
<p>1700 这一次是在 merge 前，虽然知道因为分叉会带走一点价格、缺少了矿工的硬性支撑会跌，但是长期还是看好 ETH 的生态。</p>
<p>没想到美联储一直加息，ETH 都 1300 了，美股还没见底。</p>
]]></content>
  </entry>
  <entry>
    <title>有钱真好 😂</title>
    <link href="https://t.smallyu.net/#2022-32"/>
    <id>micro:1256865246</id>
    <published>2022-09-24T05:21:49Z</published>
    <updated>2022-09-24T05:21:49Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有钱真好 😂</p>]]></summary>
    <content type="html"><![CDATA[<p>有钱真好 😂</p>
]]></content>
  </entry>
  <entry>
    <title>罗永浩的成功只是偶然。 ——认真看了罗永浩早期的自传《我的奋斗》</title>
    <link href="https://t.smallyu.net/#2022-31"/>
    <id>micro:1256862735</id>
    <published>2022-09-24T05:09:27Z</published>
    <updated>2022-09-24T05:09:27Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>罗永浩的成功只是偶然。 ——认真看了罗永浩早期的自传《我的奋斗》</p>]]></summary>
    <content type="html"><![CDATA[<p>罗永浩的成功只是偶然。  ——认真看了罗永浩早期的自传《我的奋斗》</p>
]]></content>
  </entry>
  <entry>
    <title>我给手机设置了自动换壁纸（iPhone 的捷径和自动化），随机从相册里挑出一张作为壁纸，同时从相册里删掉这个壁纸的原图片...</title>
    <link href="https://t.smallyu.net/#2022-30"/>
    <id>micro:1242651156</id>
    <published>2022-09-10T06:57:50Z</published>
    <updated>2022-09-10T06:57:50Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>我给手机设置了自动换壁纸（iPhone 的捷径和自动化），随机从相册里挑出一张作为壁纸，同时从相册里删掉这个壁纸的原图片。 发现对于不喜欢的壁纸，总是希望自动换壁纸的时间快点到来，或者嫌换壁纸的频率不够高，甚至等不及手动触发一次换壁纸。 对于喜欢的壁纸，舍不得换掉，不惜把自动换壁纸的功能关掉，而且因为壁纸的原文件已经没...</p>]]></summary>
    <content type="html"><![CDATA[<p>我给手机设置了自动换壁纸（iPhone 的捷径和自动化），随机从相册里挑出一张作为壁纸，同时从相册里删掉这个壁纸的原图片。</p>
<p>发现对于不喜欢的壁纸，总是希望自动换壁纸的时间快点到来，或者嫌换壁纸的频率不够高，甚至等不及手动触发一次换壁纸。</p>
<p>对于喜欢的壁纸，舍不得换掉，不惜把自动换壁纸的功能关掉，而且因为壁纸的原文件已经没有了，不敢再换其他壁纸。</p>
<p>所以就意识到，对于换壁纸这个事，重点不在于换的快不快、多不多，而在于到底喜不喜欢。</p>
]]></content>
  </entry>
  <entry>
    <title>读一下 vitalik 的 博客 ，可以看到很多他对以太坊的思考，以及以太坊未来有可能的技术趋势。如果感觉阅读网页比较累...</title>
    <link href="https://t.smallyu.net/#2022-29"/>
    <id>micro:1242181628</id>
    <published>2022-09-09T16:18:40Z</published>
    <updated>2022-09-09T16:18:40Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>读一下 vitalik 的 博客 ，可以看到很多他对以太坊的思考，以及以太坊未来有可能的技术趋势。如果感觉阅读网页比较累，可以把所有文章用一个 pdf 文件 打印成纸质。</p>]]></summary>
    <content type="html"><![CDATA[<p>读一下 vitalik 的 <a href="https://vitalik.ca/">博客</a>，可以看到很多他对以太坊的思考，以及以太坊未来有可能的技术趋势。如果感觉阅读网页比较累，可以把所有文章用一个 <a href="https://github.com/smallyunet/vitalik-blog-pdf">pdf 文件</a> 打印成纸质。</p>
]]></content>
  </entry>
  <entry>
    <title>VRF + BFT 共识引起交易失败的问题</title>
    <link href="https://smallyu.net/2022/09/03/VRF-BFT-%E5%85%B1%E8%AF%86%E5%BC%95%E8%B5%B7%E4%BA%A4%E6%98%93%E5%A4%B1%E8%B4%A5%E7%9A%84%E9%97%AE%E9%A2%98/"/>
    <id>blog:https://smallyu.net/2022/09/03/VRF-BFT-%E5%85%B1%E8%AF%86%E5%BC%95%E8%B5%B7%E4%BA%A4%E6%98%93%E5%A4%B1%E8%B4%A5%E7%9A%84%E9%97%AE%E9%A2%98/</id>
    <published>2022-09-02T22:39:51.000Z</published>
    <updated>2025-11-09T09:22:13.309Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>昨天遇到一个问题，是 Ontology 的节点不出块了。节点使用的是 VBFT]]></summary>
    <content type="html"><![CDATA[<p>昨天遇到一个问题，是 Ontology 的节点不出块了。节点使用的是 VBFT 共识，网络互通没有隔离，也就没有分叉，报的错是提案（proposal）过来的块，和预期的块哈希（MerkleRoot）不一样。由于种种原因，昨天的问题没有深入去查，用比较暴力的方法先让网络恢复正常。不过提到 VBFT，我想到了以前公司的一些事情。</p><p>我是在之前的公司开始接触区块链的，当时的项目号称自研区块链，也是用 VBFT（VRF + BFT）的共识，不过在共识方面不那么说，叫成 UBFT 还是什么。</p><p>我猜测 VRF + BFT 的主意是 Ontology 提出来的，我之前的公司把这种创意抄了过来，模仿着实现了一下。说来讽刺。</p><p>主要想说的是之前公司由于对 VRF + BFT 不靠谱的实现，引起的一个隐藏的 bug。那件事情距今快 2 年了，不记得当时为什么没有写博客记录一下，可能是在忙着做 PPT？昨天遇到共识相关的问题，我想起有那么一回事，正好现在有时间有心情写一下。由于过去时间太长了，细节上可能有出入。</p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>先介绍一下那个项目的情况，主打的特点有几个。</p><p>一个是异构多链，含义是可以在同一个节点上包含多条异构的链。异构是指一条链可以使用不同的共识机制、基于不同数据库运行起来。多链是指多条链可以在同一个节点上运行，因为觉得一条链不够用，一条链就相当于传统业务里的一张数据表，多条链可以方便地进行数据拆分，在联盟链的场景下更好地支持业务。异构多链，可以理解为把以太坊不同 chain id 的链，用同一个二进制包启动了。现在的某条开源联盟链，还在拿从异构多链演变来的灵活装配作为一大特点呢，猜猜为什么。</p><p>再一个是多数据库的支持，同时支持很多关系型数据库和非关系型数据库，做法是针对各种数据库，写数据操作的中间层做适配。</p><p>还有就是共识机制方面，基于开源的 Tendermint 项目。Tendermint core 是一个对 BFT 类共识的实现，在那个基础上，做的改动是把轮询选择提案节点，用 VRF 函数，替换为随机选择提案节点。另外还增加了对分层共识的支持，也就是共识组的概念，每隔多少个块换一次共识组，换共识组的方式借鉴 BFT 的流程，保证换共识组过程的安全性。分层共识这个理念也不知道起源于哪儿，可能同时期的项目流行这个？</p><p>项目的这些特点都是在我接触之前就已经开发完成的，我也只是有所了解。</p><p>我当时遇到的问题是，如果向区块链发送一笔失败交易，节点会立即返回交易失败的结果，然后如果再次发送一笔失败交易，第二笔交易的结果将迟迟不返回，节点不出块了。接下来如果仍然是失败交易，第三笔、第四笔，都会是同样的现象。这个时候，如果发送一笔正确的交易，节点会立即返回结果，之后一切恢复正常。而且这种现象是概率性出现的，并不是每一次失败交易都会引起问题。</p><h3 id="前提"><a href="#前提" class="headerlink" title="前提"></a>前提</h3><p>首先是失败交易指合约返回执行结果为失败的交易。区块链系统的交易失败有两种，一种是交易不能被执行，另一种是交易能被执行，但是合约中返回了合约层面的失败。那个项目并没有严格区分这两种失败的类型，合约有权限返回交易层面的失败，这其实是有问题的设计。</p><p>不正确的交易，将会在提案的时候，被忽略掉，因为不正确交易没有必要记录在区块链上。加上项目对失败交易错误的处理，造成的现象就是，合约执行失败的交易，会被忽略掉。这是前提。</p><p>BFT 共识的基础，是投两轮票，最终确定一个块。不管是什么 BFT，在前面加什么字母，不管通过多么复杂的流程决定出哪个节点提案、如何提案，不管对共识的效率做什么优化，是并行提案还是流水线共识什么的，只要是 BFT 类的共识，都是投票两轮。对两个阶段的命名可能不一样，不管是用 proposal 还是 prepare 来描述，都是那样一个过程。</p><p>BFT 的流程，是先有一个节点生成一个块，然后把这个块发送给其他节点，如果超过 2&#x2F;3 节点同意，会进行下一轮投票。第二轮投票如果超过 2&#x2F;3 节点同意，这个块就算确认下来了。两轮投票是理解 BFT 共识的关键。至于为什么投票两轮就可以达到 3f + 1 的容错效果、为什么至少要两轮，我也不知道。</p><p>忽略掉失败交易的操作，是在检查交易的过程中完成的。项目里有两次检查，共识前检查和共识后检查。有一些交易是没办法在共识前进行检查的，比如在合约里进行的写数据库操作，如果共识前就写库了，然后共识失败了，数据不就乱套了吗。所以只能共识后进行检查。这是第二个前提。</p><h3 id="第一笔失败交易"><a href="#第一笔失败交易" class="headerlink" title="第一笔失败交易"></a>第一笔失败交易</h3><p>我们根据 bug 的现象分析一下，第一笔失败交易的流程是正常的。一笔失败交易进来，在共识之前是不会检查出失败的，所以预提案的节点正常提出了一个块，分发给其他节点，进行第一轮投票。之后正常进行第二轮投票，在确认块的阶段，写入块之前，会进行共识之后的检查，检查过程中发现交易失败，并且这个块只包含这一笔交易，这个块就作废了，没出块。同时，其他节点也都会返回消息告诉提案节点，这个块没出来，这笔交易失败了。所以第一笔失败交易是正常返回结果的。</p><p>第二笔失败交易进来，按照同样的处理流程，一切都应该是正常的才对。因为即使是失败交易，即使是在确认块的阶段，如果检查失败了，也会广播处理结果给其他节点。整个协议中投票失败或者落块失败，都是用空消息表示。其他节点不会因为交易失败，就收不到消息苦苦等待超时。那么既然 BFT 协议的流程没有问题，为什么还是出现 bug？</p><p>这个时候要提到项目在 VRF 方面的改造。</p><p>在 BFT 的协议中，是需要一个节点去生成一个块，分发给其他节点开始进行第一轮投票的。那么由哪个节点来进行这个生成块的操作呢？总不能是同一个节点吧，那就太中心化了。Tendermint 的做法是依次进行，比如有 4 个节点，第一次节点 A，第二次节点 B，这样轮询。</p><p>VRF（Verfiable Random Function）做的事情，是改变依次选择节点的方式。因为如果按照顺序来，那很容易预测到下一轮要由哪个节点去生成块，顺序可以预测之后，就存在节点被贿赂、节点被攻击等安全隐患。VRF 的功能是参数相同结果一定相同，参数不同则结果随机。把块高度、投票的轮数作为参数，就可以很好地实现，每一个块都能由随机的节点来生成，无法预测。这个改动也是作为项目的一个亮点的。</p><p>不过 VRF 存在一个问题，既然是随机的，那就有一定可能，第一次随机到节点 A ，第二次也随机到节点 A，这样的概率还是不小的。如果节点 A 是恶意节点，然后由节点 A 连续两次生成块，会给网络带来一些负担，虽然不至于破坏网络，但也是一点小小的麻烦。所以项目为了解决这个问题，在 VRF 的基础上加了黑名单的机制。</p><p>如果上一轮是节点 A 生成块，就把节点 A 放到黑名单里。如果 VRF 的结果在黑名单里，就再 VRF 一次，避免重复选择相同的节点。</p><h3 id="第二笔失败交易"><a href="#第二笔失败交易" class="headerlink" title="第二笔失败交易"></a>第二笔失败交易</h3><h4 id="不返回结果"><a href="#不返回结果" class="headerlink" title="不返回结果"></a>不返回结果</h4><p>结合 VRF 和黑名单，再来看看第一笔失败交易发生了什么。节点 A 收到交易，会先把这笔交易广播给其他节点，然后打包成块进行投票的流程。此时节点 A 在黑名单里。投票失败后，节点 A 返回失败，并且这笔交易已经不在节点 A 的交易池里了，因为已经处理过了。</p><p>那么节点 B 呢？块里面的交易验证失败了，但是交易池里收到的交易还在，因为这笔交易还没有处理啊，处理的只是广播过来的块里面的交易。这个时候是不是应该把交易池里面的交易删掉？对，但是没删。所以造成一个问题，节点 B 被选作生成块的节点，把这笔交易打包了一下，广播了出去。这个块当然也是提案失败的。此时节点 A、节点 B 都在黑名单里。</p><p>以此类推，就这一笔交易，一轮下来，4 个节点全在 VRF 的黑名单里。但是对这笔交易结果的返回是没有影响的，因为交易结果在节点 A 的时候就已经返回了。</p><p>第二笔失败交易过来了，所有节点全在黑名单里，会发生什么？当然不能选不出节点，节点全在黑名单里，黑名单就失效了。VRF 的结果是哪个节点，就是哪个节点。</p><p>分析一下第二笔失败交易。同样是节点 A 收到交易，假如这一次是节点 B 负责生成块，然后这个块验证失败了，节点 B 就会删掉这笔交易，对吧，这个没问题。</p><p>注意，删掉交易的同时，通知客户端，交易失败了，返回交易结果。节点 B 被选中，节点 B 生成块，节点 B 返回通知。但提交这笔交易的客户端，连的是节点 A 啊！</p><p>第一笔失败交易为什么会收到响应？因为黑名单还没有失效，所有节点都处理了一遍交易，所有节点都返回了一遍交易结果。现在黑名单失效了，只有节点 B 会返回结果，所以节点 A 的客户端收不到交易结果。</p><p>那为什么黑名单失效，就不能像第一笔交易一样，所有节点都处理一遍？</p><h4 id="阻塞后续交易"><a href="#阻塞后续交易" class="headerlink" title="阻塞后续交易"></a>阻塞后续交易</h4><p>接着分析一下第二笔失败交易，节点 C 还有交易啊，节点 C 上面的这笔失败交易还没处理呢，节点 C 就开始用 VRF 选节点了。</p><p>刚才提到，此时黑名单失效，VRF 选出哪个就是哪个。刚才选出了节点 B，这一轮有没有可能再选一次节点 B？黑名单失效，就变得可能了。这个时候如果又是节点 B 负责生成块，会发生什么？</p><p>节点 B 生成不了块，因为节点 B 已经没有交易了，它已经把唯一的失败交易，在上一轮就删掉了。也就是说，在新一轮的共识过程中，4 个节点全部在等节点 B 生成块，节点 B 自己也知道该自己了，但是节点 B 拿不出块，节点 B 直接放弃这一轮共识，进入下一轮，并且节点 B 没有发出任何消息。</p><p>在分布式系统中，没有消息是一件可怕的事情。其他节点都在等节点 B 呢，节点 B 自己玩了。这个时候，节点 B 的轮数要比其他节点快一轮。</p><p>在 BFT 共识中，有两个索引值，一个是块高度，一个是共识的轮数。同一个块高度，有可能因为块没确认，就经过很多轮共识。由于节点 B 自己没生成块，轮数增加了，其他节点还不知道。</p><p>现在，所有节点都在 VRF 的黑名单里，节点 B 的共识轮数高于其他节点，</p><p>如果节点 A 再收到失败交易，有两种情况。一种情况是 VRF 又选中节点 B 了，节点 B 提出的块会被拒绝，因为其他节点还在等节点 B 上上轮的块，它拿出了高轮数的块，是对不上的。另一种情况是，VRF 选中了其他节点，那其他节点首先要等节点 B 上上轮的出块超时。超时之后，其他节点把轮数最高的数值同步一下，共识就算恢复正常了，然后 VRF 再选。</p><p>但是注意，这可是一笔失败交易，此时黑名单仍然失效，即使共识恢复正常，也还是有概率重蹈整个覆辙，节点 A 仍然收不到交易结果。至于具体的概率是多少，就懒得算了。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>可以看到，这个 bug 是由很多系统性的不合理设计共同造成的，直接原因在于 VRF 黑名单的失效，因为所有节点都在黑名单里了。或者说，黑名单没有及时清空，原先的错误之处在于，只有在块高度变化的时候才清空黑名单，可能是认为每个块的产生都应该由不同的节点来处理。这种想法的失误在于忽略了相同块高度的时候，共识的轮数也会发生变化，每一轮都会产生一个新的块。所以只要在共识轮数发生变化的时候，也清一下黑名单就好了。实际的代码改动只有两行。</p><p>上面写的东西，可能我自己也不想仔细去看，不好理解、抽象，而且文字的表达能力也弱，看起来费劲。这种类似状态机状态转换的文字描述，看起来是很痛苦的事情。尤其是内容和当时项目的耦合很深。总的来说，对于这个问题的分析和解决，我认为在逻辑上是自治的，能很好的解释成因和现象，以及用最简单的方式在表面上修复它。</p><p>时隔近 2 年的时间，我竟然还能记起来这些，感觉也是很奇怪。</p>]]></content>
  </entry>
  <entry>
    <title>一年的工作回顾</title>
    <link href="https://b.smallyu.net/2022/08/27/%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/"/>
    <id>blog-b:https://b.smallyu.net/2022/08/27/%E4%B8%80%E5%B9%B4%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%9B%9E%E9%A1%BE/</id>
    <published>2022-08-27T03:17:16.000Z</published>
    <updated>2026-05-27T07:31:08.212Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>来到公司一年多了，想要简单做一点阶段性的回顾，因为平时会把大致的工作内容记录在内部的 Confluence]]></summary>
    <content type="html"><![CDATA[<p>来到公司一年多了，想要简单做一点阶段性的回顾，因为平时会把大致的工作内容记录在内部的 Confluence 上，所以总结起来会有据可循。</p><p>一年的时间内发生了很多事情，我交到了一个很好的朋友，也因此在工作上不是那么专心，相比以前不管是工作效率还是用心程度都大打折扣。不过总的来看仍然有很大收获。</p><h3 id="State-channels"><a href="#State-channels" class="headerlink" title="State channels"></a>State channels</h3><p>来到公司的第一个月主要是熟悉项目，这个项目比之前公司的项目规模大很多很多，功能上相当于整合了 Filecoin、IPFS、Raiden Network、Ontology 等公链项目，还自己实现了类似于 libp2p 的网络模块和网络代理。一开始看起来还是有点吃力的，一方面因为代码体量大，另一方面因为确实不了解公链，虽然知道区块链本身的技术模块，但不知道什么是 Layer 2、IPFS、PoC。第一个月把项目搭建运行起来，了解了上传下载的基本流程，主要看了 p2p 网络在协议层面的交互实现，第一次知道了 DHT 是什么意思。</p><p>第二个月除了深入熟悉代码细节外，做了一件事情就是把 State channels 中的路由查找从 DFS 换成了 Dijkstra 算法。项目里有一个类似于 Raiden Network 的 Layer 2，用来解决文件下载过程中要对其他节点频繁支付的问题。改路由查找是因为这个部分相对独立，不会给整个项目带来麻烦，至于 Dijkstra 算法可以考虑路径长度做出选择而 DFS 不能，这点优化其实没有意义，因为我们 DNS 节点不会那么多，这个和 Raiden Network 完全 P2P 的模式是不一样的。</p><p>后来两个月也就是第三、四个月，主要做的事情是在 State channels 中增加手续费，在中转节点上扣掉一部分转账金额。那是一个痛苦的过程，因为我当时不懂 Layer 2 也不懂 State channels。好在用了两个月的时间还是把协议搞明白了，由于项目场景的限制不能由发起转账的节点直接验证交易，引起一些 channel 状态不稳定的情况，不过无伤大雅。</p><p>进入公司后我几乎没有请教同事关于项目的情况，不管是项目的整体架构还是具体的代码细节，全部是自己去看代码、查文档，尤其是要面对很多自己完全不了解的概念，这样做当然是有意而为之。全部自己折腾效率低是理所当然的事情，不过好处就是，在那个过程之后我可以有足够的信心，仅凭自己的实力就可以搞明白那样规模的项目，完成该做的事情。</p><p>因为我是第一次跳槽，我对自己的能力是疑惑的，不知道在之前公司的感觉是错觉还是事实，我觉得之前公司的项目不行、技术也不行，而且跳槽是有工资的增长，我多少有点心虚，想知道在进入一家新的公司后，我能不能够称职地独立应付起这样的项目，有没有实力对得起工资。请教同事是多么简单的事情！在之前的公司我也受到了很多关照，不过我希望自己有独当一面的能力，这正好是个机会，必须不依赖外部帮助去解决问题了。</p><h3 id="Solidity-合约"><a href="#Solidity-合约" class="headerlink" title="Solidity 合约"></a>Solidity 合约</h3><p>第五个月，我在纠结 Layer 2 该往什么方向优化，有点难以下手，正准备解决性能低下的问题，但也没有思路。后来得到一个需求是把项目里的原生合约用 Solidity 写一遍，因为后续有想支持 EVM 的计划。当时我不了解以太坊也不了解 Solidity，花了大概一周时间看 Solidity 文档。</p><p>第六个月也就是今年一月份，用 Solidity 重写合约，那其实是一段愉快的时间，因为不太需要思考做什么、怎么做，照着现成的写就行，产出的代码量还大。只是用不同的编程语言，你知道的，换编程语言没什么压力。</p><p>第七个月今年二月份，在节点的 SDK 中加入对以太坊 SDK 的支持。折腾了一下以太坊的测试网发现不太好用，最后还是先用节点的开发模式了。</p><p>Solidity 虽然语法容易理解，但是由于 EVM 的限制，也有很多需要注意的问题，以及很多语言上的细节需要时间不断熟悉，当时用一个月写完合约，后面却断断续续用了不少时间去修改完善。总之在那个过程里，那个需求上，我学会了写 Solidity 合约，熟悉了以太坊智能合约的开发，尽管对于生产级别的合约安全问题还缺少经验。</p><h3 id="文件夹上传下载"><a href="#文件夹上传下载" class="headerlink" title="文件夹上传下载"></a>文件夹上传下载</h3><p>今年三月份开始，做的一件事情是文件夹的上传下载。这个想法的起点是项目对 Git 的支持，想要支持 Git 协议，能够直接用 git 命令克隆 Git 仓库，结果发现普通文件夹的上传下载都没有，只有对文件的上传下载。</p><p>我们的项目用了一部分 IPFS 的 IPLD 协议，把文件转换成块进行传输，但是没有用 IPFS 的文件管理部分。IPFS 有一层针对文件系统操作的 API，可以统一处理文件和文件夹，数据结构之间还能方便地互相转化。我们是直接读取文件转化成块的，这也给文件夹上传下载的实现增加了难度。</p><p>这件事情一直断断续续持续至今，因为总是不断有各种各样的小问题出现，也感谢测试同事耐心的配合。文件夹的处理比单个文件复杂一点点，因为文件夹会存在无限的嵌套，文件夹内同时包含文件和文件夹，子文件夹内还会有文件和文件夹。以及其他问题像空文件夹、大文件的处理。</p><p>IPLD 节点储存在 Merkle DAG 的数据结构中，单个文件会生成一个 Merkle Tree，而文件夹需要做的是在上传的时候，把多个 Merkle Tree 组织起来成为同一个树，然后在下载的时候根据这个树反序列化成文件夹、把内容写入到磁盘上。</p><p>其实实现思路是简单的，这个树结构中有数据块 raw node 和用来做中间节点连接数据块的 proto node，只要把文件夹相关的额外信息写到 proto node 的 links 中，就可以把文件之间的关联信息储存传输到其他节点了。</p><p>不过在具体的实现过程中花了不少功夫，也绕了一些弯路，比如上传生成块的时候因为添加了额外的数据导致块数据验证不成功，不能生成完整的树结构，不得不深入到 IPLD 的代码里 debug；下载的时候对块数据的解析不熟悉，也没有意识到节点之间块数据的传输是没有顺序的，在功能不成功的时候一度怀疑整体思路出了问题。</p><p>由于块数据的传输是无序的，就需要在下载的时候自己整理块的顺序，排序过程中因为搞混了树的层序遍历和前序遍历，一开始深度优先生成顺序发现总是有几个块的位置错乱，debug 了好久才定位到问题改成广度优先。</p><p>这是一个无关紧要但是有意思的功能，在这个过程中加深了对文件的上传下载的了解。</p><h3 id="文件的非对称加密"><a href="#文件的非对称加密" class="headerlink" title="文件的非对称加密"></a>文件的非对称加密</h3><p>今年四五月份疫情严重，居家办公一个多月，做的事情是文件对非对称加密的支持，之前只支持 AES 的对称加密。</p><p>这个没太多可说的，就是要注意 ECDSA 是数字签名算法，没有加解密这回事，要用 ECIES 之类的混合模式，结合对称加密去实现对文件的非对称加解密。</p><h3 id="支持以太坊账户"><a href="#支持以太坊账户" class="headerlink" title="支持以太坊账户"></a>支持以太坊账户</h3><p>今年六七八月份，重点关注新 Layer 2 的方案，想要实现基于 Optimistic rollups 的 Layer 2。</p><p>Rollups 部分还没怎么动，目前停留在存储节点对以太坊账户的支持上。这一段不短的时间内，除了编译运行一下 Optimism 的项目、增加储存节点对多种网络模式的选项，还花了不少时间完善之前的 Solidity 合约、解决像合约大小超过限制需要拆分、节点真实运行过程中合约结果和预期不符等问题。</p><p>由于账户地址和公私钥都变成了另外一种格式，储存节点的协议消息也需要使用另外的签名方法，这些内容的改动都还在进行中。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>其实没多少事情，但也没怎么闲着。不算太认真，但也收获很多。</p>]]></content>
  </entry>
  <entry>
    <title>最近一段时间都在玩，得专心搞技术了 😂</title>
    <link href="https://t.smallyu.net/#2022-28"/>
    <id>micro:1221500719</id>
    <published>2022-08-21T08:47:18Z</published>
    <updated>2022-08-21T08:47:18Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最近一段时间都在玩，得专心搞技术了 😂</p>]]></summary>
    <content type="html"><![CDATA[<p>最近一段时间都在玩，得专心搞技术了 😂</p>
]]></content>
  </entry>
  <entry>
    <title>为什么要重视编程思想</title>
    <link href="https://smallyu.net/2022/07/24/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E9%87%8D%E8%A7%86%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3/"/>
    <id>blog:https://smallyu.net/2022/07/24/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E9%87%8D%E8%A7%86%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3/</id>
    <published>2022-07-24T14:53:55.000Z</published>
    <updated>2025-08-22T08:54:30.259Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="（1）"><a href="#（1）" class="headerlink" title="（1）"></a>（1）</h3><p>前两天遇到一个小问题，Solidity 写的智能合约超过 24 KB，不能部署到以太坊主网上，因为 EVM]]></summary>
    <content type="html"><![CDATA[<h3 id="（1）"><a href="#（1）" class="headerlink" title="（1）"></a>（1）</h3><p>前两天遇到一个小问题，Solidity 写的智能合约超过 24 KB，不能部署到以太坊主网上，因为 EVM 对合约的代码小小有限制。于是考虑怎么减小合约的大小，当时对合约大小的概念都是模糊不清的。</p><p>其中注意到一个地方，合约是可以引入其他合约、调用其他合约方法的，只需要把部署后的合约地址作为参数传到合约里：</p><pre><code class="solidity">contract Demo &#123;&#125;contract Main &#123;    Demo demo;    constructor(Demo _demo) public &#123;        demo = _demo;    &#125;&#125;</code></pre><p>合约大小包括引入的合约吗？EVM 在执行合约的时候，会不会先把其他合约的代码也加载进来，然后一起运行？代码大小的计算要包括所有合约？那可就麻烦了。</p><p>后来注意到，可以使用接口替代合约：</p><pre><code class="solidity">contract IDemo &#123;&#125;contract Demo is IDemo &#123;&#125;contract Main &#123;    IDemo demo;    contract(IDemo _demo) public &#123;        demo = _demo;    &#125;&#125;</code></pre><p>接口的代码量一定是少于具体实现的，因为接口不包含方法体，把引入的合约全部替换成接口，合约不就小多了？</p><p>当然，在这里纠结的不是 Solidity 合约怎么写或者合约代码大小怎么计算的问题，后来搞清楚了。比较在意的是，那个时候突然有点恍惚，用接口和直接用合约，有什么区别？</p><p>之前给合约定义接口是为了提供一个对外方法的描述，这里才意识到接口可以替代合约本身，直接用来定义变量，并且使用接口定义的变量，去调用合约里面的方法。但为什么可以呢，它不就只是一个接口吗？</p><h3 id="（2）"><a href="#（2）" class="headerlink" title="（2）"></a>（2）</h3><p>如果你刚学习过 Java，或者使用 Java 作为工作语言，一定会有哑然失笑的感觉，这个问题太幼稚了，这不就是多态吗？</p><p>上第一节 Java 的课程，老师就告诉我们，面向对象有三大特性，封装、继承、多态，这句话时至今日我都能想起来，这是多么基础的概念，结果在工作多年后的今天，我竟然在实际工作上因为如此简单的问题犯了难，一时没反应过来，用接口作为类型的写法是什么意思。这太荒唐了。可能也是因为很久没写 Java，现在一直在用 Golang。</p><p>不得不说 Java 是面向对象编程语言的标杆，Solidity 虽然是一种看似新的用于智能合约的脚本语言，揉杂了多种语言的特性，但基本的编程思想还是基于面向对象的。合约就是类，部署一个合约就是实例化了一个对象，合约地址就是对象的内存地址，合约调用就是对象的方法调用……</p><p>只要是支持面向对象的编程语言，就包含有面向对象的特性，就可以使用面向对象的写法，就离不开最基本的像多态一样的特性。从面向对象的角度去理解，Solidity 有什么难的呢？无非不就是换了一些表面上的形式，编程思路甚至可以一模一样，此外再添上一些区块链特有的概念，像转账、块高度之类，就没了。</p><p>从编程语言的角度看，Solidity 和 Java 那样成熟的语言自然没法比，面向对象的特性是残缺的，modifier、require 之类的写法看似好用却增加了很多理解成本，而且代码结构也变得不是太统一。EVM 怎么能和 JVM 相提并论呢？但作为一种轻量级的脚本语言，Solidity 又要使用静态类型那样冗余的写法。</p><p>当然要注意，编程思想是先于编程语言的，我仍然会认为形式上的编程语言<a href="/2022/02/16/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%AD%A6%E4%B9%A0%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/">不值得学习</a>，但是不否认从学习编程语言的角度入手去学习编程思想。比如<a href="https://en.wikipedia.org/wiki/Polymorphism_(computer_science)">多态</a>这个概念，含义是使用统一的符号去代表不同的类型，包括三种类型的解释，一是支持多种类型的参数，对应 Java 里方法的重载，二也是支持多种类型的参数，对应 Java 里的范型，三是子类型，也就是把接口作为类型，对应上面提到的场景中的多态的含义。</p><p>面向对象是一种编程思想，包含很多计算机科学的概念，而 Java 是一种完全的面向对象的编程语言，不但涵盖众多有用的特性，而且实现的完整漂亮，如果你学习了 Java，自然也就知道面向对象是怎么回事了，受用无尽。从这个角度看，和 Java 相比，Golang 有什么值得学习的地方吗？是 struct 的写法还是 * 号的用法？可能 Golang 更像是一种快餐式的语言吧，可以很方便地 go func()。不过要是为了学习，就不是太推荐了。</p><p>花了几分钟看 Java 文档的目录，倒是能很快想起来那些内容，毕竟实在是太基础了。也是要告诫自己，别忘了代码怎么写。</p>]]></content>
  </entry>
  <entry>
    <title>如果你没有经历过枯燥的生活，当你看到别人精彩的生活，是不会感到羡慕，也不会感到遗憾的，你不会去想，如果我的生活精彩一点就...</title>
    <link href="https://t.smallyu.net/#2022-27"/>
    <id>micro:1172870480</id>
    <published>2022-07-02T09:46:44Z</published>
    <updated>2022-07-02T09:52:07Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果你没有经历过枯燥的生活，当你看到别人精彩的生活，是不会感到羡慕，也不会感到遗憾的，你不会去想，如果我的生活精彩一点就好了！因为你的生活本就精彩。 这是一个悖论，想要感受到遗憾，就必须经历遗憾。如果经历是没有遗憾的，也就不会感受到遗憾。同时，没有遗憾自然也就没有精彩。 所以，安心地去羡慕别人吧！</p>]]></summary>
    <content type="html"><![CDATA[<p>如果你没有经历过枯燥的生活，当你看到别人精彩的生活，是不会感到羡慕，也不会感到遗憾的，你不会去想，如果我的生活精彩一点就好了！因为你的生活本就精彩。</p>
<p>这是一个悖论，想要感受到遗憾，就必须经历遗憾。如果经历是没有遗憾的，也就不会感受到遗憾。同时，没有遗憾自然也就没有精彩。</p>
<p>所以，安心地去羡慕别人吧！</p>
]]></content>
  </entry>
  <entry>
    <title>有的人，世界很大，生活动态分享面向全网，很多人关注，都是陌生人。 有的人，世界很小，生活动态分享面向家人朋友，关注的人不...</title>
    <link href="https://t.smallyu.net/#2022-26"/>
    <id>micro:1172790017</id>
    <published>2022-07-02T00:00:12Z</published>
    <updated>2022-07-02T00:00:12Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有的人，世界很大，生活动态分享面向全网，很多人关注，都是陌生人。 有的人，世界很小，生活动态分享面向家人朋友，关注的人不多，都是……</p>]]></summary>
    <content type="html"><![CDATA[<p>有的人，世界很大，生活动态分享面向全网，很多人关注，都是陌生人。<br>有的人，世界很小，生活动态分享面向家人朋友，关注的人不多，都是……</p>
]]></content>
  </entry>
  <entry>
    <title>有人喜欢用微信来管理人际关系，这显然是不合适的，微信本身的可靠性就成问题，微博被禁言也提醒我们，国内平台普通用户是没有自...</title>
    <link href="https://t.smallyu.net/#2022-25"/>
    <id>micro:1169453684</id>
    <published>2022-06-29T02:04:44Z</published>
    <updated>2022-06-29T02:04:44Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有人喜欢用微信来管理人际关系，这显然是不合适的，微信本身的可靠性就成问题，微博被禁言也提醒我们，国内平台普通用户是没有自由的，加上今年开始国内开始全平台显示 IP 归属地，言论管控越来越紧。 这种时候就意识到 SSI 的理念有多么珍贵，期待 Web 3.0 到来的一天。我们是旧时代的残党，但走在正确的道路上。</p>]]></summary>
    <content type="html"><![CDATA[<p>有人喜欢用微信来管理人际关系，这显然是不合适的，微信本身的可靠性就成问题，微博被禁言也提醒我们，国内平台普通用户是没有自由的，加上今年开始国内开始全平台显示 IP 归属地，言论管控越来越紧。</p>
<p>这种时候就意识到 SSI 的理念有多么珍贵，期待 Web 3.0 到来的一天。我们是旧时代的残党，但走在正确的道路上。</p>
]]></content>
  </entry>
  <entry>
    <title>突然发现在新浪微博的账号被禁言 14 天，但是没有收到任何原因说明，问客服也没有结果。 我的微博阅读量平均不超过 500...</title>
    <link href="https://t.smallyu.net/#2022-24"/>
    <id>micro:1166828746</id>
    <published>2022-06-27T04:26:25Z</published>
    <updated>2022-06-27T04:26:25Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>突然发现在新浪微博的账号被禁言 14 天，但是没有收到任何原因说明，问客服也没有结果。 我的微博阅读量平均不超过 500，近期也没有发什么内容，被禁言而且没有说明是很奇怪的事情。我在一两个月前发过暗讽动态清零的内容，但是尺度不大，到现在也很长时间了，没什么理由到现在才封我。 想不到现在国内的言论环境，不讲理到这种程度了...</p>]]></summary>
    <content type="html"><![CDATA[<p>突然发现在新浪微博的账号被禁言 14 天，但是没有收到任何原因说明，问客服也没有结果。</p>
<p>我的微博阅读量平均不超过 500，近期也没有发什么内容，被禁言而且没有说明是很奇怪的事情。我在一两个月前发过暗讽动态清零的内容，但是尺度不大，到现在也很长时间了，没什么理由到现在才封我。</p>
<p>想不到现在国内的言论环境，不讲理到这种程度了，百闻不如一见。</p>
]]></content>
  </entry>
  <entry>
    <title>当年在学校的时候学 node.js，跟着教程做了两三个 React.js、Vue.js 的项目，放到了 GitHub 上...</title>
    <link href="https://t.smallyu.net/#2022-23"/>
    <id>micro:1162576108</id>
    <published>2022-06-22T02:54:08Z</published>
    <updated>2022-06-22T02:54:53Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>当年在学校的时候学 node.js，跟着教程做了两三个 React.js、Vue.js 的项目，放到了 GitHub 上。后来考虑到那些项目不是自己的，只是学习而已，就删了。当时觉得那只是个开始，而且只花了不到一个月的时间，删就删了，以后会有更多更好的项目的。 再后来想起来，老后悔了。要是能留下来，也是一些很好的学习记...</p>]]></summary>
    <content type="html"><![CDATA[<p>当年在学校的时候学 node.js，跟着教程做了两三个 React.js、Vue.js 的项目，放到了 GitHub 上。后来考虑到那些项目不是自己的，只是学习而已，就删了。当时觉得那只是个开始，而且只花了不到一个月的时间，删就删了，以后会有更多更好的项目的。</p>
<p>再后来想起来，老后悔了。要是能留下来，也是一些很好的学习记录。于是从那件事情中学到一个道理：不要轻易删除网上的东西，没准以后会用到。</p>
<p>今天在某个平台看到自己 2018 年贴出来的已经 404 的仓库链接了 😂</p>
]]></content>
  </entry>
  <entry>
    <title>越了解一些东西，就越找不到可靠的信息源，因为没有人是对的……</title>
    <link href="https://t.smallyu.net/#2022-22"/>
    <id>micro:1161768901</id>
    <published>2022-06-21T13:43:36Z</published>
    <updated>2022-06-21T13:43:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>越了解一些东西，就越找不到可靠的信息源，因为没有人是对的……</p>]]></summary>
    <content type="html"><![CDATA[<p>越了解一些东西，就越找不到可靠的信息源，因为没有人是对的……</p>
]]></content>
  </entry>
  <entry>
    <title>对 Web 3.0 的理解</title>
    <link href="https://smallyu.net/2022/06/19/%E5%AF%B9Web3.0%E7%9A%84%E7%90%86%E8%A7%A3/"/>
    <id>blog:https://smallyu.net/2022/06/19/%E5%AF%B9Web3.0%E7%9A%84%E7%90%86%E8%A7%A3/</id>
    <published>2022-06-19T11:47:30.000Z</published>
    <updated>2025-11-09T09:22:13.447Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="Web-3-0-开发"><a href="#Web-3-0-开发" class="headerlink" title="Web 3.0 开发"></a>Web 3.0 开发</h3><p>Web 3.0]]></summary>
    <content type="html"><![CDATA[<h3 id="Web-3-0-开发"><a href="#Web-3-0-开发" class="headerlink" title="Web 3.0 开发"></a>Web 3.0 开发</h3><p>Web 3.0 是一个几年前就存在的概念，可能随着区块链的推广越来越有名了。当人们还不知道 3.0 版本的 Web 会是什么样子的时候，区块链出现了，尤其是以太坊的 dApp 提供了一种很大的可能性，于是 Web 3.0 就和区块链、去中心化、自我主权这些概念绑定在一起。</p><p>前几天<a href="https://smallyu.net/micro-blog/#2022-18">提到</a>说。「Web 3.0 开发」是可以作为一种职业定位去描述的，而且这个词可以涵盖区块链开发的范畴，立意比「区块链开发」这个描述高一点。</p><p>Web 2.0 时代，我们说的 Web 开发指普通的前后端开发，前端用所谓的三大框架 React.js、Vue.js、Angular.js 结合组件库，后端用 Spring 全家桶，加上各种中间件 Zookeeper、Kafka、Elasticsearch 之类，还有常用的数据库 MySQL、Oracle，就是 Web 开发的常用技术栈。</p><p>Web 3.0 开发的技术栈，可能会演进为 Remix、Hardhat、Ruffle 这些智能合约的开发工具和框架，人们像关注 Java 的语言特性一样去关注 Solidity，以及各种区块链节点的搭建运行调用、二次开发，甚至及区块链节点本身的开发等等。当然，很难简单地把这些技术栈去和 Web 2.0 一一对应。一个简单的例子是，当你从事区块链开发的工作，你已经很难用前端开发或者后端开发来形容自己的工作内容了，就只能是区块链开发，或者智能合约开发，或者其他的描述方式。</p><p>现在已经有一些岗位在用「web3 开发」的形容了，不过我们要区分清楚 Web 3.0 和 web3 不是一回事，目前很多岗位说的 web3 指以太坊的那个 web3 框架。我们需要一个新的描述，同时我们需要有一个更好的、更有前景的职业定位，那就是 Web 3.0 开发。</p><p>我这里想说的是，要相信我们走在正确的道路上。</p><h3 id="一级市场和二级市场"><a href="#一级市场和二级市场" class="headerlink" title="一级市场和二级市场"></a>一级市场和二级市场</h3><p>区块链的一级市场，指比特币、以太坊这种原生的链。二级市场更多是基于这些链，衍生出的一些项目，基于以太坊的项目尤其多，Layer 2、预言机、NFT、ENS，都属于二级市场。</p><p>有一些团队是做一级市场也就是区块链开发的，Solana、Filecoin、Neo 都是在以太坊之后出现的，Dfinity 的 IC 也是处于活跃的一种一级市场的例子，再比如像 Bitcoin SV 是在做 “支持智能合约的比特币” 这样的事情。</p><p>还有很多创业团队是在做二级市场，比如有从 360 出来的去做智能合约的安全，把合约扫描一遍报出安全漏洞给你；还有做 NFT 的交易协议，去定制一些类似 NFT 交易所的 API，想建立通用的交易网络；还有炒元宇宙概念的，给虚拟人物定制不同样式的衣服；也有基于 IC 做去中心化邮箱的等等。以太坊的各种扩容方案当然也算二级市场，OP 前段时间还发行 token 了。</p><p>从商业角度没有什么高下之分，从技术角度也不好说简单和难，不过我觉得还是一级市场更基础一些，但是技术上的发展相对缓慢，花样没那么多。具体倾向于哪一种看个人意愿了，这里想提醒的是，Web 3.0 开发是统称，要了解这些不同层级市场的区别。</p><h3 id="去中心化是历史的倒退"><a href="#去中心化是历史的倒退" class="headerlink" title="去中心化是历史的倒退"></a>去中心化是历史的倒退</h3><p>刚才说希望 Web 3.0 是有前景的方向，这个部分想说的是 Web 3.0 的前景也没有那么好。</p><p>想到这个话题是在关心钱包安全的时候，意识到一个问题，就是账户的私钥一旦泄露，你就永远失去了对账户资产的控制权，或者说别人永远拥有了你账户资产的控制权。</p><p>因为我们知道，账户地址是可以从私钥解码出来的，私钥就是你的资产，在备份钱包的时候，备份的就是私钥。你的私钥泄露，就相当于把金钱摆到别人手里，至于别人会不会及时拿走，你能不能在对方动手之前抢回来，那就是另外的问题了。</p><p>这个和传统的账户模型是不一样的，你不可能说你的用户密码是你的财产，因为中心化账户是基于 KYC 的，你只要能证明自己的身份，身份证或者指纹或者长相，都可以找回你的财产，因为财产是和你绑定在一起，而不是你的账户，你的账户密码是可以修改的，即使泄露，别人也只能在短时间内拥有你账户的控制权，你把密码改掉，别人就没办法了。</p><p>私钥是不可能更改的，你能做的，就是及时把资产转移到另外的私钥。去中心化的世界有意区分了身份和数字身份的概念，增加了数字身份的主权，但同时也削弱了身份对数字身份的控制能力。</p><p>这里衍生出的问题就是，去中心化的资产安全吗？把钱拿在自己手里，比把钱存到银行，更加安全吗？考虑到比特币诞生的背景，是出于对中心化机构的不信任，才有了去中心化的理念。</p><p>想想吧！一开始就是没有中心化机构的，人们以物换物，打一开始，就是去中心化的世界。后来为了降低个人保护自己财产的成本，为了增加对坏人作恶更有力的惩罚机制，人们共同组建起中心化机构，保护大部分人的利益。</p><p>现在炒作去中心化的理念，不正是一种历史的倒退吗？去中心化并非新产生的事物，而是早就已经存在的、被人们选择性抛弃的东西。</p><p>不过现在的去中心化和以前的去中心化，最大的不同就是现在的技术手段更为先进，有可能做到之前做不到的事情，把世界推到一种新的愿景上。但是也要注意现在的技术不是那么先进，还远没有发展到那种程度，区块链的技术瓶颈非常多。</p><p>所以我的观点是，现在的去中心化理念不是中心化世界的演进，而是中心化世界的补充。在接下来的时间，中心化和去中心化会同时存在。</p><p>要注意的是，去中心化不等于 Web 3.0，Web 3.0 是 Web 2.0 的演进，因为版本号增加了。Web 3.0 将是中心化和去中心化同时存在的时代。 </p><h3 id="LUNA-归零"><a href="#LUNA-归零" class="headerlink" title="LUNA 归零"></a>LUNA 归零</h3><p>前段时间有一件搞笑的事情，有一天，LUNA 的价格早上还是 80 美元一个，晚上的时候就跌到 1 美元一个了。在接下来的三四天，LUNA 的价格从 1 美元，跌到了 0.00001 美元。几天之内，近万倍的跌幅。曾经号称前十的加密货币，突然归零了。</p><p>我粗浅的理解是，UST 有一个交易池，当短时间有大量卖出的时候，交易池会有小幅的倾斜。当时先是小幅的波动，然后随着社交媒体的传播，大量散户失去了对 UST 的信任，开始大幅卖出，越卖价格越低。Terra 团队是有 5 万个比特币作为储备的，当时也及时打进去想把平衡拉回来，结果比特币也在跌，质押进去的比特币在结算的时候已经不值预期那么多钱了，没能把价格拉回来，后来 Terra 团队也放弃了，任由价格下跌。</p><p>LUNA 的事情发生后不久，看到有的人讨论说，LUNA 还有机会吗？有一种机会是，Terra 团队还有 20 亿，等 UST 的价格跌到总市值小于 20 亿的时候，Terra 团队可以把市场上所有 UST 都买下来，销毁掉多余的 UST，只留 20 亿个，UST 的价格就可以回到 1 美元了。不过 Terra 团队可能没打算那么做，后来发行了新的 LUNA。</p><p>LUNA 的失败不意味着算法稳定币的失败，有的团队也在研发新的算法稳定币，据说是想把美联储的运行模式，用算法模拟出来，正在写白皮书。</p><p>在 Web 3.0 宏大的时代背景下，LUNA 的事情就算是先行的笑料吧。</p><h3 id="Web5"><a href="#Web5" class="headerlink" title="Web5"></a>Web5</h3><p>最近新出一个 Web5 的概念，就是 Web 5.0 的意思。提出这个概念的人<a href="https://blog.web3labs.com/web5">说</a>，跳过 Web4 是因为 Web2 + Web3 &#x3D; Web5。好家伙，不愧是 Web5，提出 Web5 的能是一般人吗？但凡对软件工程有了解的敢这么说？</p><p>简而言之，我的结论是，Web5 一定不会成功。不管它叫 Web5 还是 Web6、Web7，它的理念还是围绕去中心化、SSI 那一套，还在我理解的 Web 3.0 的范畴之内。如果认真了解过 DIDs 的理念，就知道现阶段所谓的 Web5 完全是噱头了。</p>]]></content>
  </entry>
  <entry>
    <title>你不应该对对你具有成长意义、让你学会成长、让你变得更好的人，怀有恨意、没有耐心、不去包容，你应该对对方好、相信对方、不再...</title>
    <link href="https://t.smallyu.net/#2022-21"/>
    <id>micro:1159440869</id>
    <published>2022-06-18T10:31:06Z</published>
    <updated>2022-06-18T10:31:06Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>你不应该对对你具有成长意义、让你学会成长、让你变得更好的人，怀有恨意、没有耐心、不去包容，你应该对对方好、相信对方、不再怀疑、不再放弃，并且坚信自己在做正确的事情。 就此定调。</p>]]></summary>
    <content type="html"><![CDATA[<p>你不应该对对你具有成长意义、让你学会成长、让你变得更好的人，怀有恨意、没有耐心、不去包容，你应该对对方好、相信对方、不再怀疑、不再放弃，并且坚信自己在做正确的事情。</p>
<p>就此定调。</p>
]]></content>
  </entry>
  <entry>
    <title>今年博客和微博的更新频率都相对低一点，一方面是因为很多内容分散到其他平台了，另一方面是因为，今年以来确实关注了很多技术之...</title>
    <link href="https://t.smallyu.net/#2022-20"/>
    <id>micro:1159363990</id>
    <published>2022-06-18T05:07:31Z</published>
    <updated>2022-06-18T05:07:31Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>今年博客和微博的更新频率都相对低一点，一方面是因为很多内容分散到其他平台了，另一方面是因为，今年以来确实关注了很多技术之外的、人际关系类的问题。 其实我以前的戾气实在是很重了，而且处于对人际关系和人际交往没有概念的一种状态。 相信明天会更好。</p>]]></summary>
    <content type="html"><![CDATA[<p>今年博客和微博的更新频率都相对低一点，一方面是因为很多内容分散到其他平台了，另一方面是因为，今年以来确实关注了很多技术之外的、人际关系类的问题。</p>
<p>其实我以前的戾气实在是很重了，而且处于对人际关系和人际交往没有概念的一种状态。</p>
<p>相信明天会更好。</p>
]]></content>
  </entry>
  <entry>
    <title>知道一个单词什么意思的前提是，要先认识这个单词，在确保各种不同的语境下面，能看出来是相同的一个词，再去查它的意思，也不晚...</title>
    <link href="https://t.smallyu.net/#2022-19"/>
    <id>micro:1154654824</id>
    <published>2022-06-14T02:58:20Z</published>
    <updated>2022-06-14T02:58:20Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>知道一个单词什么意思的前提是，要先认识这个单词，在确保各种不同的语境下面，能看出来是相同的一个词，再去查它的意思，也不晚。不然即使你知道它的意思了，但是你看到的时候根本认不出来，完全没有意义。 就像人的名字，你要先认得出来一个人，再知道他的名字。光知道有那么个人，他的名字是什么，但是马路上见了也认不出来，不也没有意义吗...</p>]]></summary>
    <content type="html"><![CDATA[<p>知道一个单词什么意思的前提是，要先认识这个单词，在确保各种不同的语境下面，能看出来是相同的一个词，再去查它的意思，也不晚。不然即使你知道它的意思了，但是你看到的时候根本认不出来，完全没有意义。</p>
<p>就像人的名字，你要先认得出来一个人，再知道他的名字。光知道有那么个人，他的名字是什么，但是马路上见了也认不出来，不也没有意义吗。</p>
]]></content>
  </entry>
  <entry>
    <title>一个新的代表职业定位的名称：Web 3.0 开发。 Web 3.0 开发涵盖了区块链开发的范畴，因为区块链是 Web 3...</title>
    <link href="https://t.smallyu.net/#2022-18"/>
    <id>micro:1153423254</id>
    <published>2022-06-13T03:25:56Z</published>
    <updated>2022-06-13T03:57:43Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>一个新的代表职业定位的名称：Web 3.0 开发。 Web 3.0 开发涵盖了区块链开发的范畴，因为区块链是 Web 3.0 的基础设施，要参与 Web 3.0 的建设，开发区块链或者智能合约是其中一环。 传统的 Web 开发指 Web 2.0 的前后端开发。当然，要注意 Web 3.0 和 Web3 是两回事。</p>]]></summary>
    <content type="html"><![CDATA[<p>一个新的代表职业定位的名称：Web 3.0 开发。</p>
<p>Web 3.0 开发涵盖了区块链开发的范畴，因为区块链是 Web 3.0 的基础设施，要参与 Web 3.0 的建设，开发区块链或者智能合约是其中一环。</p>
<p>传统的 Web 开发指 Web 2.0 的前后端开发。当然，要注意 Web 3.0 和 Web3 是两回事。</p>
]]></content>
  </entry>
  <entry>
    <title>人际交往中的心态问题</title>
    <link href="https://crazy.smallyu.net/2022/05/25/%E4%BA%BA%E9%99%85%E4%BA%A4%E5%BE%80%E4%B8%AD%E7%9A%84%E5%BF%83%E6%80%81%E9%97%AE%E9%A2%98/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2022/05/25/%E4%BA%BA%E9%99%85%E4%BA%A4%E5%BE%80%E4%B8%AD%E7%9A%84%E5%BF%83%E6%80%81%E9%97%AE%E9%A2%98/</id>
    <published>2022-05-25T15:31:50.000Z</published>
    <updated>2025-08-16T03:27:11.370Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<h3 id="1"><a href="#1" class="headerlink" title="1"></a>1</h3><p>我刚才想到一个问题，有点想不通。</p>
<p>假如你有一个价值 10 块钱的东西，另一个人拿出价值 5]]></summary>
    <content type="html"><![CDATA[<h3 id="1"><a href="#1" class="headerlink" title="1"></a>1</h3><p>我刚才想到一个问题，有点想不通。</p><p>假如你有一个价值 10 块钱的东西，另一个人拿出价值 5 块钱的东西，非常想和你交换，那么这个时候，你愿意换吗？</p><blockquote><p>那我肯定不会跟他交换呀，你既然要跟我交换，你肯定得等价交换呀，那凭什么那个什么，我这个比你的这个价值高，你拿价值低的跟我交换，这对于我来说不公平啊，我不会跟他交换。</p></blockquote><h3 id="2"><a href="#2" class="headerlink" title="2"></a>2</h3><p>这个时候你有两种做法，</p><p>一种是，拿出价值 5 块钱的东西，和他交换，剩 5 块，得到一个东西；</p><p>另一种是，不交换，剩 10 块，没有得到东西，等有人愿意拿出 10 块钱的东西，再换。</p><p>选哪一种？</p><blockquote><p>这个就是因情况而定，如果我特别着急，想跟人家交换东西嘛，然后我可能选择第一个，因如果说我不想着急交换，我对这个东西还挺喜欢的，那么慢慢儿等呗。</p></blockquote><h3 id="3"><a href="#3" class="headerlink" title="3"></a>3</h3><p>换另一个问题，</p><p>假如一个人有 10 块钱，愿意把 10 块钱都拿出来，在某一个时间点拿了 3 块出来；</p><p>另一个人也有10块钱，总共愿意拿 5 块钱出来，在相同的时间点，把 5 块钱都拿出来了。</p><p>表面上拿出来的 5 块大于 3 块，但是他们后面的意愿是不一样的。</p><p>你觉得他们，谁的代价更大一点?</p><blockquote><p>应该是第一个，代价大呀，他愿意把他的全部都给我，只是可能那一段时间有困难吧，只能拿出三块钱，但他之后也愿意拿出七块钱都给我呀，所以他付出的代价更大一点呀。第二个，我感觉他怎么说呢，虽然有，但他并不是全部都给我呀。</p></blockquote><h3 id="4"><a href="#4" class="headerlink" title="4"></a>4</h3><p>如果你只需要 5 块呢，多了也没用。</p><p>情况就不一样了。</p><blockquote><p>我觉得越多越好。我比较贪心。</p></blockquote><h3 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h3><p>如果你只需要 5 块钱，但是有人愿意给你 10 块钱。</p><p>他知道你只需要 5 块钱吗？</p><p>如果知道，他的意愿就是自作多情。</p><p>如果不知道，你为什么没有告诉他？</p><h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>没有朋友的人，有 10 块钱。有朋友的人，只剩 5 块钱。没有朋友的人，应该拿 5 块出来，还是等 10 块钱的人？</p><p>没有对象的人，有 10 块钱。有对象的人，只剩 5 块钱。没有对象的人，如果愿意拿 10 块出来，即使现在只拿出 3 块，你的 5 块怎么比？</p><h3 id="备注"><a href="#备注" class="headerlink" title="备注"></a>备注</h3><p>上述钱的单位是相同的，不存在汇率问题。</p><h3 id="延伸"><a href="#延伸" class="headerlink" title="延伸"></a>延伸</h3><p>如果考虑汇率的不同，每个人钱总量、剩余数量的不同，以及随着时间的变化，这些变量都会改变，问题更复杂一点。</p><br><h1 id="补充一个案例"><a href="#补充一个案例" class="headerlink" title="补充一个案例"></a>补充一个案例</h1><div class="time">2022-06-18</div><h3 id="5"><a href="#5" class="headerlink" title="5"></a>5</h3><p>假如你现在被关在监狱里，痛苦不堪，经年累月，你逐渐习惯了这样的痛苦。</p><p>你一直等啊等，等一个能为你打开牢门、放你出去的人。</p><p>终于有一天，你等来一个人，他为你打开牢门，只不过，是有时间限制的，两个小时之后，你还需要回到牢房里。</p><p>他答应你，每天都会来这里，为你打开牢门，虽然只有两个小时。</p><p>此时，你会感谢他为你带来的短暂的自由吗？</p><p>你越是能够体会自由的快乐，就越难以忍受在牢房里的痛苦。你多了两个小时的快乐，但其余时间的痛苦也加倍了。</p><p>也许你甚至会怨恨，为什么来的是一个只能打开两小时牢门的人，而不是一个，能够真正放你出去的人？</p><p>此情此景，你会是什么样的感想？</p><h3 id="6"><a href="#6" class="headerlink" title="6"></a>6</h3><p>随着时间的累加，你对打开牢门的人有所了解。</p><p>你发现，原来他不只是给你打开牢门，你隔壁的狱友，牢门也会打开两个小时，而且也是他。</p><p>这个时候，你会嫉妒，你会害怕。为什么不只是你，为什么还有别人，会不会有一天，他不再为你，打开牢门。</p><p>你本想过主动放弃，但你没有放弃。也许以后连放弃的机会都没有了，你同样抓狂。</p><p>你质问他，为什么？</p><p>他一脸无辜，完全不知道做错了什么。</p><p>他再次承诺，不会忘记你。</p><h3 id="7"><a href="#7" class="headerlink" title="7"></a>7</h3><p>再后来，你发现，不只你，不只你隔壁的狱友。</p><p>还有很多人，也是两个小时，也是他。</p><p>他的时间被分散在很多人身上，所以你只有两个小时。</p><p>其他人的时间，有的多，有的少，反正你，是两个小时。</p><p>你期待的，是一个能放你出去、给你二十四小时的人，结果等来的，是只能给你两小时的人。</p><p>怎么办？</p><h3 id="延伸-1"><a href="#延伸-1" class="headerlink" title="延伸"></a>延伸</h3><p>如果不是单方面的保释一样的需求，而是双向的、相互为对方打开牢门，情况会有什么样的不同？</p>]]></content>
  </entry>
  <entry>
    <title>MIT 的公开课是相对质量比较高、内容比较系统的课程。比如这个 Mathematics for Computer Sci...</title>
    <link href="https://t.smallyu.net/#2022-17"/>
    <id>micro:1117488193</id>
    <published>2022-05-04T15:25:05Z</published>
    <updated>2022-05-08T08:02:27Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>MIT 的公开课是相对质量比较高、内容比较系统的课程。比如这个 Mathematics for Computer Science 值得一看，短小精悍。如果在 YouTube 上搜 &amp;quot;rsa&amp;quot;，就会搜到这个课程的其中一个视频。</p>]]></summary>
    <content type="html"><![CDATA[<p>MIT 的公开课是相对质量比较高、内容比较系统的课程。比如这个 <a href="https://www.youtube.com/watch?v=wIq4CssPoO0&list=PLUl4u3cNGP60UlabZBeeqOuoLuj_KNphQ">Mathematics for Computer Science</a> 值得一看，短小精悍。如果在 YouTube 上搜 &quot;rsa&quot;，就会搜到这个课程的其中一个视频。</p>
]]></content>
  </entry>
  <entry>
    <title>心理疾病诊疗记录</title>
    <link href="https://crazy.smallyu.net/2022/05/02/%E5%BF%83%E7%90%86%E7%96%BE%E7%97%85%E8%AF%8A%E7%96%97%E8%AE%B0%E5%BD%95/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2022/05/02/%E5%BF%83%E7%90%86%E7%96%BE%E7%97%85%E8%AF%8A%E7%96%97%E8%AE%B0%E5%BD%95/</id>
    <published>2022-05-02T06:02:44.000Z</published>
    <updated>2025-08-16T03:27:11.431Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<style>
li:nth-child(odd) {
  list-style-type: "A：";
}
li:nth-child(even) {
  list-style-type: "B：";
}
</style>

<h4 id="1"><a href="#1"]]></summary>
    <content type="html"><![CDATA[<style>li:nth-child(odd) {  list-style-type: "A：";}li:nth-child(even) {  list-style-type: "B：";}</style><h4 id="1"><a href="#1" class="headerlink" title="1"></a>1</h4><ul><li><p>你好。</p></li><li><p>主教你好，我来忏悔我的罪行，我最近不太开心，我想我精神虐待了一个女孩。</p></li><li><p>别着急，慢慢说，一点一点来。你是说，你虐待别人，然后自己不开心了？</p></li><li><p>是的，这说来复杂。我认为在行为上是我的错，但我的行为因她而起，所以归根结底，是她的错。</p></li><li><p>你把我搞糊涂了。从现在的情况说起吧，你们现在是什么关系，关系怎么样？</p></li><li><p>我们是朋友，也许……如果她愿意的话。我们之前吵架了，后来和好了，她说没事了。但是我不确定她到底怎么想，不知道她的主意会不会改变，你知道，女人嘛，总是变来变去的。</p></li><li><p>你们是情侣吗？之前是情侣吗？</p></li><li><p>不是，她有男朋友了。一提到这个我就伤心。</p></li><li><p>你的意思是，作为普通朋友，吵架了，然后和好了，你不确定她有没有原谅你是吗？这个精神虐待有什么关系呢？你又为什么伤心呢？</p></li><li><p>你的问题太多了，我不知道先回答哪个。</p></li></ul><h4 id="2"><a href="#2" class="headerlink" title="2"></a>2</h4><ul><li><p>是我的失职。一个一个来，你不确定她有没有原谅你是吗？</p></li><li><p>她原谅我了。我虽然担心她会改变主意，但是又没什么理由怀疑她。或者说，我害怕她改变主意。</p></li><li><p>你害怕她改变主意，是因为害怕失去她这个朋友？</p></li><li><p>是的。</p></li><li><p>你为什么没有理由怀疑她？</p></li><li><p>因为她说要相信她，她不会骗我。</p></li><li><p>她骗过你吗？</p></li><li><p>几乎没有，也不算骗，就是有过一些事情。</p></li><li><p>所以你不相信她，害怕她骗你。</p></li><li><p>我觉得她不会故意骗我。</p></li><li><p>你说有过一些事情，是什么事情呢，这些事情导致你不相信她吗？</p></li><li><p>是的。她并不总是说到做到。我担心她做不到她说的，比如原谅我。</p></li><li><p>言行一致倒是个可贵的品质。</p></li><li><p>我本以为，这是做人的基本素养。</p></li><li><p>说一说具体的事情吧，她到底怎么说到做不到了。</p></li><li><p>她答应我什么时候去玩，但到了约定的时间，由于种种原因，就没有玩。</p></li><li><p>她违约了？</p></li><li><p>也不算违约，中间发生了很多事情。</p></li><li><p>你刚才说的 “种种原因”，你知道是什么吗？你觉得那些原因合理吗？</p></li><li><p>合理倒是合理，但都是因为她，她总是说一些自己的原因。我在怀疑，她不想和我一起玩了，于是找了一些借口，编造出那些理由。</p></li><li><p>你怀疑她骗你。</p></li><li><p>对。</p></li><li><p>她不是说，她不会骗你吗？你刚才说，你相信她不会故意骗你。</p></li><li><p>啊，倒也是。信还是不信，这是个问题。</p></li></ul><h4 id="3"><a href="#3" class="headerlink" title="3"></a>3</h4><ul><li><p>你的逻辑是矛盾的，如果你相信她，就不应该怀疑她骗你。如果你不相信她，就……不相信她，还和她交朋友？</p></li><li><p>我只是害怕，她不想和我一起玩。</p></li><li><p>为什么不直接问她，她是不是不想和你一起玩？</p></li><li><p>她的回答一定是：“不是”。我没必要问。</p></li><li><p>你怀疑她的回答是在骗你。</p></li><li><p>不排除这样的可能。</p></li><li><p>为什么？</p></li><li><p>因为她几乎没有过，真的和我一起玩。如果只是问问，她说话可好听了。</p></li><li><p>所以你想让她和你一起玩，证明她说的话是真的。不然你没有安全感是吗？</p></li><li><p>安全感……我只是拿不定主意，该不该相信她。我想要相信她，和她做朋友，但是我需要一些事实，证明她说的话是真的，让我能够相信她。这确实是安全感的问题，我没有安全感。</p></li><li><p>换个角度想，她为什么要骗你？</p></li><li><p>也许她说谎成性，或者习惯说善意的谎言。善意的谎言也是谎言，我讨厌谎言。可能她为了不伤害我，才说好话骗我的。但是她不明白，这同样会伤害我。</p></li><li><p>无论是不是谎言，她的本意都是好的。</p></li><li><p>我希望她直说。</p></li><li><p>有区别吗？</p></li><li><p>区别太大了，如果她说不想和我玩，那我什么都不会去想。如果她编造了一些理由，我还是会想着以后约她玩。</p></li><li><p>你觉得她吊着你？</p></li><li><p>倒也……我相信她不是吊着我，至少不是故意的。</p></li><li><p>你还是相信她的。</p></li><li><p>她本意不坏。</p></li><li><p>你还怀疑她吗？</p></li><li><p>不了。如果我不相信她的回答，但是相信她的人品，我的逻辑就是混乱的。我应该相信她。</p></li></ul><h4 id="4"><a href="#4" class="headerlink" title="4"></a>4</h4><ul><li><p>回到一开始的问题，你说的 “精神虐待” 是什么意思？</p></li><li><p>是我的错，我做了很多对她不好的事情。</p></li><li><p>不具体说说吗？</p></li><li><p>忽然不想说了，我承认是我的错，只希望有机会能够弥补我的错误。</p></li><li><p>那关于你的 “伤心” 呢？</p></li><li><p>也没有必要提了。</p></li><li><p>我们的对话会不会结束得太潦草了？</p></li><li><p>已经足够了，</p></li></ul><h3 id="附"><a href="#附" class="headerlink" title="附"></a>附</h3><blockquote><p>#给闹掰朋友发的短信#</p><p>我最近明白了一些道理，我知道我哪儿错了，但是我不会告诉你，因为我怕理解的不对、不到位、不深刻，因为 talk is cheap。我只希望有机会，用实际行动证明，我可以做得比以前更好。</p><p>前段时间玩九不思议街，我拿的角色是汉诺和莎士比亚，故事以我的角色写的一句诗结尾，当时玩本的时候就有点破防。</p><p>那句诗是：“你若呼唤，我必归来。”</p><p>– 2022.04.21（新浪微博）</p></blockquote><h3 id="附-1"><a href="#附-1" class="headerlink" title="附"></a>附</h3><p>推荐一本书 《<a href="https://book.douban.com/subject/26369699/" target="_blank">被讨厌的勇气：“自我启发之父”阿德勒的哲学课</a>》，作者是岸见一郎。</p><img src="book.jpeg" width="30%"><p>内容非常值得一看，带给我很大启发，主要是用 “阿德勒心理学”（个体心理学）来解释诸多心理问题，是我最近看的几十本情感类和心理学相关书籍中，个人认为最好的一本。</p>]]></content>
  </entry>
  <entry>
    <title>《终身成长》里提到固定型思维模式和成长型思维模式两种，并且对成长型思维模式大加赞赏。这本书可以给人信心和力量，有则改之，...</title>
    <link href="https://t.smallyu.net/#2022-16"/>
    <id>micro:1105326425</id>
    <published>2022-04-21T14:51:02Z</published>
    <updated>2022-04-21T14:51:02Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>《终身成长》里提到固定型思维模式和成长型思维模式两种，并且对成长型思维模式大加赞赏。这本书可以给人信心和力量，有则改之，无则加勉。</p>]]></summary>
    <content type="html"><![CDATA[<p>《终身成长》里提到固定型思维模式和成长型思维模式两种，并且对成长型思维模式大加赞赏。这本书可以给人信心和力量，有则改之，无则加勉。</p>
]]></content>
  </entry>
  <entry>
    <title>如何面对误解</title>
    <link href="https://b.smallyu.net/2022/04/21/%E5%A6%82%E4%BD%95%E9%9D%A2%E5%AF%B9%E8%AF%AF%E8%A7%A3/"/>
    <id>blog-b:https://b.smallyu.net/2022/04/21/%E5%A6%82%E4%BD%95%E9%9D%A2%E5%AF%B9%E8%AF%AF%E8%A7%A3/</id>
    <published>2022-04-21T13:31:39.000Z</published>
    <updated>2026-03-02T09:02:54.288Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>所有误解都来源于，用自己的思维方式，去理解别人的行为。</p>
<p>每个人都是独立的个体，善良、自由、快乐。</p>
<img src="1.png"]]></summary>
    <content type="html"><![CDATA[<p>所有误解都来源于，用自己的思维方式，去理解别人的行为。</p><p>每个人都是独立的个体，善良、自由、快乐。</p><img src="1.png" width="80%"><p>每个人都有属于自己的世界观，那是在经历过曲折人生之后沉淀下来的，用以面对残酷世界和复杂人性的武器，也许像一面魔法镜，有丰富而神奇的魔力。</p><p>世界观给予每个人不同程度的理解能力，可以把别人的话在内心中翻译成，自己能够理解的含义。</p><img src="2.png" width="80%"><p>当你想要表达某种想法，你会将想法转换为语言，转换的过程由表达能力负责。你的魔法镜是红色的，你说出的话也是红色的，这句红色的话是善意的。</p><img src="3.png" width="80%"><p>经过一些媒介的传播，你的话会到达对方的位置。</p><img src="4.png" width="80%"><p>不幸的是，对方的魔法镜，是蓝色的。你理解这样的情况，因为很难要求每个人，都拥有和你一样的理解能力、一样颜色的魔法镜，这个世界本就是多姿多彩的。</p><p>所以很可惜，你红色的话，经由蓝色魔法镜的解析，被理解为了粉色的含义。红色是不带恶意的，但粉色，就包含了一些其他意味在里面，偏离了你原本要表达的心意。</p><img src="5.png" width="80%"><p>对方基于粉色的含义，用蓝色的话语回复了你。对方在回复你的时候，就已经有一些偏颇了，因为对方误解了你的意思。</p><img src="6.png" width="80%"><p>蓝色的内容也许没有恶意，也许带有一点恶意，总之会朝你飞来。</p><img src="7.png" width="80%"><p>再次不幸的是，你的魔法镜是红色的。对于对方蓝色的内容，你的魔法镜，会把它解析为黄色。</p><img src="8.png" width="80%"><p>这实在是加深了误解。原本赤红、纯蓝的两颗心，都感觉受到了不可原谅的伤害。对方怎么可以这样！</p><img src="9.png" width="80%"><p>久而久之，两个人的隔阂越来越大。</p><img src="10.png" width="80%"><p>作为聪颖的魔法师，你力图改变这种状况。经过自己的勤学苦练，你想办法拥有了蓝色的魔法镜。</p><img src="11.png" width="80%"><p>今后，当对方使用蓝色魔法镜和你交流。</p><img src="12.png" width="80%"><p>你可以拿出自己的蓝色魔法镜，来解析对方的内容。</p><img src="13.png" width="80%"><p>经过蓝色魔法镜的解析，对方善意的内容可以原封不动到达你的脑海里。</p><img src="14.png" width="80%"><p>你不会因此而受伤了。</p><img src="15.png" width="80%"><p>当然，你没有理由去要求别人，拥有和自己一样的红色魔法镜。这太难了，且不说别人愿不愿意，对方也不一定有足够的实力，驾驭你的红色魔法镜。</p><p>如果你想和对方沟通，只要拿出自己的蓝色魔法镜就可以了。</p><p>总而言之，就是让自己变得强大。</p>]]></content>
  </entry>
  <entry>
    <title>区块链网络的一种走向：在同一个网络中，存在多种负责不同功能的节点类型，不同类型的节点使用不同的共识，利用共识擅长的一面做...</title>
    <link href="https://t.smallyu.net/#2022-15"/>
    <id>micro:1073258507</id>
    <published>2022-03-20T14:03:14Z</published>
    <updated>2022-03-20T14:03:14Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>区块链网络的一种走向：在同一个网络中，存在多种负责不同功能的节点类型，不同类型的节点使用不同的共识，利用共识擅长的一面做擅长的事情。</p>]]></summary>
    <content type="html"><![CDATA[<p>区块链网络的一种走向：在同一个网络中，存在多种负责不同功能的节点类型，不同类型的节点使用不同的共识，利用共识擅长的一面做擅长的事情。</p>
]]></content>
  </entry>
  <entry>
    <title>程序员的职业病：难以忍受结果无法预测的事情。</title>
    <link href="https://t.smallyu.net/#2022-14"/>
    <id>micro:1070670467</id>
    <published>2022-03-17T09:46:29Z</published>
    <updated>2022-03-17T13:18:07Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>程序员的职业病：难以忍受结果无法预测的事情。</p>]]></summary>
    <content type="html"><![CDATA[<p>程序员的职业病：难以忍受结果无法预测的事情。</p>
]]></content>
  </entry>
  <entry>
    <title>之前公司存在的问题（2）</title>
    <link href="https://b.smallyu.net/2022/03/11/%E4%B9%8B%E5%89%8D%E5%85%AC%E5%8F%B8%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98_2/"/>
    <id>blog-b:https://b.smallyu.net/2022/03/11/%E4%B9%8B%E5%89%8D%E5%85%AC%E5%8F%B8%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98_2/</id>
    <published>2022-03-11T10:58:39.000Z</published>
    <updated>2025-12-03T10:02:00.860Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近<a href="/micro-blog/#2022-10">注意到</a>服务集成这个软件开发的领域，以及在这个方向上有所成就的<a]]></summary>
    <content type="html"><![CDATA[<p>最近<a href="/micro-blog/#2022-10">注意到</a>服务集成这个软件开发的领域，以及在这个方向上有所成就的<a href="https://coolshell.cn/articles/20765.html">创业公司</a>，同时看到有人来公司面试，偶然想起一些以前的事情，回想起我在上家公司的经历。之前文中没有具体说的是，部门的市场定位不清晰。当然造成那样的结果，有很多历史原因，公司一开始是有靠山的子公司，作为甲方立场很足，后来转变为乙方的形式，没有活跃在市场上的基因。这里只说结果。</p><p>如果部门的定位是拥有技术基础去自研产品，那么问题就很严重。</p><p>我在正式接手核心产品的开发后，发现项目的代码在工程上有凌乱不堪，不是代码乱，是没有顶层设计，没有明确的模块划分，没有清晰的目录结构，没有靠谱的软件设计。项目支持四五种数据库，然而数据库的配置方式竟然不统一，分散在不同配置文件的不同位置，哪儿生效哪儿不生效，哪个功能好使哪个功能不好使，要么靠经验，要么靠猜。API 的设计也很糟糕，我在《<a href="/2021/11/23/%E9%9A%8F%E6%83%B3/">随想</a>》中提到过关于 URL 参数的问题，另外 URL 的配置和参数的校验是写在单个的配置文件中，意味着如果在智能合约中想新增 URL，就需要改配置文件然后重启节点。至于配置规则的热加载，好像没有人关心。</p><p>智能合约的机制也有问题。交易在提交到合约后，交易的检查和执行分为两个步骤，检查函数的入参和出参都是 bitMap，必须要严格保证入参和出参的长度一致，否则节点就会 panic，因为外面是用循环处理的，会 out of index。问题在于，那可是智能合约，怎么会用那么生硬的写法。后来前面的人告诉我，写智能合约的原则就是，“绝对不能出错”，因为说是智能合约，其实是和项目耦合很深的功能模块，美其名曰系统合约，是底层链的开发人员去开发的，而不是交给用户使用。开发合约，就需要对底层链有足够的了解。当时的人似乎还对这种事情有一点自豪感，感觉像是，“我们能写，因为我们比较熟悉”，丝毫不认为那是一种功能的不健全，而认为是有门槛的 feature。听说本来是没有打算支持智能合约的，由于需要的不断扩张，就硬生生加上了。当时的某人还拿 leader 的某篇文章奉为真理，说，其实区块链也不一定需要智能合约，对那种和广义智能合约理念背道而驰的设计大加赞赏。</p><p>多写几个合约后，就会注意到每个合约的检查函数上，都会有一个判断交易是否为空指针的语句。本以为系统内部的函数调用，怎么会凭空出现空交易呢，经过复现和排查，发现在并发情况下，队列偶尔会出现异常，push 一批交易进去，pop 出来就有空交易了，这纯粹是数据结构的问题。然后虽然定位到问题，但没有去解决，因为大不了每次都在合约上写个判断，算是我偷懒。也不知道前面的人，还埋了多少隐性 bug 在里面。</p><p>当用合约处理业务的时候，就会发现数据库的读写性能会成为交易性能的瓶颈，比如 MySQL，而且存在一个我一直没想通的问题：合约里的检查函数，怎么判断交易是成功还是失败？因为合约是要针对业务去开发的。合约对交易的检查和执行，都是是在 BFT 共识的 commit 阶段，这个时候已经完成共识了，检查函数并不能去预执行数据库的写操作（如果合约依赖数据库的特性比如事务，区块链就没有意义了），难道要把所有有可能失败的场景全排除一遍？是语义层面的排除，还是执行层面的排除？即使能够枚举出异常，又会损耗多少性能？那可能会产生疑问，为什么不在共识前检查？共识前的检查也是有的，但不管在共识前还是共识后，对数据库的操作总量不会变，对性能的损耗不会变。（延伸思考：为什么公有链不存在这样的问题，联盟链存在。）</p><p>版本管理的混乱也是在工程方面的问题之一，甚至都没有人能说清楚，当前的版本号到底是多少，是 2.0 吗？配置文件里可还写的是 1.4，是 2.0.1 吗？仓库里可还有 2.0.3，但不知道是谁改的，有哪些变动。甚至主干代码中会出现用于测试的 case，有些需要异常场景测试的情况，比如在 BFT 共识过程中恶意投票，只能通过改代码的方式观察效果，结果那部分代码就保留在了项目中，可以通过配置启用。其他原因的代码冗余也存在，比如智能合约的公用接口，为了兼容 UTXO，就不得不增加对应的接口，但其他合约完全用不到那些，又不得不实现。</p><p>项目在技术方面是存在各种各样问题的，包括我之前解决的由于使用 VRF 导致共识在提案阶段黑名单失效的问题，都说明系统尤其是在比较核心的地方都不够完善，而重构项目的成本又非常高。项目存在的最大价值和意义，就是参加一个行业内知名的测试活动，测试通过后某机构会给企业颁发证书，以证明这个软件是合格的、有资质的、符合标准的。然后企业拿着这个证书就可以宣传、投标、卖钱。至于软件本身好不好，并不重要。我当时光看测试项还感觉没啥，都是一些对区块链的基本要求，能通过测试没什么大不了的。直到亲手操作后发现，测试过程中存在大量的困难，都是人为困难，由于之前开发人员的不专业、团队管理的松散，以及项目本身很多不合理的设计，加上文档和人员的流失，都大大增加了测试过程的准备难度。也许大家没有意识到，什么是有效的困难，才造成了一种项目很好的假象。</p><p>如果部门的定位是服务集成，提供解决方案和技术支持，也是不合格的。</p><p>除了区块链底层，部门还有 Bass、中间件、SDK、浏览器之类的项目，会涉及到 Kafka、Zoopeeper、Redis、普罗米修斯等组件，但用的很浅，本身技术含量低，整体上做的也不到位，没有产品、没有 UI、没有用户思维、没有 owner 意识，全是在有业务需求的情况下临时改进，结果每次都手忙脚乱，总是以优先应付客户为要务。服务集成的事情，可以简单也可以难，可以做好也容易做不好。然而部门另一方面又不太想做服务集成，比如在用 Hyperledger Fabric 做一些什么事情的时候，leader 就说：客户会问，你们底层用的 Fabric，只是拿来用，也没干什么呀，为什么要收钱？至少能体现出部门的定位有多混乱了。</p>]]></content>
  </entry>
  <entry>
    <title>不要试图用虚假的勤奋代替真正的辛苦。</title>
    <link href="https://t.smallyu.net/#2022-13"/>
    <id>micro:1062684447</id>
    <published>2022-03-09T08:45:10Z</published>
    <updated>2022-03-09T08:45:20Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>不要试图用虚假的勤奋代替真正的辛苦。</p>]]></summary>
    <content type="html"><![CDATA[<p>不要试图用虚假的勤奋代替真正的辛苦。</p>
]]></content>
  </entry>
  <entry>
    <title>以前试图基于 “没有第三方依赖包” 的原则设计程序，后来发现不应该重复造轮子，尤其是重复制造的成本很高，以及重复制造的是...</title>
    <link href="https://t.smallyu.net/#2022-12"/>
    <id>micro:1062624963</id>
    <published>2022-03-09T07:22:33Z</published>
    <updated>2022-03-09T07:22:33Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>以前试图基于 “没有第三方依赖包” 的原则设计程序，后来发现不应该重复造轮子，尤其是重复制造的成本很高，以及重复制造的是非常成熟的轮子。 有时候可能会觉得，如果你不能制造一个东西，那你就不是真的懂。问题在于，懂了又怎么样呢？我们从小就明白 “站在巨人的肩膀上” 的道理，我们不可能把整个世界重新创造一遍，或者把整个人类社...</p>]]></summary>
    <content type="html"><![CDATA[<p>以前试图基于 “没有第三方依赖包” 的原则设计程序，后来发现不应该重复造轮子，尤其是重复制造的成本很高，以及重复制造的是非常成熟的轮子。</p>
<p>有时候可能会觉得，如果你不能制造一个东西，那你就不是真的懂。问题在于，懂了又怎么样呢？我们从小就明白 “站在巨人的肩膀上” 的道理，我们不可能把整个世界重新创造一遍，或者把整个人类社会的历程重新体验一遍，以示我们明白它了。</p>
<p>不过另一方面，又确实不希望做 “缝合怪”，把各种各样的东西拼凑在一起。这里的区别就在于，拿来拼凑的那些东西，不是 “巨人”。所以不是不应该依靠任何东西，而是应该只依靠靠谱的东西。</p>
<p>Bitcoin 的设计其实基于很丰富的已有的技术，但它本身又是很厉害的创新。Bitcoin 的创意绝非偶然，它的作者是很厉害的人。不禁让人好奇，他到底有着怎么样的背景？</p>
]]></content>
  </entry>
  <entry>
    <title>Finally, I am near the normal status.</title>
    <link href="https://t.smallyu.net/#2022-11"/>
    <id>micro:1060686514</id>
    <published>2022-03-07T13:27:13Z</published>
    <updated>2022-03-07T13:27:13Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Finally, I am near the normal status.</p>]]></summary>
    <content type="html"><![CDATA[<p>Finally, I am near the normal status.</p>
]]></content>
  </entry>
  <entry>
    <title>有一个不好估量技术含量的领域：服务集成。</title>
    <link href="https://t.smallyu.net/#2022-10"/>
    <id>micro:1060640301</id>
    <published>2022-03-07T12:33:23Z</published>
    <updated>2022-03-07T12:33:23Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有一个不好估量技术含量的领域：服务集成。</p>]]></summary>
    <content type="html"><![CDATA[<p>有一个不好估量技术含量的领域：服务集成。</p>
]]></content>
  </entry>
  <entry>
    <title>其实被奴役、驯化、压制的动物是幸福的，因为它们不需要有自己的思考和判断，不需要为自己的想法和行为承担后果。我得到很多吃的...</title>
    <link href="https://t.smallyu.net/#2022-9"/>
    <id>micro:1060169413</id>
    <published>2022-03-07T04:10:18Z</published>
    <updated>2022-03-07T04:10:18Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>其实被奴役、驯化、压制的动物是幸福的，因为它们不需要有自己的思考和判断，不需要为自己的想法和行为承担后果。我得到很多吃的，是因为主子给了我很多吃的。我吃不到东西，是因为主子不开心了，没有给我，我应该更加努力去讨好主人。主子愿意给就给，不愿意给我也没有办法。 看似没有自由，其实是幸福的，没有心理压力、顺其自然、听天由命、...</p>]]></summary>
    <content type="html"><![CDATA[<p>其实被奴役、驯化、压制的动物是幸福的，因为它们不需要有自己的思考和判断，不需要为自己的想法和行为承担后果。我得到很多吃的，是因为主子给了我很多吃的。我吃不到东西，是因为主子不开心了，没有给我，我应该更加努力去讨好主人。主子愿意给就给，不愿意给我也没有办法。</p>
<p>看似没有自由，其实是幸福的，没有心理压力、顺其自然、听天由命、各安天命。</p>
]]></content>
  </entry>
  <entry>
    <title>前几天 Ontology 宣布兼容 EVM （ 链接 ），想到的问题是，是不是只要 EVM 版本更新，Ontology...</title>
    <link href="https://t.smallyu.net/#2022-8"/>
    <id>micro:1060157274</id>
    <published>2022-03-07T03:37:41Z</published>
    <updated>2022-03-07T03:37:51Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>前几天 Ontology 宣布兼容 EVM （ 链接 ），想到的问题是，是不是只要 EVM 版本更新，Ontology 就需要跟进最新的版本，才能够支持最新的特性？如果是，那么兼容多少种虚拟机，就需要及时跟进多少个项目，这样 Ontology 就变成了其他项目的附庸，尽管以太坊是非常知名的项目。 以太坊会试图兼容比特币...</p>]]></summary>
    <content type="html"><![CDATA[<p>前几天 Ontology 宣布兼容 EVM （<a href="https://ont.io/news/869">链接</a>），想到的问题是，是不是只要 EVM 版本更新，Ontology 就需要跟进最新的版本，才能够支持最新的特性？如果是，那么兼容多少种虚拟机，就需要及时跟进多少个项目，这样 Ontology 就变成了其他项目的附庸，尽管以太坊是非常知名的项目。</p>
<p>以太坊会试图兼容比特币吗？Polkdot 倒是用 bridge 的方式兼容各种链，问题是 Polkdot 的初衷的定位就是跨链。</p>
]]></content>
  </entry>
  <entry>
    <title>现在越来越喜欢听周杰伦的歌，因为他的歌足够复杂，旋律很多。以前喜欢听李荣浩的一首歌《李白》，现在听起来感觉简单、平庸、无...</title>
    <link href="https://t.smallyu.net/#2022-7"/>
    <id>micro:1060112683</id>
    <published>2022-03-07T01:59:46Z</published>
    <updated>2022-03-07T10:28:56Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>现在越来越喜欢听周杰伦的歌，因为他的歌足够复杂，旋律很多。以前喜欢听李荣浩的一首歌《李白》，现在听起来感觉简单、平庸、无聊。人总是一个不断的从简单到复杂的过程。一开始会喜欢一些简单的东西，觉得这些简单的东西就很好，因为在那个阶段，这些简单的东西就是复杂的，已经足够占用自己处理这些信息的头脑了。 这对于个人成长来说有什么...</p>]]></summary>
    <content type="html"><![CDATA[<p>现在越来越喜欢听周杰伦的歌，因为他的歌足够复杂，旋律很多。以前喜欢听李荣浩的一首歌《李白》，现在听起来感觉简单、平庸、无聊。人总是一个不断的从简单到复杂的过程。一开始会喜欢一些简单的东西，觉得这些简单的东西就很好，因为在那个阶段，这些简单的东西就是复杂的，已经足够占用自己处理这些信息的头脑了。</p>
<p>这对于个人成长来说有什么样的意义呢？可能更多的意义在于，可以通过这样的方式去判断一个人的水平。如果一个人总是喜欢重复地、不断地、乐此不疲地做一些简单的事情，那么就证明他的水平属于简单的阶段。如果一个人无法意识到自己处于那样的阶段，或者不能判断自己做的事情是不是简单的、判断不了一件事情是简单还是复杂，同样说明他处于简单的阶段。</p>
]]></content>
  </entry>
  <entry>
    <title>UTXO 是一种模型吗？当你想要把它抽出来，独立成一种 ”模型“，却发现它和其他模块的结合都太紧密了，它已经和区块链的架...</title>
    <link href="https://t.smallyu.net/#2022-6"/>
    <id>micro:1059240900</id>
    <published>2022-03-04T15:04:15Z</published>
    <updated>2022-03-04T15:04:15Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>UTXO 是一种模型吗？当你想要把它抽出来，独立成一种 ”模型“，却发现它和其他模块的结合都太紧密了，它已经和区块链的架构绑定在一起。 有一种理解是，区块链本身就是一种状态机，UTXO 是改变状态的动作。UTXO 怎么是一种模型呢？</p>]]></summary>
    <content type="html"><![CDATA[<p>UTXO 是一种模型吗？当你想要把它抽出来，独立成一种 ”模型“，却发现它和其他模块的结合都太紧密了，它已经和区块链的架构绑定在一起。</p>
<p>有一种理解是，区块链本身就是一种状态机，UTXO 是改变状态的动作。UTXO 怎么是一种模型呢？</p>
]]></content>
  </entry>
  <entry>
    <title>其实 Proof of Work 的思想已经在生活中广泛应用了。有一次玩剧本杀，男生需要在单独的房间里完成一些任务，主持...</title>
    <link href="https://t.smallyu.net/#2022-5"/>
    <id>micro:1035864118</id>
    <published>2022-02-11T04:01:47Z</published>
    <updated>2022-02-11T04:01:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>其实 Proof of Work 的思想已经在生活中广泛应用了。有一次玩剧本杀，男生需要在单独的房间里完成一些任务，主持人为了给男生拖延足够的时间，就出了一些数学题给女生做，题目是随机手写的，加减乘除的算式，当然没收了手机。主持人在没有意识到的情况下，使用了类似 Proof of Work 的机制。 几年前有人把 Pr...</p>]]></summary>
    <content type="html"><![CDATA[<p>其实 Proof of Work 的思想已经在生活中广泛应用了。有一次玩剧本杀，男生需要在单独的房间里完成一些任务，主持人为了给男生拖延足够的时间，就出了一些数学题给女生做，题目是随机手写的，加减乘除的算式，当然没收了手机。主持人在没有意识到的情况下，使用了类似 Proof of Work 的机制。</p>
<p>几年前有人把 Proof of Work 结合一些其他形式的技术，构想出了另一种足够大的新的东西。</p>
]]></content>
  </entry>
  <entry>
    <title>Web 3.0 需要一种信息聚合服务。</title>
    <link href="https://t.smallyu.net/#2022-4"/>
    <id>micro:1027559891</id>
    <published>2022-02-02T04:12:22Z</published>
    <updated>2022-02-02T04:12:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Web 3.0 需要一种信息聚合服务。</p>]]></summary>
    <content type="html"><![CDATA[<p>Web 3.0 需要一种信息聚合服务。</p>
]]></content>
  </entry>
  <entry>
    <title>除夕</title>
    <link href="https://crazy.smallyu.net/2022/02/01/%E9%99%A4%E5%A4%95/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2022/02/01/%E9%99%A4%E5%A4%95/</id>
    <published>2022-02-01T11:47:43.000Z</published>
    <updated>2025-08-16T03:27:11.460Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>堆在墙角的快递很久都没拆<br>想换掉的被子到现在都没买</p>
<p>剧本杀的拼场没有往日红火<br>工作日的玩家没有往日沉浸<br>游戏像往常无数次一样进行<br>新的故事新的剧本新的店家<br>脑子里却只是想起过往场景 ]]></summary>
    <content type="html"><![CDATA[<p>堆在墙角的快递很久都没拆<br>想换掉的被子到现在都没买</p><p>剧本杀的拼场没有往日红火<br>工作日的玩家没有往日沉浸<br>游戏像往常无数次一样进行<br>新的故事新的剧本新的店家<br>脑子里却只是想起过往场景  </p><p>开源项目像往常一样没有动态<br>没有什么事情非春节才可以做<br>总是想不去虚度光阴浪费生命<br>可是提升自我已经是日常生活  </p><p>玩不感兴趣的游戏去消磨时间<br>但焦虑时间能否真的用来消遣<br>可是不消耗时间又能做些什么  </p><p>有的人年纪轻轻就已生子成家<br>有的人年纪不小还是对影成双<br>相同的年龄有人已经被迫成人<br>相同的年龄有人不想承担责任  </p><p>街上的车辆没有往日繁华<br>除夕的当天格外不想出门<br>想让自己一个人体会烦扰<br>主要是出门也做不了什么  </p><p>合租的邻居说记得关好门窗<br>但家乡的善意让人猝不及防<br>在这盛世的繁荣美景之下<br>掩盖着多少挣扎的牛与马  </p><p>窗外的风景看了很多遍<br>风云变幻<br>一成不变  </p><p>也许我写东西水平有所降低<br>最近确实很多事情没有头绪<br>有太多的事情想不清楚结局<br>不过至少我会一直都在这里  </p>]]></content>
  </entry>
  <entry>
    <title>It&amp;#39;s not enough the single knowledge point, and we shoul...</title>
    <link href="https://t.smallyu.net/#2022-3"/>
    <id>micro:1023237202</id>
    <published>2022-01-27T13:57:51Z</published>
    <updated>2022-01-27T13:57:51Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>It&amp;#39;s not enough the single knowledge point, and we should learn to make them linked.</p>]]></summary>
    <content type="html"><![CDATA[<p>It&#39;s not enough the single knowledge point, and we should learn to make them linked.</p>
]]></content>
  </entry>
  <entry>
    <title>长大以后，为了理想而努力 渐渐地忽略了父亲和母亲和故乡的消息 如今的我，生活就像在演戏 说着言不由衷的话，戴着伪善的面具...</title>
    <link href="https://t.smallyu.net/#2022-2"/>
    <id>micro:1018640217</id>
    <published>2022-01-21T16:02:22Z</published>
    <updated>2022-01-22T04:46:06Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>长大以后，为了理想而努力 渐渐地忽略了父亲和母亲和故乡的消息 如今的我，生活就像在演戏 说着言不由衷的话，戴着伪善的面具 总是拿着微不足道的成就来骗自己 总是莫名其妙感到一阵的空虚</p>]]></summary>
    <content type="html"><![CDATA[<blockquote>
<p>长大以后，为了理想而努力<br>渐渐地忽略了父亲和母亲和故乡的消息<br>如今的我，生活就像在演戏<br>说着言不由衷的话，戴着伪善的面具<br>总是拿着微不足道的成就来骗自己<br>总是莫名其妙感到一阵的空虚    </p>
</blockquote>
]]></content>
  </entry>
  <entry>
    <title>我今年 8 岁。 我很喜欢来家里做客的阿姨，阿姨总是对我很好，说话也温柔，给我买好吃的，还经常夸赞我，不会对我大吼大叫，...</title>
    <link href="https://t.smallyu.net/#2022-1"/>
    <id>micro:1016101270</id>
    <published>2022-01-19T05:34:14Z</published>
    <updated>2022-01-19T05:34:52Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>我今年 8 岁。 我很喜欢来家里做客的阿姨，阿姨总是对我很好，说话也温柔，给我买好吃的，还经常夸赞我，不会对我大吼大叫，几乎能容忍我的所有缺点，不会指责我什么。 我的妈妈就很不一样，总是对我充满抱怨，这儿不好那儿不好，对人没有礼貌啦，姿势动作不优雅啦，不会打扫房间啦，吃饭太挑剔啦，成绩不如别人家小孩啦。 我喜欢阿姨，不...</p>]]></summary>
    <content type="html"><![CDATA[<p>我今年 8 岁。</p>
<p>我很喜欢来家里做客的阿姨，阿姨总是对我很好，说话也温柔，给我买好吃的，还经常夸赞我，不会对我大吼大叫，几乎能容忍我的所有缺点，不会指责我什么。</p>
<p>我的妈妈就很不一样，总是对我充满抱怨，这儿不好那儿不好，对人没有礼貌啦，姿势动作不优雅啦，不会打扫房间啦，吃饭太挑剔啦，成绩不如别人家小孩啦。</p>
<p>我喜欢阿姨，不喜欢妈妈，我心想。后来，我发现阿姨对自己的孩子是充满苛责的，不像对我那么好。我发现阿姨家的孩子并不喜欢阿姨，就像我不喜欢妈妈一样。</p>
]]></content>
  </entry>
  <entry>
    <title>This year</title>
    <link href="https://crazy.smallyu.net/2021/12/31/This-year/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/12/31/This-year/</id>
    <published>2021-12-31T11:39:00.000Z</published>
    <updated>2025-10-01T00:52:52.142Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>Maybe I should write something today, but I don’t would to write anything recently. I use a grammar tool named “Grammarly” to help me]]></summary>
    <content type="html"><![CDATA[<p>Maybe I should write something today, but I don’t would to write anything recently. I use a grammar tool named “Grammarly” to help me correct my grammar error this moment. As for why I started to write this in English because I found Simplified Chinese is limited for some reason. And I am difficult to write something about emotion directly. I am trying a new way, although I could just use simple sentences.</p><p>Changing the job is the most correct and biggest thing this year I did. No need to talk about it more.</p><p>I make a new friend this mouth when playing script-killing. She was once an overseas study in Korea. She will be my first friend if she is exactly to be my friend. I recalled It’s full 3 years today from I come to Beijing. It’s full 3 years I don’t have any friends.</p><p>This is life, it keeps going on.</p>]]></content>
  </entry>
  <entry>
    <title>看到以太坊的 “可升级合约” 这种机制，莫名有一种熟悉的感觉，但是一时想不起来为什么会感觉熟悉。</title>
    <link href="https://t.smallyu.net/#2021-113"/>
    <id>micro:1002891895</id>
    <published>2021-12-30T06:31:24Z</published>
    <updated>2021-12-30T06:31:24Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>看到以太坊的 “可升级合约” 这种机制，莫名有一种熟悉的感觉，但是一时想不起来为什么会感觉熟悉。</p>]]></summary>
    <content type="html"><![CDATA[<p>看到以太坊的 “可升级合约” 这种机制，莫名有一种熟悉的感觉，但是一时想不起来为什么会感觉熟悉。</p>
]]></content>
  </entry>
  <entry>
    <title>明年见</title>
    <link href="https://t.smallyu.net/#2021-112"/>
    <id>micro:991852299</id>
    <published>2021-12-12T08:07:17Z</published>
    <updated>2021-12-12T08:07:17Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>明年见</p>]]></summary>
    <content type="html"><![CDATA[<p>明年见</p>
]]></content>
  </entry>
  <entry>
    <title>一周前决定一星期内不 “写” 任何内容，发现现在身体和心态都健康多了。🐶 由于之前长期 “不正常” 的状态，可以再延长...</title>
    <link href="https://t.smallyu.net/#2021-111"/>
    <id>micro:985950416</id>
    <published>2021-12-04T02:24:37Z</published>
    <updated>2021-12-04T02:24:58Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>一周前决定一星期内不 “写” 任何内容，发现现在身体和心态都健康多了。🐶 由于之前长期 “不正常” 的状态，可以再延长一周，不接受任何 “新” 的信息。（但是 “安乐” 毕竟不是长久之计。</p>]]></summary>
    <content type="html"><![CDATA[<p>一周前决定一星期内不 “写” 任何内容，发现现在身体和心态都健康多了。🐶 由于之前长期 “不正常” 的状态，可以再延长一周，不接受任何 “新” 的信息。（但是 “安乐” 毕竟不是长久之计。</p>
]]></content>
  </entry>
  <entry>
    <title>《 我也曾对这种力量一无所知 》——韩寒</title>
    <link href="https://t.smallyu.net/#2021-110"/>
    <id>micro:982203767</id>
    <published>2021-11-30T01:49:53Z</published>
    <updated>2021-11-30T01:50:11Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>《 我也曾对这种力量一无所知 》——韩寒</p>]]></summary>
    <content type="html"><![CDATA[<p>《<a href="http://wufazhuce.com/article/3028">我也曾对这种力量一无所知</a>》——韩寒</p>
]]></content>
  </entry>
  <entry>
    <title>之前 吐槽 说阮一峰为什么会透露出某种思想。后来想到，他可是博士，能安心接受学校导师 “历练” 的人，服从性是刻在骨子里...</title>
    <link href="https://t.smallyu.net/#2021-109"/>
    <id>micro:982203474</id>
    <published>2021-11-30T01:49:10Z</published>
    <updated>2021-11-30T01:49:10Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>之前 吐槽 说阮一峰为什么会透露出某种思想。后来想到，他可是博士，能安心接受学校导师 “历练” 的人，服从性是刻在骨子里的。</p>]]></summary>
    <content type="html"><![CDATA[<p>之前 <a href="https://smallyu.net/micro-blog/#2021-65">吐槽</a> 说阮一峰为什么会透露出某种思想。后来想到，他可是博士，能安心接受学校导师 “历练” 的人，服从性是刻在骨子里的。</p>
]]></content>
  </entry>
  <entry>
    <title>What to Do When Bored at Work (And Why You Feel Bored Actual...</title>
    <link href="https://t.smallyu.net/#2021-108"/>
    <id>micro:981493921</id>
    <published>2021-11-29T10:17:47Z</published>
    <updated>2021-11-29T10:17:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>What to Do When Bored at Work (And Why You Feel Bored Actually)</p>]]></summary>
    <content type="html"><![CDATA[<p><a href="https://www.lifehack.org/572501/feeling-bored-work-here-are-causes-you-may-not-realize-and-how-you-can-cure-the-boredom">What to Do When Bored at Work (And Why You Feel Bored Actually)</a></p>
]]></content>
  </entry>
  <entry>
    <title>中式英语</title>
    <link href="https://crazy.smallyu.net/2021/11/25/%E4%B8%AD%E5%BC%8F%E8%8B%B1%E8%AF%AD/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/11/25/%E4%B8%AD%E5%BC%8F%E8%8B%B1%E8%AF%AD/</id>
    <published>2021-11-25T13:50:59.000Z</published>
    <updated>2025-08-16T03:27:11.368Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>最近注意到几个典型的中式英语的词汇：</p>
<ul>
<li>这本书里没有 magic，只是一些词法表达式的教程</li>
<li>这种做法太 low 了；那个方案太 low 了</li>
<li>我是不是 out]]></summary>
    <content type="html"><![CDATA[<p>最近注意到几个典型的中式英语的词汇：</p><ul><li>这本书里没有 magic，只是一些词法表达式的教程</li><li>这种做法太 low 了；那个方案太 low 了</li><li>我是不是 out 了</li></ul><p>这些都是中文句子里夹杂英文单词的例子，类似的现象很多，包括很多（国内的）影视剧、综艺节目都频繁出现。</p><p>问题在于，这些英文单词，在这些句子里面，怎么翻译？直译肯定是不能表达全部含义的（为什么？）。有一种悲哀的可能性就是，这样说话的人，英文不好，中文也不好，无法把中文全部替换为英文，也无法把英文全部替换为中文。</p><p>如果把中式英语也理解为一种语言的话，就属于第三种混合的语言了，不会英文的人无法理解，不会中文的人也无法理解。看到一个视频说，也许是段子，一个英国人在中国生活，回到英国后他和家人聊天，说 “这个太 low 了、那个太 low 了”。他的家人问他，“low” 是什么意思？他说，“low 就是 low ……”</p><p>语言的含义也会受到意识形态的影响。在国内的一些平台，很多中文词汇都打不出来了，但是并不影响人们理解在谈论什么。</p><p>有的人宣称自己有 “语言洁癖”，无法容忍中英混杂的句子，认为这是一种不干净的表达，应该用纯粹的中文或者英文。这样的人是有民族主义的嫌疑的。</p><p>无论是象形文字还是拉丁字母，都是人类用来表达自己想法的工具，都是人类社会在思想上达成共识的媒介。90 后的火星文字、00 后的拼音简写，都是属于一代人的集体记忆，同样属于一种另类形式的语言。</p><p>言尽其意就好。</p>]]></content>
  </entry>
  <entry>
    <title>知识的诅咒</title>
    <link href="https://b.smallyu.net/2021/11/24/%E7%9F%A5%E8%AF%86%E7%9A%84%E8%AF%85%E5%92%92/"/>
    <id>blog-b:https://b.smallyu.net/2021/11/24/%E7%9F%A5%E8%AF%86%E7%9A%84%E8%AF%85%E5%92%92/</id>
    <published>2021-11-24T14:19:55.000Z</published>
    <updated>2026-03-02T09:02:54.303Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>一开始，每个人都是一个空的容器：</p>
<img src="1.png" width="20%">

<p>随着经历的增长，容器内增添新的内容：</p>
<img src="2.png" width="20%">

<p>并且会不断增加新的内容：</p>
<img]]></summary>
    <content type="html"><![CDATA[<p>一开始，每个人都是一个空的容器：</p><img src="1.png" width="20%"><p>随着经历的增长，容器内增添新的内容：</p><img src="2.png" width="20%"><p>并且会不断增加新的内容：</p><img src="3.png" width="20%"><p>当两个容器相遇，容器内装着不同的内容：</p><img src="4.png" width="40%"><p>两个容器会尽可能拿出内容相同的一面，产生关联，在某些问题上达成一致，并且形成更密切的关系：</p><img src="5.png" width="40%"><p>随着各自内容的继续增长，它们相同的一面占比由 1&#x2F;2 变为 1&#x2F;3，它们之间的联系变弱了：</p><img src="6.png" width="40%"><p>相同内容占比变为 1&#x2F;4 的时候，它们不再继续有联系：</p><img src="7.png" width="40%"><p>此时第三个容器出现了：</p><img src="8.png" width="60%"><p>最左边和中间的容器，相同之处占比为 2&#x2F;4 &#x3D; 1&#x2F;2，它们产生了联系：</p><img src="9.png" width="60%"><p>随着时间的继续增加和内容的继续增长，中间的节点获得了一些特殊的独一无二的内容，这个独特的内容是一个容器区别于其他容器的关键，俗称独立思考能力：</p><img src="10.png" width="70%"><p>这一部分特殊的内容不仅自己特殊，还会影响之前存在的已有的内容，将之前的内容变为更加丰富的、带有独立思考的内容：</p><img src="11.png" width="70%"><p>由于特殊内容对之前内容产生了干扰，混杂在之前的内容中，之前内容相同的占比已经降低，最左边容器和中间容器的关系变弱了：</p><img src="12.png" width="70%"><p>甚至再没有关联：</p><img src="13.png" width="70%"><p>最左边的容器，始终没有获得那样特殊的内容：</p><img src="14.png" width="70%"><p>直到有一天，最右边的节点获得了一些特殊的内容，只不过是三角形的：</p><img src="15.png" width="70%"><p>中间的容器和右边的容器无法达成一致：</p><img src="16.png" width="70%"><p>中间容器的内容没有停止增长，在有了特殊内容之后，再增添的内容也变成彩色了：</p><img src="17.png" width="70%"><p>中间的容器和左右两边的节点，都没有联系了，也难以再产生联系：</p><img src="18.png" width="70%"><p>中间的容器，只剩自己了，和一开始一样：</p><img src="19.png" width="70%"><p>中间容器的内容继续增长着：</p><img src="20.png" style="width:25%"><p>和其他容器一起，各自独立地继续累加内容：</p><img src="21.png" width="60%"><p>林林总总，花花绿绿：</p><img src="22.png" width="40%">]]></content>
  </entry>
  <entry>
    <title>子曰：“不患无位，患所以立。不患莫己知，求为可知也。”</title>
    <link href="https://t.smallyu.net/#2021-107"/>
    <id>micro:977568508</id>
    <published>2021-11-24T06:22:11Z</published>
    <updated>2021-11-24T06:22:11Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>子曰：“不患无位，患所以立。不患莫己知，求为可知也。”</p>]]></summary>
    <content type="html"><![CDATA[<p>子曰：“不患无位，患所以立。不患莫己知，求为可知也。”</p>
]]></content>
  </entry>
  <entry>
    <title>《 马说 》</title>
    <link href="https://t.smallyu.net/#2021-106"/>
    <id>micro:977568324</id>
    <published>2021-11-24T06:21:49Z</published>
    <updated>2021-11-24T06:21:49Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>《 马说 》</p>]]></summary>
    <content type="html"><![CDATA[<p>《<a href="https://baike.baidu.com/item/%E9%A9%AC%E8%AF%B4/1563391">马说</a>》</p>
]]></content>
  </entry>
  <entry>
    <title>《 伪工作 》</title>
    <link href="https://t.smallyu.net/#2021-105"/>
    <id>micro:977548021</id>
    <published>2021-11-24T05:33:52Z</published>
    <updated>2021-11-24T05:33:52Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>《 伪工作 》</p>]]></summary>
    <content type="html"><![CDATA[<p>《<a href="https://yinwang1.wordpress.com/2020/06/29/pseudowork/">伪工作</a>》</p>
]]></content>
  </entry>
  <entry>
    <title>随想</title>
    <link href="https://crazy.smallyu.net/2021/11/23/%E9%9A%8F%E6%83%B3/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/11/23/%E9%9A%8F%E6%83%B3/</id>
    <published>2021-11-23T15:40:59.000Z</published>
    <updated>2025-08-16T03:27:11.460Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>现在是凌晨快 1 点，睡不着，稍微写写。今天白天（昨天），测试提醒我，REST 接口的输入参数应该以大写字母开头。</p>
<p>我一开始还紧张了一下，我 out 了？我没有按照该有的规范开发？REST 接口的参数大写开头？（接口的]]></summary>
    <content type="html"><![CDATA[<p>现在是凌晨快 1 点，睡不着，稍微写写。今天白天（昨天），测试提醒我，REST 接口的输入参数应该以大写字母开头。</p><p>我一开始还紧张了一下，我 out 了？我没有按照该有的规范开发？REST 接口的参数大写开头？（接口的 <code>Content-Type</code> 是 <code>application/json</code>）</p><p>然后就去查了一下 GitHub 的 API 文档，又看了一眼 DIDs (Decentralized Identifiers) 的标准文档，以及结合长时间接触使用 json 的经验，没有啊，json 的 key，哪有大写字母开头的习惯？</p><p>后来想到了一个吐血的原因，就问了一句，“参数首字母大写，是公司的规范吗？”。测试回复的原话是：</p><blockquote><p>我之前问过，就是你们开发自己都这么写，好像是，公有变量还是私有变量，就要首字母大写</p></blockquote><p>果然是。（微笑）</p><h3 id="权限控制"><a href="#权限控制" class="headerlink" title="权限控制"></a>权限控制</h3><p>Java 里的权限修饰符是很基础的概念，用来控制类的访问权限，一共有 3 个关键词、4 种情况，比如 <code>public</code> 表示公开，<code>private</code> 表示私有：</p><pre><code class="Java">public class aaa &#123;    public int a;    private String b;&#125;</code></pre><p>具体内容可以参考 Java 的文档： <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html">Controlling Access to Members of a Class</a></p><p>像 Python 那样的脚本语言本身没有访问权限控制的概念，所以约定俗成地认为以 <code>_</code> 开头命名的变量是私有的，不过没有代码层面的保护，只是命名上的区别。</p><pre><code>class aaa:    a = 1    _b = 2</code></pre><p>Pthon 里 <code>__</code> 开头的变量名可以达到代码层面私有变量的效果，但把 <code>__</code> 用做私有变量并不完全是 Python 的本意。参考 Pthon 的文档：<a href="https://docs.python.org/3/tutorial/classes.html#private-variables">9.6. Private Variables</a></p><p>众所周知，Golang 是一种奇葩的语言，不但要求你大括号必须写在函数名同一行，还会要求你必须做一些什么事情，比如，大写字母开头的变量意味着公开，小写字母开头的变量意味着私有。</p><p>Golang 对变量大小写的区分，可不仅仅是命名上的区别，而是代码层面的控制。下面的代码会输出什么？</p><pre><code class="Golang">func main() &#123;    a := struct &#123;        i int    &#125;&#123;        i: 1,    &#125;    s, _ := json.Marshal(a)    fmt.Println(string(s))&#125;</code></pre><p>当然是 <code>&#123;&#125;</code>，由于 <code>i</code> 是小写的，在 marshal 的时候自动忽略了。</p><p>这其实算是比较不正常的要求了。Golang 为了设计上的 “简洁”，很大程度上减少关键字、关键字复用，但是又不得不提供某些能力，就需要一些奇怪的方式做变通。 </p><p>我在上面的 Java 代码中，刻意用了小写的 <code>aaa</code> 做类名。Java 的类一般使用大写字母开头，但是不会在代码层面限制你把代码写成什么样子。</p><p>虽然我工作使用 Golang，但我不是它的教徒，当然，也不是其他语言的教徒。如果你仍然是某种语言的教徒，祝愿你可以尽早改变一下观念。</p><p>所以，由于 Golang 的一些 “特性”，为了在序列化的时候方便一点，项目的 REST 接口就习惯于使用大写字母开头的变量名作为 key 了。</p><p>睡觉了，明天再写。</p><h3 id="没有问题"><a href="#没有问题" class="headerlink" title="没有问题"></a>没有问题</h3><p>json 的 key 大写或者小写开头，其实都没有问题。输出参数为了省去写 <code>`json`</code> 的麻烦，就默认大写开头，所以输入参数也大写开头了。这是一种工程上的对称，并没有什么问题。</p><p>想起之前有一次，我把 REST 接口设计为，输入参数用驼峰命名 <code>myName</code>，输出参数用下划线分割 <code>my_name</code>。这样做的原因，是参数输入的时候，Java 的 Entity 能够把 POST Body 里驼峰命名的变量自动识别到对象上。返回参数时，程序直接把从数据库查出来的数据返回出去，是下划线形式的（不符合开发规范是真的）。这样做可以达到代码上的最简洁，但确实输入输出不对称不合适。</p><h3 id="一件事"><a href="#一件事" class="headerlink" title="一件事"></a>一件事</h3><p>如果只是这么点事，就不值得写什么了。昨天测试说我什么地方该怎么样做的时候，我想到另一件事，在之前的公司里发生的事。</p><p>URL 的输入参数有两种形式，一种是 <code>.com/?a=1&amp;b=2</code>，另一种是 <code>.com/:a/:b</code>。当时的项目里全是第二种形式，也就是路由形式的参数。</p><p>全部是第二种形式，有时候特别长，比如 <code>.com/:a/:b/:c/:d/:e</code>。参数很多时候是查询条件，如果中间的某个参数不需要作为条件，也就是不需要传参数，但是这种路由形式的参数又不能跳过中间的一段，就用了一种很奇葩的方式变通：<code>all</code>。用 <code>all</code> 来代替不需要传参的情况，<code>.com/:a/:b/all/:d/:e</code>。程序里面的判断也是各种离谱。</p><p>REST 接口本身是一种 Web 服务，但是如果缺少 Web 开发的基础，就容易做的有一些欠缺。</p><p>我当时怀疑开发那个项目的人技术水平有问题，也就是我当时名义上的小组长。好吧，也许是一段不怎么开心的往事。</p><p>顺便解释一下，我也不是有事没事就会对别人有意见。我当时所在的公司，有一种绩效的制度，每个季度开始前都需要写绩效计划，大概是接下来一段时间要做什么之类，一般是组长制定一个大方向上的目标，然后组员分配分别完成一些节点。我因为质疑他的水平，担心他制定的目标比较低，限制我的发挥，就借题发挥试探一下。对别人有意见对我自己没有任何好处，我也是出于一种恐惧，担心自己接下来会置于难以发挥的处境。</p><p>我当时并没有想离职，所以还是在极力想办法改善自己周围的环境和情况，给自己争取一个自己可以适应的状况。记得当时有其他同事离职的时候，（以前好像说过？好像说过，不记得了，再说一遍），我开玩笑说，工作中最开心的时候，可能就是提离职的时候和收到 offer 的时候了。同事说，最开心的时候是年底发奖金的时候……也是开玩笑。后来接着说，如果不是到没有办法的地步，不会有人愿意离职的。</p><p>我知道参数形式这种问题是小问题，但是我坚持认为，在当时的接口设计上，应该用参数形式的参数而不是路由形式的参数。参数形式的参数明明更好用，为什么不用？说说你的理由，我已经拿出了话题，还把话头递给了你，你说一说啊，你的理由，除了 “以前的人就是这么写的” 之外，你有没有其他的在技术方面的思考？能不能够在技术方面碾压我，以小见大，体现一下自己的技术能力？</p><p>我的基本观点是，他缺少 Web 开发的经验，不是认为路由形式的参数好用，而是完全不知道有参数形式的参数存在。我分析有两种可能，一种是他自己有实力，但是不轻易和我说，另一种就是自己没有实力。所以啊，我从一个很小的问题，制造了话题，给他说话的机会，甚至之后用比较强硬的态度在 leader 面前，表达了我对他能力的质疑。我心想，我都这么挑事了，要真有实力，总该表现出来了吧。</p><p>唉再之后就是一些收场环节了。</p><h3 id="设身处地"><a href="#设身处地" class="headerlink" title="设身处地"></a>设身处地</h3><p>我当时也想过，如果我是他，我会怎么办？</p><p>如果以后有小伙子那样对我，我能处理地比他更好吗？</p><p>如果有人质疑我的技术实力，或者揪着我的失误不放，借题发挥，我该怎么办？</p><p>我也知道，我好像破坏了一种和谐的宁静。</p><h3 id="然后呢"><a href="#然后呢" class="headerlink" title="然后呢"></a>然后呢</h3><p>现在的我，已经没有兴趣在类似那样的小问题上较真了，怎么样是对的，什么样是错的，有什么所谓呢。</p><p>不过过去的经历好像也是必要的。如果不是过去认真过，可能现在也还是会好奇：如果在一些问题上，我坚持自己的观点，或者非要争个对错，会是什么样的结果呢。</p><p>由于过去的经历，我已经知道是什么样的结果了。</p><p>其实结果不太好，也有点无聊。</p><p>我不太喜欢也并不期望是那样。</p><p>暂时没有然后了。</p>]]></content>
  </entry>
  <entry>
    <title>GitBook 好用吗？</title>
    <link href="https://smallyu.net/2021/11/21/GitBook%E5%A5%BD%E7%94%A8%E5%90%97%EF%BC%9F/"/>
    <id>blog:https://smallyu.net/2021/11/21/GitBook%E5%A5%BD%E7%94%A8%E5%90%97%EF%BC%9F/</id>
    <published>2021-11-21T06:21:20.000Z</published>
    <updated>2025-11-09T09:22:13.308Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>10 月 15 日，我写下<a href="https://smallyu.net/micro-blog/#2021-84">一句话</a>：</p>
<blockquote>
<p>用 cloudflare cloud 的 DNS，把子域名 gub 从原来 CNAME]]></summary>
    <content type="html"><![CDATA[<p>10 月 15 日，我写下<a href="https://smallyu.net/micro-blog/#2021-84">一句话</a>：</p><blockquote><p>用 cloudflare cloud 的 DNS，把子域名 gub 从原来 CNAME 到 gitbook 改为指向到 github，到现在已经超过 72 小时，开启 DNS proxy 的情况下依然跳转到 gitbook，看样子是一个 302 forward。</p><p>不是 cacheing 的问题，已经很多次打开 dev mode 并且 purge 所有内容了。猜测 cloudflare cloud proxy 服务对于 forward 记录的更新非常慢，甚至有 bug。现在经过的时长一定超过 TTL 了。</p></blockquote><p>一个月过去了，问题无意间得到了解决。想展开详细描述一下我遇到的问题。</p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>这里会涉及到两个概念，DNS（Domain Name System）和 CDN（Content Delivery Network）。如果你不太接触 Web service 领域，可以先了解一下它们的联系和区别。</p><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>一开始的时候，我计划写一本开源书，选择 GitBook 作为写作平台。GitBook 名声在外，又有 GitbookIO&#x2F;gitbook 那样广为人知的开源渲染工具，是开源书的不二选择。经过短暂的试用后，在平台的使用上没有感觉到异常。我创建了 Workspace，然后在 GitHub 上新建仓库，把仓库关联到 GitBook 上，一切都很顺利。我简单测试了一下 GitBook 和 GitHub 自动同步的能力，有可能会出现一点点冲突，但还是容易解决的。</p><p>我在 GitBook 上绑定了自定义的域名。<code>smallyu.net</code> 这个域名托管在 Cloudflare 上，子域名 <code>gub.smallyu.net</code> 也是在 Cloudflare 上设置 DNS 记录。全世界都知道，Cloudflare 会提供免费的 CDN 服务，只要在 DNS 记录上打开 Proxy 的橙色按钮开关就可以了：</p><img src="1.png"><p>当时在解析到 GitBook 的时候，开关是打开的。之后没几天，正好遇到了 GitBook 改版大升级，写作界面完全改变了。改版后一两天，我想要更新一些页面的内容，发现改版后的 GitBook 操作流程反直觉、bug 满天飞，每次修改都相当于 Git的 Pull Request，而且每次点编辑按钮，都会新增一个 Pull Request 的条目。当同时存在多个 Pull Request 记录时，页面状态会完全不可控，这个是 1、那个是 2、另一个是 3，还不能增量合并，因为你无法区分两个 PR 之间，一些内容是没修改过还是被删除了。重点在于，PR 没有删除选项，稍微有点强迫症都受不了。网速不好的时候，多刷新两下编辑页面，草稿箱就会多出好几个 PR 的条目，还不知道哪个是刚刚修改的。包括一些其他使用体验上的小问题，当时我还吐槽说：</p><blockquote><p>现在 gitbook 的在线编辑难用过头了，不能删除 commit，不能新建文档，光标会自动跳转……他们是怎么对用户负责的。</p></blockquote><p>后来决定放弃 GitBook，换成了 docsify，页面部署在 GitHub Pages 上，<code>sub.smallyu.net</code> 域名的解析也换到了 GitHub 上。更改 DNS 的解析记录后，发现解析没有生效（Cloudflare 上的 CDN Proxy 开着），访问 <a href="https://gub.smallyu.net/">https://gub.smallyu.net</a> 总是跳转到原来的 GitBook 页面上。</p><p>一开始怀疑是 DNS TTL 的问题，因为在 Proxied 的状态下，TTL 的值只能是 Auto。毕竟 Cloudflare 的 CDN 节点多，我的域名访问量又低，可能 DNS 记录更新比较慢。幸幸苦苦等了 3 天，这个时间足够长了，发现解析依然不生效，因为域名还是跳转到了旧的页面。</p><p><code>dig</code> 域名的记录，是这样的结果：</p><pre><code>gub.smallyu.net.300INA104.21.81.212gub.smallyu.net.300INA172.67.146.253</code></pre><p>此时域名是查不到 CNAME 记录的。对比之后，发现这就是 Cloudflare CDN 的 IP。域名已经解析到了 CDN 上，问题是 CDN 没有返回预期的新页面的内容。</p><p>然后偶然发现，把 CDN Proxy 关了，域名解析正常了，A 记录是 GitHub 的，CNAME 也是 GitHub 的，页面是新的。</p><p>是什么问题呢？Cloudflare 的 CDN 没有刷新内容。</p><p>Cloudflare 有一个 Caching 的配置，也提供了 Purge 的能力：</p><img src="2.png"><p>在点过很多次 Purge Everything 的按钮后，CDN 内容仍然没有刷新，即使打开其他人都说有效的开发者模式，也是徒劳：</p><img src="3.png"><p>包括自定义页面规则，不走任何缓存，也无济于事：</p><img src="4.png"><p>甚至为了让内容更新生效，我在 GitBook 上删除了原有的 Workspace，还注销了账号。仍然没有用。</p><p>之后就不了了之了，只要不开 Proxy，域名解析就是能用的。不过，我当时认为可能是 CDN 的 bug，也许 GitBook 用了 302 forward 之类的记录，CDN 不能正确刷新这种类型的记录。</p><h3 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h3><p>最近，在访问 <a href="https://gub.smallyu.net/">https://gub.smallyu.net</a> 的时候页面稍微卡顿了一下，想起这个页面是没有走 CDN 的，想到了 Cloudflare 上的这条不正常的 DNS 记录。顺手 Google 了一下相关问题，没想到这次找到了有用的信息。之前遇到问题的时候也在网上搜过，搜出来的全是更新缓存之类，这次却找到了不一样的内容。</p><p>Cloudflare 有一些 partners，这些 partners 有着控制 Cloudflare DNS 的权力，Cloudflare 的域名在解析到 GitBook 上后，CDN 的 DNS 就受 GitBook 控制了，在 Cloudflare 上的配置优先级低于 GitBook 上的配置。</p><p>相关问题的链接：</p><ul><li><a href="https://community.cloudflare.com/t/dns-subdomain-no-longer-works-nor-redirects-to-anything/240984/7">DNS subdomain no longer works nor redirects to anything</a></li><li><a href="https://community.cloudflare.com/t/subdomain-cname-does-not-update/280696/2">Subdomain CNAME does not update</a></li></ul><p>我发邮件给 GitBook Support：</p><img src="11.png"><p>没想到 GitBook Supoort 一天之内就回复并解决了问题：</p><img src="12.png"><p>经过测试，现在一些正常，确实是那样的原因。</p><h3 id="教训"><a href="#教训" class="headerlink" title="教训"></a>教训</h3><p>谁能想到，Cloudflare 如此广泛使用的服务提供商，会把域名在 CDN 上的解析权限交给 partners。</p><p>谁能想到，GitBook 的产品即使用户删除了 Workspace 注销了账户，在系统内的域名解析记录都不会被删除。</p><p>这件事情可以带来的启发是，我们应该从普通的用户思维转变为开发者思维。也许在某种观念的影响下，因为所谓 “官网”、“权威” 的概念，当使用一些平台的时候，我们习惯于首先质疑自己的使用方法和操作错误，却很少质疑平台的问题。即使明确是平台的问题，也不会优先试图联系平台方解决问题。从这个点其实可以发散出很多内容，以后有机会再展开。</p><h3 id="工具"><a href="#工具" class="headerlink" title="工具"></a>工具</h3><p>最后现在用 Rust 团队开发的 mdbook 了。GitBook 稍微有点过时、处于不怎么维护的状态。docsify 也有问题，docsify 更适合项目文档，除了样式不那么凸显文字外，页面和页面之前是没有关联的，没有上一页下一页的跳转链接，不太像是一本书。虽然 mdbook 的样式没有很时尚，但是功能齐全完整、编译速度能感受到的快，好用就行。</p>]]></content>
  </entry>
  <entry>
    <title>不要害怕做过一些错误的事情或者做了一些无畏的努力，它们的意义就在于，排除了错误的答案。</title>
    <link href="https://t.smallyu.net/#2021-104"/>
    <id>micro:974233157</id>
    <published>2021-11-19T16:46:08Z</published>
    <updated>2021-11-19T16:46:08Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>不要害怕做过一些错误的事情或者做了一些无畏的努力，它们的意义就在于，排除了错误的答案。</p>]]></summary>
    <content type="html"><![CDATA[<p>不要害怕做过一些错误的事情或者做了一些无畏的努力，它们的意义就在于，排除了错误的答案。</p>
]]></content>
  </entry>
  <entry>
    <title>你真的不应该再为一些无关痛痒的小事烦心了，你应该清楚自己力量的来源，以及，don&amp;#39;t work too hard...</title>
    <link href="https://t.smallyu.net/#2021-103"/>
    <id>micro:974006406</id>
    <published>2021-11-19T11:53:00Z</published>
    <updated>2021-11-19T11:53:00Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>你真的不应该再为一些无关痛痒的小事烦心了，你应该清楚自己力量的来源，以及，don&amp;#39;t work too hard。 你无法说服不相信自己的人。也不需要去说服。</p>]]></summary>
    <content type="html"><![CDATA[<p>你真的不应该再为一些无关痛痒的小事烦心了，你应该清楚自己力量的来源，以及，don&#39;t work too hard。</p>
<p>你无法说服不相信自己的人。也不需要去说服。</p>
]]></content>
  </entry>
  <entry>
    <title>有的人或者公司喜欢发明概念，因为如果能发明一个概念的话，他就是这个概念上的专家，他是最了解这个概念的人。有的概念在被大量...</title>
    <link href="https://t.smallyu.net/#2021-102"/>
    <id>micro:966739748</id>
    <published>2021-11-12T01:14:40Z</published>
    <updated>2021-11-12T01:14:40Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有的人或者公司喜欢发明概念，因为如果能发明一个概念的话，他就是这个概念上的专家，他是最了解这个概念的人。有的概念在被大量宣传的时候，大家还在纳闷，这个概念到底是什么意思？</p>]]></summary>
    <content type="html"><![CDATA[<p>有的人或者公司喜欢发明概念，因为如果能发明一个概念的话，他就是这个概念上的专家，他是最了解这个概念的人。有的概念在被大量宣传的时候，大家还在纳闷，这个概念到底是什么意思？</p>
]]></content>
  </entry>
  <entry>
    <title>我不太喜欢的一个人</title>
    <link href="https://b.smallyu.net/2021/11/12/%E6%88%91%E4%B8%8D%E5%A4%AA%E5%96%9C%E6%AC%A2%E7%9A%84%E4%B8%80%E4%B8%AA%E4%BA%BA/"/>
    <id>blog-b:https://b.smallyu.net/2021/11/12/%E6%88%91%E4%B8%8D%E5%A4%AA%E5%96%9C%E6%AC%A2%E7%9A%84%E4%B8%80%E4%B8%AA%E4%BA%BA/</id>
    <published>2021-11-11T16:11:46.000Z</published>
    <updated>2025-12-03T10:02:00.865Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>其实我不太了解那个人，只有非常少数的一点印象。</p>
<p>我实习的时候，正赶上政策压制，公司裁员，同一批的实习生走了一半，包括和我同部门另一个组的小伙伴。应该是当时的部门 leader]]></summary>
    <content type="html"><![CDATA[<p>其实我不太了解那个人，只有非常少数的一点印象。</p><p>我实习的时候，正赶上政策压制，公司裁员，同一批的实习生走了一半，包括和我同部门另一个组的小伙伴。应该是当时的部门 leader 把简历给了其他部门，我就转到后来做区块链的部门了。</p><p>我到部门第一个见到的就是那个人，也是 leader。从对话内容看应该是看过我留在简历上的博客地址。之后我的工作就全部由小组长分配了，一开始做做网页，到后来做一些其他事情。</p><p>我毕业转正正式工作后不久，那个 leader 就离职了，去了一家初创公司当合伙人，那家公司目前在做开源的联盟链。也因此我不太看好那条开源联盟链的技术，甚至一开始感觉能在那个项目上看到一点点，我上家公司区块链产品的影子。也可能是联盟链都是那种样子。</p><p>在他离职的欢送仪式上，我记得他说过一些话，我不太喜欢那些话。</p><p><strong>“有些人下班到点就走，不加班，怎么提高自己？”</strong></p><p>好像还说他虽然走得早，但是回家也仍然在工作什么的。时间太久，记不清具体内容了，大概是那样的意思。当然不是冲我说，是对所有人说的，不是针对谁。</p><p>虽然我当时还年轻，加得动班，但是我完全不认同那样的混蛋逻辑。后来公司有段时间还要求 996，我完全能做到去得最早走得最晚，就差公司没床了。况且我上班的时候也挺认真的，主要是简单，做网页什么的老本行了。而且，你怎么知道下班时间只有你在做有用的事情？</p><p><strong>“如果我创业不行了，希望大家能给我留个位置。”</strong></p><p>这话我是理解不了，走都走了，还想着后路。不过不幸的事实，“大家” 倒的比他的创业事业还快，不知道是不是因为他走了。</p><p><strong>“你们都不行！”</strong></p><p>饭局上，有人说，“你创业，把我们也带过去吧？” 然后他就说了这样的话。终于在离开的时候把心里话说出来了，哈哈。</p><p>后来就没什么了，总之感觉自己看到了一个经典的油腻大叔的形象。记得我喝了两杯白酒就开始头晕了。</p><p>再后来见面是一次部门团建，把他一起叫上了。他和部门 leader 比较熟。一起团建的还有另一个部门的 leader。</p><p>同样是在吃饭的时候，另一个部门的 leader 提到了落俗老套的问题，没什么人搭茬。然后话题就到了他创业的公司那边有没有女的，有女的给我们介绍一下之类。</p><p><strong>“有女的。（停顿一下）女博士！”</strong></p><p>这是和我价值观几乎相悖的一种言论。言外之意就是，博士嘛！你们呢？</p><p>在一个匿名的社区上，可以查到有人对他们公司的评价是，既有国企的腐朽文化，又有互联网公司加班、on-call 的优良传统。</p><p>有一次他们的产品发大版本直播，简直像是在谈笑风生，气氛松松垮垮，着装和环境都很 low。</p><p>在他离职创业的同年，他们公司开始做现在的项目，也可能稍后几个月的时间。反正到现在没多少时候，他们也没多少人，版本倒是发的老勤快了。当时还看到他发朋友圈说要打造国内最牛的区块链平台。</p><p>看看他们在其他直播会议上的演讲 PPT，最亮眼的就是列了一大堆指导单位和成员单位的一页。</p><p>之前偶尔有猎头联系我，说那个公司在招人。</p><p>由于这样一些特殊的原因，我可能永远也不会去或者说去不了人家那种高大上的有女博士的公司了。</p>]]></content>
  </entry>
  <entry>
    <title>一种区块链节点存储扩容的方式</title>
    <link href="https://smallyu.net/2021/11/10/%E4%B8%80%E7%A7%8D%E5%8C%BA%E5%9D%97%E9%93%BE%E8%8A%82%E7%82%B9%E5%AD%98%E5%82%A8%E6%89%A9%E5%AE%B9%E7%9A%84%E6%96%B9%E5%BC%8F/"/>
    <id>blog:https://smallyu.net/2021/11/10/%E4%B8%80%E7%A7%8D%E5%8C%BA%E5%9D%97%E9%93%BE%E8%8A%82%E7%82%B9%E5%AD%98%E5%82%A8%E6%89%A9%E5%AE%B9%E7%9A%84%E6%96%B9%E5%BC%8F/</id>
    <published>2021-11-10T14:25:28.000Z</published>
    <updated>2025-06-19T03:30:33.160Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>区块链是天然支持水平扩容的系统，节点扩展能力首屈一指。</p>
<img src="1.png"]]></summary>
    <content type="html"><![CDATA[<p>区块链是天然支持水平扩容的系统，节点扩展能力首屈一指。</p><img src="1.png" width="50%"><p>但区块链的垂直扩展能力还是一个经常被讨论的课题。单个节点的硬盘容量总是有限，如果节点拥有全部的数据，对单机性能要求会比较高；如果节点没有全量数据，就不能认为是 P2P 网络的节点之一。</p><p>最直接的办法就是用分布式数据库，数据库本身就支持扩容，区块链节点的存储模块就也算是支持扩容了。（如果区块链在立场上和数据库没有冲突的话。）</p><p>这里描述一种简单的实现思路的设想。</p><p>节点的垂直扩展，是想用多个节点合力代替原有的一个节点的位置，整体形式上一个集群提供了和单个节点一样的输入输出。</p><img src="2.png" width="80%"><p>节点完全可以将块数据分散储存在不同的子节点上，比如按照数据库分库分表的经典思路，对块号取模，或者随机分发也行。</p><img src="3.png" width="50%"><p>节点可以区分为索引节点和存储节点，索引节点只记录块号和子节点的对应关系，子节点集群就作为索引节点的储存模块。索引节点同时负责发送和接收块等操作。除了网络延迟带来的存取速度的降低，似乎没有大碍。</p><p>对于节点类型的问题，是必须要有不只一种类型的节点吗？有没有办法实现只要一份源代码、只有一种二进制程序、只用一种类型的节点，就能实现所有的功能？当然，不是说把三种类型的节点打包到一起就行了。由于功能侧重点的不同，尤其是节点 “身份” 的不同，可能节点不得不区分类型。一个节点对外提供能力和一个集群合作对外提供能力，集群内的节点和单个节点应该是一样的地位吗？</p><p>将块数据分散开后，对于 “世界状态” 一类的数据，可以全部储存在索引节点上。</p><img src="4.png" width="50%"><p>如果状态数据也想扩容，同样可以只在索引节点上保留索引数据，然后将状态数据也分散到储存节点上。</p><img src="5.png" width="50%"><p>这样的方案也许过于简单了，万一行之有效呢。</p>]]></content>
  </entry>
  <entry>
    <title>自然语言是人类社会达成共识的工具。由于现有的庞大的体系，没有人可以重新发明语言。只能被动接受现有规则。</title>
    <link href="https://t.smallyu.net/#2021-101"/>
    <id>micro:964807923</id>
    <published>2021-11-10T05:47:23Z</published>
    <updated>2021-11-10T05:47:23Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>自然语言是人类社会达成共识的工具。由于现有的庞大的体系，没有人可以重新发明语言。只能被动接受现有规则。</p>]]></summary>
    <content type="html"><![CDATA[<p>自然语言是人类社会达成共识的工具。由于现有的庞大的体系，没有人可以重新发明语言。只能被动接受现有规则。</p>
]]></content>
  </entry>
  <entry>
    <title>但是咖啡好喝。忍不住想喝。</title>
    <link href="https://t.smallyu.net/#2021-100"/>
    <id>micro:962464681</id>
    <published>2021-11-06T15:05:34Z</published>
    <updated>2021-11-06T15:05:34Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>但是咖啡好喝。忍不住想喝。</p>]]></summary>
    <content type="html"><![CDATA[<p>但是咖啡好喝。忍不住想喝。</p>
]]></content>
  </entry>
  <entry>
    <title>《 故乡 》—鲁迅</title>
    <link href="https://t.smallyu.net/#2021-99"/>
    <id>micro:961777441</id>
    <published>2021-11-05T10:21:00Z</published>
    <updated>2021-11-06T15:05:14Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>《 故乡 》—鲁迅</p>]]></summary>
    <content type="html"><![CDATA[<p>《<a href="https://zh.m.wikisource.org/zh-hans/%E6%95%85%E9%84%89">故乡</a>》—鲁迅</p>
]]></content>
  </entry>
  <entry>
    <title>Top 25 Tips To Change Your Life</title>
    <link href="https://t.smallyu.net/#2021-98"/>
    <id>micro:961750675</id>
    <published>2021-11-05T09:37:36Z</published>
    <updated>2021-11-05T09:37:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Top 25 Tips To Change Your Life</p>]]></summary>
    <content type="html"><![CDATA[<p><a href="https://www.realbuzz.com/articles-interests/health/article/top-25-tips-to-change-your-life/">Top 25 Tips To Change Your Life</a></p>
]]></content>
  </entry>
  <entry>
    <title>结论：不要喝咖啡，不管是速溶咖啡、咖啡饮料、咖啡店外卖。会改变身体的状态。</title>
    <link href="https://t.smallyu.net/#2021-97"/>
    <id>micro:959397145</id>
    <published>2021-11-03T15:13:47Z</published>
    <updated>2021-11-03T15:13:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>结论：不要喝咖啡，不管是速溶咖啡、咖啡饮料、咖啡店外卖。会改变身体的状态。</p>]]></summary>
    <content type="html"><![CDATA[<p>结论：不要喝咖啡，不管是速溶咖啡、咖啡饮料、咖啡店外卖。会改变身体的状态。</p>
]]></content>
  </entry>
  <entry>
    <title>想尝试交互式游戏，mac 上能玩的不多，有一个叫《隐形的守护者》的国产游戏，16 块钱，虽然只有国语，但是好评多、有人推...</title>
    <link href="https://t.smallyu.net/#2021-96"/>
    <id>micro:955637481</id>
    <published>2021-10-31T05:00:23Z</published>
    <updated>2021-10-31T05:00:23Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想尝试交互式游戏，mac 上能玩的不多，有一个叫《隐形的守护者》的国产游戏，16 块钱，虽然只有国语，但是好评多、有人推荐、各种获奖，我不看好国产，也不看好谍战题材，但是不贵就试试水。 玩了两分钟，太烂了。</p>]]></summary>
    <content type="html"><![CDATA[<p>想尝试交互式游戏，mac 上能玩的不多，有一个叫《隐形的守护者》的国产游戏，16 块钱，虽然只有国语，但是好评多、有人推荐、各种获奖，我不看好国产，也不看好谍战题材，但是不贵就试试水。</p>
<p>玩了两分钟，太烂了。</p>
]]></content>
  </entry>
  <entry>
    <title>Netflix 上有一集《黑镜》的剧场版竟然是交互式的！是交互式的！剧情游戏的那种！ 可以操纵《黑镜》剧情的走向，是什么...</title>
    <link href="https://t.smallyu.net/#2021-95"/>
    <id>micro:955627672</id>
    <published>2021-10-31T02:55:55Z</published>
    <updated>2021-10-31T03:01:41Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Netflix 上有一集《黑镜》的剧场版竟然是交互式的！是交互式的！剧情游戏的那种！ 可以操纵《黑镜》剧情的走向，是什么感觉！ 以前在其他网站上看过这集，有点可惜。千万不要看盗版！</p>]]></summary>
    <content type="html"><![CDATA[<p>Netflix 上有一集《黑镜》的剧场版竟然是交互式的！是交互式的！剧情游戏的那种！</p>
<p>可以操纵《黑镜》剧情的走向，是什么感觉！</p>
<p>以前在其他网站上看过这集，有点可惜。千万不要看盗版！</p>
]]></content>
  </entry>
  <entry>
    <title>一种基于“自我中心主义”的共识机制</title>
    <link href="https://smallyu.net/2021/10/29/%E4%B8%80%E7%A7%8D%E5%9F%BA%E4%BA%8E%E2%80%9C%E8%87%AA%E6%88%91%E4%B8%AD%E5%BF%83%E4%B8%BB%E4%B9%89%E2%80%9D%E7%9A%84%E5%85%B1%E8%AF%86%E6%9C%BA%E5%88%B6/"/>
    <id>blog:https://smallyu.net/2021/10/29/%E4%B8%80%E7%A7%8D%E5%9F%BA%E4%BA%8E%E2%80%9C%E8%87%AA%E6%88%91%E4%B8%AD%E5%BF%83%E4%B8%BB%E4%B9%89%E2%80%9D%E7%9A%84%E5%85%B1%E8%AF%86%E6%9C%BA%E5%88%B6/</id>
    <published>2021-10-29T14:28:52.000Z</published>
    <updated>2025-06-19T03:30:33.145Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>“自我中心主义”]]></summary>
    <content type="html"><![CDATA[<h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>“自我中心主义” 的含义是，对于每个人来说，世界的大小取决于他能够接触到多大的世界，世界很大，和我无关，世界很小，全和我有关。一个人认识的人、了解的事、接收到的信息，无论是否命中注定，一定是有限的，你不可能认识世界上所有的人，知道世界上所有的事。才学渊博、见多识广，又怎样呢。</p><p>在区块链中，共识机制是用来保证数据一致性的关键手段，也给区块链带来了最核心的去中心化的特点。共识机制是强一致性的，或者是在拥有一定容错能力的情况下，达到大多数一致的效果。有没有一种可能，存在一种共识机制，不以数据一致为首要目标呢？</p><p>世界本就是复杂的，试图将所有节点同步到仅仅一种数据状态，其实是违反直觉的。而且，无论是不需要授权的大范围共识，还是基于身份授权的小范围共识，最终实现数据一致的方法，都是 “多点变单点”，也就是同一时间只有一个节点在处理数据，其他节点可能是在共识后接受满足条件的数据，也可能在确认数据前投票是否同意对数据的操作，总之都需要有一个 “英雄” 一样的节点，在关键的变更数据的时刻，做一些事情。</p><p>有的英雄实力强大，先斩后奏，改过数据后过来跟你说，“我改了数据”，你一开始不满意，但是接触后发现英雄确实厉害，能做出你没有解决的难题，于是你就认可了英雄的行动。</p><p>还有的英雄被公众授予权力，行动之前作为代表被选举出来，行动的时候会万分小心，挨个问民众，“改动这里的数据，你同意吗？” 如果大多数人同意，英雄就会行动。</p><p>当然，每个人都有平等地享有做英雄的机会，虽然有的人天生神力，有的人八面玲珑，但机会总还是有的，题放在那里，你做不出来，怪谁？每个人就可以被选举，别人不选你，怪谁？</p><p>所以，为什么我们不能做自己的英雄？为什么我们要屈就于别人的光环之下？每个人都是自己的英雄，在我们的世界里，在大小受限于个人接触范围的世界里。一种共识机制，节点的边界受限于其触及的网络规模。</p><h3 id="网络概况"><a href="#网络概况" class="headerlink" title="网络概况"></a>网络概况</h3><p>在非结构化的点对点网络中，路由表是必不可少的组成部分，节点能够接触到的网络大小，就取决于路由表中存着多少 “联系方式”。共识对数据的处理，就以路由表中的节点为依据，路由表中有 10 个节点，就争取和这 10 个节点达成一致，路由表中有 10,000 个节点，就和 10,000 个节点达成一致。也没有必要使用分布式路由表，就普通的数组就可以。在这种情况下，网络中的节点会是这种样子：</p><img src="21.png" width="40%"><p>以当前节点为中心，连接到的节点数量可多可少，有的很远，有的很近。弱水三千，只取一瓢。在路由发现的问题上，节点也是需要种子地址的，比如节点启动的时候先解析种子地址的记录：</p><pre><code>lookup(&quot;seek.domain&quot;)     -&gt; 127.0.0.1    -&gt; 127.0.0.2</code></pre><p>然后依次请求解析出来的节点地址，去得到他们路由表中的内容，将其添加到自己的路由表。这其实是常规做法，不过这样有可能引起的后果是，节点会瞬间获取到整个网络的路由信息。这并非不好，只是感觉有点快了，我们认识一个人是需要时间的，和人交谈也是需要时间的，你无法同时和三个人交谈，或者无法同时听三个人说话。即使拿到了很多人的联系方式，也没办法 “多线程” 联系每个人。我们处理信息的 “带宽” 有限，节点也一样。我们甚至可以对网络发现的速度稍微做一点限制，比如串行处理路由表新增记录的动作，先与节点建立连接然后再添加信息。</p><p>让路由发现慢一点，似乎听起来不太正常，难道是想让网络处于不同步的状态吗？很多共识的瓶颈就在网络带宽上，就在协议交互的复杂上。如果降低节点间的交流成本，共识的容错能力也会随之降低。网络可能会被划分为不同的区域，可能形成大大小小的圈子。</p><img src="22.png" width="50%"><p>对于共识算法来说，脑裂是要尽可能避免的问题，但其实网络分割是再正常不过的事情，是自然存在的情况。我们人类的思想是分裂的，有可能是对立的，但是经过一些事件后又可能达成一致。所以在一个网络中出现割裂是完全允许的情形，形成的小规模网络可能是互联互通开放的，也可能是保守封闭与外界隔离的。重点是要有一种机制能够 “修正” 这种分裂，也就是在某种条件下，割裂的两个网络可以相互合并。</p><h3 id="同步数据"><a href="#同步数据" class="headerlink" title="同步数据"></a>同步数据</h3><h4 id="主动"><a href="#主动" class="headerlink" title="主动"></a>主动</h4><p>这里保留区块链创世块的概念，所有节点的第一个块内容是相同的。新加入网络的节点，会从创世块开始启动，此时其他节点的块高度已经有很多了。比如当前节点的块高度是 2，想要从网络中同步第 3 个块高度的内容，节点的路由表中有其他节点的地址，其他节点块高度均等于 3。当前节点会发起一个对块高度 3 的请求，依次到其他节点。</p><img src="1.png" width="50%"><p>请求过后，发现有 2 个节点块高度为 3 的块一样，块的内容一样、块哈希一样、前块哈希也一样，那当前节点就把这个多数节点都存在的块作为第 3 个块。</p><img src="2.png" width="50%"><p>如果请求的时候发现有的节点的块高度已经大于 3 了，那么是不是应该块高度最高的优先呢？如果考虑时间尺度的话，就会觉得事物发展是需要遵次序的，你不能跳过 3 岁直接过起 4 岁的人生，区块链的数据也应该有先后次序。况且，当前节点需要的块高度是 3，请求的块高度是 3，管你有没有其他高度的块？你的块高度再高，我就要 3 的，你说你多高有什么用？</p><p>那么如果请求过所有节点，发现每个节点的块都不一样呢？该信谁？</p><img src="3.png" width="50%"><p>总得挑一个吧。如果不能确定哪个节点或者哪个内容可信的话，就随机选吧。最好是选择最后一个请求的节点，因为错过的节点就已经错过了，此时最后一个节点是距离你最近的节点，并且在此之前你并不能判断，是否存在块内容相同的节点。所以在放弃之前的节点后，最后一个节点就是你不可以放手的选择。</p><p>对于主动请求块数据的情况，很关键的地方是，请求一定是按照路由表顺序依次进行的，在得到第 1 个节点的响应之前，绝不向第 2 个节点发起请求，做人不能太三心二意了。如果有节点就刻意加速、同时请求多组数据呢？其实也无伤大雅，毕竟只是同步数据，有的人喜欢快点，有的人喜欢慢点，有的人喜欢快生活，有的人享受慢生活。</p><h4 id="被动"><a href="#被动" class="headerlink" title="被动"></a>被动</h4><p>除了主动请求某一高度的块数据，节点也会收到其他节点的广播消息，比如当前节点的块高度是 2，收到了来自其他节点的内容分别是 3、4、4 的块。</p><img src="4.png" width="50%"><p>按大多数一致的原则，是不是应该选择内容是 4 的块放在自己的第 3 个块高度上？但是这样存在一个问题是，你无法预测自己会收到多少个块，没办法计算块内容的总量和占比。所以对于被动接收的块，可以以第一个收到的块内容为准。</p><p>人生的出场顺序很重要，如果正好需要的块高度是 3，接收到广播的块高度也是 3，那就它吧，遇到哪个算哪个。实在不行后面遇到更合适的再换。如果有节点很激进，为了自己的块能够被大范围接受，把同一个块标记为从 1 到很大块高度广播出去，就为了碰运气，让正好缺块的节点接收，那也就随他吧。因为节点在主动同步块的时候，是按照高度获取内容的，这种激进一点的做法并不能带来很好的收益。</p><h3 id="新增数据"><a href="#新增数据" class="headerlink" title="新增数据"></a>新增数据</h3><p>网络中的数据由谁产生？为了解决这个问题，可以先定义为，每个节点都可以产生数据。一种极端的情况是，每个人都只相信自己的数据，各玩各的，整个网络就变成单机版了。所以节点也需要将自己产生的数据散播出去，发送给其他节点。对于其他节点来说，就是 “被动同步数据” 的情况了。</p><h4 id="有节点需要"><a href="#有节点需要" class="headerlink" title="有节点需要"></a>有节点需要</h4><p>主动广播块数据分两种情况，一种是有节点正好需要块，你正好发送给他了。</p><img src="5.png" width="50%"><p>当前节点接收到内容的请求，新增了块高度为 4 的块，这时会直接把块持久化到主链上。接着开始对块高度为 4 的块进行广播，广播按照路由表依次进行，在广播结束之前，当前节点不会打包下一个块。广播开始后，有节点块高度为 3，说明你是第一个发送给他块高度 4 的节点，它一定会接收你的块，同时给你一个响应消息。在收到响应后你就可以知道，当前网络至少有一个节点接收了你的块，你可以继续处理下一个块了。当然，在路由表遍历结束之前，节点即使收到响应消息也不会停止这一轮广播，这是理所当然的，希望有更多节点可以接收块内容。</p><p>如果对方节点在收到块后，发现块内容是 5，前块哈希是 3，并不对应它自己的前块哈希 4，对方依然会接收这个块，并且依次替换自己之前的块，直到哈希一致。</p><img src="51.png" width="50%"><img src="52.png" width="50%"><p>这种机制有可能带来的风险是，接收到一个块，然后把整条链都替换掉了，这是非常严重的不能接受的开销。但确实存在这样的可能，你遇到了一个坏人，这个坏人乘虚而入，他的思想颠覆了你的人生观，让你误入歧途，六亲不认。倒是你需要反思一下，你的路由表里为什么会有这样的坏人。而且这样的坏人多吗？如果一个恶意节点用一个块替换了你的整条链，但是接下来会有很大概率有好人来把你的整条链置换到大多数一致的情况。</p><p>这里暴露出了一点问题，接收到第一个块就认可，是不是太草率了？如果是坏人怎么办？为了增加节点作恶的难度，在接收到块内容为 5 发现前块哈希对不上的时候，应该不止向第一条链请求块内容，而是走完整的 “主动同步数据” 的逻辑，根据块高度把路由表里的所有节点都请求一遍。如果块内容为 5 的块，前块哈希和大多数节点不一致，就直接把 5 抛弃掉。如果一致，就说明它不是有害内容。</p><h4 id="没有节点需要"><a href="#没有节点需要" class="headerlink" title="没有节点需要"></a>没有节点需要</h4><p>节点新增块后，可能遇到没有节点需要当前块高度的情况，</p><img src="6.png" width="50%"><p>其他节点的块高度都大于等于广播出去的块。这种时候，当前节点就有必要做一点点妥协，为了让别人接收自己，为了让其他节点接收自己的块数据，只好先从其他节点同步数据，和其他节点保持一致。</p><img src="7.png" width="50%"><p>在块高度为 4 的块上，当前节点广播了一圈发现没有节点愿意接收这个块，那当前节点就把最后一个访问的节点的，当前块高度的块，请求过来。为什么是最后一个请求的节点？这里也可以走一遍完整的 “主动同步数据” 的流程，但为了提高效率，减少网络交互，可以先随意接收一个块内容，再做后续的判断。选择最后一个节点，是因为离得近。在错过了万丈红尘纷纷扰扰之后，恍然回首，发现最后一个节点是你此时最亲近的伙伴。</p><img src="8.png" width="50%"><img src="9.png" width="50%"><p>收到最后一个节点的块内容是 7 的块后，当前节点继续广播块内容为 5 的块。</p><p>如果不幸遇到了其他节点的块高度都远高于自己的情况，那说明自己确实落后了，先把其他节点的内容都同步过来再说。想要创新，想要新增内容，至少要先到达某一种顶端，</p><img src="10.png" width="50%"><p>不一定是整个网络的顶端，至少是某种圈子的顶端。</p><h3 id="交换数据"><a href="#交换数据" class="headerlink" title="交换数据"></a>交换数据</h3><h4 id="类型"><a href="#类型" class="headerlink" title="类型"></a>类型</h4><p>在目前的机制下，网络可能是混乱、不同步的。虽然对数据同步的速度预设是慢的，但如果有的节点就喜欢快呢，用快的计算、大的网络带宽，就是要达到整个网络的最前沿。</p><img src="33.png" width="50%"><p>也就是大多数节点慢，少数节点快的情况。每个节点都是按照块高度平行更新内容的，也都是按照块高度广播内容的，在一定程度上会缓解这种问题。你想快就快，和我们没有关系，我们慢的自成一派，我们遵循大多数一致的原则，不是谁块高度高就听谁的。你想内卷就尽力去卷，我们不跟你玩。</p><img src="32.png" width="50%"><p>另一种是一半节点慢，一半节点快的情况，也没有什么好担心的，最坏就是形成两个网络，无关痛痒。</p><img src="31.png" width="50%"><p>至于少数节点慢，多数节点快，属于最正常的情况了。</p><h4 id="融合"><a href="#融合" class="headerlink" title="融合"></a>融合</h4><p>在一半节点慢，一个节点快的情况下，很容易造成这样数据对立的情况，即使块高度一致，也是两种数据。</p><img src="34.png" width="50%"><img src="35.png" width="50%"><p>这个时候就不得不有一方妥协了。如果两个网络想要融合，就必须有一方做出一些牺牲。在块高度一致的情况下，假设路由表互通，产生新的块数据后，其实就是 “主动广播数据” 的过程，当前节点先产生一个块：</p><img src="36.png" width="50%"><p>例如最后一个节点在收到块后，发现前块哈希和自己的对不上：</p><img src="37.png" width="50%"><p>就去其他节点请求上一个块高度的内容：</p><img src="38.png" width="50%"><img src="39.png" width="50%"><p>发现上上个块的哈希对不上：</p><img src="40.png" width="50%"><p>继续请求其他节点对应块高度的内容；</p><img src="41.png" width="50%"><img src="42.png" width="50%"><p>依次类推，直到整条链完全相同。</p><p>被替换掉的块内容可以放到一个缓存队列，作为新块的内容，继续向外广播，减少节点内容的丢失。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>这是一种没有经过实践考验的、也无法简单用公式来建模的共识机制的设想，共识以自身立场为出发点，关心自己如何应对网络中其他节点的不同行为，而不是从整个网络的角度 “上帝式” 地设计交互协议。这样的机制会给网络带来不确定性，但也会带来很多可能性。我们只能考虑节点基本的行为规则，就像我们学习生活规则一样，我们很难预测整个网络的走向，就像我们无法预测世界会向什么趋势发展。这种共识机制并不是而且也许不能解决特定的问题，比如建立电子现金系统或者提供图灵完备的运行平台，它关注在更基础一点的层面，提供一种实现数据一致性的方法和思路。</p><p>计算机通过网络组成的虚拟世界，一定也很精彩。</p>]]></content>
  </entry>
  <entry>
    <title>Linghting Network 的代码注释量就很离谱。Raiden Network 的相对差一点。。</title>
    <link href="https://t.smallyu.net/#2021-94"/>
    <id>micro:954466640</id>
    <published>2021-10-29T06:32:19Z</published>
    <updated>2021-10-29T06:32:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Linghting Network 的代码注释量就很离谱。Raiden Network 的相对差一点。。</p>]]></summary>
    <content type="html"><![CDATA[<p>Linghting Network 的代码注释量就很离谱。Raiden Network 的相对差一点。。</p>
]]></content>
  </entry>
  <entry>
    <title>在我的想象中，有一双滑板鞋，时尚时尚最时尚 /狗头</title>
    <link href="https://t.smallyu.net/#2021-93"/>
    <id>micro:954085436</id>
    <published>2021-10-28T18:14:44Z</published>
    <updated>2021-10-28T18:14:44Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>在我的想象中，有一双滑板鞋，时尚时尚最时尚 /狗头</p>]]></summary>
    <content type="html"><![CDATA[<p>在我的想象中，有一双滑板鞋，时尚时尚最时尚 /狗头</p>
]]></content>
  </entry>
  <entry>
    <title>链表常见算法题及解析</title>
    <link href="https://smallyu.net/2021/10/27/%E9%93%BE%E8%A1%A8%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98%E5%8F%8A%E8%A7%A3%E6%9E%90/"/>
    <id>blog:https://smallyu.net/2021/10/27/%E9%93%BE%E8%A1%A8%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E9%A2%98%E5%8F%8A%E8%A7%A3%E6%9E%90/</id>
    <published>2021-10-27T03:04:20.000Z</published>
    <updated>2025-11-09T09:22:13.536Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>目录：</p>
<ul>
<li><a href="#%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8">翻转链表</a></li>
<li><a]]></summary>
    <content type="html"><![CDATA[<p>目录：</p><ul><li><a href="#%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8">翻转链表</a></li><li><a href="#%E5%88%A4%E6%96%AD%E9%93%BE%E8%A1%A8%E6%98%AF%E5%90%A6%E6%9C%89%E7%8E%AF">判断链表是否有环</a></li><li><a href="#%E9%93%BE%E8%A1%A8%E5%A6%82%E6%9E%9C%E6%9C%89%E7%8E%AF%EF%BC%8C%E6%89%BE%E5%88%B0%E7%8E%AF%E7%9A%84%E8%B5%B7%E7%82%B9">链表如果有环，找到环的起点</a></li><li><a href="#%E5%88%A4%E6%96%AD%E4%B8%A4%E4%B8%AA%E9%93%BE%E8%A1%A8%E6%98%AF%E5%90%A6%E7%9B%B8%E4%BA%A4">判断两个链表是否相交</a></li><li><a href="#%E9%93%BE%E8%A1%A8%E5%A6%82%E6%9E%9C%E7%9B%B8%E4%BA%A4%EF%BC%8C%E6%89%BE%E5%88%B0%E4%BA%A4%E7%82%B9">链表如果相交，找到交点</a></li><li><a href="#%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%9C%89%E5%BA%8F%E9%93%BE%E8%A1%A8">合并两个有序链表</a></li></ul><br><h2 id="翻转链表"><a href="#翻转链表" class="headerlink" title="翻转链表"></a>翻转链表</h2><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>对于一个这样的链表：</p><img src="4.png" width="50%"><p>希望经过函数处理后，变成这样：</p><img src="5.png" width="50%"><h3 id="链表结构定义"><a href="#链表结构定义" class="headerlink" title="链表结构定义"></a>链表结构定义</h3><p>节点的定义为：</p><pre><code class="go">type Node struct &#123;    Value int    Next  *Node&#125;</code></pre><p>构造链表方法为：</p><pre><code class="go">func createLinkedList(n int) *Node &#123;    head := &amp;Node&#123;Value: 0&#125;    node := head    for i := 0; i &lt; n; i++ &#123;        if i &lt; n &#123;            node.Next = &amp;Node&#123;Value: i + 1&#125;        &#125;        node = node.Next    &#125;    return head&#125;</code></pre><p>函数会返回一个链表的指针。使用指针而不是结构体类型是因为，Go 语言的某些关于变量的设计，无法使用 <code>Node&#123;&#125; == nil</code> 的形式判断变量是否为空，因为理论上 <code>Node&#123;&#125;</code> 不是 <code>nil</code>。这就造成了如果使用<code>Node&#123;&#125;</code>作为链表头部的变量类型，在遍历的时候找不到一个合理的结束时机，只能使用类似 <code>Node&#123;&#125;.Next == nil</code> 这样的形式，还会遗漏掉最后一个节点。</p><h3 id="迭代翻转链表"><a href="#迭代翻转链表" class="headerlink" title="迭代翻转链表"></a>迭代翻转链表</h3><p>这里不能使用直接改变节点值的方式，比如遍历一次后把链表节点的值按照顺序储存到数组中，然后再遍历一次，一次修改链表节点的值。这个违背了数据结构的意义。可以使用递归完成翻转链表的操作。</p><img src="6.png" width="50%"><p>比如第一个节点，使用 <code>temp</code> 变量储存翻转前的下一个节点的位置，然后把 <code>head.Next</code> 指向翻转后应该有的节点位置，第一个节点的下一个节点是<code>空节点</code>，第二个节点的下一个节点是<code>节点 1</code>。完成 <code>head.Next </code>的指向后，<code>head</code> 要指向 <code>temp</code> 也就是原来的下一个节点用以完成遍历。这时还需要要用一个 <code>curr</code> 变量来储存<code>head</code> 跳转前的位置，方便下一次 <code>head.Next</code> 指向上一个节点的位置。这应该是一个简单的过程。</p><pre><code class="go">func reverseLinkedList(head *Node) *Node &#123;    curr := new(Node)    for head != nil &#123;        temp := head.Next        head.Next = curr        curr = head        head = temp    &#125;    return curr&#125;</code></pre><ul><li>时间复杂度：O(n)</li><li>空间复杂度：O(1)</li></ul><h3 id="执行"><a href="#执行" class="headerlink" title="执行"></a>执行</h3><p>执行程序后结果和预期一致：</p><pre><code class="go">func main() &#123;    head := createLinkedList(4)    head = reverseLinkedList(head)    for head != nil &#123;        fmt.Println(head.Value)        head = head.Next    &#125;&#125;</code></pre><p><br><br></p><h2 id="判断链表是否有环"><a href="#判断链表是否有环" class="headerlink" title="判断链表是否有环"></a>判断链表是否有环</h2><h3 id="问题-1"><a href="#问题-1" class="headerlink" title="问题"></a>问题</h3><p>链表有环是指链表中“最后”的一个节点，它的下一个节点指向了链表中位于它之前的节点。</p><img src="9.png" width="50%"><p>当程序遍历这个链表，会发现进入了死循环，永远找不到出口了。怎么判断一个链表，是否存在这样的环呢？</p><h3 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h3><p>常用的解决思路是双指针。设想一个在赛道上的场景，两个人 A 和 B 处于同样的起点，但是他们跑步的速度并不相同，A 的速度 v<sub>1</sub>&#x3D;1，B 的速度 v<sub>2</sub>&#x3D;2，也就是 B 比 A 快。在这样的情况下，只要他们不停，B 一定会超过 A 一圈然后再次追上 A，这是一种生活中的常识。</p><img src="7.png" width="50%"><p>在一个圈里，一快一慢的两个点一定会再次相遇，而且他们经过的路程是可以计算的，路程 s<sub>1</sub> 和 s<sub>2</sub> 应该满足这样的关系：</p><pre><code>s2 - s1 = nR</code></pre><p>R 是圆圈的周长，n 是正整数，他们位于出发点时 n&#x3D;0，第一次相遇的时候 B 比 A 多跑了一圈，多出了 1 倍周长的路程，n&#x3D;1。</p><p>和链表的情景相比较，赛道的场景还少了开始的一段距离，在进入赛道之前，A 和 B 会先从赛道外的小路进入赛道，然后再开始绕圈跑步。他们的起点在赛道外，为了便于计算，他们的速度从始至终不发生变化，那么当他们进入赛道之后，就已经不是同样的起点了。</p><img src="8.png" width="50%"><p>在这种情况下，他们经过的路程 s<sub>1</sub> 和 s<sub>2</sub> 还有规律可循吗？设圆形赛道外的直道距离为 d，相比上面的关系式，他们在圆圈内的路径依然满足 n 倍的周长 R，只不过现在的表达式不同了：</p><pre><code>(s2 - d) - (s1 - d) = nR    s2 - d - s1 + d = nR            s2 - s1 = nR</code></pre><p>结果表达式在相互抵消路径 d 之后，和之前的一样。</p><p>A 的路程 s<sub>1</sub>&#x3D;v<sub>1</sub>t，B的路程 s<sub>2</sub>&#x3D;v<sub>2</sub>t，时间 t 是一样的，速度 v<sub>1</sub> 和 v<sub>2</sub> 是已知的 1 和 2，有：</p><pre><code>    s2 - s1 = nR  v2t - v1t = nR     2t - t = nR          t = nR</code></pre><p>取 n &#x3D; 1，<code>t = R</code>。</p><h3 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h3><p>回到链表的问题，其实我们只要用快慢指针就可以判断链表是否有环了，并不需要知道他们具体相遇的点在哪儿，不过计算路径关系的公式可以辅助我们验证结果的正确性。</p><p>回到这个链表，用两个指针 A 和 B 从节点 1 分别以速度 1 和 2 出发：</p><img src="9.png" width="50%"><p>他们的位置关系将会是：</p><table><thead><tr><th>时间 t</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th></tr></thead><tbody><tr><td>A 的位置</td><td>节点 1</td><td>节点 2</td><td>节点 3</td><td>节点 4</td><td><strong>节点 5</strong></td></tr><tr><td>B 的位置</td><td>节点 1</td><td>节点 3</td><td>节点 5</td><td>节点 3</td><td><strong>节点 5</strong></td></tr></tbody></table><p>在第 4 个时间点的时候，A 和 B 相遇了，环的周长正好等于 4，满足 <code>t = R</code> 的关系。</p><p><br><br></p><h2 id="链表如果有环，找到环的起点"><a href="#链表如果有环，找到环的起点" class="headerlink" title="链表如果有环，找到环的起点"></a>链表如果有环，找到环的起点</h2><h3 id="问题-2"><a href="#问题-2" class="headerlink" title="问题"></a>问题</h3><p>这个问题是上一个问题的延伸，在判断链表已经有环的基础上，找到环的起点。比如这样的一个链表，环的起点是节点 3。</p><img src="20.png" width="50%"><h3 id="分析-1"><a href="#分析-1" class="headerlink" title="分析"></a>分析</h3><p>（1）</p><p>在判断链表是否有环的问题中，我们得到了一个至关重要的结论：</p><pre><code>t = R</code></pre><p>两个快慢指针将会在等于环长度的时间点相遇。对于上图的链表，快慢指针的位置关系是这样：</p><table><thead><tr><th>时间 t</th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th></tr></thead><tbody><tr><td>A 的位置</td><td>节点 1</td><td>节点 2</td><td>节点 3</td><td>节点 4</td><td>节点 5</td><td>节点 6</td><td><strong>节点 7</strong></td></tr><tr><td>B 的位置</td><td>节点 1</td><td>节点 3</td><td>节点 5</td><td>节点 7</td><td>节点 3</td><td>节点 5</td><td><strong>节点 7</strong></td></tr></tbody></table><p>我们可以观察到，环的长度是 6，快慢指针也会在第 6 秒相遇，他们交点位置是节点 7:</p><img src="21.png" width="50%"><p>（2）</p><p>根据上面提到的之前的结论，按照慢指针 v<sub>1</sub> &#x3D; 1 的速度，它经过的路程和时间是一样的，也就是说，从出发点到两指针相遇的路径长度，根据 <code>t = R</code>，此刻的时间是 t，正好是环的长度 R：</p><img src="22.png" width="50%"><p>（3）</p><p>做一个假设，慢指针保持着这个长度为 R 的走过的路径，向前移动一步，会变成这样：</p><img src="23.png" width="50%"><p>再走一步，变成了这样：</p><img src="24.png" width="50%"><p>（4）</p><p>到这里似乎还不知道我们要干什么。现在对路径设一个变量，从 <code>出发点</code> 到 <code>环的起点</code> 之间的距离设为 l<sub>1</sub>，整个链表的长度设为 l，环的长度仍然为 R。</p><img src="25.png" width="50%"><p>这 3 个变量将满足这样的关系：</p><pre><code>l - l1 = R</code></pre><p>这是太显而易见的事情。</p><p>（5）</p><p>记得我们一开始的结论吗？从 <code>出发点</code> 到 <code>快慢指针的交点</code> 之间的距离，等于环的长度 R：</p><img src="22.png" width="50%"><p>变量 l 和 l<sub>1</sub> 保持不变，图就成了这样：</p><img src="26.png" width="50%"><p>此时的 l 仍然等于 <code>l1 + R</code>，不同的是，<code>l1</code> 和 <code>R</code> 重合了。</p><p>（6）</p><pre><code>l - l1 = R</code></pre><p>重合之后，等式关系还成立吗？当然成立，因为整个链表没有变，变量的大小没有变。但好像又觉得哪里奇怪。</p><p>现在新设一个变量，设从 <code>快慢指针的交点</code> 到 <code>环的起点</code> 的距离为 l<sub>2</sub>：</p><img src="27.png" width="50%"><p>此时：</p><pre><code>l - l2 = R</code></pre><p>（7）</p><p>经过这样一些比较，发现 <code>l1 == l2</code>，也就是从 <code>出发点</code> 到 <code>环的起点</code> 的距离，等于 <code>快慢指针的交点</code> 到 <code>环的起点</code> 的距离。</p><h3 id="解决-1"><a href="#解决-1" class="headerlink" title="解决"></a>解决</h3><pre><code>出发点 -&gt; 环的起点 == 快慢指针的交点 -&gt; 环的起点</code></pre><p>这是一个很重要的结论，因为我们此时的快慢指针就在 <code>快慢指针的交点</code> 上，在节点 7 的位置。</p><p>如果这个时候在新增一个指针 p<sub>3</sub>，在快慢指针相交的时刻，从整个链表的 <code>出发点</code> 1 出发（速度为 1），那么 p<sub>3</sub> 和慢指针一定会相交，因为 p<sub>3</sub> 到 <code>环的起点</code> 的距离等于慢指针到 <code>环的起点</code> 的距离。p<sub>3</sub> 遇到慢指针的位置，就是环的起点。</p><img src="28.png" width="50%"><p><br><br></p><h2 id="判断两个链表是否相交"><a href="#判断两个链表是否相交" class="headerlink" title="判断两个链表是否相交"></a>判断两个链表是否相交</h2><h3 id="问题-3"><a href="#问题-3" class="headerlink" title="问题"></a>问题</h3><p>存在两个链表，分别在某一个节点指向了同一个节点作为下个节点：</p><img src="10.png" width="50%"><p>这里有两个链表：</p><pre><code>1 -&gt; 2 -&gt; 3 -&gt; 4     5 -&gt; 3 -&gt; 4</code></pre><p>怎么判断两个链表是否相交？</p><h3 id="分析-2"><a href="#分析-2" class="headerlink" title="分析"></a>分析</h3><p>一种简单的做法是，分别遍历每条链表到最后一个节点，判断最后一个节点是否相同。如果两个链表在中间节点相交，则最后一个节点一定相同。</p><p><br><br></p><h2 id="链表如果相交，找到交点"><a href="#链表如果相交，找到交点" class="headerlink" title="链表如果相交，找到交点"></a>链表如果相交，找到交点</h2><h3 id="问题-4"><a href="#问题-4" class="headerlink" title="问题"></a>问题</h3><p>对于这样两个链表：</p><img src="31.png" width="50%"><img src="32.png" width="50%"><p>如何找到第一个交点 3 ？</p><h3 id="分析-3"><a href="#分析-3" class="headerlink" title="分析"></a>分析</h3><p>一种简单的解决思路是，把这个链表的尾节点和任意一个链表的头节点连起来：</p><img src="33.png" width="50%"><p>可以是链表 1 的尾节点到链表 2 的头节点，或者链表 2 的尾节点到链表 2 的头节点，总之连起来以后，问题就转变成了，找到链表环的起点。</p><p><br><br></p><h2 id="合并两个有序链表"><a href="#合并两个有序链表" class="headerlink" title="合并两个有序链表"></a>合并两个有序链表</h2><h3 id="问题-5"><a href="#问题-5" class="headerlink" title="问题"></a>问题</h3><img src="11.png" width="50%"><p>给出两个有序链表，将两个链表合并为一个有序链表。</p><h3 id="分析-4"><a href="#分析-4" class="headerlink" title="分析"></a>分析</h3><p>思路暴力简单，同时迭代两个链表，按照顺序依次合并就可以了。控制好边界条件。</p><img src="12.png" width="50%"><img src="13.png" width="50%"><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>node 结构定义：</p><pre><code class="go">type Node struct &#123;    Value int    Next  *Node&#125;</code></pre><p>构建两条链表：</p><pre><code class="go">func main() &#123;    root1 := &amp;Node&#123;        Value: 1,    &#125;    root1.Next = &amp;Node&#123;        Value: 1,    &#125;    root1.Next.Next = &amp;Node&#123;        Value: 3,    &#125;    root1.Next.Next.Next = &amp;Node&#123;        Value: 5,    &#125;    root2 := &amp;Node&#123;        Value: 1,    &#125;    root2.Next = &amp;Node&#123;        Value: 2,    &#125;    root2.Next.Next = &amp;Node&#123;        Value: 4,    &#125;    root := merge(root1, root2)    for root != nil &#123;        fmt.Println(root.Value)        root = root.Next    &#125;&#125;</code></pre><p>合并链表：</p><pre><code class="go">func merge(root1 *Node, root2 *Node) *Node &#123;    var root *Node    var temp *Node    if root1.Value &lt;= root2.Value &#123;        root = root1        temp = root2    &#125; else &#123;        root = root2        temp = root1    &#125;    p1 := root    p2 := p1.Next    for &#123;        if p2 == nil || temp == nil &#123;            break        &#125;        if p2.Value &lt;= temp.Value &#123;            p1.Next = p2            p1 = p1.Next            p2 = p2.Next        &#125; else &#123;            p1.Next = temp            p1 = p1.Next            temp = temp.Next        &#125;    &#125;    return root&#125;</code></pre>]]></content>
  </entry>
  <entry>
    <title>我养了一只狗，它经常会摇着尾巴来找我要吃的。我很喜欢它，它也很喜欢我，我需要他，它也需要我。可我从来不会把它当人看，他只...</title>
    <link href="https://t.smallyu.net/#2021-92"/>
    <id>micro:951103380</id>
    <published>2021-10-25T16:35:40Z</published>
    <updated>2021-10-25T16:35:40Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>我养了一只狗，它经常会摇着尾巴来找我要吃的。我很喜欢它，它也很喜欢我，我需要他，它也需要我。可我从来不会把它当人看，他只是一只狗。</p>]]></summary>
    <content type="html"><![CDATA[<p>我养了一只狗，它经常会摇着尾巴来找我要吃的。我很喜欢它，它也很喜欢我，我需要他，它也需要我。可我从来不会把它当人看，他只是一只狗。</p>
]]></content>
  </entry>
  <entry>
    <title>越来越觉得，公众人物的演讲是不可以相信的，出于自身立场的考虑，即使他们知道真相，知道事实是残酷的，也不敢和不能说出来。倒...</title>
    <link href="https://t.smallyu.net/#2021-91"/>
    <id>micro:950316653</id>
    <published>2021-10-24T12:29:24Z</published>
    <updated>2021-10-24T12:29:24Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>越来越觉得，公众人物的演讲是不可以相信的，出于自身立场的考虑，即使他们知道真相，知道事实是残酷的，也不敢和不能说出来。倒是一些不那么有名没有那么大负担的“小人物”，不是在公共场合尤其是写出来而不是演讲的内容，可能会更真实一点。</p>]]></summary>
    <content type="html"><![CDATA[<p>越来越觉得，公众人物的演讲是不可以相信的，出于自身立场的考虑，即使他们知道真相，知道事实是残酷的，也不敢和不能说出来。倒是一些不那么有名没有那么大负担的“小人物”，不是在公共场合尤其是写出来而不是演讲的内容，可能会更真实一点。</p>
]]></content>
  </entry>
  <entry>
    <title>你永远没办法做出最好的选择，你一定会错过很多很多事情。做选择的时候往往会考虑机会成本，但机会是未知的。</title>
    <link href="https://t.smallyu.net/#2021-90"/>
    <id>micro:950315736</id>
    <published>2021-10-24T12:24:05Z</published>
    <updated>2021-10-24T12:24:05Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>你永远没办法做出最好的选择，你一定会错过很多很多事情。做选择的时候往往会考虑机会成本，但机会是未知的。</p>]]></summary>
    <content type="html"><![CDATA[<p>你永远没办法做出最好的选择，你一定会错过很多很多事情。做选择的时候往往会考虑机会成本，但机会是未知的。</p>
]]></content>
  </entry>
  <entry>
    <title>去了解一个人的生平经历，他遇到过哪些困难，他是怎么解决的，如果有值得借鉴的地方，我们就可以学过来。 如果经过自己的思考，...</title>
    <link href="https://t.smallyu.net/#2021-89"/>
    <id>micro:950044547</id>
    <published>2021-10-23T02:43:01Z</published>
    <updated>2021-10-23T02:43:01Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>去了解一个人的生平经历，他遇到过哪些困难，他是怎么解决的，如果有值得借鉴的地方，我们就可以学过来。 如果经过自己的思考，发现他有不对的地方，或者还有更好的做法，我们也可以学过来，避开他的错误而做出正确的选择。</p>]]></summary>
    <content type="html"><![CDATA[<p>去了解一个人的生平经历，他遇到过哪些困难，他是怎么解决的，如果有值得借鉴的地方，我们就可以学过来。</p>
<p>如果经过自己的思考，发现他有不对的地方，或者还有更好的做法，我们也可以学过来，避开他的错误而做出正确的选择。</p>
]]></content>
  </entry>
  <entry>
    <title>如果“不相信宿命决定论”这种行为本身就是宿命决定的呢？</title>
    <link href="https://t.smallyu.net/#2021-88"/>
    <id>micro:948843967</id>
    <published>2021-10-21T17:23:00Z</published>
    <updated>2021-10-21T17:23:00Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果“不相信宿命决定论”这种行为本身就是宿命决定的呢？</p>]]></summary>
    <content type="html"><![CDATA[<p>如果“不相信宿命决定论”这种行为本身就是宿命决定的呢？</p>
]]></content>
  </entry>
  <entry>
    <title>“年度神曲” 每次听都想笑 🤪</title>
    <link href="https://t.smallyu.net/#2021-87"/>
    <id>micro:948271406</id>
    <published>2021-10-21T05:30:56Z</published>
    <updated>2021-10-21T05:30:56Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“年度神曲” 每次听都想笑 🤪</p>]]></summary>
    <content type="html"><![CDATA[<p>“年度神曲” 每次听都想笑 🤪 </p>
]]></content>
  </entry>
  <entry>
    <title>The Witcher 应该是个好故事，就是没太看懂。</title>
    <link href="https://t.smallyu.net/#2021-86"/>
    <id>micro:947695577</id>
    <published>2021-10-20T13:59:13Z</published>
    <updated>2021-10-20T13:59:13Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>The Witcher 应该是个好故事，就是没太看懂。</p>]]></summary>
    <content type="html"><![CDATA[<p><em>The Witcher</em> 应该是个好故事，就是没太看懂。</p>
]]></content>
  </entry>
  <entry>
    <title>人生终极目标</title>
    <link href="https://crazy.smallyu.net/2021/10/20/%E4%BA%BA%E7%94%9F%E7%BB%88%E6%9E%81%E7%9B%AE%E6%A0%87/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/10/20/%E4%BA%BA%E7%94%9F%E7%BB%88%E6%9E%81%E7%9B%AE%E6%A0%87/</id>
    <published>2021-10-20T13:57:55.000Z</published>
    <updated>2025-08-16T03:27:07.296Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>衣食无忧、冬暖夏凉、结婚生子、安享晚年。</p>
<p>这个目标高吗？</p>
]]></summary>
    <content type="html"><![CDATA[<p>衣食无忧、冬暖夏凉、结婚生子、安享晚年。</p><p>这个目标高吗？</p>]]></content>
  </entry>
  <entry>
    <title>冷笑话：打开微信需要 1 分钟 :)</title>
    <link href="https://t.smallyu.net/#2021-85"/>
    <id>micro:945154226</id>
    <published>2021-10-17T16:27:49Z</published>
    <updated>2021-10-17T16:27:49Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>冷笑话：打开微信需要 1 分钟 :)</p>]]></summary>
    <content type="html"><![CDATA[<p>冷笑话：打开微信需要 1 分钟 :)</p>
]]></content>
  </entry>
  <entry>
    <title>基于 Multi-Linked List 的区块链设想</title>
    <link href="https://smallyu.net/2021/10/17/%E5%9F%BA%E4%BA%8EMulti-Linked-List%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E8%AE%BE%E6%83%B3/"/>
    <id>blog:https://smallyu.net/2021/10/17/%E5%9F%BA%E4%BA%8EMulti-Linked-List%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E8%AE%BE%E6%83%B3/</id>
    <published>2021-10-17T03:27:17.000Z</published>
    <updated>2025-11-09T09:22:13.413Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>区块链有没有可能不再是线性的结构，而是有多条链路的、图式的数据结构呢，比如从 singly-linked list 进化到 multi-linked list。假设是 multi-linekd list]]></summary>
    <content type="html"><![CDATA[<p>区块链有没有可能不再是线性的结构，而是有多条链路的、图式的数据结构呢，比如从 singly-linked list 进化到 multi-linked list。假设是 multi-linekd list 的形式，会给区块链带来什么样的变化，或者说，可行吗？</p><p>首先是正向的 multi-linked list，像是这样：</p><img src="1.png" width="50%"><p>然后是适用于区块链的、反向的 multi-linked list，像这样：</p><img src="2.png" width="50%"><p>对于 multi-lineked list，一种是固定数量的情况，比如每个节点的后续节点一定是 2 个，或者是不固定数量的 multi-linked list，每个节点可以指向任意多个子节点，它们的区别不大。</p><p>还有一个分歧是要不要保留块高度的概念，块高度是用来表示块顺序的索引，在多个节点之间同步数据的时候起到很重要的作用，在 multi-linked list 中，如果按照树结构层数来定义块高度，会是这样：</p><img src="3.png" width="50%"><p>或者可以按照块写入的顺序定义，也就是初始的标号意味着块高度：</p><img src="2.png" width="50%"><p>对于区块链来说，很重要的是确认数据的完整性，当只有一个子节点的时候，其他节点很容易同步一个块的数据，并且根据 hash values 校验块的有效性。对于 multi-linked list 的情形，这个校验块数据的步骤会复杂一些，但也并非无法处理，只要把原先校验一个块的操作，多几次循环，多校验几次就可以了。</p><p>正向和反向 multi-linked list 最大的区别是，一种是向外发散的，会随着层级的增大，每一层容纳的节点数不断增大，指数级增长。另一种是收敛的，每一层的节点数会不断减少，最终只剩下一个。也就是正着的树和倒着的树的区别。</p><img src="6.png" width="50%"><p>区块链中有一个创始块的概念，如果是正向的 multi-linked list，创世块还是一个保持不变，但是子节点逐渐膨胀以后，会越来越不可控。对于保留块高度的情况，其实除了程序处理多几个步骤，并没有无法实现的理由。对于不保留块高度或者说用索引值代替块高度的情况，块仍然可以一个一个地出，也没有在技术上实现不了的理由，但其实还是链式结构的处理方式。单纯数据结构从 linked list 转为 multi-linked list，似乎没有明确的理由，因为无法想象到，这样做可以带来什么样的好处。</p><img src="7.png" width="50%"><p>如果是反向的 multi-linked list，一个很大的问题是创世块怎么办，反向的树结构子节点会越来越少，最后只剩一个，难不成创世块规定足够大数量的节点数，然后后期逐步趋于1？这非常不合理，相当于给程序设置了一个停机条件，到达一定块高度后就无法在增加内容了，显然是不可取的做法。</p><p>由于树结构的发散或者收敛，multi-linked list 的设想是有问题的。那么这样呢，使用平行的 multi-linked list，可行吗？</p><img src="4.png" width="50%"><p>因为必须有多个输入和输出，并且输入和输出的数量必须一样，所以使用这样带有重复指向的方式。</p><p>同样地，在技术上可行，问题在于，有什么好处呢？这样的数据结构带来了什么？除了程序复杂程度的增加，还有什么？</p><p>好像还真有，这样的数据结构，允许同时出两个块。两个节点只要使用相同的父节点，即使没有先后，同一时刻产生了内容，也可以将块累加到链后面，作为子节点。</p><p>不过这样又回带来很多问题，比如怎么防止 double-spending ？同一个账户交易分别出现在了两个块里，以哪个为准？分布式系统的数据同步，一定是多点变单点的过程，并行处理的程序也会有一个资源竞争的问题，同时出两个块后还是需要某种机制单点处理数据，同时出块就没有意义了，并不能加快整个系统的数据处理速度。</p><p>而且，其实平行的 multi-linked list，可以认为是这样：</p><img src="5.png" width="50%"><p>这样来看，平行的 multi-linked list 就更没有意义了。</p><p>总的来说，区块链有可能基于 multi-linked list 的数据结构吗？似乎没有必要。singly-linked list 是简单的数据结构，但又确实是很适合于区块链的数据结构。</p><p><br><br></p><h3 id="背景知识"><a href="#背景知识" class="headerlink" title="背景知识"></a>背景知识</h3><h4 id="Singly-linked-list"><a href="#Singly-linked-list" class="headerlink" title="Singly-linked list"></a>Singly-linked list</h4><img src="10.png" width="50%"><p>Singly-linked list 是一种线性的数据结构， 每个节点都包含一个指向下个节点的 field，用于显式表示节点之间的关联关系，一般在程序中会用对象的引用地址来填充这个字段。当然直接使用节点的值也可以，只是为了在数据类型上有明显的区分。</p><pre><code class="go">type Node struct &#123;    Value int    Next  *Node&#125;func main() &#123;    node1 := Node&#123;Value: 1&#125;    fmt.Printf(&quot;%p\n&quot;, &amp;node1) // 0x14000104210    node2 := Node&#123;Value: 2&#125;    fmt.Printf(&quot;%p\n&quot;, &amp;node2) // 0x14000104220    node1.Next = &amp;node2    fmt.Println(node1) // &#123;1 0x14000104220&#125;    fmt.Println(node2) // &#123;2 &lt;nil&gt;&#125;&#125;</code></pre><p>node1 的内存地址为 <code>0x14000104210</code> ，node2 的内存地址为 <code>0x14000104220</code> ，然后将 node2 的内存地址赋值给 node1 的 next 变量，这个时候只要访问 node1，就可以通过 next 得到 node2 的内容了。以此类推，即使有很多很多 node，只需要知道起始位置 node1 的内容，就可以访问到整个 Linked list 的所有节点了。</p><h4 id="Doubly-linked-list"><a href="#Doubly-linked-list" class="headerlink" title="Doubly-linked list"></a>Doubly-linked list</h4><img src="11.png" width="50%"><p>Doubly-linked list 在 Singly-lined list 的基础上，多了一个字段，用于保存指向上一个节点的信息。在这样的数据结构下，获得一个节点的内容时，不但可以知道下一个节点的位置，还可以知道上一个节点的位置。</p><pre><code class="go">type Node struct &#123;    Value int    Next  *Node    Prev  *Node&#125;</code></pre><h4 id="Doubly-linked-list-Singly-linked-list"><a href="#Doubly-linked-list-Singly-linked-list" class="headerlink" title="(Doubly-linked list) - (Singly-linked list)"></a>(Doubly-linked list) - (Singly-linked list)</h4><p>Singly-linked list 时保留了下一个节点的信息，Doubly-linked list 上一个和下一个节点的信息都保留了，那么有没有一种数据结构，是只保留上一个节点的信息呢？比如这样：</p><pre><code class="go">type Node struct &#123;    Value int    Prev  *Node&#125;</code></pre><p>为什么会需要以保留上一个节点信息的形式，构造 Linked list 呢？因为存在这样一种场景：在创建当前节点的时候，下一个节点的内容和引用地址还不确定或者不存在。</p><p>当下一个节点内容确定后，还要更改上一个节点的内容吗？Demo 代码改起来是容易的，如果是在一个海量数据的数据库中呢？update 的成本是很高的；如果是在一个分布式系统中呢？网络交互、数据一致性的成本也很高。</p><img src="12.png" width="50%"><p>也许这样的数据结构并不差劲，它既没有牺牲 Linked list 的特性，又可以在不改动之前节点数据的基础上，使列表不断延长。只不过访问顺序和 Singly-lined list 是相反的，需要按照从最后一个节点向前的顺序才能遍历所有节点，就像是 Singly-linked list 倒过来了。其实倒过来的 Singly-linked list 也是 Singly-linked list。</p>]]></content>
  </entry>
  <entry>
    <title>用 cloudflare cloud 的 DNS，把子域名 gub 从原来 CNAME 到 gitbook 改为指向到...</title>
    <link href="https://t.smallyu.net/#2021-84"/>
    <id>micro:944166721</id>
    <published>2021-10-15T10:04:37Z</published>
    <updated>2021-10-15T10:06:01Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>用 cloudflare cloud 的 DNS，把子域名 gub 从原来 CNAME 到 gitbook 改为指向到 github，到现在已经超过 72 小时，开启 DNS proxy 的情况下依然跳转到 gitbook，看样子是一个 302 forward。 不是 cacheing 的问题，已经很多次打开 dev...</p>]]></summary>
    <content type="html"><![CDATA[<p>用 cloudflare cloud 的 DNS，把子域名 gub 从原来 CNAME 到 gitbook 改为指向到 github，到现在已经超过 72 小时，开启 DNS proxy 的情况下依然跳转到 gitbook，看样子是一个 302 forward。</p>
<p>不是 cacheing 的问题，已经很多次打开 dev mode 并且 purge 所有内容了。猜测 cloudflare cloud proxy 服务对于 forward 记录的更新非常慢，甚至有 bug。现在经过的时长一定超过 TTL 了。</p>
]]></content>
  </entry>
  <entry>
    <title>“十年来，深恩负尽，死生师友。” 我对这句诗的理解一直是，十年以来，辜负尽了深厚的恩情，以前的老师和朋友都像是死了一样。</title>
    <link href="https://t.smallyu.net/#2021-83"/>
    <id>micro:943572659</id>
    <published>2021-10-14T17:34:19Z</published>
    <updated>2021-10-14T17:34:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“十年来，深恩负尽，死生师友。” 我对这句诗的理解一直是，十年以来，辜负尽了深厚的恩情，以前的老师和朋友都像是死了一样。</p>]]></summary>
    <content type="html"><![CDATA[<p>“十年来，深恩负尽，死生师友。”</p>
<p>我对这句诗的理解一直是，十年以来，辜负尽了深厚的恩情，以前的老师和朋友都像是死了一样。</p>
]]></content>
  </entry>
  <entry>
    <title>看《鱿鱼游戏》的时候，最大的感触就是希望游戏是假的，人的死亡是假的，游戏可以随时终止。 玻璃球游戏中两个女主有一段对话。</title>
    <link href="https://t.smallyu.net/#2021-82"/>
    <id>micro:941920903</id>
    <published>2021-10-13T04:55:33Z</published>
    <updated>2021-10-13T04:55:33Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>看《鱿鱼游戏》的时候，最大的感触就是希望游戏是假的，人的死亡是假的，游戏可以随时终止。 玻璃球游戏中两个女主有一段对话。</p>]]></summary>
    <content type="html"><![CDATA[<p>看《鱿鱼游戏》的时候，最大的感触就是希望游戏是假的，人的死亡是假的，游戏可以随时终止。</p>
<p>玻璃球游戏中两个女主有一段对话。</p>
]]></content>
  </entry>
  <entry>
    <title>理解哈希函数与序列化</title>
    <link href="https://smallyu.net/2021/10/13/%E7%90%86%E8%A7%A3%E5%93%88%E5%B8%8C%E5%87%BD%E6%95%B0%E4%B8%8E%E5%BA%8F%E5%88%97%E5%8C%96/"/>
    <id>blog:https://smallyu.net/2021/10/13/%E7%90%86%E8%A7%A3%E5%93%88%E5%B8%8C%E5%87%BD%E6%95%B0%E4%B8%8E%E5%BA%8F%E5%88%97%E5%8C%96/</id>
    <published>2021-10-13T03:47:31.000Z</published>
    <updated>2025-11-09T09:22:13.461Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="Hash-function"><a href="#Hash-function" class="headerlink" title="Hash function"></a>Hash function</h3><p>Hash function 用于处理数据和其]]></summary>
    <content type="html"><![CDATA[<h3 id="Hash-function"><a href="#Hash-function" class="headerlink" title="Hash function"></a>Hash function</h3><p>Hash function 用于处理数据和其 hash values 的映射关系，hash values 是数据类似唯一标识的东西，可以用内存比较小的形式标识数据。hash function 有各种各样的实现，可以认为是一个黑盒子，进去的是 data，出来的是 hash values。</p><img src="7.png" width="50%"><p>比如，我们可以把字符的 ASCII 码作为字符的 hash values：</p><pre><code>HASH(&quot;a&quot;) = 97HASH(&quot;b&quot;) = 98HASH(&quot;c&quot;) = 99HASH(&quot;d&quot;) = 100</code></pre><p>对于 2 个字符的 data，就把两个字符的 ASCII 相加，作为 hash values：</p><pre><code>HASH(&quot;ab&quot;) = 97 + 98 = 195HASH(&quot;cd&quot;) = 99 + 100 = 199</code></pre><p>但是这样很容易发现存在问题，<code>HASH(&quot;ad&quot;) == HASH(&quot;bc&quot;) == 197</code>。对于 3 个、4 个甚至更多字符的情形，hash values 重复的可能性更大。</p><p>hash values 是允许重复的，但如果存在大量重复，hash function 也就失去了它的作用和使用场景：如果全部都一样，无法区分，还用 hash values 干嘛？</p><p>不幸的是，目前最好的 hash function 也无法避免 hash values 重复的问题，只能尽可能减少 hash values 重复的概率，比如用类似数据库分库分表的方式，给每个字符足够的余量。</p><p>我们可以重新设计一下我们的 hash function，在只有 1 个字符的时候，仍然使用 ASCII 作为输出。在有 2 个字符的时候，让 第 1 个字符乘以一个基数，再加上第 2 个字符。由于第 1 个字符在乘以基数后会足够大，无论第 2 个字符是什么，在其基础上加上第 2 个字符的 ASCII 码，应该不会重复。</p><pre><code>HASH(&quot;ab&quot;) = 97 * 1000 + 98 = 97098HASH(&quot;cd&quot;) = 99 * 1000 + 100 = 99100HASH(&quot;ad&quot;) = 97 * 1000 + 100 = 97100HASH(&quot;cd&quot;) = 98 * 1000 + 99 = 98099</code></pre><p>这样至少解决了 2 个字符 hash values 重复的问题。</p><p>推广到更一般的场景，在面对可能很多字符的情况下，基数使用质数以避免累加造成的重复，为了保证基数足够大，使用质数的不同次方分别作为每个字符的基数，公式为：</p><pre><code>hashCodes = char1 * base^(l-1) + char2 * base^(l-2) + ...</code></pre><p><code>hashCodes</code> 是输出的 hash values，<code>char1</code> 是第 1 个字符，<code>char2</code> 是第 2个字符，<code>base</code> 是基数，<code>l</code> 指字符串的长度。对于 3 个字符长度的字符串，第 1 个字符的基数就是质数的 2 次方，第 2 个字符的基数是质数的 1 次方，第 3 个字符是 0 次方，以此类推。</p><p>如果质数选择为 31，hash function 的实现为：</p><pre><code class="java">public static int hashCode(byte[] value) &#123;    int h = 0;    for(int i = 0; i &lt; value.length; ++i) &#123;        h = 31 * h + value[i];    &#125;    return h;&#125;</code></pre><p>也许具体的代码不是完全符合直觉，但你可以相信，和上面描述的公式是一致的。</p><pre><code>hashCode(&quot;a&quot;) = 97hashCode(&quot;ab&quot;) = 97 * 31 + 98 = 3105hashCode(&quot;abc&quot;) = 97*31^2 + 98*31 + 99 = 96354</code></pre><p>这就是 JDK (Java Development Kit) 中 hashCode 的实现方式。</p><h3 id="Cryptographic-hash-function-CHF"><a href="#Cryptographic-hash-function-CHF" class="headerlink" title="Cryptographic hash function (CHF)"></a>Cryptographic hash function (CHF)</h3><p>不难发现的是， hash function 比较容易根据 hash values 反推出原始的 data 是什么。我们可以写出这样的程序，假设我们已经知道字符长度是 2，由于字符使用 ASCII 编码，范围在 0 ~ 255，因此设 x 和 y 两个变量，枚举所有符合目标 hash values 的情况：</p><pre><code class="java"> public static String deHashCode(int code) &#123;    for (int x = 0; x &lt;= 255; x++) &#123;        int y = code - 31 * x;        if (y &lt; 0 || y &gt; 255) &#123;            continue;        &#125;        System.out.println(((char) x)+&quot;,&quot;+((char) y));    &#125;    return &quot;&quot;;&#125;</code></pre><p>比如当 <code>hashCode = 3105</code>，得到的输出是：</p><pre><code>\,ý],Þ^,¿_, `,a,bb,Cc,$d,</code></pre><p>原始数据 <code>ab</code> 就出现在了为数不多不多的可能性中。</p><p>那么有没有办法减少 hash values 推出原始 data 的方法？在 Public-key cryptography 中 <code>%</code> 可是起到了很大的作用。hash function 也可以与一些加密算法的原理结合。</p><p>cryptographic 是 hash function 的修饰词，即使用了加密算法的 hash function。</p><img src="8.png" width="50%"><p>md5 是使用非常广泛也接近过时的一种 cryptographic hash function，可以把任意长度的 data 计算输出为 128 bit 的 hash values。</p><pre><code>md5(&quot;a&quot;) = 0cc175b9c0f1b6a831c399e269772661md5(&quot;ab&quot;) = 187ef4436122d1cc2f40dc2b92f0eba0</code></pre><p>md5 的加密原理步骤很多，是一种不可逆的、单向的 hash function，无法轻易根据 hash values 得到 data。md5 的输入可以是任意大小的，1 GB 的二进制文件也可以hash 为 128 bit 的字符串。</p><p>md5 之外，SHA-1 的安全性更高，BLAKE2 的计算速度更快，它们都是典型的 cryptographic hash function。</p><br><h3 id="Serialization"><a href="#Serialization" class="headerlink" title="Serialization"></a>Serialization</h3><p>序列化是编程中很常见的一种操作，主要用于把复杂格式的数据转化成易于在不同环境中统一处理的格式，类似于定义一种接口格式，便于网络传输。</p><img src="9.png" width="50%"><p>把数据转换为统一的过程称为 serialization，从统一格式转换为特殊格式的过程为 deserialization。JSON stringify 的过程也可以认为是一种序列化：</p><pre><code class="javascript">let object = &#123;    field1: &quot;abc&quot;,    field2: 123&#125;let str = JSON.stringify(object)    print(str)    // &#123;&quot;field1&quot;:&quot;abc&quot;,&quot;field2&quot;:123&#125;</code></pre><h3 id="Serialization-CHF"><a href="#Serialization-CHF" class="headerlink" title="Serialization + CHF"></a>Serialization + CHF</h3><p>可以明确的是，JSON stringify 的结果是一个字符串，这个时候就可以和之前的 cryptographic hash function 结合起来用了：</p><pre><code>md5(str) = d79152b724c5f1e52e6bd4bfaf6e1532</code></pre><p>只要定义过数据的 serialization 方法，我们就可以得到任意数据格式的 hash values。</p><h3 id="Serialization-CHF-Linked-List"><a href="#Serialization-CHF-Linked-List" class="headerlink" title="Serialization + CHF + Linked List"></a>Serialization + CHF + Linked List</h3><p>Linked list 之间的关联关系常用变量的引用地址表示，但指针不是惟一的方式，数据结构的含义也可以扩展到更大的范围。我们完全可以用节点数据的 hash values 作为关联：</p><img src="10.png" width="50%"><p><code>98</code> 是 <code>b</code> 的 hash values，表明值为 <code>a</code> 的节点，下一个节点的 hash values 为 <code>98</code>，也就是值为 <code>b</code> 的节点。</p><p>我们也可有使用反向的 linked-list：</p><img src="11.png" width="50%"><p><code>a</code> 的 hash values 是 97，表明值为 <code>b</code> 的节点，上一个节点的 hash values 为 <code>97</code>。</p><p>当然，这里的值可以是更复杂的数据结构，只要定义好 serialization 格式，也可以应用到更复杂的 hash function 上，比如这样正向的 linked-list：</p><pre><code class="go">type Node struct &#123;    Value int    Next  string&#125;node1 = Node&#123; Value: &quot;a&quot; &#125;node1_str = JSON.stringify(node1)   // &#123; &quot;Value&quot;: &quot;a&quot; &#125;node1_hash = md5(node1_str)         // 9ad06e8a44d0daf821f110794fb012c7node1.Next = node1_hash</code></pre><p>这就构建好了一个节点，以此类推。</p><p>另一种也许更好或者更适用于某种特定场景的形式是，将其改为反向的 linked-list：</p><pre><code class="go">type Node struct &#123;    Prev string    Value int&#125;node1 = Node&#123; Value: &quot;a&quot; &#125;node1_str = JSON.stringify(node1)   // &#123; &quot;Value&quot;: &quot;a&quot; &#125;node1_hash = md5(node1_str)         // 9ad06e8a44d0daf821f110794fb012c7node2 = Node&#123; Value: &quot;b&quot; &#125;node2_str = JSON.stringify(node2)   // &#123; &quot;Value&quot;: &quot;b&quot; &#125;node2_hash = md5(node2_str)         // 7e332b78dbaac93a818a6ab639f5a71bnode2.Prev = node1_hash</code></pre><p>这种反向的 linked-list 就是区块链的基础数据结构。 </p>]]></content>
  </entry>
  <entry>
    <title>现在 gitbook 的在线编辑难用过头了，不能删除 commit，不能新建文档，光标会自动跳转……他们是怎么对用户负责...</title>
    <link href="https://t.smallyu.net/#2021-81"/>
    <id>micro:940104321</id>
    <published>2021-10-11T14:55:37Z</published>
    <updated>2021-10-11T14:55:37Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>现在 gitbook 的在线编辑难用过头了，不能删除 commit，不能新建文档，光标会自动跳转……他们是怎么对用户负责的。</p>]]></summary>
    <content type="html"><![CDATA[<p>现在 gitbook 的在线编辑难用过头了，不能删除 commit，不能新建文档，光标会自动跳转……他们是怎么对用户负责的。</p>
]]></content>
  </entry>
  <entry>
    <title>小孔成像 光现象 中学物理</title>
    <link href="https://t.smallyu.net/#2021-80"/>
    <id>micro:939996660</id>
    <published>2021-10-11T12:45:33Z</published>
    <updated>2021-11-06T15:04:52Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>小孔成像 光现象 中学物理</p>]]></summary>
    <content type="html"><![CDATA[<p><a href="https://www.youtube.com/watch?v=F-RAXHfUHxo">小孔成像 光现象 中学物理</a></p>
]]></content>
  </entry>
  <entry>
    <title>这个 Senegal 语言的 Pipline Operator 还是有意思的。</title>
    <link href="https://t.smallyu.net/#2021-79"/>
    <id>micro:939801406</id>
    <published>2021-10-11T08:22:15Z</published>
    <updated>2021-10-11T08:22:15Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>这个 Senegal 语言的 Pipline Operator 还是有意思的。</p>]]></summary>
    <content type="html"><![CDATA[<p>这个 Senegal  语言的 <a href="https://lang-senegal.web.app/docs/pipeline">Pipline Operator</a> 还是有意思的。</p>
]]></content>
  </entry>
  <entry>
    <title>&amp;quot;Blog&amp;quot; 这个词的来源好像是，一开始叫 &amp;quot;web log&amp;quot;，后来有人把在网站...</title>
    <link href="https://t.smallyu.net/#2021-78"/>
    <id>micro:939615853</id>
    <published>2021-10-11T02:01:10Z</published>
    <updated>2021-10-11T02:01:10Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>&amp;quot;Blog&amp;quot; 这个词的来源好像是，一开始叫 &amp;quot;web log&amp;quot;，后来有人把在网站的 logo 里把字母 &amp;quot;b&amp;quot; 移到了后面，变成 &amp;quot;we blog&amp;quot;，就有了 &amp;quot;blog&amp;quot; 这个词。</p>]]></summary>
    <content type="html"><![CDATA[<p>&quot;Blog&quot; 这个词的来源好像是，一开始叫 &quot;web log&quot;，后来有人把在网站的 logo 里把字母 &quot;b&quot; 移到了后面，变成 &quot;we blog&quot;，就有了 &quot;blog&quot; 这个词。</p>
]]></content>
  </entry>
  <entry>
    <title>想起一件事，之前在一个 TBI 开源技术沙龙的群里，TBI 开源组说是想搞一个开源项目名录，几个月前就想发区块链开源项目...</title>
    <link href="https://t.smallyu.net/#2021-77"/>
    <id>micro:939378458</id>
    <published>2021-10-09T23:59:33Z</published>
    <updated>2021-10-10T00:17:25Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想起一件事，之前在一个 TBI 开源技术沙龙的群里，TBI 开源组说是想搞一个开源项目名录，几个月前就想发区块链开源项目白皮书的，后来发现名录不全。 信通院就爱干发白皮书之类的事情。在他们眼里，“国内的”“开源的”“联盟链”屈指可数，自然可以有一个名录。长安链有一次演讲中提到，做开源的只有 3 家 :) 结果怎么样呢，...</p>]]></summary>
    <content type="html"><![CDATA[<p>想起一件事，之前在一个 TBI 开源技术沙龙的群里，TBI 开源组说是想搞一个开源项目名录，几个月前就想发区块链开源项目白皮书的，后来发现名录不全。</p>
<p>信通院就爱干发白皮书之类的事情。在他们眼里，“国内的”“开源的”“联盟链”屈指可数，自然可以有一个名录。长安链有一次演讲中提到，做开源的只有 3 家 :)</p>
<p>结果怎么样呢，他们也觉得不好搞了。</p>
]]></content>
  </entry>
  <entry>
    <title>魔法师</title>
    <link href="https://crazy.smallyu.net/2021/10/09/%E9%AD%94%E6%B3%95%E5%B8%88/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/10/09/%E9%AD%94%E6%B3%95%E5%B8%88/</id>
    <published>2021-10-09T10:44:10.000Z</published>
    <updated>2025-10-01T00:53:52.266Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>勇者受伤了。</p>
<p>他来到山脚，发现有怪物挡住了上山的路。</p>
<p>怪物的名字，叫做权威。</p>
<p>他和怪物完成交易，放弃此前所有的勋章和荣誉。</p>
<p>他扔掉了剑，丢掉了盔甲，杀掉了马。</p>
<p>他可以上山了，他没有上山。</p>
<p>他]]></summary>
    <content type="html"><![CDATA[<p>勇者受伤了。</p><p>他来到山脚，发现有怪物挡住了上山的路。</p><p>怪物的名字，叫做权威。</p><p>他和怪物完成交易，放弃此前所有的勋章和荣誉。</p><p>他扔掉了剑，丢掉了盔甲，杀掉了马。</p><p>他可以上山了，他没有上山。</p><p>他需要新的宝剑。</p><p>他去了附近的魔法镇，去了远处的藏宝山。</p><p>去了最好的兵器店，去了神秘的海盗湾。</p><p>秃鹰啄伤了他的肩膀，刺猬挡住了他的去路。</p><p>门卫刁难他衣着朴素，法官质疑他没有天赋。</p><p>他累了。</p><p>他回到寄居的酒馆，想起了从前。</p><p>他需要回家一趟。</p><p>他想休息。</p><p>甚至想放弃。</p><p>他回到新手村，见到了朋友。</p><p>他是凯旋的冒险者，他是无畏的勇士。</p><p>他有亮丽的盔甲，他有傲人的白马。</p><p>他不再是新手，也再没有朋友。</p><p>他不可以倒下，也不可以害怕。</p><p>虽然他累了。</p><p>一间房子，一年住 351 天，另一间房子，一年住 14 天。</p><p>哪个是家，哪个是旅店。</p><p>一个地方，一年度过 351 天，另一个地方，一年度过 14 天。</p><p>哪里是生活，哪里是旅途。</p><p>他回到酒馆，一切从新，一切照旧。</p><p>他终究没有找到宝剑。</p><p>如果你看到他，</p><p>他可能在迷茫，</p><p>也可能在游荡。</p><p>请你告诉他，</p><p>他可以继续前进，</p><p>也可以稍作停留，</p><p>也可以后退几步，</p><p>他可以写一本魔法书，</p><p>可能掌握高明的法术，</p><p>他会成为优秀的魔法师，</p><p>而不仅仅是挥剑的战士。</p>]]></content>
  </entry>
  <entry>
    <title>漫威电视剧《洛基》</title>
    <link href="https://t.smallyu.net/#2021-76"/>
    <id>micro:935451123</id>
    <published>2021-10-06T04:54:19Z</published>
    <updated>2021-10-06T04:54:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>漫威电视剧《洛基》</p>]]></summary>
    <content type="html"><![CDATA[<p>漫威电视剧《洛基》</p>
]]></content>
  </entry>
  <entry>
    <title>最近热门 series《鱿鱼游戏》( Squid Game )</title>
    <link href="https://t.smallyu.net/#2021-75"/>
    <id>micro:934439779</id>
    <published>2021-10-05T13:57:38Z</published>
    <updated>2021-10-05T14:05:10Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最近热门 series《鱿鱼游戏》( Squid Game )</p>]]></summary>
    <content type="html"><![CDATA[<p>最近热门 series《鱿鱼游戏》(<em>Squid Game</em>)</p>
]]></content>
  </entry>
  <entry>
    <title>A Short Hike on steam，找了两天只有这个游戏好玩</title>
    <link href="https://t.smallyu.net/#2021-74"/>
    <id>micro:933153800</id>
    <published>2021-10-04T05:23:47Z</published>
    <updated>2021-10-04T05:23:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>A Short Hike on steam，找了两天只有这个游戏好玩</p>]]></summary>
    <content type="html"><![CDATA[<p><a href="https://store.steampowered.com/app/1055540/A_Short_Hike/"><em>A Short Hike</em></a> on steam，找了两天只有这个游戏好玩</p>
]]></content>
  </entry>
  <entry>
    <title>你是……</title>
    <link href="https://b.smallyu.net/2021/10/02/%E4%BD%A0%E6%98%AF%E2%80%A6%E2%80%A6/"/>
    <id>blog-b:https://b.smallyu.net/2021/10/02/%E4%BD%A0%E6%98%AF%E2%80%A6%E2%80%A6/</id>
    <published>2021-10-02T09:03:56.000Z</published>
    <updated>2026-03-02T09:03:29.889Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>你是内战时期的军阀，伪装成屠杀了全村并抢劫了公主的强盗，押着公主到交流情报的酒馆，寻找生活在黑暗里的情报头子摩尔斯帮忙，想要找到军火的藏匿地图。你遇到了幼时有救命之恩的记者，遇到了追求公主至今的特务。他们笑里藏刀，想要抢走你的地位和朋友。最终你输了，死在血泊里，值得欣慰的是]]></summary>
    <content type="html"><![CDATA[<p>你是内战时期的军阀，伪装成屠杀了全村并抢劫了公主的强盗，押着公主到交流情报的酒馆，寻找生活在黑暗里的情报头子摩尔斯帮忙，想要找到军火的藏匿地图。你遇到了幼时有救命之恩的记者，遇到了追求公主至今的特务。他们笑里藏刀，想要抢走你的地位和朋友。最终你输了，死在血泊里，值得欣慰的是，她过的幸福。</p><p>你是年轻有钱的渣男，女友背叛你和兄弟约会，你背叛女友和同学约会，同学喜欢你的钱，女友也喜欢你的钱。最后你需要选择，新欢还是旧爱。无论哪种选择，都是凄惨的结局。</p><p>你是来自美国的富商，受邀参加一场神秘的宴会。宴会主人曾在十几年前犯下杀人罪行，宴会当天遭到复仇惨死密室。你作为警官调查这起案件，发现凶手精通易容术，来自美国的富商不是富商本人，发现外表纯洁的美女主播暗藏杀机，隐忍多年配合凶手完成报仇。</p><p>你是秦国公子扶苏，荆轲来进贡献上地图，胡亥受小人控制想要篡位，你想保住秦国的千秋大业。你的盟友毫不怀疑胡亥伪装的面目，输的理所当然。</p><p>你是身负血海深仇的日本警察。在警局办公系统数字化的过程中，很多罪犯利用关系伪造了自己的死亡。世界上没有人知道他们的存在，因为他们没有“身份”。你暗中搜查并一个接一个杀掉“身份干净”的人，他们才是真正的罪犯，因为司法机制的不健全，那帮愚蠢的警察总是无动于衷。你的妻子死于未成年罪犯之手，你怀孕的妻子一尸两命，被罪犯一刀一刀刺进肚子失血而死。你眼睁睁看着未成年的犯罪被释放。这个肮脏的司法系统，这个无能的侦查体系。你亲自动手，替上天惩罚早不该活在世界上的人。</p><p>你是龙族公子，你的爷爷是众神族长，由于其他族落的叛乱惨遭杀害。真的是叛乱吗？不是！你想起了前世收养你的爷爷，为了包庇你的军事起义，用脚印引导追捕你的军队走向错误的道路。你成为了雄霸一方势力的首领，才得知你的爷爷舍命为你争取的这个机会。你想起了前世的青梅竹马，由于地位悬殊，神妖殊途，你们的结合引发天谴降临。结婚当日，一半族人为你们的婚礼献祭。你想起了今世，原来族长为了避免悲剧发生，为了保护各族的孩子，走火入魔迷失了心智。三生石，三生路。</p><p>你是一味追求大学旧爱的男生，她受到你父母的干预无声息消失，你念念不忘。</p><p>你是一只妖怪，在怪谈中寻找自己的故事。</p><p>你是反叛军的首领。机器人占领星球，你带领强大的势力奋起反抗。后来发现你不是真正的你，你只是被覆盖了意识的克隆人，你的梦里出现了奇怪的画面，有雪山、有草地、有风、有散落满地的红色眼睛，你唯一的亲人其实是在苦苦寻找你的姐姐。</p><p>你是电话诈骗团伙的成员，负责选择合适的语音风格针对不同的目标进行下手。你是公交车祸里的受害者，伙同其他受害者一起，用诈骗的方式让当初事故的始作俑者受到惩罚。</p><p>你是小镇的猎魔人，配合小镇唯一的警官一起处理小镇上忽然疯掉的居民。原来你们都生存在计算机的世界里，主网服务器已经停机，你们是仅存的拥有完整建模的主机，病毒很快就会侵入这里。你的好兄弟警官勇敢地牺牲在和病毒的搏斗中。你面临选择，是毁掉这里让一切瞬间消失，还是带着渺茫的希望伙同伙伴们和机器战斗下去？</p><p>你是王朝的君主，鸟类神族的公主弃你而去，你征战多年，遇到一个很像公主的女孩，你隐约把她看成了梦中人的样子。多年后，你发现手上的伤口中残留着公主的神识，她没有忘记你，她一直在关心你，但是她不能背叛自己的种族。一边是自己深深想念的深明大义的公主，一边是陪伴自己多年的可爱的女孩。从前车马慢，一生只够爱一人。</p><p>你是班里的大哥。一场突如其来的灾难把你们压在倒塌的房屋废墟之下。古木低吟，你们得以重生在另一个世界。新的世界中，校园是黑色的，操场上的老奶奶面目苍白、肚子里的肠子还在对外淌血。教室里有很多带着面具的红头娃娃，睁眼看着你。树林里白色衣服的女人来回飘荡，手上是阴森的长指甲。你们齐心协力战胜恐怖的幽魂，世界重归于美好，正好是校庆日。生活回到正轨了吗？校庆日当天，你自杀身亡在舞台之上。地震了，只有你意识清醒，你为了让弟弟妹妹们勇敢起来面对今后的生活，许愿让古木将你们带到更加可怕的生活中，让他们一次又一次重复面对不堪的世界。</p><p>你是山神的孩子。那一年闹山鬼，你的父亲消失在对抗山鬼的战斗中。长大后，每个孩子都很忙，约定的每年的忌日，也没有人再关心。他只想看你们一眼，今年他买了可以延迟拍照的相机，终于可以把他自己拍进去了。人呢？没有人回来？那年森林火灾，你们的消防员父亲死在火灾之中，他一个人将你们 7 个孩子抚养长大。你们儿时晚上看到的油鬼，是他脸上绑着绷带面目全非不忍吓到你们的脸。他一直在默默关注和保护你们。</p><p>你是经常光顾青楼的公子。你和招牌艺妓青梅竹马、私定终身，却无疾而终。</p><p>你是有钱的大学生，有个人为了钱接近你，装作你的好朋友。他亲手杀了你喜欢的女生，拜月教献祭，是她死亡的表象。混杂着地下交易的地下组织，她终究没有逃脱那里。</p><p>你是星期一。从星期一到星期日，一人一天。你们是一个人，又不是一个人，你们的性格不同。你们被坏人关到地下室，一个好朋友救了你们。从被救的那天开始，你却察觉到异常，你真的是你吗？你希望七个人永远在一起，可其他人逐渐有了新朋友，只有你孤单一人。你们许下的生日愿望，都被躲藏在黑暗中的神秘人用奇怪的方式完成了。有人想要母亲的怀抱，神秘人就把母亲的尸体藏在沙发里，每次躺到沙发上，都可以感受到母亲的温暖。有人想要重见小时的朋友一面，神秘人就杀掉一个体型相仿的孩子，把照片贴在尸体脸上。对了，这个神秘人，儿时父亲和母亲吵架，他害怕自己被抛弃，在父亲自杀后，亲手用刀子割开了父亲的肚子，钻了进去。这个神秘人，就是把你从地下室解救出来的好朋友。</p><p>你是台湾原住民。荷兰军队进驻台湾，想要占领中国大陆。你一面作为明朝的卧底，在荷兰军官中深受赏识，一面想要团结台湾原住民们团结奋战，建立自己的军事政权。她是你唯一想念的人，你曾经落船漂流岛孤岛上，和一个自以为是的野蛮人共同生活十二年，从零开始种植作物、建造房子。他现在是荷兰军队的高级将领了。你不忍和他兵刃相见，可又必须将荷兰人赶出这片土地。没想到，决战当天，清朝军队、西班牙军队、飞翔的荷兰人号，都来了。</p><p>你是一个依靠作弊拥有傲人成绩的学生，你是一个商场得意却患有抑郁症的商人，你是一个在马戏团工作的小丑，你是一个商场失意的货车司机。你的父亲也许不理解你，高考当天你离家出走，逃离你熟悉的城市。第二天，你的父亲满脸疲倦，敲开你的房门。走！抑郁症也是病，咱们慢慢治！你以为会迎来一阵毒打，但收到一个充满愧疚的拥抱。</p><p>你是北欧之神奥丁诅咒的产物，你的祖先曾刺伤奥丁的一只眼睛。其他人看到你是白色的乌鸦，失心人看到你是正常的男孩。每当有白色乌鸦从蛋壳中诞生，当天会凭空多出不存在的第十三个小时，一切事物都停滞了，来自地狱的怪物会在此刻出现，肆意杀害方圆一公里的人类，夺走他们代表过去和未来的心脏和眼睛。被怪物杀害的人类会进入眼中世界，等待下次代表预言的第十三个小时出现，他们可以趁机再次回到人类世界，夺舍还处于存活状态人类的身体。你的姐姐，你唯一想念的人，唯一对你好的人，唯一想放你走的人。你咬断自己的一根手指，和怪物做交易，让他不要杀害你的姐姐。可是由于万一挑一的能够记住梦境内容的人出现，害你姐姐穿上了女仆的衣服，被怪物误杀。在这个世界上，你唯一挂念的人也离你而去。你本就是邪恶的产物，你的存在只会带来灾难。下一个诅咒之子，又是谁呢。</p><p>你是罪演师的候选人。你曾经是全国最优秀的刑侦警官，一同全来的还有你曾最欣赏的部下。神探仪的出现让刑侦警察显得可有可无，公安系统大规模减员，随之兴起的是配合神探仪定位真正凶手的职业罪演师。当年最优秀的罪演师团队六边形集体身亡，数次愚弄大众的逃脱者到底身在何方。</p><p>你是重点大学的毕业生，你是表妹的哥哥，今天替父母参加她的家长会。你的父母重男轻女，对自幼遭遇家庭变故的表妹并不上心。你的女朋友送妹妹一双皮鞋，不知道妹妹有多高兴。可是有一天你发现妹妹弄丢了他的皮鞋，穿着一双破破烂烂的鞋子回家。妹妹怕你生气，专程到你的房间里道歉。你对一切并没有什么感觉，直到收到学校妹妹身亡的消息。妹妹和其他同学一起，尸体被发现在悬崖的下面。你和其他家长一起分析妹妹和其他同学的日记，这么可爱的妹妹，这么可爱的同学们，全部遭遇混蛋老师的猥亵。更加可恶的是，你们没有任何证据指认凶手。你们只有用一生去弥补，自己对罪犯的无能为力。</p><p>你是……</p><p>你不想玩一场剧本杀，体验一次光怪陆离的奇异人生吗？</p>]]></content>
  </entry>
  <entry>
    <title>小时侯坐车觉得好玩，现在只会觉得烦躁。</title>
    <link href="https://t.smallyu.net/#2021-73"/>
    <id>micro:931854026</id>
    <published>2021-10-01T02:55:00Z</published>
    <updated>2021-10-01T02:55:00Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>小时侯坐车觉得好玩，现在只会觉得烦躁。</p>]]></summary>
    <content type="html"><![CDATA[<p>小时侯坐车觉得好玩，现在只会觉得烦躁。</p>
]]></content>
  </entry>
  <entry>
    <title>联盟链比公有链差在哪儿</title>
    <link href="https://smallyu.net/2021/09/29/%E8%81%94%E7%9B%9F%E9%93%BE%E6%AF%94%E5%85%AC%E6%9C%89%E9%93%BE%E5%B7%AE%E5%9C%A8%E5%93%AA%E5%84%BF/"/>
    <id>blog:https://smallyu.net/2021/09/29/%E8%81%94%E7%9B%9F%E9%93%BE%E6%AF%94%E5%85%AC%E6%9C%89%E9%93%BE%E5%B7%AE%E5%9C%A8%E5%93%AA%E5%84%BF/</id>
    <published>2021-09-29T06:27:43.000Z</published>
    <updated>2025-11-09T09:22:13.536Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>中文语境下的 “公有链” 和 “联盟链” 并没有明确标准的定义。2018 年，美国国家标准与技术研究院（NIST, National Institute of Standards and Technology）在 <em><a]]></summary>
    <content type="html"><![CDATA[<p>中文语境下的 “公有链” 和 “联盟链” 并没有明确标准的定义。2018 年，美国国家标准与技术研究院（NIST, National Institute of Standards and Technology）在 <em><a href="http://vpb.smallyu.net/[Tech]%20blockchain/Blockchain%20Technology%20Overview%20-%20NIST.IR.8202.pdf">Blockchain Technology Overview</a></em> 中将区块链分为 Permissionless blockchain 和 Permissioned blockchain，但那样的分类方式并不严格对应公有链和联盟链。也许公有链和联盟链的区别在于节点网络规模的大小，也许区别在于区块链面向的范围是公共互联网还是私有局域网。无论是怎样的定义，我们至少可以大概区分出公有链和联盟链。</p><p>公有链和联盟链的好坏，不单纯在于技术或者某些评价指标的比较，也许会有人下意识地认为，公有链面对比联盟链更复杂的网络环境和用户体量，但其实技术上的差距总是有办法弥补，联盟链也有少数好于公有链的技术特性。</p><p>有一个段子《<a href="https://baike.baidu.com/item/%E7%9A%87%E5%B8%9D%E7%9A%84%E9%87%91%E9%8B%A4%E9%A0%AD/23725819">皇帝的金锄头</a>》：</p><blockquote><p>古代有两个老农民畅想皇帝的奢华生活，一个说：“我想皇帝肯定天天吃白面馍吃到饱！” 另一个说：“不止不止，我想皇帝肯定下地都用的金锄头！”</p></blockquote><p>联盟链就是在用区块链做传统行业的业务，甚至可以说是打着区块链的幌子到处骗钱。联盟链的问题就在于，格局小了。</p>]]></content>
  </entry>
  <entry>
    <title>享受你的生活</title>
    <link href="https://crazy.smallyu.net/2021/09/28/%E4%BA%AB%E5%8F%97%E4%BD%A0%E7%9A%84%E7%94%9F%E6%B4%BB/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/09/28/%E4%BA%AB%E5%8F%97%E4%BD%A0%E7%9A%84%E7%94%9F%E6%B4%BB/</id>
    <published>2021-09-28T10:39:30.000Z</published>
    <updated>2025-08-16T03:27:07.295Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>我本可以有很多开心起来的理由，但总是因为一些不必要的目标让自己感到困扰。</p>
<p>我没有任何理由因为工作不相关的人和事情，放弃自己感兴趣的职业和技术方向。</p>
<p>我不想再花费时间关心自己不需要关心的问题，我有很多感兴趣的事情还没有做。</p>
<p>我为什么不]]></summary>
    <content type="html"><![CDATA[<p>我本可以有很多开心起来的理由，但总是因为一些不必要的目标让自己感到困扰。</p><p>我没有任何理由因为工作不相关的人和事情，放弃自己感兴趣的职业和技术方向。</p><p>我不想再花费时间关心自己不需要关心的问题，我有很多感兴趣的事情还没有做。</p><p>我为什么不优先关注自己的事情？</p><br><blockquote><p>Maybe today is not an “improve yourself” day. Maybe it can be an “accept yourself and get through” day instead.</p></blockquote><br><img src="life.jpeg">]]></content>
  </entry>
  <entry>
    <title>我的问题是什么</title>
    <link href="https://crazy.smallyu.net/2021/09/27/%E6%88%91%E7%9A%84%E9%97%AE%E9%A2%98%E6%98%AF%E4%BB%80%E4%B9%88/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/09/27/%E6%88%91%E7%9A%84%E9%97%AE%E9%A2%98%E6%98%AF%E4%BB%80%E4%B9%88/</id>
    <published>2021-09-27T15:58:51.000Z</published>
    <updated>2025-08-17T12:48:28.503Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>唉，又要发牢骚了。我希望博客可以多一些纯粹的技术性的内容，似乎很难。最近几天感到一些焦虑和不安，但是不清楚来源是什么。想了几天，发现是一个有点熟悉的、想想就有点心累的话题。</p>
<h3 id="说明"><a href="#说明" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>唉，又要发牢骚了。我希望博客可以多一些纯粹的技术性的内容，似乎很难。最近几天感到一些焦虑和不安，但是不清楚来源是什么。想了几天，发现是一个有点熟悉的、想想就有点心累的话题。</p><h3 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h3><p>入职的时候，直接用已有的 Github 账号用作账号了。到现在也不确定是不是正确的选择。为了避免看起来像是对人有意见或者像是在吵架。后面的内容尽可能只描述客观发生的事实，不掺杂我自己的体会和感受，尽量不以对话形式写什么内容。</p><p><strong>求生欲：博客就是写着玩，不要把网络上的言论和现实中的人物对应起来。</strong></p><h3 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h3><p>今天发生了一些事情。我先后在微信上问了 HR、市场、测试一共 3 个人，想了解一下目前项目的进展和情况。后来 HR 知道后说，“市场的直接汇报对象是谁谁谁，你是不是疯了，怎么能直接问人家呢，这不合适”。</p><p>后来 HR 把我叫到会议室，问我说，我还有什么问题、有什么不知道的，可以直接问他。</p><p>HR 说，你为什么要问测试那些问题，测试的那些东西你也不懂。</p><p>HR 说，你就安心敲你的代码就行了，用得着了解那么多吗？</p><p>HR 说，公司融资路径清晰、前景很好，要是不好我自己就先走了，你有什么好担心的，人不都是为了那些吗？</p><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>我认真想了想，我的问题到底是什么。我刚才想明白了，并且能解释我的行为和动机，解释我为什么要做那些事情。</p><p>我的问题是：<strong>我可以做些什么？</strong></p><p>对于这个问题，我为什么没有直接问技术负责人？因为不是我没有事干，想找工作上的安排。</p><p>这个问题的另一种表述是：<strong>我能力的上限是什么？</strong></p><p>这个问题，问是问不出答案的，没有人知道，除了我自己，甚至我自己，也不知道。</p><p>所以我为了回答自己这个问题，需要了解整个项目的情况，包括公司的盈利模式、市场计划、项目进度、开发节奏，等等。技术方面，代码放在那儿，我自己去看就可以了，其他的，可能得问人。</p><p>为什么要了解那么多？只了解技术方面的东西不够吗？</p><p>假设，强调，假设，我的能力上限是可以负责起整个项目，甚至在公司没有项目的时候，考虑公司未来产品的方向，就需要结合市场计划、营收状况等进行判断了。</p><p>是不是想多了？这些东西用得着我操心？这些东西轮得着我操心？</p><p>所以要假设……</p><p>我需要尽可能多地知道，哪些事情我能做，哪些事情我做不了，更重要的是，我做不了的那些事情，我为什么做不了，差距有多大。这个，也许只有我自己能判断。</p><h3 id="立场"><a href="#立场" class="headerlink" title="立场"></a>立场</h3><p>我面临的这个问题，其实长期存在，只是现在明确出来了。这个问题不会因为外界环境而改变。</p><h3 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h3><p>换工作解决了一些旧的问题，带来了一些新的问题。</p><p>重要的是，解决这个问题需要大量时间和经历。</p><p>具体的工作其实多么脚踏实地都可以，对于问题本身，目前只是处于了解状况的阶段，短时间内不希望和没办法做出什么动作。</p><h3 id="回忆"><a href="#回忆" class="headerlink" title="回忆"></a>回忆</h3><p>可能因为之前经历的项目规模比较小，我是有信心负责起整个项目的，当然，指技术方面，从前端到后端，从应用层到底层。也可能之前的公司放权限比较多，我们从写标书开始跟进整个项目到交付。也当然，由于工作经验、资历、为人处事，公司不会给我直接的权力和位置。</p><p>最近总是时不时想起，当时提离职的时候，当时的领导说，你要是去大厂或者安全一点的公司，我们也只能是祝福，可是……也不是不好，怕你走错路。</p><p>当时的领导说，他和现在公司的高管也是有过来往的，你……（想好。（没明说，可能是这个意思））</p><h3 id="最近"><a href="#最近" class="headerlink" title="最近"></a>最近</h3><p>有同学要结婚了。每次都怀疑自己，是不是真的错了。</p><p>最近身体不舒服的厉害，十一假期后可能需要去医院检查一下。</p><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>唉，发现很多东西不敢写出来。</p>]]></content>
  </entry>
  <entry>
    <title>网易云音乐开会员有无损音质。</title>
    <link href="https://t.smallyu.net/#2021-72"/>
    <id>micro:924887906</id>
    <published>2021-09-22T12:34:47Z</published>
    <updated>2021-09-22T12:34:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>网易云音乐开会员有无损音质。</p>]]></summary>
    <content type="html"><![CDATA[<p>网易云音乐开会员有无损音质。</p>
]]></content>
  </entry>
  <entry>
    <title>网易云音乐的音质比 Youtube Music 差多了，手机上不太听得出来，Mac 外放把声音调大，低音效果差距太大了。</title>
    <link href="https://t.smallyu.net/#2021-71"/>
    <id>micro:923571855</id>
    <published>2021-09-21T03:07:28Z</published>
    <updated>2021-09-21T03:09:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>网易云音乐的音质比 Youtube Music 差多了，手机上不太听得出来，Mac 外放把声音调大，低音效果差距太大了。</p>]]></summary>
    <content type="html"><![CDATA[<p>网易云音乐的音质比 Youtube Music 差多了，手机上不太听得出来，Mac 外放把声音调大，低音效果差距太大了。</p>
]]></content>
  </entry>
  <entry>
    <title>在 Dijkstra 算法中保存路径</title>
    <link href="https://smallyu.net/2021/09/18/%E5%9C%A8Dijkstra%E7%AE%97%E6%B3%95%E4%B8%AD%E4%BF%9D%E5%AD%98%E8%B7%AF%E5%BE%84/"/>
    <id>blog:https://smallyu.net/2021/09/18/%E5%9C%A8Dijkstra%E7%AE%97%E6%B3%95%E4%B8%AD%E4%BF%9D%E5%AD%98%E8%B7%AF%E5%BE%84/</id>
    <published>2021-09-18T11:00:45.000Z</published>
    <updated>2025-11-09T09:22:13.317Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>区块链的 Layer 2 中有一种 State Channels 的扩容方案，其中会需要搜索距离最近的路由节点。</p>
<h3 id="Dijkstra-算法思路"><a href="#Dijkstra-算法思路" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>区块链的 Layer 2 中有一种 State Channels 的扩容方案，其中会需要搜索距离最近的路由节点。</p><h3 id="Dijkstra-算法思路"><a href="#Dijkstra-算法思路" class="headerlink" title="Dijkstra 算法思路"></a>Dijkstra 算法思路</h3><p>Dijkstra 算法能够解决 single-source 的最短路径问题，算法本身只输出一个点到其他点的最短距离。比如在这样一个图中，起点是 A，想知道到 D 点的最短距离是多少：</p><img src="g1.png" width="50%" /><p>Dijkstra 算法实质是动态规划的贪心算法的结合，要寻找最短路径，就去遍历所有的点，每到一个点更新最短距离的记录，直到走过所有的点，就可以确信拿到了可靠的最短距离的记录。初始化的状态集合为：</p><table><thead><tr><th>A</th><th>B</th><th>C</th><th>D</th></tr></thead><tbody><tr><td>0</td><td>-</td><td>-</td><td>-</td></tr></tbody></table><p>此时位于 A 点，未出发的状态，到自身的距离为 0，到其余点的距离未知。</p><p>从 A 点出发后，发现 A 点可以到达 B 点和 C 点，距离分别为 4 和 2，那么就更新状态集合为：</p><table><thead><tr><th>A</th><th>B</th><th>C</th><th>D</th></tr></thead><tbody><tr><td>0</td><td>-</td><td>-</td><td>-</td></tr><tr><td></td><td>4</td><td>[2]</td><td>-</td></tr></tbody></table><p>中括号的含义是在当前这一轮中距离最短的点，哪个距离最短，下一步就到哪个点。到 C 点的距离比到 B 点的距离短，所以下一轮到 C 点：</p><img src="g2.png" width="50%" /><p>到 C 点以后，发现 C 点可以到达 A、B、D 三个点，这个时候意识到，其实 A 点已经走过了，不会再往回走的。于是需要另一个集合记录走到过哪些点，以避免下一步重复。定义 <code>prev = []</code>，因为 A 和 C 已经走过了，就把这两个点放到集合里， <code>prev = [A, C]</code>。</p><p>在这一步的时候，到达 B 点的距离从 4 变成了 3，<code>A -&gt; C -&gt; B</code> 的距离小于 <code>A -&gt; B</code> 的距离，更新状态集合，同时因为已经能够到 D 点了，更新到 D 点的距离：</p><table><thead><tr><th>A</th><th>B</th><th>C</th><th>D</th></tr></thead><tbody><tr><td>0</td><td>-</td><td>-</td><td>-</td></tr><tr><td></td><td>4</td><td>[2]</td><td>-</td></tr><tr><td></td><td>[3]</td><td></td><td>5</td></tr></tbody></table><p>这一轮中，到达 B 点的距离小于到达 D 点的距离，中括号选中 3，并且下一步到 B 点：</p><img src="g3.png" width="50%" /><p>此时 <code>prev = [A, C, B]</code>，状态集合更新为：</p><table><thead><tr><th>A</th><th>B</th><th>C</th><th>D</th></tr></thead><tbody><tr><td>0</td><td>-</td><td>-</td><td>-</td></tr><tr><td></td><td>4</td><td>[2]</td><td>-</td></tr><tr><td></td><td>[3]</td><td></td><td>5</td></tr><tr><td></td><td></td><td></td><td>[5]</td></tr></tbody></table><p>中括号只剩一个选择，只有 D 点没去过了：</p><img src="g4.png" width="50%" /><p><code>prev = [A, C, B, D]</code>，所有点遍历结束，最终结果为：</p><table><thead><tr><th>A</th><th>B</th><th>C</th><th>D</th></tr></thead><tbody><tr><td>0</td><td>3</td><td>2</td><td>5</td></tr></tbody></table><p>现在就可以知道从 A 点到 D 点的最短距离为 5.</p><h3 id="最短路径跟踪"><a href="#最短路径跟踪" class="headerlink" title="最短路径跟踪"></a>最短路径跟踪</h3><p>算法结束后，可以得到从 A 点到其他点的最短距离数据。可是如果不只想要距离值，还想要具体路径，比如从 A 点到 D 点的最短路径，该怎么处理？</p><h4 id="正向贪心算法"><a href="#正向贪心算法" class="headerlink" title="正向贪心算法"></a>正向贪心算法</h4><p>可以判断出，从 A 到 D 的最短路径是 <code>A -&gt; C -&gt; D</code>，而上面的 <code>prev</code> 集合为 <code>A, C, B, D</code>。因为从 C 直接到 D 比 <code>C -&gt; B -&gt; D</code> 的距离要短，所以在路径中抛弃了 B 点。</p><p>按照这样的现象进行对比，是不是只要在 <code>prev</code> 的基础上，在合适时候抛弃某些点，就可以得到正确路径了？比如上面从 B 到 D，存在 4 种情况：</p><ul><li>B 可以到达 D</li><li>B 不可以到达 D</li><li>通过 B 到达 D 是状态集合中到达 D 距离最短的方案</li><li>通过 B 到达 D 不是状态集合中到达 D 距离最短的方案</li></ul><p>这 4 中情况中，只有 <code>B 可以到达 D</code> 并且 <code>通过 B 到达 D 是状态集合中到达 D 距离最短的方案</code> 的时候，才会保留 B 这个点到路径中。否则就应该去掉 B 点。</p><p>中括号每选择到一个点，就把点放到路径中，如果不满足上面的条件，就从路径中去掉这个点，也就是不放到路径里面。这样的话，即使有其他捣乱的点存在，程序也可以应对，比如：</p><img src="g5.png" width="50%" /><p>在选中 B 点后，发现 B 点不满足条件，此时路径由 <code>path = [A, C, B]</code> 回退到了 <code>path = [A, C]</code>。如果下一轮最小的点选中了 E，<code>path = [A, C, E]</code>，但是 E 点不满足条件，<code>path = [A, C]</code>。直到最小的点选中目标点 D，整个程序结束。</p><p>或者这样的，也可以处理，E 点不会被放到路径中：</p><img src="g6.png" width="50%" /><p>那么这样的思路存在问题吗？当然有问题，这样的程序是不能处理这种情况的：</p><img src="g7.png" width="50%" /><p>假如最短路径是 <code>[A, E, C, D]</code>，E 点是不满足上面被放进路径的条件的，E 点无法直接到达 D 点，但是又必须被包含在路径里。去掉 <code>可以直接到达 D 点</code> 的限制？那上上图的 E 点也会被放到路径里。</p><p>也就是说，需不需要能够直接到达目标点，取决于对于最终的路径，被选中的点是不是倒数第二个点。这样的条件在一个未知的图中是无法判断的，谁能知道一个点是最终路径的倒数第几个点？</p><p>正向的贪心算法试图每一次都把距离最小并且在最终路径上的点记录下来，但其实很难做到，因为根本无法判断一个点是不是在最终的路径上。</p><h4 id="反向贪心算法"><a href="#反向贪心算法" class="headerlink" title="反向贪心算法"></a>反向贪心算法</h4><p>当 D 点被中括号选中，作为本轮距离最小的点，就已经能够确定从 A 点到 D 点最短距离了。那么只要知道这一步是从哪个点过来的，来源的点就一定是最短路径的倒数第二个点。依次类推，只要层层回推到出发的点，整条路径就出来了。</p><img src="g4.png" width="50%" /><p>假如在到达 D 点后，能够知道是从 C 点而不是 B 点过来，在 C 点的时候，能够知道是从 A 点而不是 B 点过来，整个路径就很清晰了。</p><p>问题是怎么在 D 点的时候，知道是从 C 点而不是 B 点过来的？选中最小距离点的顺序可是 <code>[A, C, B, D]</code>，按照最小点的顺序显然是不行的。</p><p>这看起来不是一件难事，在 DFS 或者树的遍历中，经常会前后进入多个路径然后在适当的时候返回以修正路径。换个角度看，其实在 DFS 中维护最短距离，也可以达到目的。<code>维护了距离状态的 DFS</code> &#x3D;&#x3D; <code>Dijkstra algorithm</code> 吗？显然不是。</p><p><strong>递归 vs 尾递归</strong></p><p>Dijkstra 适合写成循环的形式：</p><pre><code class="go">for &#123;&#125;</code></pre><p>更适合写成尾递归的形式：</p><pre><code class="go">func recursion() &#123;        recursion()&#125;</code></pre><p>总之，程序会是单向的循环。适合写成递归的形式吗？</p><pre><code class="go">func recursion() &#123;    for &#123;        recursion()    &#125;&#125;</code></pre><p>当遇到分支情况的时候，用 for 循环 “同时” 进入多个路径，寻找最合适的那个。比如到 C 点的时候，for 循环前后进入 <code>C -&gt; B -&gt; D</code> 和 <code>C -&gt; D</code> 的路径，每次循环将只保留一条路径，找到最合适的直接终止递归就可以。</p><p>这样的写法存在问题吗？问题在于，怎么确定在哪个节点进行分叉。在 C 点分叉？为什么是 C 点？为什么不是 B 点？如果是 B 点，路径上就会多出 B 点。为什么不是 A 点？如果是 A 点，到了 C 点的时候需不需要继续分叉？是每一个点都需要分叉吗？想象一下那会造成多么大的冗余……为什么树可以同时遍历？因为树的节点不会交叉。</p><h4 id="第二个动态规划"><a href="#第二个动态规划" class="headerlink" title="第二个动态规划"></a>第二个动态规划</h4><p>第一个动态规划是指算法本身距离数据的维护。第二个动态规划可以维护一个路径数据的状态：</p><pre><code class="js">pathList = &#123;    A: [],    B: [],    C: [],    D: []&#125;</code></pre><p>路径状态保存从源点到达每个节点在当前阶段的最短路径，在一开始的时候，因为 A 点已经可以到达 B 和 C：</p><img src="g1.png" width="50%" /><pre><code class="js">pathList = &#123;    A: [A],    B: [A, B],    C: [A, C],    D: []&#125;</code></pre><p>选择并到达 C 点，这个时候因为 C 点可以到达 B 点并且 <code>A -&gt; C -&gt; B</code> 的距离小于 <code>A -&gt; B</code>，所以更新路径状态数据为 <code>pathList[C].push(B)</code>。D 点也可以到达了，更新路径状态。（更新路径状态数据发生在进入下一个点之前，甚至发生在选择下一个节点之前。可以想一想为什么这样做。）</p><img src="g2.png" width="50%" /><pre><code class="js">pathList = &#123;    A: [A],    B: [A, C, B],    C: [A, C],    D: [A, C, D]&#125;</code></pre><p>这一轮在距离的状态数据上，会把 B 点选中为最小距离的节点，判断到达 D 的路径 <code>A -&gt; C -&gt; B -&gt; D</code> 大于目前已有的距离记录 <code>A -&gt; C -&gt; D</code>，所以不更新路径状态。（判断距离是否大于已有距离是根据距离的状态数据，也就是表格的数据。）</p><img src="g3.png" width="50%" /><p>最终进入目标 D 结束，路径状态不更新。</p><img src="g4.png" width="50%" /><p>得到路径 <code>A -&gt; C -&gt; D</code>。</p><p>路径的状态数据可以为了节省空间，只维护到达目标点的路径吗？不可以，因为更新下一个点的路径需要依赖当前点的路径，路径的状态必须是全量的。</p><h3 id="非最短路径跟踪"><a href="#非最短路径跟踪" class="headerlink" title="非最短路径跟踪"></a>非最短路径跟踪</h3><p>Dijkstra 算法包含了贪心算法的思维，每一步选出的都是距离最短的点。如果需要保存不是最短路径的路径，Dijkstra 算法也许可以做到，但是就已经不需要 Dijkstra 算法了。DFS&#x2F;BFS 更合适一点。</p><p><br><br></p><h3 id="补充（2025-05-11）"><a href="#补充（2025-05-11）" class="headerlink" title="补充（2025.05.11）"></a>补充（2025.05.11）</h3><p>这个 Dijkstra 相关的工作，是当时在一个 State Channels 的项目 <a href="https://github.com/saveio-backup/pylons">pylons</a> 上，用来在多个通道之间寻找最短路径用的，原本是 <a href="https://github.com/saveio-backup/pylons/blob/master/route/dfs.go">DFS</a>，后来我加了一个 <a href="https://github.com/saveio-backup/pylons/blob/master/route/dijkstra.go">Dijkstra</a>，带有黑名单的功能，以及把手续费作为路径距离的计算依据。</p><p>现在把 route 部分的代码单独拆分出一个仓库 <a href="https://github.com/smallyunet/dijkstra-demo/">smallyunet&#x2F;dijkstra-demo</a> 留作纪念。</p>]]></content>
  </entry>
  <entry>
    <title>Youtube Premium 到期了，Youtube Music 也用不了，只能换回网易云音乐，发现网易云音乐的推荐其...</title>
    <link href="https://t.smallyu.net/#2021-70"/>
    <id>micro:921921846</id>
    <published>2021-09-17T16:19:44Z</published>
    <updated>2021-09-17T16:19:44Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Youtube Premium 到期了，Youtube Music 也用不了，只能换回网易云音乐，发现网易云音乐的推荐其实很强… “没有银弹” 的思想其实远不止适用于软件工程…</p>]]></summary>
    <content type="html"><![CDATA[<p>Youtube Premium 到期了，Youtube Music 也用不了，只能换回网易云音乐，发现网易云音乐的推荐其实很强…</p>
<p>“没有银弹” 的思想其实远不止适用于软件工程…</p>
]]></content>
  </entry>
  <entry>
    <title>《 碎银几两 》</title>
    <link href="https://t.smallyu.net/#2021-69"/>
    <id>micro:917566375</id>
    <published>2021-09-12T06:24:17Z</published>
    <updated>2021-09-12T06:24:17Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>《 碎银几两 》</p>]]></summary>
    <content type="html"><![CDATA[<p>《<a href="https://music.youtube.com/watch?v=QY9WQ14UfOY&feature=share">碎银几两</a>》</p>
]]></content>
  </entry>
  <entry>
    <title>比特币是庞氏骗局吗？如果没有挖矿这回事，就是，如果是中心化的系统，就是。事情更复杂一点……</title>
    <link href="https://t.smallyu.net/#2021-68"/>
    <id>micro:916551140</id>
    <published>2021-09-10T01:02:02Z</published>
    <updated>2021-09-10T01:02:02Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>比特币是庞氏骗局吗？如果没有挖矿这回事，就是，如果是中心化的系统，就是。事情更复杂一点……</p>]]></summary>
    <content type="html"><![CDATA[<p>比特币是庞氏骗局吗？如果没有挖矿这回事，就是，如果是中心化的系统，就是。事情更复杂一点……</p>
]]></content>
  </entry>
  <entry>
    <title>简单对比一下，Hyperledger Fabeic 2.0 的 新特性 ： 智能合约的多方治理 数据库性能增强 隐私数据...</title>
    <link href="https://t.smallyu.net/#2021-67"/>
    <id>micro:915734450</id>
    <published>2021-09-09T03:33:16Z</published>
    <updated>2021-09-09T03:33:16Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>简单对比一下，Hyperledger Fabeic 2.0 的 新特性 ： 智能合约的多方治理 数据库性能增强 隐私数据增强 更简单的测试网络 长安链 2.0 的 新特性 ： 代码重构 代码重构 go dep 迁移 go mod</p>]]></summary>
    <content type="html"><![CDATA[<p>简单对比一下，Hyperledger Fabeic 2.0 的 <a href="https://hyperledger-fabric.readthedocs.io/en/release-2.0/whatsnew.html">新特性</a>：</p>
<ul>
<li>智能合约的多方治理</li>
<li>数据库性能增强</li>
<li>隐私数据增强</li>
<li>更简单的测试网络</li>
</ul>
<p>长安链 2.0 的 <a href="https://docs.chainmaker.org.cn/intro/%E7%89%88%E6%9C%AC%E8%BF%AD%E4%BB%A3.html">新特性</a>：</p>
<ul>
<li>代码重构</li>
<li>代码重构</li>
<li>go dep 迁移 go mod</li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>长安链 2.0 版本解读直播，看了半小时。是个啥……</title>
    <link href="https://t.smallyu.net/#2021-66"/>
    <id>micro:915161401</id>
    <published>2021-09-08T11:42:03Z</published>
    <updated>2021-09-09T03:13:39Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>长安链 2.0 版本解读直播，看了半小时。是个啥……</p>]]></summary>
    <content type="html"><![CDATA[<p>长安链 2.0 版本解读直播，看了半小时。是个啥……</p>
]]></content>
  </entry>
  <entry>
    <title>为什么很多人，包括像阮一峰那样见识和地位的人，都只关心 “如何改变自己以获得别人认可” 的问题？为什么没有产生 “上升”...</title>
    <link href="https://t.smallyu.net/#2021-65"/>
    <id>micro:912250566</id>
    <published>2021-09-03T04:42:44Z</published>
    <updated>2021-09-03T04:49:00Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>为什么很多人，包括像阮一峰那样见识和地位的人，都只关心 “如何改变自己以获得别人认可” 的问题？为什么没有产生 “上升” 的想法？为什么不对 “上层” 发出质疑？为什么别人有左右你的权力？为什么在那个位置的不能是你？是什么造成了这种差异？</p>]]></summary>
    <content type="html"><![CDATA[<p>为什么很多人，包括像阮一峰那样见识和地位的人，都只关心 “如何改变自己以获得别人认可” 的问题？为什么没有产生 “上升” 的想法？为什么不对 “上层” 发出质疑？为什么别人有左右你的权力？为什么在那个位置的不能是你？是什么造成了这种差异？</p>
]]></content>
  </entry>
  <entry>
    <title>《 科技爱好者周刊（第 174 期）：全能程序员 vs 特长程序员 》，当别人在讨论全能好还是特长好的时候，我不禁想起的...</title>
    <link href="https://t.smallyu.net/#2021-64"/>
    <id>micro:912188536</id>
    <published>2021-09-03T01:47:16Z</published>
    <updated>2021-09-03T01:47:16Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>《 科技爱好者周刊（第 174 期）：全能程序员 vs 特长程序员 》，当别人在讨论全能好还是特长好的时候，我不禁想起的问题是，到底是什么人在雇佣和指挥全能或者特长的人？</p>]]></summary>
    <content type="html"><![CDATA[<p>《<a href="https://www.ruanyifeng.com/blog/2021/09/weekly-issue-174.html">科技爱好者周刊（第 174 期）：全能程序员 vs 特长程序员</a>》，当别人在讨论全能好还是特长好的时候，我不禁想起的问题是，到底是什么人在雇佣和指挥全能或者特长的人？</p>
]]></content>
  </entry>
  <entry>
    <title>2018年中国网络借贷平台集体倒闭事件 ，P2P 爆雷事件，指的是 Peer-to-Peer Lending ，重点是借...</title>
    <link href="https://t.smallyu.net/#2021-63"/>
    <id>micro:911199796</id>
    <published>2021-09-02T05:25:36Z</published>
    <updated>2021-09-02T05:25:36Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>2018年中国网络借贷平台集体倒闭事件 ，P2P 爆雷事件，指的是 Peer-to-Peer Lending ，重点是借贷，和 P2P 没有关系，和 Peer-to-Peer Network 更没有关系。 很多人会说 P2P 出事了、做 P2P 的企业倒闭、追回员工工资。为什么是 P2P？明明主语是借贷，P2P 是定语...</p>]]></summary>
    <content type="html"><![CDATA[<p><a href="https://zh.wikipedia.org/wiki/2018%E5%B9%B4%E4%B8%AD%E5%9C%8B%E7%B6%B2%E7%B5%A1%E5%80%9F%E8%B2%B8%E5%B9%B3%E5%8F%B0%E9%9B%86%E9%AB%94%E5%80%92%E9%96%89%E4%BA%8B%E4%BB%B6">2018年中国网络借贷平台集体倒闭事件</a>，P2P 爆雷事件，指的是 Peer-to-Peer Lending ，重点是借贷，和 P2P 没有关系，和 Peer-to-Peer Network 更没有关系。</p>
<p>很多人会说 P2P 出事了、做 P2P 的企业倒闭、追回员工工资。为什么是 P2P？明明主语是借贷，P2P 是定语。</p>
]]></content>
  </entry>
  <entry>
    <title>之前公司存在的问题</title>
    <link href="https://b.smallyu.net/2021/08/31/%E4%B9%8B%E5%89%8D%E5%85%AC%E5%8F%B8%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98/"/>
    <id>blog-b:https://b.smallyu.net/2021/08/31/%E4%B9%8B%E5%89%8D%E5%85%AC%E5%8F%B8%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98/</id>
    <published>2021-08-31T10:58:39.000Z</published>
    <updated>2025-12-03T10:02:00.860Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>我之前任职的公司是传统类型的电信服务类企业，话费支付起家。区块链部门是创新业务部门，内部孵化项目和产品，属于成本部门，公司给钱，但也有一些收入预算。部门收入的来源主要是：</p>
<ul>
<li>政府补贴</li>
<li>招投标项目</li>
<li>熟人介绍项目</l]]></summary>
    <content type="html"><![CDATA[<p>我之前任职的公司是传统类型的电信服务类企业，话费支付起家。区块链部门是创新业务部门，内部孵化项目和产品，属于成本部门，公司给钱，但也有一些收入预算。部门收入的来源主要是：</p><ul><li>政府补贴</li><li>招投标项目</li><li>熟人介绍项目</li></ul><p>都是交付形式的项目，招投标项目是按照指定要求开发软件然后全权交付出去，熟人介绍项目是把内部开发的区块链产品交付出去，都要提供开发联调和售后支持。如果没有项目中标、没有熟人介绍，就没有收入了，存在一定收入压力。</p><p>这种营利方式属于相对好理解的模式。很早以前我还没有了解部门收入来源的时候，就无意间和同事说，“现在已经不是靠卖软件挣钱的时代了”，暗指部门领导的挣钱思路有问题。同事问，那靠什么？我随口说，“卖服务啊”。我当时并没有关注相关问题，只是闲聊而已。</p><p>想到这个话题是因为，今天问到 HR 公司盈利模式的问题，“我们又不是像卖煎饼一样，卖一个挣一个的钱。为什么互联网公司的工资高？靠的不是直接营利的收入，是投资人砸钱，花投资人的钱。互联网公司的钱都不是真实的钱，很多互联网公司，为什么财报亏损但还是很多投资人愿意投资？他们都是先占有市场和用户，然后上市，最后由股民掏钱了。我们也是有 IPO 的计划……”</p><p>当然，对这些内容的真实性和准确性存疑。但能肯定的，和之前公司的销售模式完全不同。</p><p>HR 和我提到说，有什么问题可以随时问，我们的企业文化就是 “坦诚沟通”。我说，可能直接问只会得到一些「道貌岸然」的回答，有些事需要不断「试探」才能知道真相。我想到，我这样的行为方式，可能和之前的经历有关。</p><p>如果你提出一个现实的具体的问题，一个人在回答的时候说了很多，扯得很远，某银行的金融方式什么，某大学的教授说了什么话，某体制内机构的高官是什么样的经历，公司某高层怎么要求，公司某员工有什么样的行为，名人名言、历史典故，等等。说了一圈，你发现他并没有正面回答你的问题，好像回答了，又好像没有。偶尔一两次你会觉得，这个人水平很高，接触的都是一些高级的人，说出来的都是大道理方法论。</p><p>时间长了以后，你发现，每一次具体的实际的问题，他都会用方法论来回答，顾左而言他，就是不正面回答你。甚至很多次说出来的都是相同的事例不同角度的道理，从具体问题总结出方法论是一种高级的技能，但如果一味讲究方法论，也会是一种灾难。所有问题一说出来啥都懂啥都明白，怎么回事别人是怎么做的我们应该怎么做，但就是解决不了现实的问题。后来你也许会觉得，可能他不是不想回答，是他也不知道问题的答案。有人说，其实他也很迷茫。</p><p>在具体的工作内容上，他唯一的要求就是 “客户认可”，也就是能赚钱的、最好有直接收益的。你可以把产品相关的技术方向全部列出来，但是发现在所有的技术方向上，没有一个是所谓 “客户认可” 的，甚至全国有吗？是什么？客户怎么会因为你使用了某一种技术而买账呢。你明知道项目存在各种各样的问题，知道该怎么改善那些问题，但是在 “客户认可” 的判断依据下，这些问题没有一个是需要解决的，没有一个产品的技术方向是可以深入的。</p><p>“客户认可” 绝对是再正确不过的判断标准，公司做什么事情一定是为了营利，付出的成本要体现在收入上无可厚非。但是，但就是感觉这玩意儿很难啊。公司本身是那样的营利模式，但是在那种营利模式下，国内挣钱的都没有几家。</p><p>尤其是看到国内某开源项目如火如荼势如破竹，部门的产品寻找突破口更加困难。在近几年都没有显著创新的情况下，没有技术储备、没有发展路线、没有商业资源，甚至工程质量都一言难尽，当你说产品的竞争力不足，又会听到说 “其实我们公司不是专门做这个的”，公司的高层几度放弃部门和产品，这些都预示着部门在走向灭亡。</p>]]></content>
  </entry>
  <entry>
    <title>Black Mirror 有一集 White Bear，应该像是不知情的密室逃脱。</title>
    <link href="https://t.smallyu.net/#2021-62"/>
    <id>micro:907768898</id>
    <published>2021-08-29T10:40:16Z</published>
    <updated>2021-08-29T10:40:16Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Black Mirror 有一集 White Bear，应该像是不知情的密室逃脱。</p>]]></summary>
    <content type="html"><![CDATA[<p>Black Mirror 有一集 White Bear，应该像是不知情的密室逃脱。</p>
]]></content>
  </entry>
  <entry>
    <title>今天早上上班爬楼梯，公司楼下装修，一个工人正好站在楼道口，眼睛直直看着我手里拿的统一阿萨姆奶茶。 想起来很多事情。</title>
    <link href="https://t.smallyu.net/#2021-61"/>
    <id>micro:905740559</id>
    <published>2021-08-25T17:39:32Z</published>
    <updated>2021-08-25T17:39:32Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>今天早上上班爬楼梯，公司楼下装修，一个工人正好站在楼道口，眼睛直直看着我手里拿的统一阿萨姆奶茶。 想起来很多事情。</p>]]></summary>
    <content type="html"><![CDATA[<p>今天早上上班爬楼梯，公司楼下装修，一个工人正好站在楼道口，眼睛直直看着我手里拿的统一阿萨姆奶茶。</p>
<p>想起来很多事情。</p>
]]></content>
  </entry>
  <entry>
    <title>最近</title>
    <link href="https://crazy.smallyu.net/2021/08/22/%E6%9C%80%E8%BF%91/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/08/22/%E6%9C%80%E8%BF%91/</id>
    <published>2021-08-22T10:54:00.000Z</published>
    <updated>2025-08-16T03:27:11.436Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<h3 id="理想"><a href="#理想" class="headerlink" title="理想"></a>理想</h3><p>一开始设想了一些标题《来，我们谈一谈梦想》、《我们谈一谈理想》、《理想修正案》做大标题，现在连小标题都不敢轻易用了。</p>
<p>会想到]]></summary>
    <content type="html"><![CDATA[<h3 id="理想"><a href="#理想" class="headerlink" title="理想"></a>理想</h3><p>一开始设想了一些标题《来，我们谈一谈梦想》、《我们谈一谈理想》、《理想修正案》做大标题，现在连小标题都不敢轻易用了。</p><p>会想到 “梦想” 这个话题，是因为我已经不敢用 “梦想” 这样的词汇。不记得两年前为什么会频繁用 “梦想” 这个词，也不敢回头看当时写了些什么。不同时间说话的遣词造句都会不一样，比如上一篇的内容前后历时一两个月，会不断修改之前的用语和内容，到后面就变了很多样子。现在也许会说 “理想”，不会说“梦想”，可能我已经不再做梦，不知道从什么时候开始。这是一种进步，也是一种退步。</p><p>前段时间换了工作，入职第一天和 HR 一起吃饭，谈到他们之前招人的时候，都会问有没有看过某项目源码之类，还问我有没有看过，我说没有。我当时说，我不是很担心（自己）。在后来接触到项目之后，我可以确信确实不用担心，我自认为是没有问题的，我需要考虑更多的是让别人相信我没有问题。怎么让别人相信自己呢，比如用幻灯片做技术分享。具体的内容分三个层次：</p><ol><li>写自己看到了项目的哪些东西，让别人知道一下，自己了解到那些了</li><li>了解对比同类项目，分析功能和实现上的差异</li><li>了解需要解决的问题是什么，目前有哪些做法，项目是怎么做的，其他项目是怎么做的，有没有更好的解决方法</li></ol><p>这三个层次是递进的，需要的时间也是递进的。你分享的内容在那个层次，也许会让别人把你定位到哪个层次上，可是越往后面越需要时间，技术分享其实没有一个 “准备好了” 的时间点，总有更大更难的问题摆在那里，摆在你面前，摆在人类的面前。技术分享是为数不多可选的形式，但不一定是最好的主意。</p><p>就在思考这些个问题的时候，我意识到一个危险的信号。我竟然在担心自己能不能够胜任工作，能不能够通过试用期，能不能够得到别人的认可。以前从未担心这些问题（光顾着 judge 别人了？&#x2F;捂脸）。这些问题可以关心，但不应该担心才对。</p><p>也是前几天花了一些钱，突然就感觉没钱了，钱真是好东西。喜欢和追求钱没什么不对的，钱是货币符号，是等价交换物，你花费时间和生命换取金钱，消耗劳动力获得生产资料换取金钱，金钱是大多数社会资源的代表，这没什么不好。</p><p>我需要反思的是，为什么我在找工作的时候，包括前几个月和去年，都不止一次对不止一个人说，我不在乎钱（工资）。当时确实是那么想的，我简历上的期望薪资就是当时的工资，甚至比当时的工资还要低一点。现在分析原因的话，一方面，在衣食住行得到基本满足的情况下，暂时没有花钱的地方，没有太多欲望。另一方面，我当时是相信自己技术实力的，我相信只要实力到位，工资该涨就会涨，我一开始就只希望得到和自己能力相称的报酬。</p><p>我似乎忘了自己一开始的目的，忘了为什么来北京，为什么换工作，如果我只是在担心自己能不能保住市场平均水平薪资的工作，只是在追求稳定安逸的资金来源，那不是我该有的眼界和胸怀，我自己首先会看不起我自己。</p><p>在 Hacker News 的推荐列表上出现过一篇文章 *<a href="http://www.paulgraham.com/todo.html">The Top of My Todo List</a>*，作者是 Hacker News 创始人之一，在他的 TODO list 里，第一条就是 “Don’t ignore your dream”，现在我也需要这样提醒自己。文章中还提到另一篇文章 *<a href="https://bronnieware.com/regrets-of-the-dying/">The Top Five Regrets of the Dying</a>*，两篇文章同时出现了意思相近的话，一个是 “不要工作太多”，另一个是 “不要工作太努力”，我没有明白其中的含义。</p><h3 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h3><p>前段时间的面试也反映出很多问题，我目前没有什么能够证明自己的经历，以至于我都开始怀疑自己。用阿里的话说，就是你做了哪些有难度的事情，为什么难，你是怎么做的，有没有更好的做法，等等。如果我遇到那样的问题，我会无话可说，因为我遇到最大的难题，就是没有遇到困难。也因此我需要寻找更好的出路，如果有什么能拿得出手的经历，我也不会想走。</p><p>能拿得出手的经历实质是在为工程能力做背书，我之前不是很在乎和看重工程能力，毕竟有手就行，但工程能力实际上又是我赖以生存的重要手段，我不得不关心和提高它，因为公司可以相对简单直观地判断你的工程能力，很多公司更愿意为你的工程能力买账。码农嘛。（问：有偏离 “梦想” 的原意吗？）</p><p>前几天看到一个新闻，一开始是在 YouTube 的推荐里看到了这样的标题《<a href="https://www.youtube.com/watch?v=yLmcxQfHtiM">世界上最安全的加密货币，被黑客窃取6亿美元</a>》，没有点进去看，心想应该是人类行为，被诈骗什么的，标题唬人只是噱头。后来在不同的渠道都看到了类似的新闻，比如（现找的）《<a href="https://new.qq.com/omn/20210813/20210813A09TMN00.html">被盗6.1亿美金，抽丝剥茧还原黑客攻击Poly Network 与O3 Swap现场</a>》，或者 *<a href="https://www.zdnet.com/article/poly-network-hackers-potentially-stole-610-million-is-bitcoin-still-safe/">Poly Network hackers potentially stole $610 million: Is Bitcoin still safe?</a>*，据说是去中心化金融历史上最严重的安全事件。</p><p>看到消息后各种不明白，Poly Network 那么有钱？也许只是一种营销行为？但是很多媒体都在说这事了？更多疑问和细节就不追究了。重要的是我忽然明白，我需要了解和掌握的绝不只是手上工作中接触到的项目，我需要了解的，是整个 DeFi (Decentralized Finance) 和 NFT (Non-fungible Token) 的生态和市场环境，那个圈子各种复杂……而且区块链的变化和演进相对互联网要快很多，在这样的时代的洪流中……</p><p>公有链才是真正的区块链，联盟链只是套了区块链的形式炒概念，是具有中国特色的区块链，是在用新的技术解决旧的问题。不过我也还没搞明白公有链的现状，暂时没有什么结论。很多时候一些公链项目都在强调全球生态，为什么是全球生态呢，因为国内没有生态。</p><p>反思之前，我为什么会有信心认为自己对联盟链有一定了解了？真的有足够了解到已经看不到未来的程度了吗？应该是有三个方面的原因：</p><ul><li>之前接触的项目，虽然在技术上算不上顶尖，至少在国内能排个名吧</li><li>我当时对比了网上和能听说到的各种联盟链，在技术上真就那么回事</li><li>当时认真了解了国内厂商广泛参与的某标准测试的规则，通过不算难</li></ul><p>如果局限在那个圈子里面，只会安于现状固步自封自欺欺人。</p><h3 id="哲学"><a href="#哲学" class="headerlink" title="哲学"></a>哲学</h3><p>在曾经的某个时候，我对一个人说，“我应该成为一个哲学家”。当然，没有收到任何回复。</p><p>为什么是哲学家？因为哲学家在思考的问题，人人都在思考，时刻都有人思考，没有人知道答案。为什么是苏格拉底？因为从传说来看，苏格拉底是一个粗俗的人，仅仅凭借一种执着的精神。为什么要了解耶稣？因为苏格拉底或者哲学家，一定程度上有宗教的意味，有一帮信徒，在传递某种思想。</p><p>不过，如果你去了解哲学史，会看到各种流派，各种历史人物，对几乎所有的问题，提出了几乎所有可能的观点。哲学的问题，是已经被定义好的问题。哲学的思想，是已经被穷举的思想。退一步说，哲学到底是什么？有人知道吗？哲学是什么本身不就是一个哲学问题吗？或许我们每个人都应该建立一个小目标：重新定义哲学。</p><p>有很多我们从小就熟知的哲学家，很容易被忽略。我们眼里的苏格拉底、柏拉图、亚里士多德、伊壁鸠鲁，可能就相当于西方人眼中的孔子、老子、墨子、荀子，甚至包括王阳明之类。美国在计算机技术上领先世界，可是由于历史短暂，并没有太过知名的哲学家，像德国还有叔本华、尼采之类大名鼎鼎的人物。在这个问题上，我一度充满疑惑。在技术领域上，前沿资料一定是看美国的。但其他领域，可靠的信息源是什么、在哪里？</p><h3 id="“新生代农民工”"><a href="#“新生代农民工”" class="headerlink" title="“新生代农民工”"></a>“新生代农民工”</h3><p>前几天，人社部（中华人民共和国人力资源和社会保障部）发布对新生代农民工的 <a href="http://www.mohrss.gov.cn/SYrlzyhshbzb/jiuye/gzdt/202108/t20210816_420736.html">监测报告</a>，这好像是第一次明确使用 “新生代农民工” 的称呼。这是一个正常的统计报告，发布报告的部门是 “农民工工作司”，他们就是这样的工作，即使有问题也可能是很多人觉得，把之前一些模糊不清的群体，现在明确划分到了这个部门做统计？问题他们做统计的依据是户口类型，他们一定没错。</p><p>看到报告，我第一时间想到，早在很多年前的某人语录，就吐槽国中国的户籍制度。他说的是另一个方面的问题，说我出生在中国，作为中国公民，从中国的一片土地到中国的另一片土地上，居然 TMD 只能暂住？不办证还驱逐？好在这样的现象已经改正了。</p><p>有人分析说，现在这个时候国家发布这样的信息，意思是让新生代农民工们认清楚自己的定位，安心回老家生孩子过小日子，别想那些乱七八糟的东西，只盯着光鲜亮丽看。现在不想生孩子的群体特性，一是高学历，二是在一线城市工作。学历越高、越是在一线城市工作，就越会接触到贫富悬殊的状况。他们不想生孩子，一是贫富差距大，二是阶级固化。在一线城市没有竞争力，就不敢生孩子。不敢生孩子，国家劳动力就不够。人口不增长，光是人口数据都不好编了。今年发布的一系列政策，互联网大厂减少加班、不允许孩子补课，都是在减少压力鼓励生育。</p><p>央视曾经有过论调，“认命可以，躺平不行”。有人说，自己读了研究生读了博士，结果读成了农民工。还有人说，天天自嘲码农，现在被官方叫一声怎么就破防了？我觉得，这个报告，最可怕的不是给人区分类型贴上了一个 “农民工” 的标签，而是默认了出生决定论。你是农民，本该务农，现在不从事农业工作进城打工了，我们得好好关注一下你，看看你什么情况。</p><p>不过这样真能提高生育率吗？如果你知道你的孩子生下来就是农民工，孩子就要说了，“生而为农民工，我很抱歉”。但是为什么要抱歉呢？如果有人刻意强调什么是重要的，那说明主流意识形态已经是和强调的观点相悖了，才需要强调。</p><h3 id="听说"><a href="#听说" class="headerlink" title="听说"></a>听说</h3><p>有一首歌《<a href="https://www.youtube.com/watch?v=clYdjZKrsbU">听说</a>》，演唱者是华子。大学的时候听到觉得感人，在宿舍里单曲循环。室友听到说，这么难听的歌你老听它干啥。听过几次之后，我也觉得难听了，曲实在是很差劲。</p><p>最近经过一些事情，无意间想起这首歌。这首歌确实难听，因为曲根本不重要，华子不是一个合格的歌手。他是诗人。越是对生活有体会，越是能够理解《听说》的含义。我甚至尝试模仿听说的文体写点什么，当然只是即兴的，没有任何推敲，先想起来写，后想起来这首歌。</p><p>不过，《听说》在思路上存在一个很大的问题。它只是把一些现象说了出来，这种现象还是结果形式的现象，没有说引发现象的原因是什么，人们面对的问题是什么，解决方案是什么。相比之下，白居易的《卖炭翁》就有很明显的指向。</p><p>也可能是言论尺度的问题？可以出现在古诗里的内容，不能出现在当代诗歌里？（还真有可能</p><h3 id="塔利班"><a href="#塔利班" class="headerlink" title="塔利班"></a>塔利班</h3><p>前几天有个刷屏的新闻，塔利班夺取阿富汗政权。有人大胆地开玩笑说，塔利班就是曾经的我们。还有个海外华人的自媒体说，他早在 8 月 1 日就发布预言，塔利班已经取得中国和美国的支持，将会夺取政权，然后 8 月 16 日，塔利班真的行动了，之类。</p><p>具体情况也不是一时半会儿能搞明白，我们需要明白的是，历史时刻在发生。经常有人说，在面对历史的大变革大是大非的时候，能清楚时事的往往不是哲学家，而是历史学家。历史不可能倒退，但历史总在不断重演。</p><p>在关注到一些海外平台的政治不正确的言论后，我唯一了解到的信息，就是真的有坏人，他们可能训练有素、身居要位、执掌权政，不是因为他们想坏，而是因为他们都是人。</p><p>同一个国家在不同的历史时期，即使同一个决策者都会做出不同的决定，即使是同一个执政党，内部关系也错综复杂，一些幼稚的言论经常会把问题简单化，比如阿里女员工在食堂拉横幅，很多人直接归责于阿里的制度，把阿里作为一个统一的整体看待，包括很多人把百度作为统一的整体，百度干了什么什么坏事之类。“新生代农民工” 也是同样，它只是某部门某些人发布的言论，沧海一粟而已。</p><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>好难呀。不知道为什么，这次写这些东西感觉磕磕绊绊，经常语句不通用词不当。以前写东西都是带着情绪有感而发一气呵成，现在真的不一样了，不知道发生了什么。</p><p>以前写什么还会通读几遍修修改改，我不想改了，我累了。我要出去遛弯了。</p>]]></content>
  </entry>
  <entry>
    <title>长辈说，你得有份工作。你不得不读书； 雇主说，你应该学会编程。你开始选专业，学 Java； 面试官说，你应该掌握算法。你...</title>
    <link href="https://t.smallyu.net/#2021-60"/>
    <id>micro:899079819</id>
    <published>2021-08-15T16:44:35Z</published>
    <updated>2021-08-16T00:41:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>长辈说，你得有份工作。你不得不读书； 雇主说，你应该学会编程。你开始选专业，学 Java； 面试官说，你应该掌握算法。你开始刷 Leetcode，关注awesome-algorithms； 面试官说，你应该深入原理。你开始留意 CSDN、掘金、牛客网； HR说，你应该工作稳定，积极向上。你开始关心履历，不要弄花； 中介...</p>]]></summary>
    <content type="html"><![CDATA[<p>长辈说，你得有份工作。你不得不读书；</p>
<p>雇主说，你应该学会编程。你开始选专业，学 Java；</p>
<p>面试官说，你应该掌握算法。你开始刷 Leetcode，关注awesome-algorithms；</p>
<p>面试官说，你应该深入原理。你开始留意 CSDN、掘金、牛客网；</p>
<p>HR说，你应该工作稳定，积极向上。你开始关心履历，不要弄花；</p>
<p>中介说，房子很贵。你知道，他没有错；</p>
<p>身体说，一日三餐，最少两餐。你就得吃饭。</p>
<p>生活说，我很难。你能感受到它不容易；</p>
<p>生命问，难道我不该有意义？你气喘吁吁，手忙脚乱，说，我不关心。</p>
]]></content>
  </entry>
  <entry>
    <title>看到一篇 文章 说，不要 overthinking，你总得相信点什么。挺符合我最近的疑惑的。 文章里提到了另一篇值得注意...</title>
    <link href="https://t.smallyu.net/#2021-59"/>
    <id>micro:898216125</id>
    <published>2021-08-13T06:10:38Z</published>
    <updated>2021-08-13T07:26:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>看到一篇 文章 说，不要 overthinking，你总得相信点什么。挺符合我最近的疑惑的。 文章里提到了另一篇值得注意的文章 The Tao of Go （Go 语言之道），倒不是里面的内容有多好，一开始还以为作者是 Go 语言的开发者，惊讶了一下，后来发现不是。文章内容都是在称赞 Go 语言，因为作者本身依靠 Go...</p>]]></summary>
    <content type="html"><![CDATA[<p>看到一篇 <a href="https://kerkour.com/blog/overthinking/">文章</a> 说，不要 overthinking，你总得相信点什么。挺符合我最近的疑惑的。</p>
<p>文章里提到了另一篇值得注意的文章 <a href="https://bitfieldconsulting.com/golang/tao-of-go">The Tao of Go</a>（Go 语言之道），倒不是里面的内容有多好，一开始还以为作者是 Go 语言的开发者，惊讶了一下，后来发现不是。文章内容都是在称赞 Go 语言，因为作者本身依靠 Go 语言受益，他一定是是要说 Go 语言好处的。</p>
<p>值得注意是因为，文章用了老子的哲学思想做小标题。在哲学领域上，中国由于历史悠久，还是占了一部分比重的。</p>
]]></content>
  </entry>
  <entry>
    <title>伟人为什么是伟人？或者具体一点，哲学家为什么是哲学家？ 一种可能是，他们拥有非常高贵的信息源，可以从中得到非常鲜为人知的...</title>
    <link href="https://t.smallyu.net/#2021-58"/>
    <id>micro:897689794</id>
    <published>2021-08-12T14:31:25Z</published>
    <updated>2021-08-12T14:31:25Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>伟人为什么是伟人？或者具体一点，哲学家为什么是哲学家？ 一种可能是，他们拥有非常高贵的信息源，可以从中得到非常鲜为人知的有价值的信息，利用信息差区别于众人。 另一种可能是，他们的信息源和众人一样，接收到的信息也随处可得。 如果几千年前就有那种能 “藏起来” 的信息，足以让个别人的思想留传至今，还能隐藏至今，那也太合理了...</p>]]></summary>
    <content type="html"><![CDATA[<p>伟人为什么是伟人？或者具体一点，哲学家为什么是哲学家？</p>
<ul>
<li><p>一种可能是，他们拥有非常高贵的信息源，可以从中得到非常鲜为人知的有价值的信息，利用信息差区别于众人。</p>
</li>
<li><p>另一种可能是，他们的信息源和众人一样，接收到的信息也随处可得。</p>
</li>
</ul>
<p>如果几千年前就有那种能 “藏起来” 的信息，足以让个别人的思想留传至今，还能隐藏至今，那也太合理了。</p>
]]></content>
  </entry>
  <entry>
    <title>之前的一次会议上，我说，一个软件通过某标准测试 “没什么”，然后有人说， “否定一个东西很容易，说话谁都会，如果觉得有问...</title>
    <link href="https://t.smallyu.net/#2021-57"/>
    <id>micro:897471196</id>
    <published>2021-08-12T09:04:23Z</published>
    <updated>2021-08-12T09:04:44Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>之前的一次会议上，我说，一个软件通过某标准测试 “没什么”，然后有人说， “否定一个东西很容易，说话谁都会，如果觉得有问题你可以给这个软件添砖加瓦” 之类。 其实当时我就明白，我那个并不是在 “否定” 什么，我那个叫 “对事物的正确认知”，是纠正了自己错误观念之后的感慨。</p>]]></summary>
    <content type="html"><![CDATA[<p>之前的一次会议上，我说，一个软件通过某标准测试 “没什么”，然后有人说， “否定一个东西很容易，说话谁都会，如果觉得有问题你可以给这个软件添砖加瓦” 之类。</p>
<p>其实当时我就明白，我那个并不是在 “否定” 什么，我那个叫 “对事物的正确认知”，是纠正了自己错误观念之后的感慨。</p>
]]></content>
  </entry>
  <entry>
    <title>想起之前一个会议，有人分享 “专利实审的回复技巧” 问题。临近尾声时上级问我，专利该怎么回复？（这种提问也是一种技巧，当...</title>
    <link href="https://t.smallyu.net/#2021-56"/>
    <id>micro:897458471</id>
    <published>2021-08-12T08:44:38Z</published>
    <updated>2021-08-12T11:33:31Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想起之前一个会议，有人分享 “专利实审的回复技巧” 问题。临近尾声时上级问我，专利该怎么回复？（这种提问也是一种技巧，当你身处高位、想说什么的时候，不能直接站在教育人的立场说话，可以先提问某人会不会，不管会或者不会（大概率不会），都可以很自然地接话说自己想说的）。 上级在会议过程中提到过一些比较具体的结论，比如，一要说...</p>]]></summary>
    <content type="html"><![CDATA[<p>想起之前一个会议，有人分享 “专利实审的回复技巧” 问题。临近尾声时上级问我，专利该怎么回复？（这种提问也是一种技巧，当你身处高位、想说什么的时候，不能直接站在教育人的立场说话，可以先提问某人会不会，不管会或者不会（大概率不会），都可以很自然地接话说自己想说的）。</p>
<p>上级在会议过程中提到过一些比较具体的结论，比如，一要说技术方案解决了不同的问题、二要说解决相同问题用了不同的方法、三要说使用相同的方法达到了不同的效果等等。（可能不准确，大致意思是这样，全靠回忆）</p>
<p>有没有感觉，这些结论太具体了，像不像小时候读书的时候，老师教给你知识，回答什么问题 1、2、3 步该怎么样，甚至有的老师会说，你不用理解，记住就行了。老师根据自己多年的教学经验，总结出了一些结论，你不需要也很难知道那些结论是怎么来的，只要记住就可以应付考试。</p>
<p>上级根据自己的经验总结出了一些可靠的结论（包括跨链有几种类型之类），这些结论当然是有价值而且正确的，但是这些都属于 “主观的知识”，换个人、换个老师，解决相同问题的方法会不一样，结论也会不一样。</p>
<p>想要超越老师，就必须自己直面问题，找出解决问题的方法，得到自己解决问题的方法论。</p>
<p>我当时在会议上回答提问的角度是，“分两种情况，专利审查员看明白了或者审查员没有看明白，如果看明白了，就狡辩一下，如果没有看明白，就让他明白”。</p>
<p>好像我已经无意间就在用正确的思路做事了。</p>
]]></content>
  </entry>
  <entry>
    <title>假如读书可以让人变厉害，出版社的编辑、有声书的声优、中译书的翻译，应该超过大多数人。但是他们没有。 一种可能性是，只拿着...</title>
    <link href="https://t.smallyu.net/#2021-55"/>
    <id>micro:897373194</id>
    <published>2021-08-12T06:06:04Z</published>
    <updated>2021-08-12T08:18:51Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>假如读书可以让人变厉害，出版社的编辑、有声书的声优、中译书的翻译，应该超过大多数人。但是他们没有。 一种可能性是，只拿着答案是不行的，满手都是正确答案，却不知道用来解决什么问题。他们可以学习到书里所有的内容，但几乎无法超越书的作者。没有问题比没有答案更可怕。把超级武器尘封起来，埋在土里，你还是你，武器还是你的，然后呢，...</p>]]></summary>
    <content type="html"><![CDATA[<p>假如读书可以让人变厉害，出版社的编辑、有声书的声优、中译书的翻译，应该超过大多数人。但是他们没有。</p>
<p>一种可能性是，只拿着答案是不行的，满手都是正确答案，却不知道用来解决什么问题。他们可以学习到书里所有的内容，但几乎无法超越书的作者。没有问题比没有答案更可怕。把超级武器尘封起来，埋在土里，你还是你，武器还是你的，然后呢，为了战争制造的武器，就应该用来赢得战争。</p>
<p>最近一度迷失于，到底什么是可靠的信息源。网络、视频、书籍、口述，还是别的形式？中文的、英文的，翻译的，或者别的语言？墙内的、墙外的、尺度大的、粉红的？什么样的内容可以相信，什么样的信息充满谎言，什么样内容算是有价值，什么样的内容可以用来解决问题？</p>
<p>也许方向错了。信息源或者信息都是 “答案”，一直纠结于什么样的答案是正确的，比来比去比不出结果。可能答案都是真的，都是对的，都是有价值的，真正的问题在于 “问题” 是什么，想要用这些答案来解决什么问题。</p>
]]></content>
  </entry>
  <entry>
    <title>历史学似乎更关心王朝更替、时代洪流，洪流之下小鱼小虾的命运，正史不关心，野史不能信。纪传体史书写的也都是大人物啊。 这种...</title>
    <link href="https://t.smallyu.net/#2021-54"/>
    <id>micro:896115726</id>
    <published>2021-08-10T15:14:12Z</published>
    <updated>2021-08-10T15:14:12Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>历史学似乎更关心王朝更替、时代洪流，洪流之下小鱼小虾的命运，正史不关心，野史不能信。纪传体史书写的也都是大人物啊。 这种时候自传可能更可信一点。</p>]]></summary>
    <content type="html"><![CDATA[<p>历史学似乎更关心王朝更替、时代洪流，洪流之下小鱼小虾的命运，正史不关心，野史不能信。纪传体史书写的也都是大人物啊。</p>
<p>这种时候自传可能更可信一点。</p>
]]></content>
  </entry>
  <entry>
    <title>小时候上历史课，不是 “河南周口店什么什么猿人”，就是 “秦始皇统一六国，对文化统一起到什么什么作用”，死记硬背，根本不...</title>
    <link href="https://t.smallyu.net/#2021-53"/>
    <id>micro:894827700</id>
    <published>2021-08-08T17:14:32Z</published>
    <updated>2021-08-08T17:15:45Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>小时候上历史课，不是 “河南周口店什么什么猿人”，就是 “秦始皇统一六国，对文化统一起到什么什么作用”，死记硬背，根本不明白什么意思。 有借鉴意义的一种历史知识，可以是比如，以前什么时候有一个什么人，和你一样小时候不喜欢读书，结果长大以后连饭都吃不起，因为……</p>]]></summary>
    <content type="html"><![CDATA[<p>小时候上历史课，不是 “河南周口店什么什么猿人”，就是 “秦始皇统一六国，对文化统一起到什么什么作用”，死记硬背，根本不明白什么意思。</p>
<p>有借鉴意义的一种历史知识，可以是比如，以前什么时候有一个什么人，和你一样小时候不喜欢读书，结果长大以后连饭都吃不起，因为……</p>
]]></content>
  </entry>
  <entry>
    <title>你很容易在脑子里想到一个场景，想清楚一些画面，很容易身体能感受到一些情绪，但是如果想用文字描写出来，太难了。有可能是还没...</title>
    <link href="https://t.smallyu.net/#2021-52"/>
    <id>micro:894806348</id>
    <published>2021-08-08T14:30:23Z</published>
    <updated>2021-08-08T14:31:17Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>你很容易在脑子里想到一个场景，想清楚一些画面，很容易身体能感受到一些情绪，但是如果想用文字描写出来，太难了。有可能是还没想明白这件事情，也有可能是文字能力太差了。 以前深受震撼的短篇小说《山药粥》，不光表达的含义意境深远，回味无穷，文字能力也功底深厚，看的时候就感觉这太有味道了。 也是后来才知道，日本最高文学奖 “介川...</p>]]></summary>
    <content type="html"><![CDATA[<p>你很容易在脑子里想到一个场景，想清楚一些画面，很容易身体能感受到一些情绪，但是如果想用文字描写出来，太难了。有可能是还没想明白这件事情，也有可能是文字能力太差了。</p>
<p>以前深受震撼的短篇小说《山药粥》，不光表达的含义意境深远，回味无穷，文字能力也功底深厚，看的时候就感觉这太有味道了。</p>
<p>也是后来才知道，日本最高文学奖 “介川奖” 就是用《山药粥》的作者芥川龙之介的名字命名…</p>
<p>直到自己想写一些东西但又无从下手的时候，就意识到这是怎么样的一种差距了…</p>
]]></content>
  </entry>
  <entry>
    <title>哲学有四个主要领域，形而上学、认识论、价值论、逻辑学。 “知识是什么”属于认识论的范畴。如果有人明确地告诉你知识是什么，...</title>
    <link href="https://t.smallyu.net/#2021-51"/>
    <id>micro:894732068</id>
    <published>2021-08-08T02:14:05Z</published>
    <updated>2021-08-08T02:16:30Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>哲学有四个主要领域，形而上学、认识论、价值论、逻辑学。 “知识是什么”属于认识论的范畴。如果有人明确地告诉你知识是什么，那他一定是骗子。 这种至少找到问题在哪儿的问题，就暂时不需要操心。但是哲学也有很多没有涵盖和涉及的问题。</p>]]></summary>
    <content type="html"><![CDATA[<p>哲学有四个主要领域，形而上学、认识论、价值论、逻辑学。</p>
<p>“知识是什么”属于认识论的范畴。如果有人明确地告诉你知识是什么，那他一定是骗子。</p>
<p>这种至少找到问题在哪儿的问题，就暂时不需要操心。但是哲学也有很多没有涵盖和涉及的问题。</p>
]]></content>
  </entry>
  <entry>
    <title>其实对于 “学以致用” 还是 “学以致知” 的问题，古希腊的哲学家早就有过思考。苏格拉底三位是 “学以致知” 的代表，追...</title>
    <link href="https://t.smallyu.net/#2021-50"/>
    <id>micro:890442689</id>
    <published>2021-08-01T03:39:39Z</published>
    <updated>2021-08-01T03:39:39Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>其实对于 “学以致用” 还是 “学以致知” 的问题，古希腊的哲学家早就有过思考。苏格拉底三位是 “学以致知” 的代表，追求形而上的真理。但是古希腊后期，某哲学家提倡 “学以致用”，认为哲学如果不能去除人类灵魂中的痛苦，就像医学不能治疗人类身体的疾病一样，毫无用处。</p>]]></summary>
    <content type="html"><![CDATA[<p>其实对于 “学以致用” 还是 “学以致知” 的问题，古希腊的哲学家早就有过思考。苏格拉底三位是 “学以致知” 的代表，追求形而上的真理。但是古希腊后期，某哲学家提倡 “学以致用”，认为哲学如果不能去除人类灵魂中的痛苦，就像医学不能治疗人类身体的疾病一样，毫无用处。</p>
]]></content>
  </entry>
  <entry>
    <title>我的担心不算多余，前几天第一时间预约了图书馆。面对林立的书架和千万册图书，由于时间有限，只能从中选择一本来看。不可能看完...</title>
    <link href="https://t.smallyu.net/#2021-49"/>
    <id>micro:890439145</id>
    <published>2021-08-01T03:01:28Z</published>
    <updated>2021-08-01T05:06:06Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>我的担心不算多余，前几天第一时间预约了图书馆。面对林立的书架和千万册图书，由于时间有限，只能从中选择一本来看。不可能看完的，很多人终其一生都难以在自己的细分领域内有成绩，什么分类下的什么书？还是那个问题，如果你的知识永远无法投入实用，你还愿意花费时间和精力掌握那些知识吗？增长见识扩充头脑？人类本就是渺小和无知的。</p>]]></summary>
    <content type="html"><![CDATA[<p>我的担心不算多余，前几天第一时间预约了图书馆。面对林立的书架和千万册图书，由于时间有限，只能从中选择一本来看。不可能看完的，很多人终其一生都难以在自己的细分领域内有成绩，什么分类下的什么书？还是那个问题，如果你的知识永远无法投入实用，你还愿意花费时间和精力掌握那些知识吗？增长见识扩充头脑？人类本就是渺小和无知的。</p>
]]></content>
  </entry>
  <entry>
    <title>前段时间听到一首歌《没有理想的人不伤心》，喜欢民谣里的那种虽然音乐很粗糙但是情绪都在里面的感觉。歌词甚至经不起推敲，但你...</title>
    <link href="https://t.smallyu.net/#2021-48"/>
    <id>micro:890385060</id>
    <published>2021-07-31T18:12:00Z</published>
    <updated>2021-07-31T18:13:29Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>前段时间听到一首歌《没有理想的人不伤心》，喜欢民谣里的那种虽然音乐很粗糙但是情绪都在里面的感觉。歌词甚至经不起推敲，但你就是能明白他在表达什么。 想到一个类似的标题《有实力的人不担心》，立意是清晰的，不过具体的内容需要足够的事例填充。期待全文完成的一天。</p>]]></summary>
    <content type="html"><![CDATA[<p>前段时间听到一首歌《没有理想的人不伤心》，喜欢民谣里的那种虽然音乐很粗糙但是情绪都在里面的感觉。歌词甚至经不起推敲，但你就是能明白他在表达什么。</p>
<p>想到一个类似的标题《有实力的人不担心》，立意是清晰的，不过具体的内容需要足够的事例填充。期待全文完成的一天。</p>
]]></content>
  </entry>
  <entry>
    <title>现在这个时间点，外面天气正舒服，最适合出门遛弯了。可惜不像去年有那样的时间了。</title>
    <link href="https://t.smallyu.net/#2021-47"/>
    <id>micro:890384096</id>
    <published>2021-07-31T18:05:07Z</published>
    <updated>2021-07-31T18:05:07Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>现在这个时间点，外面天气正舒服，最适合出门遛弯了。可惜不像去年有那样的时间了。</p>]]></summary>
    <content type="html"><![CDATA[<p>现在这个时间点，外面天气正舒服，最适合出门遛弯了。可惜不像去年有那样的时间了。</p>
]]></content>
  </entry>
  <entry>
    <title>要注意身体，保护眼睛，享受生活，好吃懒做，贪财好色，混吃等死。</title>
    <link href="https://t.smallyu.net/#2021-46"/>
    <id>micro:890383774</id>
    <published>2021-07-31T18:02:34Z</published>
    <updated>2021-08-01T05:06:31Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>要注意身体，保护眼睛，享受生活，好吃懒做，贪财好色，混吃等死。</p>]]></summary>
    <content type="html"><![CDATA[<p>要注意身体，保护眼睛，享受生活，好吃懒做，贪财好色，混吃等死。</p>
]]></content>
  </entry>
  <entry>
    <title>“学以致用” 的含义是，把学习到的知识运用到实际的生活和工作中。也就是说： 把学到的东西用起来是比较理想的情况 很多时候...</title>
    <link href="https://t.smallyu.net/#2021-45"/>
    <id>micro:888734785</id>
    <published>2021-07-29T01:46:27Z</published>
    <updated>2021-07-29T01:47:34Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“学以致用” 的含义是，把学习到的知识运用到实际的生活和工作中。也就是说： 把学到的东西用起来是比较理想的情况 很多时候，学到的东西用不起来，所以才希望用起来 那么有一个极端的问题，如果一些知识永远都不会用到，你还会去学吗？（但是怎么判断知识会不会用到？（又怎么定义“知识”？）） 假设可以确定不会用到，正常人都不会去学...</p>]]></summary>
    <content type="html"><![CDATA[<p>“学以致用” 的含义是，把学习到的知识运用到实际的生活和工作中。也就是说：</p>
<ul>
<li>把学到的东西用起来是比较理想的情况</li>
<li>很多时候，学到的东西用不起来，所以才希望用起来</li>
</ul>
<p>那么有一个极端的问题，如果一些知识永远都不会用到，你还会去学吗？（但是怎么判断知识会不会用到？（又怎么定义“知识”？））</p>
<p>假设可以确定不会用到，正常人都不会去学。正是因为不确定，才各种东西都学，大海捞针一样地用。现实似乎就是这样，这其实是一种悲哀不是吗？</p>
]]></content>
  </entry>
  <entry>
    <title>工作两年的体会</title>
    <link href="https://b.smallyu.net/2021/07/23/%E5%B7%A5%E4%BD%9C%E4%B8%A4%E5%B9%B4%E7%9A%84%E4%BD%93%E4%BC%9A/"/>
    <id>blog-b:https://b.smallyu.net/2021/07/23/%E5%B7%A5%E4%BD%9C%E4%B8%A4%E5%B9%B4%E7%9A%84%E4%BD%93%E4%BC%9A/</id>
    <published>2021-07-23T10:03:03.000Z</published>
    <updated>2026-04-08T08:59:48.913Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>如果你看到了这些内容，那么我已经离开上一家公司，开始了新一个阶段的职业生涯。</p>
<h3 id="最后的稻草"><a href="#最后的稻草" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>如果你看到了这些内容，那么我已经离开上一家公司，开始了新一个阶段的职业生涯。</p><h3 id="最后的稻草"><a href="#最后的稻草" class="headerlink" title="最后的稻草"></a>最后的稻草</h3><p>在一次技术分享会议上，我意识到我的技术理念和上级、和公司、甚至有可能和整个行业不同。这无关对错，没有冲突没有矛盾，仅仅只是 —— 不同。</p><p>我希望技术用来解决技术问题，更关注技术的发展趋势和形态，我并非不会让技术变得具体，只是不认为 “具体” 意味着深度，尤其是把 “具体” 和人类的心理（信任模型）联系起来。具体的技术可以解决特定的问题，有价值，可是格局小了，我不会满足于那样的程度。</p><p>比如，我认为,计算机和计算机之间的路由器，就是负责转发网络消息、保证消息准确无误到达目标计算机的，不应该牵扯到消息的具体内容。如果是转账消息，路由器还应该冻结转出方的资金保证交易事务的顺利完成？这太扯淡了。</p><p>当然不仅仅是这样的原因，只是因此突然产生了出去看看的想法。想法的产生只需要一瞬间，在上级纠正我的观点时，我绝对承认上级在技术问题上，尤其是在业界，理解上的正确性。只是突然觉得，这一切都太无聊了。那个圈，我跳不出去。</p><p>即使没有实现理想的实力，也不妨碍继续拥有理想。</p><p>一直只知道远处的山上有恶龙，现在发现，山脚下有怪物挡住了上山的路，山脚下的怪物，名字叫权威。</p><h3 id="时机"><a href="#时机" class="headerlink" title="时机"></a>时机</h3><p>去年上半年也产生过离开的想法，原因是，当时完全在从事没有技术含量的 CRUD 项目，我不能就那样下去。其实今年的原因也类似。</p><p>后来没有离开的原因，不是工作经验或者技能情况。当面试官问我一些很无聊的问题时，我突然觉得，我没有兴趣再继续找工作。换个地点上班并不能解决我的问题，不应该把技术能力的提升期望于任职的公司。甚至，我其实自己都没想清楚，对新工作的诉求是什么。外加当时大环境影响，面试不方便，以及当时的上级后来给了我不少发挥的空间，就安静呆着了。</p><p>去年下半年，降薪，项目失败，部门人心动荡，离职率高。有同事问我，为什么不跳槽？我倒一直不那么看重薪水，尤其当时在 “忙” 一些别的事情，自己的事情，没有心思关注工作的问题。包括今年也是，不是想不想，是没有去想，个人问题太多了，顾不上想。</p><p>现在是一个好的时机吗？好不好不知道，至少闲下来了。你也许能想象到，一开始看原生的英文视频和电视剧，感觉多么痛苦，听也听不懂，看也看不懂。有一段时间对美剧丧失兴趣，完全不想看，因为 TM 看不懂啊。</p><p>在个人能力的问题上，有一个简单的逻辑。如果我的能力拿得出手，我将找到更好的工作机会。如果我的能力拿不出手，那我必须得走，无论成本多高，即使挣不到钱、交不起房租、在这座城市生存不下去，一定要走。如果只有现在的公司认可我，我就会苟活在这里吗？在现在的公司算是 “被” 核心，但是一两家公司对我认可与否，并不能说明什么。我从来没有期望拿到比自己能力更多的报酬。</p><p>这两年来，我没有闲着。虽然没有把时间用在刷题或背基础知识上，但确实没闲着。速度和加速度，我选择了提高加速度。斧子和木头，我选择了打造更好的斧子。我花费时间，让自己成为一个更好的人类，而不是成为一个更好的码农。</p><p>在工作时间没有明确工作安排的时候，我在摸鱼吗？是的。但那种鱼摸起来，异常痛苦。我需要时刻思考，接下来做什么？我能做哪些工作相关的有价值的事情？每天早上醒来、每天晚上下班，想的都是，今天干什么？明天干什么？明明我已经尽力了，可什么事情都做不了。在工作上，我问心无愧（基本上）。不是故意偷懒，是实在想不到可以做的事情，何况连上级都没有。我才是真正想做些事情的人。</p><p>关于面试，我不希望刻意准备什么。必要的回顾和梳理经历是必要的，但不应该关注面试题。技术能力不可能一时半会儿提高，那种能短时间学会的东西，在哪儿学不一样呢，无论身处现在的公司还是未来的公司。我需要的，也许是一个试用期。如果能力不够份，我会自觉知趣地主动离开（当然，我知道现实社会不是那样运作）。我希望可以压力缓和的完成这次跳槽，如果在找工作过程中突然启动某个主题的学习计划，手忙脚乱不说，可能连找工作的兴趣都没了。</p><p>突然回想起在大学的时候，每次考试的前一天晚上，教室封楼，所有人都在宿舍里专心急迫地看书复习，校园里、操场上空无一人。只有我在外面溜达、在宿舍睡觉。需要会的已经在脑子，不会的临时看也没什么意思。</p><p>如果这次找工作遇到了比较大的阻力，那么我将会用亲身经历验证一个浅显的道理：两三年的工作经验远没有两三年的学历证书重要。我自认为学校里充满各种形式化的事情，各种魔幻的心理状态，无法教给我真正有用的知识。</p><p>（事实上，面试机会还是不少的，把握不住，是我自己的原因了。）</p><h3 id="一些事"><a href="#一些事" class="headerlink" title="一些事"></a>一些事</h3><p>以前没有在博客里提起，因为这些事情对我没有 “成长” 上的意义。虽然有接近 1 年的时间都牵扯在这一系列事情和情绪里面，但确实没有意义，不值一提。现在回忆一下作为记录，防止以后忘得太彻底。</p><h4 id="第一阶段"><a href="#第一阶段" class="headerlink" title="第一阶段"></a>第一阶段</h4><p>部门分两个小组，应用层小组和底层小组，简称 A 组和 B 组。我当时从属于 A 组。其实部门并没有多么明确的权限划分，我也没有搞山头的意思。</p><p>去年下半年，一个项目需要我（A组组员）和 B 组的组长合作，共同完成一件事情。从我当时的立场看，我只是个写代码的，出于在 A 组的工作经历以及对 A 组组长一定程度上的信任，心想好歹也是 B 组的组长，我又不太懂那个项目，他说什么我照做就是了。</p><p>实际的合作过程中却被难受了一把。他的思维逻辑没有足够条理，一会儿测场景一，一会二测场景二，一会儿又要测场景一。然后突然产生个想法，说那就测一下验证一下，场景一和场景二都测。完全想到哪儿做到哪儿。我们测的是分布式系统，有 4 ~ 6 台机器，每台机器上 2 ~ 3 个程序，切换场景需要所有的程序改配置、重启、清日志、记录机器状态、记录结果、分析结果等，还是在远程桌面、网络延迟到能让人爆炸的情况下。其实这个还能忍受，当时也没有多想什么，只是觉得这样的工作有点枯燥繁琐，有点抵触。</p><p>重点在于他不信任我。我事后复盘了一下，他在整个过程中、对我指手画脚的这些工作中，得出的结论，全是我早就已经知道的结论。他连带我消耗的那些时间，完全没有对事情起到推进作用。我事前就和他说过，结论是怎样怎样，然后他说，“那这个得跑一下”，“看看结果” 之类。我当时对自己没有足够的信心，毕竟他的 title 在那儿，而且我也期望他可以得到什么不一样的、更有用的结论，就听他的了。结果呢，他让我做的事情，只是把我的结论又验证了一遍。我开始对他的能力产生质疑。</p><p>后来又隔了几天，他让我重新验证一遍之前最好的一次结果。我在一些操作后，说直接写结论是多少吧。他坚持让我再操作一遍，把过程和结果拿给他。我就生气了，问 “这次测试的目的是什么？是为了把结果给你看一眼吗？” 我心想，我工作的内容就是给你打下手？我工作的价值就是给你看结果，让你相信我？在这件事情上，我们是合作的关系，还是从属关系？我凭什么做这样的事情？是你高估了自己，还是低估了我？你要真有能力也行，问题是你没有。</p><p>然后我的解决方法是，我对他说，以后再有事情，找我的领导（组长或部门负责人），让我的领导来协调，而不是直接命令我。意思就是让我的组长帮忙挡一下，拦掉一些没意义的事情。我从立场上并不能直接拒绝他，说这事我不干。如果我的领导一致认为一件事情是有意义的，从工作的角度，我肯定没有理由拒绝领导安排的工作内容。另外，如果我的领导一致认为我的工作内容就应该是给他打下手，那我当场辞职。</p><h4 id="第二阶段"><a href="#第二阶段" class="headerlink" title="第二阶段"></a>第二阶段</h4><p>经过第一阶段的事情后，我偶尔还瞎想，要是有一天领导要求或安排，我转到他们那个小组了，肯定得搞得天翻地覆，因为我并不信任他（B 组组长）的能力，我不会放心地把工作内容交给他。</p><p>然后神奇的事情发生了。B 组组长离职，B 组的某个组员成为组长，我转岗成为 B 组组员.</p><p>这 NM 搞笑呢？别说 B 组组员升的组长，就是原组长在的时候我也不服啊？甚至原组长的上一任组长、部门技术负责人（已离职），我也是一开始就怼的。</p><p>我确实没服。一个人突然来当我组长、当我领导，有权力安排我接下来要做的工作，这样的人，我不得先试试他的水平吗？我不可能轻易把将来的工作时间，任由没能力的领导瞎指挥瞎浪费啊。</p><p>然后我就用比较生硬的方式搞了点事情。^_^</p><p>事实上，各种迹象都表明，他（现任 B 组组长，即将离职）能力确实不行。不是说技术能力，是指当组长的能力。一般来说，一个内心和实力都强大的人，无论面对别人怎样的质疑，都应该是岿然不动、稳如泰山的。结果他那儿直接就歇菜了，没有反驳，甚至还有点认可和顺从我说的话、我的行为。自己都承认自己不行，那我干嘛听你的？</p><p>最后是部门负责人出面协调解决。当我说出我的判断时，部门负责人说，你不应该反抗他，而是帮助他，一起完成该做的事情……（侧面默认了我的观点，至少面对我是这样的说辞）</p><p>事后，部门负责人还找我谈话，大概意思是，你最近没有搞事情吧？你不要再说他了，再说他就要想走了，我怕他走……</p><h4 id="第三阶段"><a href="#第三阶段" class="headerlink" title="第三阶段"></a>第三阶段</h4><p>或许你会觉得，第一阶段和第二阶段都是我的问题，是我让他们的工作遇到了阻力。要是换个听话一点、服从性强的人，就完全不会发生那样的事情。</p><p>换个角度想，也许是他们太弱了，连我都压不住。我不可能主动降低自己的标准，假装服从他们的安排。</p><p>我到目前还是相信，无论身份、地位、背景、履历，过去多么辉煌、现在多么有钱、关系网络多么庞大、人际来往多么高端，技术就是技术，逻辑就是逻辑。不会因为一个人是部门负责人、首席架构师、行业知名人士，他说的话、他的技术观点就是绝对正确的。</p><p>这是一个能压得住我的人。</p><p>所以我换工作了。 :P</p><h3 id="一些坏话"><a href="#一些坏话" class="headerlink" title="一些坏话"></a>一些坏话</h3><p>我喜欢《海贼王》的故事。</p><p>如果你在一艘几乎停摆的船上。连船长都不知道，船往什么方向开，要到什么地方去。你还敢坐吗？</p><h3 id="感谢公司"><a href="#感谢公司" class="headerlink" title="感谢公司"></a>感谢公司</h3><p>必须要说明的是，上面提到的事情是从非常片面的视角、带有强烈主观个人情绪的描述。公司员工关系和睦、领导管理有方，基本不存在让人不愉快的事情。我只不过是把某条线单独拿出来说了，公司带给我的正面记忆远比写出来的事情多，我的成长离不开每一个遇到过的人。</p><p>感谢公司出现在我生命中的这两年半的时间。</p><h3 id="感谢上级"><a href="#感谢上级" class="headerlink" title="感谢上级"></a>感谢上级</h3><p>在交接工作的时间里，我一度担心会被领导卡离职流程，甚至想好了各种对策来应对各种有可能发生的情况。这种担心的主要的来源，不是上级，也不是我的交接对象，而是另一个和我的工作无关也和我的交接无关的人。</p><p>他的逻辑基本上是，在我离职后，某些事情（不是我的本职工作，友情支持）他们自己处理起来会有困难，所以期望我在离职前就做好一些一步到位的事情。我推测他的动机有两种可能：一种是他认为自己技术能力不足，无法顺利完成某些事情；另一种可能是，他认为这些本该由他自己处理的事情，比较繁琐复杂，他也懒得做，就借机推卸事情，让我做。</p><p>无论是哪一种可能，都应该和我的离职流程无关才对，但也就是稍有点担心，他会以此去影响领导在离职流程上的判断之类，因为在新的组织架构和工作安排上，他是比较重要的承担工作的人，在领导那里可能会有比较高的权重，算是我小人之心了。我相信领导还是拎得清的，事实上也确实没有出现不合理的情况。</p><p>比起这种具体的小事，我倒是更在意，其实我现在离职得稍微有点早，还没有做一些什么事情，就走了。主要也不敢继续留在这里，这次换工作，更像是在逃生。我不敢牺牲以后的可能性，在这里做不知道结局的事情。</p><p>对以前和现在的上级心怀愧疚中心怀感激。</p><h3 id="新的工作"><a href="#新的工作" class="headerlink" title="新的工作"></a>新的工作</h3><p>在新的工作上，我认为会离 “自由” 更近一步。</p><p>这里的自由也许包含多种含义，但我明面上肯定只会承认技术意义上的自由。可以接触真正的互联网，是无法用社会资源衡量的精神财富。</p><h3 id="祝好"><a href="#祝好" class="headerlink" title="祝好"></a>祝好</h3><p>将军不下马，各自奔前程。</p>]]></content>
  </entry>
  <entry>
    <title>如果想要变好，一种方式是知道并且只需要知道什么是好的。然后照做就行了，比如有一个掌握绝对真理的大师告诉你遇到什么事情该怎...</title>
    <link href="https://t.smallyu.net/#2021-44"/>
    <id>micro:882993567</id>
    <published>2021-07-20T02:05:10Z</published>
    <updated>2021-07-20T02:09:08Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果想要变好，一种方式是知道并且只需要知道什么是好的。然后照做就行了，比如有一个掌握绝对真理的大师告诉你遇到什么事情该怎么解决。你不需要知道什么是不好的，因为你就是最好的。但大多数情况下，没有人能遇到足够厉害的精神和人生导师。 这个时候，就需要先知道，什么是不好的，然后避开不好的东西，成为好的，“知耻而后勇”。那不知道...</p>]]></summary>
    <content type="html"><![CDATA[<p>如果想要变好，一种方式是知道并且只需要知道什么是好的。然后照做就行了，比如有一个掌握绝对真理的大师告诉你遇到什么事情该怎么解决。你不需要知道什么是不好的，因为你就是最好的。但大多数情况下，没有人能遇到足够厉害的精神和人生导师。</p>
<p>这个时候，就需要先知道，什么是不好的，然后避开不好的东西，成为好的，“知耻而后勇”。那不知道什么是好的，怎么判断什么是不好的？能给自己带来负面情绪的就是不好的。如果好的东西还会给人带来负面影响，那可能就是还不够好。</p>
<p>也就是说，知道什么是不好的，至少比无知稍好一点，“知耻近乎勇”。当我们说什么人不好，什么行为不好，什么东西不好，其实包含了很积极向上的含义不是吗？</p>
]]></content>
  </entry>
  <entry>
    <title>剧本杀的剧本为什么需要区分类型</title>
    <link href="https://b.smallyu.net/2021/07/20/%E5%89%A7%E6%9C%AC%E6%9D%80%E7%9A%84%E5%89%A7%E6%9C%AC%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E5%8C%BA%E5%88%86%E7%B1%BB%E5%9E%8B/"/>
    <id>blog-b:https://b.smallyu.net/2021/07/20/%E5%89%A7%E6%9C%AC%E6%9D%80%E7%9A%84%E5%89%A7%E6%9C%AC%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E5%8C%BA%E5%88%86%E7%B1%BB%E5%9E%8B/</id>
    <published>2021-07-20T00:43:43.000Z</published>
    <updated>2026-03-02T09:02:54.282Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>前段时间，我写下这样一句话：</p>
<blockquote>
<p>给剧本打标签、分类其实是非常错误、愚昧的做法，尤其会让习惯于 “循规蹈矩”]]></summary>
    <content type="html"><![CDATA[<p>前段时间，我写下这样一句话：</p><blockquote><p>给剧本打标签、分类其实是非常错误、愚昧的做法，尤其会让习惯于 “循规蹈矩” 的玩家有先入为主的映象，认为什么什么标签的本就应该怎么怎么玩。</p></blockquote><p>当时玩了一个情感本《春昼短》，游戏结束时，一个玩家吐槽（不是针对我）说，情感本不是这么玩的，重要的是代入人物体会情感，而不是全程都在分析凶杀案的凶手是谁，不应该把重点放在推理上。</p><p>我有感而发，一方面，是 DM（Dungeon Mater，主持人）说，现在是推凶环节，要找出凶手，然后所有人都在找凶手了。有什么问题？另一方面，情感本就不能关注推理和凶杀案了？剧本本身的故事情节薄弱无趣，根本不能引人注意让人感动，也不值一提啊。</p><p>过了很长时间后的最近，我满怀期待去玩一个备受好评的情感本《古木吟》，却由于其他人全程在关注凶杀案，最后感觉留有遗憾，明明是很好的剧情和故事，却没能把剧本发挥出来，体验到该有的效果。曾经讨厌别人吐槽的我，现在像那人一样（在心里）吐槽别人。</p><p>我开始反思，给剧本区分类型、打标签、划分不同玩法的做法，对吗？</p><p>答案是，对。</p><p>一般来说，剧本作者的水平高不到哪儿去，你不可能指望一个普通的剧本作者，推理部分逻辑缜密，故事部分感人至深，机制部分欢乐有趣，这不合理。</p><p>就算平时看刑侦推理电视剧、机制游戏真人秀，花那么多钱、请那么多明星、牵扯那么多资本，好看的有多少？何况是能够 “欺骗” 观众，让观众误以为真相是某一种，然后留下线索和悬念，最后有精彩反转的剧情，即使在美剧里也屈指可数。</p><p>仅仅是能达到好玩程度的剧本，就需要至少影视剧编剧水平的作者了。那样的作家又哪有功夫写剧本杀剧本，剧本杀的成本才多少。剧本杀的剧本，能有一两个亮点其实就不容易了。</p><p>所以为什么需要给剧本打类型标签？因为受限于剧本作者的水平，一种类型的剧本还真就只有一种玩法。用硬核本的玩法玩情感本，实际上牛头不对马嘴。</p><p>为什么会有 “一种剧本不应该只有一种玩法” 的错觉？因为很多剧本内容同质化严重，不管什么类型的本都会有凶杀案的桥段。好在这样的状况已经在逐渐改善，比如今年的一个热门剧本《来电》，没有凶杀案但是机制有趣、游戏欢快，最后的反转立意深刻，无论算不算最高水准的剧本，至少在好玩的同时还避开了传统落俗的套路，这是不小的进步。</p><p>那么，作为玩家，是不是应该在游戏前查看剧本的背景资料，了解这是一个什么类型的剧本，知道应该用什么样的玩法，明白重点关注哪些环节？</p><p>当然不是！</p><p>这分明是 DM 的责任。DM 自己首先应该对剧本了然于胸，然后在游戏开场前说明注意事项，让玩家知道侧重点，甚至针对不同水平的玩家在不同的游戏阶段进行单独的指导。DM 不能默认所有玩家都是老手，更不能默认所有玩家都知道某个剧本该怎么玩。</p><p>事实上，DM 的控场能力对玩家的游戏体验至关重要。</p><p>事实上，DM 的水平十有九差，剧本杀的体验十有九差。</p><p>我参与过的为数不多的体验比较好的游戏场次里，要么 DM 专业、全程在线，要么玩家之中有能自发站出来控场的老玩家。体验不好的场次里，几乎全是 DM 的问题，稍差一点的不参与不引导流程，更差一点的直接误导玩家，给不重要的环节留比较多的时间。还有的 DM 催着玩家加快节奏结束游戏、完成自己的工作任务，丝毫不顾玩家的感受。</p><p>不好的体验也算是一种经历了。我本来就在尝试不同的剧本杀店。</p><p>回到剧本类型的问题，道理是相似的，如果一部电影在宣传的时候说，这是集爱情古装玄幻动作剧情伦理喜剧历史为一体的青春偶像片，不看都知道是烂片。</p><p>如果有一种编程语言，声称同时支持 FP 和 OOP，同时支持 actors 和 pipeline，同时支持 try…catch 和 union type，既是 static typing 又是 dynamic typing 还支持 type inference，适用于熟悉不同编程语言风格的人，那这种编程语言……是 JavaScript 吧？ :P</p><p>如果一个人说他既会前端开发又会后端开发，会 APP 开发还会嵌入式开发，懂区块链原理还懂神经网络原理，对大数据处理和数据平台的建设都有深入研究，那这样的人……岁数肯定不小了……</p>]]></content>
  </entry>
  <entry>
    <title>想起 “三句话不离本行” 的 典故 ，反映出理解这个世界的角度很多，并且使用各种不同的思路都能解决相同的问题，就像 “条...</title>
    <link href="https://t.smallyu.net/#2021-43"/>
    <id>micro:882184519</id>
    <published>2021-07-19T02:26:23Z</published>
    <updated>2021-07-23T16:21:21Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想起 “三句话不离本行” 的 典故 ，反映出理解这个世界的角度很多，并且使用各种不同的思路都能解决相同的问题，就像 “条条大路通罗马” 一样，可以 “种种方式看世界”。</p>]]></summary>
    <content type="html"><![CDATA[<p>想起 “三句话不离本行” 的<a href="https://baike.baidu.com/item/%E4%B8%89%E5%8F%A5%E8%AF%9D%E4%B8%8D%E7%A6%BB%E6%9C%AC%E8%A1%8C/10348031?fr=aladdin">典故</a>，反映出理解这个世界的角度很多，并且使用各种不同的思路都能解决相同的问题，就像 “条条大路通罗马” 一样，可以 “种种方式看世界”。</p>
]]></content>
  </entry>
  <entry>
    <title>微信朋友圈里面的各种给孩子投票，看着孩子无精打采的表情搭配被打扮的西装革履的样子，像不像主人养了一只宠物，给宠物穿上漂亮...</title>
    <link href="https://t.smallyu.net/#2021-42"/>
    <id>micro:882047370</id>
    <published>2021-07-18T12:13:19Z</published>
    <updated>2021-07-18T12:13:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>微信朋友圈里面的各种给孩子投票，看着孩子无精打采的表情搭配被打扮的西装革履的样子，像不像主人养了一只宠物，给宠物穿上漂亮的衣服然后给宠物选美？ 孩子并不会明白拉人投票然后换来一个网络上的荣誉意味着什么。</p>]]></summary>
    <content type="html"><![CDATA[<p>微信朋友圈里面的各种给孩子投票，看着孩子无精打采的表情搭配被打扮的西装革履的样子，像不像主人养了一只宠物，给宠物穿上漂亮的衣服然后给宠物选美？</p>
<p>孩子并不会明白拉人投票然后换来一个网络上的荣誉意味着什么。</p>
]]></content>
  </entry>
  <entry>
    <title>之前吐槽剧本不应该区分类型，不应该做明显的划分，因为一个剧本不应该只有一种玩法。 但是当抱着某种类型的预期，玩到了没有体...</title>
    <link href="https://t.smallyu.net/#2021-41"/>
    <id>micro:882045479</id>
    <published>2021-07-18T11:58:15Z</published>
    <updated>2021-07-19T01:15:50Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>之前吐槽剧本不应该区分类型，不应该做明显的划分，因为一个剧本不应该只有一种玩法。 但是当抱着某种类型的预期，玩到了没有体现出的效果，又觉得留有遗憾。 其实问题不仅仅在于剧本的类型。</p>]]></summary>
    <content type="html"><![CDATA[<p>之前吐槽剧本不应该区分类型，不应该做明显的划分，因为一个剧本不应该只有一种玩法。</p>
<p>但是当抱着某种类型的预期，玩到了没有体现出的效果，又觉得留有遗憾。</p>
<p>其实问题不仅仅在于剧本的类型。</p>
]]></content>
  </entry>
  <entry>
    <title>尘埃落定，我应该计划开始做接下来的事情。</title>
    <link href="https://t.smallyu.net/#2021-40"/>
    <id>micro:881688617</id>
    <published>2021-07-16T20:06:02Z</published>
    <updated>2021-07-16T20:06:02Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>尘埃落定，我应该计划开始做接下来的事情。</p>]]></summary>
    <content type="html"><![CDATA[<p>尘埃落定，我应该计划开始做接下来的事情。</p>
]]></content>
  </entry>
  <entry>
    <title>最近找工作的经历</title>
    <link href="https://b.smallyu.net/2021/07/03/%E6%9C%80%E8%BF%91%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E7%BB%8F%E5%8E%86/"/>
    <id>blog-b:https://b.smallyu.net/2021/07/03/%E6%9C%80%E8%BF%91%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E7%BB%8F%E5%8E%86/</id>
    <published>2021-07-03T15:46:05.000Z</published>
    <updated>2025-12-03T09:25:54.166Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>一直以来，自知心比天高，眼高手低，目空一切。也许看不起或者不在意某些东西，但闭门造车绝对不是好的主意。我经常站在高的角度思考问题，但实际上身处底层，这是无法轻易改变的事实。我会参加一些明知道通过不了的面试，以此了解自己和现实的差距，并由此选择接下来的路。这会是一段艰难的时光]]></summary>
    <content type="html"><![CDATA[<p>一直以来，自知心比天高，眼高手低，目空一切。也许看不起或者不在意某些东西，但闭门造车绝对不是好的主意。我经常站在高的角度思考问题，但实际上身处底层，这是无法轻易改变的事实。我会参加一些明知道通过不了的面试，以此了解自己和现实的差距，并由此选择接下来的路。这会是一段艰难的时光。</p><p>面试前就明白面试通过不了，其实很离谱。主要是早对一些企业的面试难度有所耳闻，这两年我虽然没闲着，但是都把技能点加在别的地方了，前段时间还在思考公司产品的方向、能不能找到亮点之类，几乎没有过记知识点，没有专注技术细节。这两年的经历让我能够应付目前公司目前职务的工作，以及同级别公司同级别程序员的工作，但是向上跳一个台阶，我是没有信心的。</p><p>（1）</p><p>经历过一些面试，有一点简单的体会。</p><p>招聘的公司分三种。第一种是我需要你拥有哪些技能，然后去判断你是否拥有相应技能。第二种是，我想知道你拥有哪些技能。第三种是，我看不起你，你看不起我。</p><p>面试的问题分三类，面试官会问这三个方面的问题：编程语言基础；数据结构和算法；项目经历、系统架构、系统组件。</p><p>虽然目前面试次数并不多，但一次次的面试失败还是会让人沮丧。理想的工作到底是什么？薪资？办公环境？工作强度？发展前景？同事关系？不可能样样齐全啊？好的机会够不着，不好的机会又没兴趣。</p><p>还是坚持一下，怎么也得面 10 家起吧。</p><p>（2）</p><p>招聘的公司会更加关注技能匹配情况。</p><p>其实对于跳槽来说，现在不太是一个好的时机，一般都说金三银四，金九银十，现在 6 月份大热的天，属于招聘淡季。</p><p>我突然想提前换换思路。</p><p>之前投简历的全是知名公司，也就是做互联网产品的传统行业。这些公司关注的技术能力也往往侧重常见那一套。在最近的面试中，我最大的感受，就是对区块链的了解完全无法发挥。这样的跳槽，是直接换行业了。</p><p>之前对区块链是充满失望的，国内的联盟链基本都不靠谱，即使是蚂蚁链、趣链这样的行业头部，过得也并不好。除了币圈和交易所能挣到钱，其他的企业都没找到商业模式。</p><p>一方面，目前基本能认为，我没有去互联网头部企业的机会，而且我已经大概知道这些企业的招聘要求。另一方面，不得不承认，区块链是当前为数不多的 “新” 技术之一。在优先级上，肯定要排在互联网一般企业之前。</p><p>所以，我接下来开始投简历到区块链公司，重点寻找有海外业务、海外背景的创业公司，希望从事 Premissionless Blockchain 的开发工作。</p><p>（3）</p><p>为什么进不了大厂？</p><p>去大厂需要回顾基础知识和刷题，这有点不同于我的价值观。所以首先还是想试试，在不刻意准备的情况下，能不能找到合适的公司。</p><p>目前在等待某公司的结果，正好工作上也有些事情，暂时不再参加新的面试，看看后续的情况。</p><p>（4）</p><p>从开始到现在有接近三周的时间，虽然面试的公司数量少于预期，但……也很累。即使接下来会进行其他的面试，也算是下个找工作周期了。暂时先告一段落。</p><p>（5）</p><p>最近一周时间，又面试了几家公司，数量不多，质量不高，距离上一阶段时间较短，就直接把内容补充在这里了。</p><p>经历过上一阶段的面试，我意识到应该摆脱一些错误的思想。希望可以从容不迫地进行接下来的面试。</p><p>也许这一次找工作，结束地比想象中更快一些。</p><h3 id="百度-百度网盘（工程方向）"><a href="#百度-百度网盘（工程方向）" class="headerlink" title="百度 - 百度网盘（工程方向）"></a>百度 - 百度网盘（工程方向）</h3><p>记得当年找实习工作的时候，惟一电话面试的大厂就是百度，当时当场就挂了 :) </p><p>原计划视频面试，遇到点问题。百度用自家的 “如流” 视频会议软件，页面提示是有网页版本的，但实际上完全不能用，进入页面反复刷新还是提示 “会议不存在”。点击下载如流软件的按钮，网页直接跳到了 <code>about:blank</code>。我的笔记本是 Linux 系统，如流又没有 Linux 版本，临时改电话面试了。</p><p>面试反馈和我的预期基本一致，算法能力弱，语言基础不是很过关。面试过程中能听出面试官模板化的问题，以及敲键盘的声音，猜测应该是有标准化的面试流程，在记录面试结果吧。据说百度有个传统，除非特别差劲，否则一面不会挂人。。。一面的问题确实偏基础，虽然我没有答好。</p><p>我明确没有回答出来的问题有两个：</p><ul><li>Golang 怎么实现一个并发安全的 map ？</li><li>很多个数字里，找出前 N 大的数字</li></ul><p>语言方面，我经验确实不多。一直不太关注语言的细节，尤其是具体实现，除非真的用到，即使问 Java 相关的语言问题，我估计也答不上来。这也是我目前的工作很大的特点和弱点，代码量太少了！不过我不太担心这个。</p><p>第二个问题是经典的算法题，难度不大，能说上思路，但以前没有写过相关代码，说不出结论，不知道复杂度是多少。后来面试官降低难度，问排序算法有哪些？要的不是思路，是最高最低以及平均复杂度分别是多少。我不知道。</p><p>最后提问环节，我问提高技术能力从哪些方面入手？答沟通能力、代码能力，代码写的好技术不会差。</p><p>回顾及感受：今年找工作，第一家面试的公司，没有任何准备，基础不过关。面试官人还不错，但面试是有 checklist 的，一直至少目前不太喜欢这样的面试标准和流程。从意愿上，也没太期望一步到位，到所谓的大厂，跨度有点大。</p><h3 id="旷视（数据平台）"><a href="#旷视（数据平台）" class="headerlink" title="旷视（数据平台）"></a>旷视（数据平台）</h3><p>（一面）</p><p>视频面，面试官没开摄像头。</p><p>比较重视 Go 语言基础，问怎么退出协程、向已关闭的 channel 里写数据会发生什么。</p><p>算法题相对简单，反转二叉树（共享屏幕写代码）、判断链表是否有环。判断链表是否有环追加了第二个问题，环的起点在什么位置？有印象做过但不是很清楚，回答快慢指针相遇的位置。</p><p>最后提问环节，我问提高技术能力从哪些方面入手？答去模仿、造轮子。关注独立工作的能力。</p><p>（二面）</p><p>手写 LRU，要求查询和写入时间复杂度都是 O(1)。不会。面试官比较和蔼，全程在提示。仍然不会。</p><p>最后提问环节，我问比较看重哪方面的技术能力？答学习的热情，Geek 精神。</p><p>（终面）</p><p>表现最差的一次。</p><p>一开始网络信号差中断了几分钟，直接打乱自己的节奏，变得慌了起来。想说的东西很多，却反而让说话没有条理。</p><p>问，在做的工作中，认为最有成长的事情是什么？其实太多了，没能清晰条理地说出来。</p><p>问，如果重新做一次之前做过的工作，会有哪些改善的地方？答的比较差。也是第一次到终面，面对高级别的面试官，面对这种类型的问题。</p><p>后来写转置矩阵的题目，实在是太简单的题，结果卡在 Golang 语法上好几分钟。</p><p>后来问你平时写测试代码吗，我竟然说工作中写的少。</p><p>最后提问环节，我问比较看重哪方面的技术能力？答这个问题太宽泛了，人的能力是多角度的。</p><p>（HR 面）</p><p>大姐姐笑的很欢……</p><h3 id="中国知网（CNKI）"><a href="#中国知网（CNKI）" class="headerlink" title="中国知网（CNKI）"></a>中国知网（CNKI）</h3><p>现场面试。</p><p>办公环境优美。</p><p>技术栈落后互联网多年。</p><p>面试结束时，面试官建议我说，朝着一个技术细节深挖下去。</p><p>回顾及感受：属于互相看不顺眼的情况，问了一些很 low 的问题。如果脱离面试场景，那样的面试官是没资格评价我的技术能力的。</p><h3 id="亚艺网媒（探探）"><a href="#亚艺网媒（探探）" class="headerlink" title="亚艺网媒（探探）"></a>亚艺网媒（探探）</h3><p>现场面试。</p><p>一面白板写算法，是一个温柔的小姑娘。</p><p>二面白板画架构，重视对系统组件的理解，出题设计一个即时聊天系统。表现比较差。第一次遇到，稍微有点懵。也确实没有太多东西可说。</p><p>回顾及感受：能力不匹配，对方期望能够独立架构和运维整个后端服务的人，我目前架构经验比较少。突然想起来二面的过程中，面试官竟然说 WebSocket 只能在局域网通信，不能在公网通信。我当年没出学校的时候，就看着教学视频，做过基于 React.js + Node.js + WebSocket 的手机端的实时聊天 APP。估计面试官的技术能力也挺水的。</p><h3 id="海南新软（火币）"><a href="#海南新软（火币）" class="headerlink" title="海南新软（火币）"></a>海南新软（火币）</h3><p>（部门一）</p><p>电话面试。</p><p>只问语言基础。全部不会答。</p><p>回顾及感受：原来火币也是血汗工厂，至少我面试的部门是。同样属于互相看不顺眼的情况，面试官自己说，除了语言基础，就不知道问什么了。算法呢？项目经历呢？区块链呢？搞笑呢？</p><p>（部门二）</p><p>这个部门的面试官态度很好，随便问了问，说是火币集团下做联盟链业务的，不会接触到币圈相关的业务，还说我的能力挺符合他们需求的。虽然我确实没兴趣。</p><h3 id="轻松集团（轻松筹）"><a href="#轻松集团（轻松筹）" class="headerlink" title="轻松集团（轻松筹）"></a>轻松集团（轻松筹）</h3><p>现场面试。</p><p>面试结束时，面试官建议我说，要关注技术细节。</p><p>回顾及感受：面试官性格还可以，技术上不敢恭维。和知网的面试官感觉类似，属于会根据学历给人贴标签、有心理预期的人。面试半小时，当场出结果，小公司模式，就是让去也不敢去啊。</p><h3 id="主动取消-x2F-放弃"><a href="#主动取消-x2F-放弃" class="headerlink" title="主动取消 &#x2F; 放弃"></a>主动取消 &#x2F; 放弃</h3><ul><li>趣拿（去哪儿网）</li><li>华为 OD</li><li>滴滴（服务治理方向）</li><li>数美（HR 非常主动）</li></ul><p>去哪儿网是这次找工作，第一家约面试的公司，后来时间上和百度撞了，推迟一周，面试官临时有事，推迟一周，第三周面试官又有事，我说直接取消吧。</p><p>主动放弃这些面试机会。流程化的面试，就不再继续参加了。估计也过不了 :P</p><h3 id="贝斯平（Bespin）"><a href="#贝斯平（Bespin）" class="headerlink" title="贝斯平（Bespin）"></a>贝斯平（Bespin）</h3><p>问了一些语言基础和计算机基础。</p><p>问面试官，该从哪些方面提高技术能力？答深入语言基础、计算机基础，学习途径看书看博客。</p><h3 id="恩佩弗尼（Apifiny）"><a href="#恩佩弗尼（Apifiny）" class="headerlink" title="恩佩弗尼（Apifiny）"></a>恩佩弗尼（Apifiny）</h3><p>（一面）</p><p>小伙子水平不行啊。小公司和大公司的区别一下子体现出来了。</p><p>了解到岗位是区块链钱包开发，做对接加密货币的账户和资产管理服务。</p><p>（二面）</p><p>面试官级别稍高，和一面面试官的反差太大了。</p><h3 id="京东云"><a href="#京东云" class="headerlink" title="京东云"></a>京东云</h3><p>电话简单了解了一下情况。</p><div style="display:none;"><h3 id=""><a href="#" class="headerlink" title="**"></a>**</h3><p>随手投了简历，一开始兴趣不大，后来 HR 三番五次约面试。感觉对方一开始就是有意向的，面试只是见见面。</p><p>（一面）</p><p>电话简单了解了一下情况。</p><p>（二面）</p><p>到北京分公司现场。办公环境稍差一点，不如目前在职的公司。公司里全是技术人员。</p><p>技术负责人的面试，很能忽悠的样子。说的东西全在我的点上，非常契合我的意向。不过也太符合我在技术方面的追求了，有点虚幻……</p><p>（HR 面）</p><p>电话沟通了 offer 内容。</p></div><h3 id="知乎"><a href="#知乎" class="headerlink" title="知乎"></a>知乎</h3><p>很快结束，方向完全不匹配，面试官临时看简历，一开始就是放弃的。</p>]]></content>
  </entry>
  <entry>
    <title>“我”是……（系列）</title>
    <link href="https://b.smallyu.net/2021/06/24/%E2%80%9C%E6%88%91%E2%80%9D%E6%98%AF%E2%80%A6%E2%80%A6%EF%BC%88%E7%B3%BB%E5%88%97%EF%BC%89/"/>
    <id>blog-b:https://b.smallyu.net/2021/06/24/%E2%80%9C%E6%88%91%E2%80%9D%E6%98%AF%E2%80%A6%E2%80%A6%EF%BC%88%E7%B3%BB%E5%88%97%EF%BC%89/</id>
    <published>2021-06-24T14:23:19.000Z</published>
    <updated>2025-12-03T10:02:00.858Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>“我”是一个有洁癖的人。</p>
<p>住在别墅的富商们都有洁癖，他们的柜子上摆满金银珠宝，他们认真擦拭灰尘、小心翼翼摆放，把一切整理的井井有条错落有致一尘不染。</p>
<p>我看到琼楼玉宇里的达官显贵们都是那么做的。</p>
<p>虽然我面前只有一个垃圾桶，堆满了肮脏的]]></summary>
    <content type="html"><![CDATA[<p>“我”是一个有洁癖的人。</p><p>住在别墅的富商们都有洁癖，他们的柜子上摆满金银珠宝，他们认真擦拭灰尘、小心翼翼摆放，把一切整理的井井有条错落有致一尘不染。</p><p>我看到琼楼玉宇里的达官显贵们都是那么做的。</p><p>虽然我面前只有一个垃圾桶，堆满了肮脏的废弃的物品，但是我看到它们不整齐，我要把它们变得干净整洁，因为我有洁癖。</p><p>当我看到有人往垃圾桶里随意丢弃垃圾，不屑一顾置之不理，我会大声抱怨甚至斥责他们，虽然他们毫无悔改之心。</p><p>为什么他们不懂得干净和整洁，为什么不能像我一样，不能像达官显贵们一样，做一个严于律己有洁癖爱干净整洁的人，</p><p>我有洁癖，我比那些不懂干净整洁的人高贵，我比他们都高级。（狗头）</p><div style="text-align: right;">（2021年03月11日）</div><br><hr><p>“我”是一个设计者。</p><p>我定义了一种新的加法运算，在这种运算规则下，1+1&#x3D;3，2+2&#x3D;5。</p><p>我出了一些题目，比如 3+3&#x3D;?、4+4&#x3D;?，如果有人能回答出题目，就说明他们已经掌握了我创造的“知识”。</p><p>有的人热衷于学习我创造的知识，奉我为神灵，乐此不疲，以此为荣，甚至看不起没有掌握这些知识的人。</p><p>有的人还会为了我争吵，面红耳赤，在讨论是我创造的知识好，还是另一个设计者创造的知识好。</p><p>有的人会觉得掌握了我创造的知识，就比掌握了另一个设计者创造的知识的人高级。</p><p>我喜欢这些有趣的人，虽然在我眼里，他们都是虫子。（狗头）</p><div style="text-align: right;">（2021年03月23日）</div><br><hr><p>“我” 是一个建筑师，能够进行普通建筑物设计图纸的绘制。</p><p>有一次工头喊我帮忙，工地缺人手，需要把砖头从一个地方搬到另一个地方。我去了。</p><p>搬砖的工人不明白，为什么搬同样的砖，从同样的一个地方搬到同样的另一个地方，给我的报酬比给他们的多。</p><div style="text-align: right;">（2021年04月22日）</div><br><hr><p>“我” 是奥特曼。</p><p>人类总是 “好心” 地劝告我，怪兽特别厉害，怪兽特别强大，怪兽摧毁了很多人类的房屋和土地，怪兽给很多人类战士带来了死亡和恐惧，要我小心怪兽的攻击，要我对怪兽有 “敬畏之心” ，不要小看了怪兽。</p><p>我懒得解释我的手一举起来就可以发射激光。</p><div style="text-align: right;">（2021年04月22日）</div><br><hr><p>“我” 是一个船长。</p><p>我命令我的船员去一个小岛上寻找宝藏。一定有的，宝藏就在那里。</p><p>如果你非要问我，我为什么肯定那个小岛上有宝藏，因为别的船都到那里去找，而且找的很热闹，大张旗鼓。</p><p>即使有去探索过小岛的船员说，那里没有什么。</p><p>即使有去过更大的岛的船员说，那里没有什么。</p><p>一定有的，宝藏就在那里。</p><p>如果你非要问我，我为什么肯定那个小岛上有宝藏，因为别的船都到那里去找，而且找的很热闹，大张旗鼓。</p><div style="text-align: right;">（2021年04月29日）</div><br><hr><p>“我” 是一个游戏的资深玩家。</p><p>我经常说这个游戏如何好玩，为什么好玩，为什么值得玩，多有前景。</p><p>我们经常讨论这个游戏的玩法，阵营，策略，升级，成就，装备，公会，任务，操作，等等。</p><p>一个新手玩家说，这个游戏不好玩。</p><p>一个新手玩家说，这个游戏虽然好玩，但没有另一个游戏好玩，没有另一个游戏有价值，没有另一个游戏有前景，没有另一个游戏有意义。</p><p>我怎么可能抛下在这个游戏上的积累，去玩另一个我没玩过的游戏。</p><p>我甚至不会承认，新手玩家说的是对的。</p><p>即使新手玩家真是对的。</p><div style="text-align: right;">（2021年05月07日）</div><br><hr><p>“我” 是一个地主。</p><p>秋天到了，家里需要雇佣工人去田地里收割麦子，长工短工都有。</p><p>经常看见工人们相互探讨收割麦子的手法、步法、心法，相互比较谁割麦子速度快、质量高，谁经验多、能够快速收割掉各式各样没长齐的麦子。</p><p>越是手艺好、会说话、忠心的工人，我自然越是喜欢。他们也会为此洋洋得意，因为得到了比其他工人更多的认可和报酬。</p><p>手艺好的工人是有优越感的，他们可以到任意一家地主家里去收割麦子，因为他们有精湛的收割麦子的技术，大多数地主没理由拒绝这样的工人。这可不是一般工人能享有的待遇，他们已经算是高级的工人了。</p><p>高级的工人有时还是给普通工人讲解割麦子的技巧，传授收麦子的心得。地主招收新的工人时，也会让高级工人代为把关，用一些刁钻的技术问题判断，想来的工人到底能不能达到地主家的要求。</p><div style="text-align: right;">（2021年05月26日）</div><br>]]></content>
  </entry>
  <entry>
    <title>发现一个特别好看的电视剧： Girl From Nowhere 注意到至少前 4 集的故事背景都是校园。也许从侧面反映出...</title>
    <link href="https://t.smallyu.net/#2021-39"/>
    <id>micro:848829033</id>
    <published>2021-05-26T14:43:18Z</published>
    <updated>2021-05-26T14:43:18Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>发现一个特别好看的电视剧： Girl From Nowhere 注意到至少前 4 集的故事背景都是校园。也许从侧面反映出，只有在学校那样的地方，在学校那样的阶段，才更可能发生那种 “魔幻” 的事情。</p>]]></summary>
    <content type="html"><![CDATA[<p>发现一个特别好看的电视剧： <em>Girl From Nowhere</em></p>
<p>注意到至少前 4 集的故事背景都是校园。也许从侧面反映出，只有在学校那样的地方，在学校那样的阶段，才更可能发生那种 “魔幻” 的事情。</p>
]]></content>
  </entry>
  <entry>
    <title>感觉自己有点像段子里的模样，拿着打工人的工资，净想些 “忧国忧民” 的事情。 每当看到工作多年的人还在讨论 “编程语言的...</title>
    <link href="https://t.smallyu.net/#2021-38"/>
    <id>micro:846114234</id>
    <published>2021-05-21T17:16:12Z</published>
    <updated>2021-05-23T05:45:44Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>感觉自己有点像段子里的模样，拿着打工人的工资，净想些 “忧国忧民” 的事情。 每当看到工作多年的人还在讨论 “编程语言的用法” 之类，我羡慕他们，可以心安理得地关注这种 “低级” 的问题。 他们运气并不算差，不需要额外的技能也可以安身立命，混到不错的位置上。 我羡慕他们。如果世界如此简单，我可以安心地躺平。 可是，就像...</p>]]></summary>
    <content type="html"><![CDATA[<p>感觉自己有点像段子里的模样，拿着打工人的工资，净想些 “忧国忧民” 的事情。</p>
<p>每当看到工作多年的人还在讨论 “编程语言的用法” 之类，我羡慕他们，可以心安理得地关注这种 “低级” 的问题。</p>
<p>他们运气并不算差，不需要额外的技能也可以安身立命，混到不错的位置上。</p>
<p>我羡慕他们。如果世界如此简单，我可以安心地躺平。</p>
<p>可是，就像黑客帝国里面对红蓝药丸的选择，有些东西一旦知道，就再也回不去了。</p>
]]></content>
  </entry>
  <entry>
    <title>给剧本打标签、分类其实是非常错误、愚昧的做法，尤其会让习惯于 “循规蹈矩” 的玩家有先入为主的映象，认为什么什么标签的本...</title>
    <link href="https://t.smallyu.net/#2021-37"/>
    <id>micro:842496039</id>
    <published>2021-05-17T17:18:28Z</published>
    <updated>2021-05-17T17:18:28Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>给剧本打标签、分类其实是非常错误、愚昧的做法，尤其会让习惯于 “循规蹈矩” 的玩家有先入为主的映象，认为什么什么标签的本就应该怎么怎么玩。</p>]]></summary>
    <content type="html"><![CDATA[<p>给剧本打标签、分类其实是非常错误、愚昧的做法，尤其会让习惯于 “循规蹈矩” 的玩家有先入为主的映象，认为什么什么标签的本就应该怎么怎么玩。</p>
]]></content>
  </entry>
  <entry>
    <title>机器人必须做出足够正确的决定，这是连人类都无法做到的事情。（爱死机 S2E1</title>
    <link href="https://t.smallyu.net/#2021-36"/>
    <id>micro:841759956</id>
    <published>2021-05-16T03:25:30Z</published>
    <updated>2021-05-16T03:25:30Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>机器人必须做出足够正确的决定，这是连人类都无法做到的事情。（爱死机 S2E1</p>]]></summary>
    <content type="html"><![CDATA[<p>机器人必须做出足够正确的决定，这是连人类都无法做到的事情。（爱死机 S2E1</p>
]]></content>
  </entry>
  <entry>
    <title>时间过得太快了，什么事都没干就过去了。 时间过得太慢了，这点时间什么都干不了。</title>
    <link href="https://t.smallyu.net/#2021-35"/>
    <id>micro:840712785</id>
    <published>2021-05-13T17:29:57Z</published>
    <updated>2021-05-13T17:29:57Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>时间过得太快了，什么事都没干就过去了。 时间过得太慢了，这点时间什么都干不了。</p>]]></summary>
    <content type="html"><![CDATA[<p>时间过得太快了，什么事都没干就过去了。<br>时间过得太慢了，这点时间什么都干不了。</p>
]]></content>
  </entry>
  <entry>
    <title>不知所言</title>
    <link href="https://crazy.smallyu.net/2021/05/06/%E4%B8%8D%E7%9F%A5%E6%89%80%E8%A8%80/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/05/06/%E4%B8%8D%E7%9F%A5%E6%89%80%E8%A8%80/</id>
    <published>2021-05-06T15:59:10.000Z</published>
    <updated>2025-08-16T03:27:11.336Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<h3 id="人生中必须要做的事"><a href="#人生中必须要做的事" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<h3 id="人生中必须要做的事"><a href="#人生中必须要做的事" class="headerlink" title="人生中必须要做的事"></a>人生中必须要做的事</h3><p>探索自己的可能性，探索自己能力的边界。这是值得为之努力的事情。</p><p>庙堂之高的人，和江湖之远的人，总结出的人生道理是相似的。</p><p>谁比谁高级，谁比谁高雅。</p><p>人类几千年没有进化，人性没有变，本能没有变，欲望没有变，故事没有变，结局没有变。</p><p>用技术的眼光看待人类是狭隘的，只存在不到一百年的计算机技术也是狭隘的。</p><p>世界上没有惊喜，因为太阳底下没有新鲜事。</p><p>新鲜事时常发生，因为对于个体，每天都是全新的。</p><h3 id="价值"><a href="#价值" class="headerlink" title="价值"></a>价值</h3><p>文字的价值不以篇幅衡量。</p><p>文学的价值不会随时间消失。</p><p>诗词寥寥几句，流传百年，古今传颂。</p><p>鲁迅留有长篇，也留有短篇。</p><p>周杰伦的歌曲，光良的《第一次》，加上 MV，是任何时候都会动容的故事。</p><p>《圣经》中对人生和哲理的思考，穿越千年。</p><p>历史上少有闪光点，但每一个闪光点都惊为天人。</p><p>很多很多。</p><h3 id="自然规律"><a href="#自然规律" class="headerlink" title="自然规律"></a>自然规律</h3><p>生物的行为符合自然规律。</p><p>两个细胞进行复制和分化，需要 10 个月变成人类。</p><p>大脑接收信息，脑细胞形成特定形状的结构，也需要过程和时间。</p><p>不管什么博士教授天才地才。</p><p>所以问题从 “我要做些什么” 变成了 “在当前阶段，我能做些什么” 。</p><p>范围一下子小了。</p><h3 id="公平"><a href="#公平" class="headerlink" title="公平"></a>公平</h3><p>大年初二晚上，凌晨一点，《你好，李焕英》散场。</p><p>我在街上散步，看到睡在路边长椅的人。他们是谁的孩子，是谁的父母，是谁的亲人，是谁的朋友。</p><p>我比他们多拥有什么，他们比我差在哪里。他们从哪里来，到哪里去，为什么坚持活着。</p><p>我从哪里来，到哪里去，为什么要活着。</p><p>他们活着开心吗，对生活充满期盼吗，有人关心他们吗，他们的未来有转机和希望吗。</p><p>我难道不会沦落至此吗。</p><p>虽然近在咫尺。</p><h3 id="天下熙熙，天下攘攘"><a href="#天下熙熙，天下攘攘" class="headerlink" title="天下熙熙，天下攘攘"></a>天下熙熙，天下攘攘</h3><p>一开始，加了一些群聊。</p><p>后来兴起，自己组建社群。</p><p>一开始，群里来了富二代。随手发三四个 88 的红包。</p><p>大家前仆后继。</p><p>后来富二代走了，大家全力挽留，争相怀念。</p><p>天下熙熙，天下攘攘。</p><p>一开始，大家感到新鲜和开心。</p><p>后来，没有新的渠道，没有新的人。</p><p>我为此感到疲倦。</p><p>来了很多人，走了很多人。</p><p>我为此感到不安。</p><p>大家叫我群主。</p><p>我不敢乱发消息，不敢灌水，怕说错话，怕一不小心，说了别人不喜欢的话，怕人走。</p><p>我不敢轻易 cue 人，顾忌被误以为利用身份，牟取什么。</p><p>群主的身份，总是有人盯着。</p><p>感谢 “群主” ，让我被很多人认识。</p><p>我认真地把 “群主” 转让出去。</p><p>一身轻松。</p>]]></content>
  </entry>
  <entry>
    <title>区块链玩家： 区块链 = cryptocurrency + 交易所 + 杠杆 + 钱包 + …… 区块链从业者： 区块链...</title>
    <link href="https://t.smallyu.net/#2021-34"/>
    <id>micro:829847609</id>
    <published>2021-04-30T05:25:34Z</published>
    <updated>2021-05-01T00:49:29Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>区块链玩家： 区块链 = cryptocurrency + 交易所 + 杠杆 + 钱包 + …… 区块链从业者： 区块链 = 智能合约 + 共识 + 数据库 + ……</p>]]></summary>
    <content type="html"><![CDATA[<p>区块链玩家：</p>
<pre><code>区块链 = cryptocurrency + 交易所 + 杠杆 + 钱包 + ……
</code></pre>
<p>区块链从业者：</p>
<pre><code>区块链 = 智能合约 + 共识 + 数据库 + ……
</code></pre>
]]></content>
  </entry>
  <entry>
    <title>《 聪明人和儍子和奴才 》 ——鲁迅</title>
    <link href="https://t.smallyu.net/#2021-33"/>
    <id>micro:827336262</id>
    <published>2021-04-27T06:01:57Z</published>
    <updated>2021-04-27T06:01:57Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>《 聪明人和儍子和奴才 》 ——鲁迅</p>]]></summary>
    <content type="html"><![CDATA[<p>《<a href="https://zh.m.wikisource.org/zh-hans/%E8%81%B0%E6%98%8E%E4%BA%BA%E5%92%8C%E5%84%8D%E5%AD%90%E5%92%8C%E5%A5%B4%E6%89%8D">聪明人和儍子和奴才</a>》 ——鲁迅</p>
]]></content>
  </entry>
  <entry>
    <title>不加糖的白咖啡最好喝。</title>
    <link href="https://t.smallyu.net/#2021-32"/>
    <id>micro:826761776</id>
    <published>2021-04-26T11:31:43Z</published>
    <updated>2021-04-26T11:31:43Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>不加糖的白咖啡最好喝。</p>]]></summary>
    <content type="html"><![CDATA[<p>不加糖的白咖啡最好喝。</p>
]]></content>
  </entry>
  <entry>
    <title>平时听惯了抖音热歌，偶然听到周杰伦的歌，感觉耳朵受到了洗礼。</title>
    <link href="https://t.smallyu.net/#2021-31"/>
    <id>micro:826507454</id>
    <published>2021-04-26T05:15:27Z</published>
    <updated>2021-04-26T05:15:27Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>平时听惯了抖音热歌，偶然听到周杰伦的歌，感觉耳朵受到了洗礼。</p>]]></summary>
    <content type="html"><![CDATA[<p>平时听惯了抖音热歌，偶然听到周杰伦的歌，感觉耳朵受到了洗礼。</p>
]]></content>
  </entry>
  <entry>
    <title>你在玩游戏，制造游戏的人在玩你。</title>
    <link href="https://t.smallyu.net/#2021-30"/>
    <id>micro:826037608</id>
    <published>2021-04-24T05:23:52Z</published>
    <updated>2021-04-24T05:23:52Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>你在玩游戏，制造游戏的人在玩你。</p>]]></summary>
    <content type="html"><![CDATA[<p>你在玩游戏，制造游戏的人在玩你。</p>
]]></content>
  </entry>
  <entry>
    <title>我没有在博客上骂人</title>
    <link href="https://crazy.smallyu.net/2021/04/23/%E6%88%91%E6%B2%A1%E6%9C%89%E5%9C%A8%E5%8D%9A%E5%AE%A2%E4%B8%8A%E9%AA%82%E4%BA%BA/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/04/23/%E6%88%91%E6%B2%A1%E6%9C%89%E5%9C%A8%E5%8D%9A%E5%AE%A2%E4%B8%8A%E9%AA%82%E4%BA%BA/</id>
    <published>2021-04-23T01:54:03.000Z</published>
    <updated>2025-08-16T03:27:11.436Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>我过去没有、将来也不会在博客上骂人。</p>
<p>对于博客的存在，我的态度一直是不主动、不拒绝。我当然不会在意有人从我的 Github]]></summary>
    <content type="html"><![CDATA[<p>我过去没有、将来也不会在博客上骂人。</p><p>对于博客的存在，我的态度一直是不主动、不拒绝。我当然不会在意有人从我的 Github 主页看到了博客链接，或者从其他网站账号看到博客网址的字样，但是也不太可能主动跟人说，“这是我的博客，你过来看一眼吧”。</p><p>博客就像是把自己写的一本书放到了公共图书馆的书架上，我不会刻意引导别人到第几排的书架第几个格子去找一本什么样子的书看看吧，但如果有人无意间看到了，自然也随意。如果看到的人正好发现，书里的内容和自己的行径有点相似，难道会认为这本书是为了嘲讽自己而写吗？即使指名道姓，也不会有人那么 “自恋” 吧。</p><p>对于现实生活中认识的人，博客里面的内容有比较大的可能提及相关的人或者事，稍微有点担心尤其是当事人会理解出 “听者有意” 的含义。对于网络世界中不认识的人，smallyu 只是沧海一粟，不值一提，班门弄斧，怕人笑话。而且，如果真有很多人看的话，我会有包袱和压力，不敢轻易写 “没有含量” 的内容，那样的感觉太糟糕太压抑了。</p><p>记得很久之前有一次，把博客链接填写在一个小型的博客导航网站上，那种按点赞和点击排权重的全是博客的导航网站，当时好像收到了（起码在某个时间段）排名第二的点赞数量。我第一次意识到，博客里的内容可能会有人认可，也是第一次感受到到 “被看到” 的压力。后来就没有再主动把博客链接发到什么地方了，我不会做类似 “在论坛日经贴下面留言博客链接” 的事情。</p><p>博客具体的内容，肯定不会专门为了针对某一个人写什么，更多的情况是希望描述某一类人，这些人可能会具有一些共同的特征，然后将某人某事作为典型举例。</p><p>如果有人非要认为，这就是在写谁谁谁或者什么什么事，你就是对谁有意见有看法，在表述一些不满或者不敢直接说的想法等等。有一个相关的逻辑：</p><ul><li>问：为什么毛当年可以从一个北大的图书管理员，成为国家主席？</li><li>答：只是一个将会成为国家主席的人，在成为主席之前，当了几天图书管理员而已。</li></ul><p>与之类比，</p><ul><li>问：你一个过往经历不堪的人，凭什么觉得将来有可能会做一些什么事情？</li><li>答：只是一个有可能将来会做一些事情的人，有一段比较寻常的过往而已。</li></ul><p>博客的立场不会是 “谁的朋友” 或者 “某公司的员工”，而是 “认识过拥有某些特征的人的人” 或者 “有过在某公司任职经历的人”。</p><p>所以，如果真的有人感觉“被针对”了，天地良心，我根本没有把那些人放在眼里。&#x2F;doge</p><p>在关于人生的问题上，我比较好奇也有点盲目地崇拜耶稣、苏格拉底这样的人，同时也对西方神学和古希腊哲学充满兴趣。只是目前没有足够空闲的时间，也没有找到合适的门道去深入了解相关内容。</p><p>至于为什么会突然提到这个话题，其实也只是作为预防，包括以前存在的和以后有可能出现的内容。随着时间的推移、生活中往来的增多、网络中内容的增长，这个博客有可能会被越来越多次 “不经意” 地看到。还是同样的态度，我不会刻意掩饰什么，也不会主动宣扬什么。</p>]]></content>
  </entry>
  <entry>
    <title>Git 误操作，导致多出至少 1/3 的 commit 次数。 ...(｡•ˇ‸ˇ•｡) ...</title>
    <link href="https://t.smallyu.net/#2021-29"/>
    <id>micro:824158283</id>
    <published>2021-04-21T15:35:06Z</published>
    <updated>2021-04-21T15:37:20Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Git 误操作，导致多出至少 1/3 的 commit 次数。 ...(｡•ˇ‸ˇ•｡) ...</p>]]></summary>
    <content type="html"><![CDATA[<p>Git 误操作，导致多出至少 1/3 的 commit 次数。 ...(｡•ˇ‸ˇ•｡) ...</p>
]]></content>
  </entry>
  <entry>
    <title>为什么数字货币使用区块链是政治问题</title>
    <link href="https://smallyu.net/2021/04/18/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%95%B0%E5%AD%97%E8%B4%A7%E5%B8%81%E4%BD%BF%E7%94%A8%E5%8C%BA%E5%9D%97%E9%93%BE%E6%98%AF%E6%94%BF%E6%B2%BB%E9%97%AE%E9%A2%98/"/>
    <id>blog:https://smallyu.net/2021/04/18/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%95%B0%E5%AD%97%E8%B4%A7%E5%B8%81%E4%BD%BF%E7%94%A8%E5%8C%BA%E5%9D%97%E9%93%BE%E6%98%AF%E6%94%BF%E6%B2%BB%E9%97%AE%E9%A2%98/</id>
    <published>2021-04-18T15:33:54.000Z</published>
    <updated>2025-11-09T09:22:13.310Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>本来不想再专门提区块链。由于工作相关，接触相关话题比较频繁。</p>
<p>最近，一个高级别的技术管理吐槽我 “数字货币不可能用区块链”]]></summary>
    <content type="html"><![CDATA[<p>本来不想再专门提区块链。由于工作相关，接触相关话题比较频繁。</p><p>最近，一个高级别的技术管理吐槽我 “数字货币不可能用区块链” 完全是外行的观点，即使只是把四大行的大额交易记录到区块链上，也是很好的一件事情，而且可以用分层交易的技术架构，顺势解决小额支付在区块链上性能受限的问题……</p><p>我的逻辑很简单。</p><p>假如区块链在世界上从来没有出现过，没有存在过。在这种情况下，如果“上面”要求各大银行的交易数据必须同步一致可追溯。下面的人能做到吗？</p><p>不但能做到，而且可以做得很好。</p><p>区块链能解决的问题，不用区块链也能解决。这几乎是众所周知的事情。这也是为什么有人说 “区块链没有新技术” 的原因。</p><p>当然，这里的 “数字货币” 特指中国的数字货币，“区块链” 指——在讨论区块链怎么用之前，是不是应该先把 “区块链是什么” 搞清楚？奇怪的是，似乎没有人关心这个问题。</p><p>在这个方面上，和区块链形成对比的是人工智能。人工智能能做的事情，如果技术跟不上，就确实做不到。</p>]]></content>
  </entry>
  <entry>
    <title>嘿，好久不见</title>
    <link href="https://crazy.smallyu.net/2021/04/11/%E5%98%BF%EF%BC%8C%E5%A5%BD%E4%B9%85%E4%B8%8D%E8%A7%81/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/04/11/%E5%98%BF%EF%BC%8C%E5%A5%BD%E4%B9%85%E4%B8%8D%E8%A7%81/</id>
    <published>2021-04-10T17:31:14.000Z</published>
    <updated>2025-08-16T03:27:11.405Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>电影《小丑》里有一句似有非有的台词，我也想说这句话，“我记不清曾经发生过什么……”</p>
<p>也许只有像海子那样有奇特经历的人，才能写出“面朝大海，春暖花开”这样充满美好的诗句。不过这种梦想看似简单，那可是海景房……</p>
<p>想到几个关于外语学习的讨论：</p>
]]></summary>
    <content type="html"><![CDATA[<p>电影《小丑》里有一句似有非有的台词，我也想说这句话，“我记不清曾经发生过什么……”</p><p>也许只有像海子那样有奇特经历的人，才能写出“面朝大海，春暖花开”这样充满美好的诗句。不过这种梦想看似简单，那可是海景房……</p><p>想到几个关于外语学习的讨论：</p><ol><li><p>某网友在回答我的提问“50岁还能学会日语吗？”时提到，学习一种外语，至少要上千个小时。</p></li><li><p>一个视频里的女性作者说，她刚到美国的时候，完全听不懂英语，然后就每天看那种谈话节目。三年后的突然有一天，她发现自己可以听懂了。后来她说学英语要看视频节目尤其是谈话节目，不要指望阅读材料更不要查单词，英语单词那么多查能会几个……</p></li><li><p>罗永浩在讲话中提到，他用一年多的时间，像坐牢一样地学习英语，成为了新东方的 GRE 教师。他后来培训学校的一个老师，用了大概六个月的时候成为 GRE 入门课的教师。</p></li><li><p>一个演讲视频里提到，演讲者在很多国家进行英语的教育，有一次她遇到一个听众用英语提问题，那位听众的英语水平一听就是 low level 的，但奇怪的是，和这位听众交流起来，甚至这位听众和其他人用英语交流，对话都非常流畅，虽然确实只是用了 low level 的英语。</p></li></ol><p>我比较在意上千小时这个数字。</p><ol><li>假如一天看 1 个小时的视频，1000 小时就需要接近 3 年的时间。</li><li>假如一天学习 8 个小时，学习 1 年大概是 3000 个小时。当然，一天 8 小时不是一般人能坚持的。</li><li>假如一天学习 6 个小时，学习 6 个月大概是 1000 个小时。</li></ol><p>数字是巧合的，光看数字可能无法断定什么，但基本上能够认为，技能的掌握情况和付出的学习时长有非线性但很强的关联关系。</p><p>虽然我以前不认可“工作经验”这种评价方式（比如中国古代的官僚制度里，满几年才有机会升迁之类），但一种技能确实需要足够的时间才有可能熟练掌握。更折磨人的地方在于，技能的掌握不是断崖式的，不会说昨天还不会，到了某个时间点，今天突然就会了。现实世界根本不存在这种类型的惊喜。</p><p>更常见的情况是，昨天一句话里面听懂了 1 个词，十天后一句话里面听懂了 2 个词，直到一百天后一句话里面可以听懂 10 个词了，但一句话总共有 20 个词，听懂 10 个词根本于事无补。两百天后能听懂 20 个词就可以了吗？语句千变万化，语气、语调、语速……更准确一点的比喻，就像一张图片从分辨率很低开始逐渐清晰，在完全清楚之前无法准确地识别内容但又可以稍微获取到一些信息，而且这张图片分辨率变高的位置和速度是不均匀的。</p><p>《神探夏洛克》里的夏洛克·福尔摩斯有个人设，就是关于探案所需要的知识技能无所不知无所不会，看一眼鞋底上沾的泥土就能知道一个人在最近三天的行程，知晓各种枪械的型号、子弹的直径以及各种场合对枪械的使用习惯。会把犯人尸体的人头搁在家里的冰箱研究人类死亡后唾液凝固的过程。就是这样的探案鬼才，却不知道一些常人知道的常识，比如月亮是绕着地球转的，地球是围着太阳转的。</p><p>猜到我想说什么了吗？也许而且一定是的，并不需要全知全会。无论是知识还是技能。如果非要说一种技能掌握到什么程度最合适，只能说，当下的情况就是一切刚刚好。这种观点正好和胡适的“怕什么真理无穷”不谋而合 :P</p><p>顺便提一下，我对“知识”和“技能”的分类方法是，知识是可以短时间内知晓并理解的规则，而技能则是很多很多个知识组合起来形成的可以解决一类问题的方式。知识可以用 3 分钟的时间掌握，而技能需要 3 + 3 + 3 + …… 如果用有没有掌握某几个知识来判断一个人的技能情况，是以偏概全的。</p><p>生硬地切换一下话题。最近发现一种有趣的桌游叫剧本杀，虽然经常不尽人意但总还会留有兴趣。戏剧演员有两大表演体系，布莱希特体系和斯坦尼斯拉夫斯基体系，也就是体验派和表演派，在游戏里，我倾向于体验……当然，对这种游戏有个感触：我会玩的是游戏，不会玩的是人心。游戏有好有坏，剧本有好有坏，玩家有好有坏，体验有好有坏，心情有好有坏……</p><p>太阳底下没有新鲜事，但是太阳总会照常升起。</p><p>我也想有一间房子，面朝大海，春暖花开。</p><p>明天你好。</p>]]></content>
  </entry>
  <entry>
    <title>分享两个比较喜欢的异曲同工的句子： （1） 8 岁的小外甥跟我说，他喜欢上了一个女孩。 我问他，“你知道什么是喜欢吗？”...</title>
    <link href="https://t.smallyu.net/#2021-28"/>
    <id>micro:813151790</id>
    <published>2021-04-05T02:46:29Z</published>
    <updated>2021-04-05T02:46:29Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>分享两个比较喜欢的异曲同工的句子： （1） 8 岁的小外甥跟我说，他喜欢上了一个女孩。 我问他，“你知道什么是喜欢吗？” 他说：“我不喜欢胖的，但她胖就没事。” （2） 有时候，喜欢就是喜欢，与理性无关。 —— 选自散文集《我在人间凑数的日子》</p>]]></summary>
    <content type="html"><![CDATA[<p>分享两个比较喜欢的异曲同工的句子：</p>
<p>（1）</p>
<blockquote>
<p>8 岁的小外甥跟我说，他喜欢上了一个女孩。</p>
<p>我问他，“你知道什么是喜欢吗？”</p>
<p>他说：“我不喜欢胖的，但她胖就没事。”</p>
</blockquote>
<p>（2）</p>
<blockquote>
<p>有时候，喜欢就是喜欢，与理性无关。</p>
<p>—— 选自散文集《我在人间凑数的日子》</p>
</blockquote>
]]></content>
  </entry>
  <entry>
    <title>如果一个人认识了 1000 个异性，然后从这 1000 个人里面出来 1 个志趣相投的、合适的、不会互相嫌弃的人度过余生...</title>
    <link href="https://t.smallyu.net/#2021-27"/>
    <id>micro:813151245</id>
    <published>2021-04-05T02:43:47Z</published>
    <updated>2021-04-05T02:43:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果一个人认识了 1000 个异性，然后从这 1000 个人里面出来 1 个志趣相投的、合适的、不会互相嫌弃的人度过余生，这个比例不低吧，1000 : 1，要放弃所有其他的可能性，在接下来至少 30 年一起生活。 假如一周可以 “ 认识 ” 5 个人，这个数量不少了，那么一个月就是 20 个人。想认识 1000 个人需...</p>]]></summary>
    <content type="html"><![CDATA[<p>如果一个人认识了 1000 个异性，然后从这 1000 个人里面出来 1 个志趣相投的、合适的、不会互相嫌弃的人度过余生，这个比例不低吧，1000 : 1，要放弃所有其他的可能性，在接下来至少 30 年一起生活。</p>
<p>假如一周可以 “ 认识 ” 5 个人，这个数量不少了，那么一个月就是 20 个人。想认识 1000 个人需要多长时间？ 50 个月，也就是 4 年多。</p>
<p>而且除非职业特殊，不然怎么保证每周认识新人的这种高频率……</p>
<p>知道你为什么单身了吗？ :P</p>
<p><strong>附</strong> ：可以试着分别用 深度搜索优先 和 广度搜索优先 的思想分析这件事情。</p>
]]></content>
  </entry>
  <entry>
    <title>Crystal 发布了 1.0.0 版本。 面向过程和面向对象的编程语言都需要边界来确认代码块的范围，一种是从 C 语言...</title>
    <link href="https://t.smallyu.net/#2021-26"/>
    <id>micro:804546383</id>
    <published>2021-03-23T03:01:43Z</published>
    <updated>2021-03-23T03:01:43Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Crystal 发布了 1.0.0 版本。 面向过程和面向对象的编程语言都需要边界来确认代码块的范围，一种是从 C 语言开始就用的大括号 {} ，一种是 Pyhton 那样严格控制缩进用的空格 ，还有一种就是像 Crystal 或者 Ruby 这样用 end 作为边界（Visual Basic 也是）。 Cystal...</p>]]></summary>
    <content type="html"><![CDATA[<p>Crystal 发布了 1.0.0 版本。</p>
<p>面向过程和面向对象的编程语言都需要边界来确认代码块的范围，一种是从 C 语言开始就用的大括号 <code>{}</code>，一种是 Pyhton 那样严格控制缩进用的空格 <code> </code>，还有一种就是像 Crystal 或者 Ruby 这样用 <code>end</code> 作为边界（Visual Basic 也是）。</p>
<p>Cystal 不仅支持静态编译，在语法上还可以直接和作为脚本语言的 Ruby 相对比，非常简洁，但是太过简洁的语法又少了一点连贯性，比如表达 <code>向 channel 发送变量的值</code>，会用 <code>channel.send lines.size</code> 这样的语句，感觉就是孤零零的两个变量并排放在那儿，虽然比 Go 语言的 <code>&lt;-</code> 可以少打一个符号，但并没有 Go 语言的写法看起来直观。</p>
]]></content>
  </entry>
  <entry>
    <title>（1） 演讲者：“ 我要表达一个观点，1+1=3。因为……所以……证明过程是……第 1 步……第 2 步……” 主持人：...</title>
    <link href="https://t.smallyu.net/#2021-25"/>
    <id>micro:801629527</id>
    <published>2021-03-18T05:08:12Z</published>
    <updated>2021-03-18T05:13:07Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>（1） 演讲者：“ 我要表达一个观点，1+1=3。因为……所以……证明过程是……第 1 步……第 2 步……” 主持人：“ 观众有问题要问的吗？” 观众：“ 在这个问题上，我的看法是……对于第 x 步证明，我的理解是……” （2） 演讲者：“ 不管你们知不知道，我都要告诉你们这个，我要教育你们，1+1=2，我也不知道为...</p>]]></summary>
    <content type="html"><![CDATA[<p>（1）  </p>
<p>演讲者：“ 我要表达一个观点，1+1=3。因为……所以……证明过程是……第 1 步……第 2 步……” </p>
<p>主持人：“ 观众有问题要问的吗？”  </p>
<p>观众：“ 在这个问题上，我的看法是……对于第 x 步证明，我的理解是……”</p>
<p>（2）  </p>
<p>演讲者：“ 不管你们知不知道，我都要告诉你们这个，我要教育你们，1+1=2，我也不知道为什么 1+1=2，别人都是这么说的，我就是要告诉你们。”  </p>
<p>主持人：“ 观众有问题要问的吗？”  </p>
<p>观众：“ ？”  </p>
]]></content>
  </entry>
  <entry>
    <title>D 语言也是很好的编程语言啊，可是没有生态。</title>
    <link href="https://t.smallyu.net/#2021-24"/>
    <id>micro:799172148</id>
    <published>2021-03-15T07:07:49Z</published>
    <updated>2021-03-15T07:07:49Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>D 语言也是很好的编程语言啊，可是没有生态。</p>]]></summary>
    <content type="html"><![CDATA[<p>D 语言也是很好的编程语言啊，可是没有生态。</p>
]]></content>
  </entry>
  <entry>
    <title>（1） 在一次讨论中，我提出过一个问题，“ xxx 是 yyy 吗？” 其实我只是提出问题，并不期望有人给出多么正确的答...</title>
    <link href="https://t.smallyu.net/#2021-23"/>
    <id>micro:797166716</id>
    <published>2021-03-12T01:21:40Z</published>
    <updated>2021-03-12T01:23:14Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>（1） 在一次讨论中，我提出过一个问题，“ xxx 是 yyy 吗？” 其实我只是提出问题，并不期望有人给出多么正确的答案。因为虽然表面上是技术问题，但实际上是可以上升到哲学高度的问题。我认为短时间内是不会有明确答案的。 没想到后来有一个人信誓旦旦的对我说，xxx 就是 yyy，因为他看了 xxx 官网，官网上就是那么...</p>]]></summary>
    <content type="html"><![CDATA[<p>（1）</p>
<p>在一次讨论中，我提出过一个问题，“ xxx 是 yyy 吗？” 其实我只是提出问题，并不期望有人给出多么正确的答案。因为虽然表面上是技术问题，但实际上是可以上升到哲学高度的问题。我认为短时间内是不会有明确答案的。</p>
<p>没想到后来有一个人信誓旦旦的对我说，xxx 就是 yyy，因为他看了 xxx 官网，官网上就是那么分类的（且不说官网上其实没有明确分类）。</p>
<p>（2）</p>
<p>想到以前脉脉的职言区有一件很出名的事情，一个在外包公司（某通）工作了五六年的人，说自己工作这几年什么都接触过，精通各个领域，欢迎大家来提问，挑战全网，红极一时，人称 “外包哥” 。根据后续的对答内容，可以看出外包哥确实是有很丰富的多领域工作经验。</p>
<p>我想起某个厉害的人关于《Java 有值类型吗》的文章，就在脉脉上的帖子留言问题，“Java 有值类型吗？”</p>
<p>得到的回答是，“Java 培训班的第一节课就讲到这个了”。潜台词是，Java 的文档怎么说，就是什么。</p>
<p>（3）</p>
<p>也许像这些有丰富实操经验但思维高度受限的人，会以别人、别的企业、别的组织机构的言论和结论为绝对的准则。</p>
]]></content>
  </entry>
  <entry>
    <title>房间里的花几个月没浇水，叶子已经变黑变枯了。后来时不时浇点水，今天发现从中间长出了新的绿色的叶子。</title>
    <link href="https://t.smallyu.net/#2021-22"/>
    <id>micro:796760290</id>
    <published>2021-03-11T14:05:54Z</published>
    <updated>2021-03-11T14:05:54Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>房间里的花几个月没浇水，叶子已经变黑变枯了。后来时不时浇点水，今天发现从中间长出了新的绿色的叶子。</p>]]></summary>
    <content type="html"><![CDATA[<p>房间里的花几个月没浇水，叶子已经变黑变枯了。后来时不时浇点水，今天发现从中间长出了新的绿色的叶子。</p>
]]></content>
  </entry>
  <entry>
    <title>之前看到个段子，内容大概是一个人买了昂贵的 VR 设备，在网络上下载了 8K 清晰度的 VR 视频，视觉体验本身非常好，...</title>
    <link href="https://t.smallyu.net/#2021-21"/>
    <id>micro:792283768</id>
    <published>2021-03-07T13:59:33Z</published>
    <updated>2021-03-07T13:59:33Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>之前看到个段子，内容大概是一个人买了昂贵的 VR 设备，在网络上下载了 8K 清晰度的 VR 视频，视觉体验本身非常好，但是当他看到，视频里面容精致的女孩对着他点头微笑在他身边走来走去，他意识到他永远也无法真正得到那样的女孩。他说，VR 视频会毁了一个人。 类似的，在某个群里有人谈到某些问题时说，千万不要因为寂寞找外围...</p>]]></summary>
    <content type="html"><![CDATA[<p>之前看到个段子，内容大概是一个人买了昂贵的 VR 设备，在网络上下载了 8K 清晰度的 VR 视频，视觉体验本身非常好，但是当他看到，视频里面容精致的女孩对着他点头微笑在他身边走来走去，他意识到他永远也无法真正得到那样的女孩。他说，VR 视频会毁了一个人。</p>
<p>类似的，在某个群里有人谈到某些问题时说，千万不要因为寂寞找外围，他朋友的亲身经历，那样只会更加空虚和迷茫。</p>
<p>这样的情绪应该类似于说出 “天下没有不散的筵席” 时候的落寞感。只不过有的人会落寞，有的人则宴会一场接着一场，这场宴会结束奔赴下一场就是了。</p>
<p>有感而发。</p>
]]></content>
  </entry>
  <entry>
    <title>“创造万物的神，请宽恕我们的魂”</title>
    <link href="https://t.smallyu.net/#2021-20"/>
    <id>micro:784851858</id>
    <published>2021-02-24T07:18:28Z</published>
    <updated>2021-02-24T07:18:28Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“创造万物的神，请宽恕我们的魂”</p>]]></summary>
    <content type="html"><![CDATA[<p>“创造万物的神，请宽恕我们的魂”</p>
]]></content>
  </entry>
  <entry>
    <title>郭德纲不止一次在节目里谈到和某人的师徒关系的时候说，“比方说我有五十个徒弟，里面走了 俩，那么我的问题就不大。” 如果走...</title>
    <link href="https://t.smallyu.net/#2021-19"/>
    <id>micro:783101290</id>
    <published>2021-02-22T05:44:50Z</published>
    <updated>2021-02-22T05:44:50Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>郭德纲不止一次在节目里谈到和某人的师徒关系的时候说，“比方说我有五十个徒弟，里面走了 俩，那么我的问题就不大。” 如果走的是能力最强的两个，可能就有问题了。</p>]]></summary>
    <content type="html"><![CDATA[<p>郭德纲不止一次在节目里谈到和某人的师徒关系的时候说，“比方说我有五十个徒弟，里面走了 俩，那么我的问题就不大。”</p>
<p>如果走的是能力最强的两个，可能就有问题了。</p>
]]></content>
  </entry>
  <entry>
    <title>passerine 是一个新的、似乎同样没什么明显特点的编程语言。</title>
    <link href="https://t.smallyu.net/#2021-18"/>
    <id>micro:783099332</id>
    <published>2021-02-22T05:40:35Z</published>
    <updated>2021-02-22T05:40:35Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>passerine 是一个新的、似乎同样没什么明显特点的编程语言。</p>]]></summary>
    <content type="html"><![CDATA[<p>passerine 是一个新的、似乎同样没什么明显特点的编程语言。</p>
]]></content>
  </entry>
  <entry>
    <title>现在，我在路上散步，又看到一个睡在路边长凳上的人，穿的旧一点，没有行李。白天好像也没看到这样的人，或者没注意。今天倒是不...</title>
    <link href="https://t.smallyu.net/#2021-17"/>
    <id>micro:782884067</id>
    <published>2021-02-21T16:25:06Z</published>
    <updated>2021-02-21T16:25:06Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>现在，我在路上散步，又看到一个睡在路边长凳上的人，穿的旧一点，没有行李。白天好像也没看到这样的人，或者没注意。今天倒是不冷。</p>]]></summary>
    <content type="html"><![CDATA[<p>现在，我在路上散步，又看到一个睡在路边长凳上的人，穿的旧一点，没有行李。白天好像也没看到这样的人，或者没注意。今天倒是不冷。</p>
]]></content>
  </entry>
  <entry>
    <title>zig 的“复杂”程度可能是冲着 Rust 去的...</title>
    <link href="https://t.smallyu.net/#2021-16"/>
    <id>micro:781000624</id>
    <published>2021-02-18T02:35:20Z</published>
    <updated>2021-02-18T02:35:35Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>zig 的“复杂”程度可能是冲着 Rust 去的...</p>]]></summary>
    <content type="html"><![CDATA[<p>zig 的“复杂”程度可能是冲着 Rust 去的...</p>
]]></content>
  </entry>
  <entry>
    <title>在一个视频短片里看到一句话，出自贾平凹的《废都》： 说你行你就行，不行也行；说你不行你就不行，行也不行。 这句话实在是太...</title>
    <link href="https://t.smallyu.net/#2021-15"/>
    <id>micro:779850574</id>
    <published>2021-02-16T13:53:12Z</published>
    <updated>2021-02-16T14:00:39Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>在一个视频短片里看到一句话，出自贾平凹的《废都》： 说你行你就行，不行也行；说你不行你就不行，行也不行。 这句话实在是太有意思了！</p>]]></summary>
    <content type="html"><![CDATA[<p>在一个视频短片里看到一句话，出自贾平凹的《废都》：</p>
<blockquote>
<p>说你行你就行，不行也行；说你不行你就不行，行也不行。</p>
</blockquote>
<p>这句话实在是太有意思了！</p>
]]></content>
  </entry>
  <entry>
    <title>就在刚才，看到路边一个睡在长凳上的人，旁边放着行李箱和小自行车。 就是现在，此时此刻，我在路上散步，寒风刺骨，手不敢拿出...</title>
    <link href="https://t.smallyu.net/#2021-14"/>
    <id>micro:779350947</id>
    <published>2021-02-15T17:04:26Z</published>
    <updated>2021-02-16T07:54:24Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>就在刚才，看到路边一个睡在长凳上的人，旁边放着行李箱和小自行车。 就是现在，此时此刻，我在路上散步，寒风刺骨，手不敢拿出口袋，帽子不敢摘下来，冻耳朵。 马路上车来车往，旁边就是快捷酒店。</p>]]></summary>
    <content type="html"><![CDATA[<p>就在刚才，看到路边一个睡在长凳上的人，旁边放着行李箱和小自行车。</p>
<p>就是现在，此时此刻，我在路上散步，寒风刺骨，手不敢拿出口袋，帽子不敢摘下来，冻耳朵。</p>
<p>马路上车来车往，旁边就是快捷酒店。</p>
]]></content>
  </entry>
  <entry>
    <title>博客主题共享计划（草稿）</title>
    <link href="https://crazy.smallyu.net/2021/02/11/%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98%E5%85%B1%E4%BA%AB%E8%AE%A1%E5%88%92/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2021/02/11/%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98%E5%85%B1%E4%BA%AB%E8%AE%A1%E5%88%92/</id>
    <published>2021-02-11T06:48:31.000Z</published>
    <updated>2026-07-04T17:36:19.119Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>两个月前写下了这篇草稿，直到今天（04.10）想起来，觉得还是发出来。当初不发的原因之一是，我没能真正把项目维护起来。想把一个软件做到人人喜欢、人人适用其实是一件很有难度的事情，而且博客主题这样的东西受限于各种环境依赖的版本，还是不折腾了。借用《妖猫传》里的一句话，“事是假的，情是真的”。祝好。</p><h3 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h3><p>现在用的博客主题，模仿自王垠的博客 <a href="http://www.yinwang.org/">当然我在扯淡</a>。几年前，我把模仿的博客主题开源在 Github 上（<a href="https://github.com/smallyunet/hexo-theme-yinwang">smallyunet&#x2F;hexo-theme-yinwang</a>）。虽然我经常更新和优化自己博客的主题，但是开源的仓库已经很久没有更新了。</p><p>一方面，不确定模仿主题算不算侵权。另一方面，我一直心怀芥蒂的是，我并没有想要依靠这样的项目来“赚星星”，我甚至不希望这样的项目出现在我的 GitHub 主页上，于是不得不开始自定义主页的项目面板。总的来说，因为这个东西不是我的，就像《夏洛特烦恼》中的夏洛，穿越回 1997 年后依靠周杰伦的作品火遍西虹市，可他终究发现那些东西不是他的。他只是做了一个很漂亮的梦。</p><p>现在，我想继续维护这个将博客主题开源的项目。</p><p>捂着不让人用、让人用着不舒服，这显然都不对，愚昧不会阻止真理的传播，好用的东西也应该被更好的利用。我甚至希望，这个主题样式可以成为一种标志，标志受到王垠鼓舞的人们，标志拥有正直和善良品质的人们，标志拥有真知灼见的人们。</p><p>这不是宗教情绪，我们不盲目信任和崇拜某人，我们崇尚 <a href="http://www.yinwang.org/blog-cn/2017/11/01/power-of-reasoning">理性的力量</a>（by yinwang）。我们不拉帮结派，不宣扬、不强制别人使用或者不使用什么，不强制别人相信或者不相信什么。我们以某人为“偶像”，自诩为某人的“粉丝”，不是因为我们归属于某种团体的莫名其妙的优越感，而是因为我们从他那里学到了很多可贵而难以言喻的东西。当我们在说“喜欢某人”的时候，其实想表达的不是某人有多么厉害，而是在说，“我们从他那里学到了一些东西，因为会的这些东西，所以我们也很厉害”。</p><p>很意外今天突然想到了这样一件事情，有点意外，有点惊喜，有点害怕和担心。今天刚好是农历大年三十，新年快乐。</p>]]></content>
  </entry>
  <entry>
    <title>刚看到竟然有人 50 元卖 clubhouse 邀请码。 clubhouse 这样的开房间多人语音聊天的功能，国内很多...</title>
    <link href="https://t.smallyu.net/#2021-13"/>
    <id>micro:776803189</id>
    <published>2021-02-10T15:44:43Z</published>
    <updated>2021-02-10T16:09:29Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>刚看到竟然有人 50 元卖 clubhouse 邀请码。 clubhouse 这样的开房间多人语音聊天的功能，国内很多 APP 像陌陌、探探之类几年前就有了吧，而且还带各种游戏和互动形式。clubhouse 大概是因为目前的邀请制，人员质量稍高一点，才有了一点热度。 不过现在国内已经用不了了，就是这两天的事，+86 开...</p>]]></summary>
    <content type="html"><![CDATA[<p>刚看到竟然有人 50 元卖 clubhouse 邀请码。</p>
<p>clubhouse 这样的开房间多人语音聊天的功能，国内很多 APP 像陌陌、探探之类几年前就有了吧，而且还带各种游戏和互动形式。clubhouse 大概是因为目前的邀请制，人员质量稍高一点，才有了一点热度。</p>
<p>不过现在国内已经用不了了，就是这两天的事，+86 开头的手机号码收不到短信验证码了。今天在一个 Telegram 群里看到有人说，退出登录后再登录进去，就可以多出几个邀请码。我想试一下，结果退出登录以后就再也没办法登录进去了，因为收不到短信验证码。当然是国内的动作了，Google Voice 号码一切正常。</p>
<p>话说 clubhouse 到底有什么好玩的，说话的人基本是依次发言，效率本身就很低，还说不出什么有用的。最大的感受就是这帮人好闲啊。</p>
]]></content>
  </entry>
  <entry>
    <title>Haxe 那样的编程语言，只能是玩具了吧。</title>
    <link href="https://t.smallyu.net/#2021-12"/>
    <id>micro:776517701</id>
    <published>2021-02-10T07:56:53Z</published>
    <updated>2021-02-12T15:36:45Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Haxe 那样的编程语言，只能是玩具了吧。</p>]]></summary>
    <content type="html"><![CDATA[<p>Haxe 那样的编程语言，只能是玩具了吧。</p>
]]></content>
  </entry>
  <entry>
    <title>终于找到了遥远记忆里印象深刻的一个短篇小说，叫《山药粥》，作者是芥川龙之介。曾经多次尝试寻找，但总误以为小说的作者是汪曾...</title>
    <link href="https://t.smallyu.net/#2021-11"/>
    <id>micro:774588807</id>
    <published>2021-02-07T03:50:38Z</published>
    <updated>2021-02-07T03:59:43Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>终于找到了遥远记忆里印象深刻的一个短篇小说，叫《山药粥》，作者是芥川龙之介。曾经多次尝试寻找，但总误以为小说的作者是汪曾祺。《山药粥》故事贴切，用词地道，原作者竟然不是本国人。 似乎是远在中学时代无意间在课本上看到的一篇小说，没想到多年来念念不忘。时间越是久远，越体会到小说深刻的立意，尤其是每当产生某种共鸣的情绪时。用...</p>]]></summary>
    <content type="html"><![CDATA[<p>终于找到了遥远记忆里印象深刻的一个短篇小说，叫《山药粥》，作者是芥川龙之介。曾经多次尝试寻找，但总误以为小说的作者是汪曾祺。《山药粥》故事贴切，用词地道，原作者竟然不是本国人。</p>
<p>似乎是远在中学时代无意间在课本上看到的一篇小说，没想到多年来念念不忘。时间越是久远，越体会到小说深刻的立意，尤其是每当产生某种共鸣的情绪时。用现在流行的一句话来说，就是 “小丑竟是我自己”。</p>
]]></content>
  </entry>
  <entry>
    <title>只有悲伤到极致的人，才能写出让人看一眼就感受到幸福的句子。</title>
    <link href="https://t.smallyu.net/#2021-10"/>
    <id>micro:767944926</id>
    <published>2021-01-27T01:27:15Z</published>
    <updated>2021-01-27T04:23:24Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>只有悲伤到极致的人，才能写出让人看一眼就感受到幸福的句子。</p>]]></summary>
    <content type="html"><![CDATA[<p>只有悲伤到极致的人，才能写出让人看一眼就感受到幸福的句子。</p>
]]></content>
  </entry>
  <entry>
    <title>人类文明进化的标志，是学会隐藏动物的本能和原始的冲动。</title>
    <link href="https://t.smallyu.net/#2021-9"/>
    <id>micro:766396964</id>
    <published>2021-01-24T17:15:48Z</published>
    <updated>2021-01-24T17:15:48Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>人类文明进化的标志，是学会隐藏动物的本能和原始的冲动。</p>]]></summary>
    <content type="html"><![CDATA[<p>人类文明进化的标志，是学会隐藏动物的本能和原始的冲动。</p>
]]></content>
  </entry>
  <entry>
    <title>V 语言是在语法上更优雅的 Go 语言。</title>
    <link href="https://t.smallyu.net/#2021-8"/>
    <id>micro:763499449</id>
    <published>2021-01-20T10:19:31Z</published>
    <updated>2021-01-20T14:48:28Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>V 语言是在语法上更优雅的 Go 语言。</p>]]></summary>
    <content type="html"><![CDATA[<p>V 语言是在语法上更优雅的 Go 语言。</p>
]]></content>
  </entry>
  <entry>
    <title>一个比喻： 在大家都没有手机的时候，有的人手里有 1000 块钱，买了个小米的低端机，有的人存了 3000 块钱，买了个...</title>
    <link href="https://t.smallyu.net/#2021-7"/>
    <id>micro:761303168</id>
    <published>2021-01-16T03:19:07Z</published>
    <updated>2021-01-16T03:19:07Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>一个比喻： 在大家都没有手机的时候，有的人手里有 1000 块钱，买了个小米的低端机，有的人存了 3000 块钱，买了个小米的旗舰机。然后这些人就嘲笑我说，为什么你还没有手机，看我们都有，你好可怜，快点买一个吧，再不买就买不到了。 我只是在攒钱买高配苹果而已。</p>]]></summary>
    <content type="html"><![CDATA[<p>一个比喻：</p>
<p>在大家都没有手机的时候，有的人手里有 1000 块钱，买了个小米的低端机，有的人存了 3000 块钱，买了个小米的旗舰机。然后这些人就嘲笑我说，为什么你还没有手机，看我们都有，你好可怜，快点买一个吧，再不买就买不到了。</p>
<p>我只是在攒钱买高配苹果而已。</p>
]]></content>
  </entry>
  <entry>
    <title>“课程质量高” 不等于 “课程内容高深” 光是明确这一概念上的区别，就能得到很多有意思的结论。</title>
    <link href="https://t.smallyu.net/#2021-6"/>
    <id>micro:760641180</id>
    <published>2021-01-15T04:41:50Z</published>
    <updated>2021-01-15T04:41:50Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“课程质量高” 不等于 “课程内容高深” 光是明确这一概念上的区别，就能得到很多有意思的结论。</p>]]></summary>
    <content type="html"><![CDATA[<p>“课程质量高” 不等于 “课程内容高深”</p>
<p>光是明确这一概念上的区别，就能得到很多有意思的结论。</p>
]]></content>
  </entry>
  <entry>
    <title>因故，前几天开始看几本关于所谓“人情世故”的书。以前没有了解过，也不是很感兴趣，虽然意识里稍微有点不喜欢的情绪存在，但是...</title>
    <link href="https://t.smallyu.net/#2021-5"/>
    <id>micro:758412719</id>
    <published>2021-01-12T05:29:21Z</published>
    <updated>2021-01-12T05:29:21Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>因故，前几天开始看几本关于所谓“人情世故”的书。以前没有了解过，也不是很感兴趣，虽然意识里稍微有点不喜欢的情绪存在，但是并没有理由吐槽什么。现在就这两三本书的内容来看，可以确实的说：这 TM 都什么玩意儿……</p>]]></summary>
    <content type="html"><![CDATA[<p>因故，前几天开始看几本关于所谓“人情世故”的书。以前没有了解过，也不是很感兴趣，虽然意识里稍微有点不喜欢的情绪存在，但是并没有理由吐槽什么。现在就这两三本书的内容来看，可以确实的说：这 TM 都什么玩意儿……</p>
]]></content>
  </entry>
  <entry>
    <title>我目前还没有过报销加班费之类，因为感觉太“麻烦”了。 刚才看到 2010 年罗永浩在海淀剧院的演讲视频，谈到他们作为一个...</title>
    <link href="https://t.smallyu.net/#2021-4"/>
    <id>micro:757419450</id>
    <published>2021-01-10T05:24:43Z</published>
    <updated>2021-01-10T05:52:33Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>我目前还没有过报销加班费之类，因为感觉太“麻烦”了。 刚才看到 2010 年罗永浩在海淀剧院的演讲视频，谈到他们作为一个小机构的员工待遇时，说很多公司确实是有加班费，但是申请流程繁琐，需要找三四个领导盖五六个戳，把合法获得自己的劳动报酬变成一件耻辱性的事情，他有个朋友申请过一次后就说再也不会申请了。他们机构是不会那样的...</p>]]></summary>
    <content type="html"><![CDATA[<p>我目前还没有过报销加班费之类，因为感觉太“麻烦”了。</p>
<p>刚才看到 2010 年罗永浩在海淀剧院的演讲视频，谈到他们作为一个小机构的员工待遇时，说很多公司确实是有加班费，但是申请流程繁琐，需要找三四个领导盖五六个戳，把合法获得自己的劳动报酬变成一件耻辱性的事情，他有个朋友申请过一次后就说再也不会申请了。他们机构是不会那样的。</p>
<p>原来不只有我一个人那么想。</p>
]]></content>
  </entry>
  <entry>
    <title>以前没太明白，为什么总是有的人任劳任怨，没有鲜明的观点，更不会做极端的事情。 后来意识到，它们工资高…… 它们并不在意真...</title>
    <link href="https://t.smallyu.net/#2021-3"/>
    <id>micro:756650318</id>
    <published>2021-01-08T09:28:58Z</published>
    <updated>2021-01-08T09:33:25Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>以前没太明白，为什么总是有的人任劳任怨，没有鲜明的观点，更不会做极端的事情。 后来意识到，它们工资高…… 它们并不在意真正的正确和错误。 这个无聊的世界…… 如果有一天我变了，要记得我曾经是少年。</p>]]></summary>
    <content type="html"><![CDATA[<p>以前没太明白，为什么总是有的人任劳任怨，没有鲜明的观点，更不会做极端的事情。</p>
<p>后来意识到，它们工资高……</p>
<p>它们并不在意真正的正确和错误。</p>
<p>这个无聊的世界……</p>
<p>如果有一天我变了，要记得我曾经是少年。</p>
]]></content>
  </entry>
  <entry>
    <title>大人们经常给小孩子构建一个美好的社会。小孩子在长大后，会发现工程师并不厉害，科学家并不伟大，老师的行为并不是无私的，医生...</title>
    <link href="https://t.smallyu.net/#2021-2"/>
    <id>micro:755353851</id>
    <published>2021-01-06T15:08:17Z</published>
    <updated>2021-01-06T15:09:06Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>大人们经常给小孩子构建一个美好的社会。小孩子在长大后，会发现工程师并不厉害，科学家并不伟大，老师的行为并不是无私的，医生的工作也不是神圣的。小孩子不断长大的过程，是一个不断失望的过程。 如果从小就让小孩子看到现实，他们不断长大的过程，将变成不断发现美好的过程。“本以为警察是为了谋生才疲于奔波，没想到偶尔也会散发正义的光...</p>]]></summary>
    <content type="html"><![CDATA[<p>大人们经常给小孩子构建一个美好的社会。小孩子在长大后，会发现工程师并不厉害，科学家并不伟大，老师的行为并不是无私的，医生的工作也不是神圣的。小孩子不断长大的过程，是一个不断失望的过程。</p>
<p>如果从小就让小孩子看到现实，他们不断长大的过程，将变成不断发现美好的过程。“本以为警察是为了谋生才疲于奔波，没想到偶尔也会散发正义的光辉，世界多么美好！”</p>
]]></content>
  </entry>
  <entry>
    <title>图灵：learning machine ... 冯诺依曼：computing machine ...</title>
    <link href="https://t.smallyu.net/#2021-1"/>
    <id>micro:755093746</id>
    <published>2021-01-06T05:43:31Z</published>
    <updated>2021-01-06T05:53:46Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>图灵：learning machine ... 冯诺依曼：computing machine ...</p>]]></summary>
    <content type="html"><![CDATA[<p>图灵：learning machine ...<br>冯诺依曼：computing machine ...</p>
]]></content>
  </entry>
  <entry>
    <title>所以为什么在讨论图灵的光环的时候，对图灵的 imitation game 和 learning machine 只字未提...</title>
    <link href="https://t.smallyu.net/#2020-33"/>
    <id>micro:748643153</id>
    <published>2020-12-20T18:26:22Z</published>
    <updated>2020-12-20T18:26:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>所以为什么在讨论图灵的光环的时候，对图灵的 imitation game 和 learning machine 只字未提？</p>]]></summary>
    <content type="html"><![CDATA[<p>所以为什么在讨论图灵的光环的时候，对图灵的 imitation game 和 learning machine 只字未提？</p>
]]></content>
  </entry>
  <entry>
    <title>单纯的记忆是没有意义的，把书本和网络上的内容背下来，只能“显得”厉害，欺骗愚昧的人。如果把计算机和互联网理解成另一种形式...</title>
    <link href="https://t.smallyu.net/#2020-32"/>
    <id>micro:748637286</id>
    <published>2020-12-20T17:37:22Z</published>
    <updated>2020-12-20T17:37:22Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>单纯的记忆是没有意义的，把书本和网络上的内容背下来，只能“显得”厉害，欺骗愚昧的人。如果把计算机和互联网理解成另一种形式的生物，它将比任何人类都博学。</p>]]></summary>
    <content type="html"><![CDATA[<p>单纯的记忆是没有意义的，把书本和网络上的内容背下来，只能“显得”厉害，欺骗愚昧的人。如果把计算机和互联网理解成另一种形式的生物，它将比任何人类都博学。</p>
]]></content>
  </entry>
  <entry>
    <title>才注意到《老友记》的原剧名是 Friends ，我一开始还用 &amp;quot;old friends&amp;quot; 的关键词去...</title>
    <link href="https://t.smallyu.net/#2020-31"/>
    <id>micro:742899460</id>
    <published>2020-12-11T01:08:58Z</published>
    <updated>2020-12-11T05:46:27Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>才注意到《老友记》的原剧名是 Friends ，我一开始还用 &amp;quot;old friends&amp;quot; 的关键词去搜，结果搜不到。这个剧名有更好的翻译吗？似乎没有。还是不要翻译了。</p>]]></summary>
    <content type="html"><![CDATA[<p>才注意到《老友记》的原剧名是 <em>Friends</em>，我一开始还用 &quot;old friends&quot; 的关键词去搜，结果搜不到。这个剧名有更好的翻译吗？似乎没有。还是不要翻译了。</p>
]]></content>
  </entry>
  <entry>
    <title>似乎只有中国人才喜欢用 “xxx之父” 这种含有个人崇拜意味的话。 可以对比一下 “没有银弹” 这个词在 Wikiped...</title>
    <link href="https://t.smallyu.net/#2020-30"/>
    <id>micro:742175551</id>
    <published>2020-12-10T01:36:39Z</published>
    <updated>2020-12-10T01:36:39Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>似乎只有中国人才喜欢用 “xxx之父” 这种含有个人崇拜意味的话。 可以对比一下 “没有银弹” 这个词在 Wikipedia 上的中文、英文、日文版本： 没有银弹 No Silver Bullet 銀の弾などない</p>]]></summary>
    <content type="html"><![CDATA[<p>似乎只有中国人才喜欢用 “xxx之父” 这种含有个人崇拜意味的话。</p>
<p>可以对比一下 “没有银弹” 这个词在 Wikipedia 上的中文、英文、日文版本：</p>
<ul>
<li><a href="https://zh.wikipedia.org/wiki/%E6%B2%A1%E6%9C%89%E9%93%B6%E5%BC%B9">没有银弹</a></li>
<li><a href="https://en.wikipedia.org/wiki/No_Silver_Bullet">No Silver Bullet</a></li>
<li><a href="https://ja.wikipedia.org/wiki/%E9%8A%80%E3%81%AE%E5%BC%BE%E3%81%AA%E3%81%A9%E3%81%AA%E3%81%84">銀の弾などない</a></li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>区块链：下一代数字身份认证体系的基石</title>
    <link href="https://smallyu.net/2020/12/08/%E5%8C%BA%E5%9D%97%E9%93%BE%EF%BC%9A%E4%B8%8B%E4%B8%80%E4%BB%A3%E6%95%B0%E5%AD%97%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E4%BD%93%E7%B3%BB%E7%9A%84%E5%9F%BA%E7%9F%B3/"/>
    <id>blog:https://smallyu.net/2020/12/08/%E5%8C%BA%E5%9D%97%E9%93%BE%EF%BC%9A%E4%B8%8B%E4%B8%80%E4%BB%A3%E6%95%B0%E5%AD%97%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E4%BD%93%E7%B3%BB%E7%9A%84%E5%9F%BA%E7%9F%B3/</id>
    <published>2020-12-08T12:02:38.000Z</published>
    <updated>2025-11-09T09:22:13.316Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>如何在互联网的世界中，证明“我是我”？在 A 网站认证过了身份信息，到了 B 网站又需要认证一次？手持身份证拍照上传、人工审核，流程太繁琐？多个账户密码记不清、容易混，管理起来困难？自主主权的数字身份（Self-soverieign identity,]]></summary>
    <content type="html"><![CDATA[<p>如何在互联网的世界中，证明“我是我”？在 A 网站认证过了身份信息，到了 B 网站又需要认证一次？手持身份证拍照上传、人工审核，流程太繁琐？多个账户密码记不清、容易混，管理起来困难？自主主权的数字身份（Self-soverieign identity, SSI）正是可以解决这些问题的理念。</p><p>SSI 是数字身份运动中的观念，指只有用户自己拥有全部的、完整的数字身份信息，没有其他管理者和组织参与的数字身份体系。在 SSI 的理念中，用户拥有属于自己的去中心化的惟一身份标识（Decentralized identifiers, DIDs），用户可以完全控制自己的身份信息，可以在任何时候使用、更新或者彻底删除信息。用户可以创建并管理自己的可验证证明（Verifiable Credentials），自主决定在什么时候使用和分享自己的证明信息，而不需要请求其他中心化的机构、通过机构授权来使用自己的个人数据。</p><p>使用 SSI 的系统，所有的密钥信息都可以通过数字身份钱包进行管理，使用一个账号就可以登录所有的网站。在钱包终端中，用户可以随时向权威机构申请签发证明，包括身份证、驾驶证、居住证等各种形式的证件，都将以数字证明的形式储存在手机或电脑上。数字证明拥有机器可读、机器可验证的特性，不但可以放心地展示给第三方应用，第三方应用还可以在没有人工干预的情况下，直接验证证明的有效性，不需要签发机构的参与。</p><p>得益于区块链技术的不断发展，SSI 理念的实现逐渐成为可能。区块链系统本身就是点对点网络，天然拥有去中心化的特性，结合独特的数据结构设计和密码学技术的应用，加上共识算法在多节点数据同步方面的优秀能力，区块链不但能够保护数据的隐私安全，而且数据一旦写入系统便任何人无法篡改，为数据提供了极高可信度的储存环境。在 SSI 系统的建设中，将区块链作为可验证数据的数据中心（Verifiable data registry）无疑是最好的选择。</p><p>SSI 目前已经有诸多先例。2017 年，Sovrin 基金会发布了世界上首个公开的用于自主主权的数字身份的分布式账本网络，整个系统运行在开放标准以及公开源码的 Sovrin 协议之上，由 Linux 基金会的 Hyperledge Indy 项目维护。Sovrin 在 2018 年公布的白皮书中自问自答，“为什么网络世界中没有像物理世界一样可以用来证明身份的证书？直到区块链技术的出现，我们解决了这个问题！”结合 W3C 的 DIDs，Sovrin 提出了完整的数字身份和证明的解决方案。Sovrin 的主意一直都很明确，就是一定要构建和使用公开的、任何人都可以访问的、像比特币和以太坊一样的区块链网络。</p><p>eSSIF-Lab（European Self-Sovereign Identity Lab）是另一个案例。欧洲区块链联盟提出的 EBSI（The European Blockchain Services Infrastructure）是一个横跨欧洲的分布式节点网络，提供跨境的公共服务，有 28 个成员国签署了相关声明。eSSIF-Lab 项目是 EBSI 的一部分，由欧盟委员会资助，旨在促进 SSI 成为下一代开放、可信、安全的数字身份解决方案。欧盟曾在 2014 年 7 月 23 日建立了针对欧盟共同市场电子交易的电子身份识别和可信服务的法规 eIDAS（electronic IDentification, Authentication and trust Services），2019 年 5 月，eIDAS 宣布支持基于 W3C 相关规范的自主主权的数字身份。</p><p>微软在相关领域也表现活跃，2018 年 10 月，微软发布《去中心化的身份》白皮书，介绍了基于区块链的去中心化数字身份系统建设的技术方案，包括 DIDs 规范、去中心化的数据系统、DID 用户终端、DID 通用解析器、DID 身份中心、DID 认证系统、去中心化的客户端和服务等核心模块，详细说明了各模块组件以及各种角色在系统中的交互流程，为 SSI 系统的建设提供了非常好的模板。目前，微软已经提供公开的服务平台，可以体验相关的产品和能力。</p><p>此外，构建在以太坊和 IPFS 网络上的 uPort、使用自研区块链和支持第三方 DApp 的 Blockstack、能够适配比特币网络的 ShoCard 等都是优秀的案例。国内的厂商和机构也在进行相关的工作，如蚂蚁链提供的分布式身份服务 DIS（Decentralized Identity Service）、腾讯云的数字身份标识解决方案、微众银行的基于区块链的分布式多中心的技术解决方案 WeIdentity 等，都利用了区块链去中心化、数据高度可信的技术特点，构建了可靠的数字身份标识和认证体系。</p><p>区块链是一项极具潜力的先进技术，具有非常广阔的发展前景和应用空间，无论是国家政策的支持还是实际案例的应用，都体现出区块链未来的无数种可能。我们也在积极探索和推进区块链相关的技术发展和场景落地，将区块链与同态加密、联邦学习、多方计算、零知识证明等前沿技术结合起来，使用最优秀的技术能力，促进下一个互联网时代的到来。</p>]]></content>
  </entry>
  <entry>
    <title>为什么人对事物的情绪会消退，也就是阈值会不断提高？从生物进化的角度怎么解释？ 一开始吃某种饭觉得好吃，多吃几次就没有那么...</title>
    <link href="https://t.smallyu.net/#2020-29"/>
    <id>micro:740030075</id>
    <published>2020-12-07T16:33:10Z</published>
    <updated>2020-12-07T16:35:35Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>为什么人对事物的情绪会消退，也就是阈值会不断提高？从生物进化的角度怎么解释？ 一开始吃某种饭觉得好吃，多吃几次就没有那么好吃了。这是普遍存在的现象。 如果看的搞笑视频很少，会觉很好笑。看得多了，只有在提高质量和加大数量的情况下才会感觉到同等的快乐。 这很不合理，明明是能给人带来正面情绪的东西，为什么生理上会主动降低对这...</p>]]></summary>
    <content type="html"><![CDATA[<p>为什么人对事物的情绪会消退，也就是阈值会不断提高？从生物进化的角度怎么解释？</p>
<p>一开始吃某种饭觉得好吃，多吃几次就没有那么好吃了。这是普遍存在的现象。</p>
<p>如果看的搞笑视频很少，会觉很好笑。看得多了，只有在提高质量和加大数量的情况下才会感觉到同等的快乐。</p>
<p>这很不合理，明明是能给人带来正面情绪的东西，为什么生理上会主动降低对这些事物的反馈？</p>
<p>后来发现，会给人带来负面情绪的东西，身体的反应也会逐渐降低。比如悲伤和痛苦。</p>
<p>长时间不吃辣的人，一开始吃一点点就会感觉很辣，吃的多了，得吃变态辣的口味才行。</p>
<p>也就是说，只要是会引起情绪波动的事物，身体都会减弱反应。身体是无法区分正面情绪和负面情绪的。对于一堆细胞来说，都是化学和生物反应。</p>
<p>问题依然存在，这样进化的理由是什么？</p>
]]></content>
  </entry>
  <entry>
    <title>一直用饿了么，最近发现经常吃的很多店突然变成了两份起购，点一下 + 号就是 2 份，点一下 - 号就全没了，还不是商家设...</title>
    <link href="https://t.smallyu.net/#2020-28"/>
    <id>micro:731517295</id>
    <published>2020-11-21T06:30:13Z</published>
    <updated>2020-11-22T05:02:13Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>一直用饿了么，最近发现经常吃的很多店突然变成了两份起购，点一下 + 号就是 2 份，点一下 - 号就全没了，还不是商家设置的那种标有明确说明的两份起购，操作起来不明不白。 如果是实付金额没有达到起送金额，也应该是提示一下，而不是直接就没有选 1 份的选项。 另外，饿了么只有多花几毛钱，选中“准时达Plus”服务，配送超...</p>]]></summary>
    <content type="html"><![CDATA[<p>一直用饿了么，最近发现经常吃的很多店突然变成了两份起购，点一下 + 号就是 2 份，点一下 - 号就全没了，还不是商家设置的那种标有明确说明的两份起购，操作起来不明不白。</p>
<p>如果是实付金额没有达到起送金额，也应该是提示一下，而不是直接就没有选 1 份的选项。</p>
<p>另外，饿了么只有多花几毛钱，选中“准时达Plus”服务，配送超时才有赔付红包，而且这个选项不能默认选中。美团外卖很多店默认就有赔付服务，还不用花钱。</p>
<p>以后应该用美团外卖了。</p>
]]></content>
  </entry>
  <entry>
    <title>想起来一句话，但是没想明白里面的逻辑：“我不了解你就无法接近你，可我了解了你就不想接近你。”</title>
    <link href="https://t.smallyu.net/#2020-27"/>
    <id>micro:727523155</id>
    <published>2020-11-15T06:29:13Z</published>
    <updated>2020-11-15T06:29:13Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>想起来一句话，但是没想明白里面的逻辑：“我不了解你就无法接近你，可我了解了你就不想接近你。”</p>]]></summary>
    <content type="html"><![CDATA[<p>想起来一句话，但是没想明白里面的逻辑：“我不了解你就无法接近你，可我了解了你就不想接近你。”</p>
]]></content>
  </entry>
  <entry>
    <title>有的人会用“在一事无成的年纪，遇到什么什么”这样的句式。前半句话就是错的，很多人一辈子都会一事无成，和年龄无关。</title>
    <link href="https://t.smallyu.net/#2020-26"/>
    <id>micro:727285780</id>
    <published>2020-11-15T00:22:43Z</published>
    <updated>2020-11-15T13:58:21Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有的人会用“在一事无成的年纪，遇到什么什么”这样的句式。前半句话就是错的，很多人一辈子都会一事无成，和年龄无关。</p>]]></summary>
    <content type="html"><![CDATA[<p>有的人会用“在一事无成的年纪，遇到什么什么”这样的句式。前半句话就是错的，很多人一辈子都会一事无成，和年龄无关。</p>
]]></content>
  </entry>
  <entry>
    <title>🥱</title>
    <link href="https://t.smallyu.net/#2020-25"/>
    <id>micro:726947275</id>
    <published>2020-11-13T18:28:15Z</published>
    <updated>2020-11-13T18:28:15Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>🥱</p>]]></summary>
    <content type="html"><![CDATA[<p>🥱</p>
]]></content>
  </entry>
  <entry>
    <title>三种迷茫的情况： 一是不知道该做什么，脑子里是空白； 二是可以做的事情很多，待办事项里的条目很多，但不确定该选择哪一个；...</title>
    <link href="https://t.smallyu.net/#2020-24"/>
    <id>micro:725955319</id>
    <published>2020-11-12T09:25:00Z</published>
    <updated>2020-11-12T09:25:00Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>三种迷茫的情况： 一是不知道该做什么，脑子里是空白； 二是可以做的事情很多，待办事项里的条目很多，但不确定该选择哪一个； 三是明知道该做什么，但是身体生理上不配合。</p>]]></summary>
    <content type="html"><![CDATA[<p>三种迷茫的情况：</p>
<p>一是不知道该做什么，脑子里是空白；<br>二是可以做的事情很多，待办事项里的条目很多，但不确定该选择哪一个；<br>三是明知道该做什么，但是身体生理上不配合。</p>
]]></content>
  </entry>
  <entry>
    <title>有的博客写了 10 年，却仍然是幼稚的内容，没有深度、没有思考和见解，内容平淡和简短。 有些“技术流”的博客，技术高大上...</title>
    <link href="https://t.smallyu.net/#2020-23"/>
    <id>micro:722066299</id>
    <published>2020-11-05T01:24:25Z</published>
    <updated>2020-11-05T01:24:58Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有的博客写了 10 年，却仍然是幼稚的内容，没有深度、没有思考和见解，内容平淡和简短。 有些“技术流”的博客，技术高大上，但硬生生把技术细节摆在上面，和技术文档一样。 还有些“技术流”的博客，技术低级和具体，写一些不值一提的内容。 有些“文艺范”的博客，一般内容比较少，原创寥寥无几。 还有些无意中“炫富”的博客，内容大...</p>]]></summary>
    <content type="html"><![CDATA[<p>有的博客写了 10 年，却仍然是幼稚的内容，没有深度、没有思考和见解，内容平淡和简短。<br>有些“技术流”的博客，技术高大上，但硬生生把技术细节摆在上面，和技术文档一样。<br>还有些“技术流”的博客，技术低级和具体，写一些不值一提的内容。<br>有些“文艺范”的博客，一般内容比较少，原创寥寥无几。<br>还有些无意中“炫富”的博客，内容大多是游玩记录。  </p>
<p>大多数人，平凡一生。</p>
]]></content>
  </entry>
  <entry>
    <title>可用的 PDF 批注工具，整个 Linux 平台没有，网页在线版本的工具也没有。 ( 2020.11.30: WPS P...</title>
    <link href="https://t.smallyu.net/#2020-22"/>
    <id>micro:720973404</id>
    <published>2020-11-03T08:26:55Z</published>
    <updated>2020-11-30T10:43:32Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>可用的 PDF 批注工具，整个 Linux 平台没有，网页在线版本的工具也没有。 ( 2020.11.30: WPS PDF )</p>]]></summary>
    <content type="html"><![CDATA[<p>可用的 PDF 批注工具，整个 Linux 平台没有，网页在线版本的工具也没有。</p>
<p>( 2020.11.30: WPS PDF )</p>
]]></content>
  </entry>
  <entry>
    <title>勇者</title>
    <link href="https://crazy.smallyu.net/2020/10/26/%E5%8B%87%E8%80%85/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2020/10/26/%E5%8B%87%E8%80%85/</id>
    <published>2020-10-25T17:07:12.000Z</published>
    <updated>2025-10-01T00:53:43.836Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>孩子们出生在新手村，一起学习，一起玩耍。</p>
<p>后来孩子们逐渐长大，到了该出门的年纪。走出村子，面对更大的世界。</p>
<p>大家都去到了外面的世界。有的离村子很远，有的离村子很近。</p>
<p>大家手里有魔法石，可以彼此联系。</p>
<p>大家会随时联系，谈]]></summary>
    <content type="html"><![CDATA[<p>孩子们出生在新手村，一起学习，一起玩耍。</p><p>后来孩子们逐渐长大，到了该出门的年纪。走出村子，面对更大的世界。</p><p>大家都去到了外面的世界。有的离村子很远，有的离村子很近。</p><p>大家手里有魔法石，可以彼此联系。</p><p>大家会随时联系，谈论最近的八卦，讨论王国的资讯。</p><p>到了特定的日期，大家会回到村子团聚，交流近况。</p><p>有的在附近的城镇打工，有的在稍远的城镇进修，还有的依然留在村子里。</p><p>有一个人，走得很远。</p><p>他在学院里修养身性，寻找高明的老师学习剑术。</p><p>修炼内功，精进技能。</p><p>他在森林里遇到过和蔼的兔子，也遇到过凶猛的野猪。</p><p>他披荆斩棘。</p><p>他向执政官证明自己的才能，成为冒险者。</p><p>他手里有一把剑。</p><p>当外敌入侵，他会用这把剑斩杀敌人。</p><p>遇到强盗，会用这把剑保护自己。</p><p>更重要的，这把剑背负使命。</p><p>不只是眼前的苟且，还有山上的恶龙。</p><p>这把剑，是他的武器。</p><p>恶龙，是他的远方。</p><p>他走在路上，看着脚下，想着远方。</p><p>有一天，他回家了，回到新手村。</p><p>他发现，大家过得都很好，生活和睦。</p><p>黄发垂髫。</p><p>怡然自乐。</p><p>他发现，小伙伴们关系融洽，有来有往。</p><p>不亦乐乎。</p><p>他想到了自己的日以继夜。</p><p>想到了自己的风雨兼程。</p><p>想到了自己手里的剑。</p><p>惟一仅有的剑。</p><p>启程的日子到了。</p><p>他回头看，看到了安居乐业</p><p>回头看，看到了市井繁荣。</p><p>回头，听到了欢声笑语。</p><p>他向前看。</p><p>满是苍茫。</p><p>身后，没有人在等他。</p><p>身前，也没有人在等他。</p><p>他想起来，曾有人愿意等他。可他拿起剑，独自上路。</p><p>出发了。</p><p>他看到了亲信好友。</p><p>看到了鸟语花香。</p><p>看到了小伙伴们。</p><p>他视若无睹。</p><p>置若罔闻。</p><p>某个小伙伴挥了挥手。</p><p>什么都没说。</p><p>他却动摇了。</p><p>出发了。</p><p>去哪儿呢？</p><p>他想到了曾经的高山流水。</p><p>想到了未来的日月星辰。</p><p>他喜欢这趟旅程。</p><p>也讨厌这趟旅程。</p><p>他再三犹豫。</p><p>反复斟酌。</p><p>辗转反侧。</p><p>彻夜难眠。</p><p>绞尽脑汁。</p><p>想尽办法。</p><p>只想问那个小伙伴一句。</p><p>“一起走好不好？”</p><p>甚至，他可以留下。</p><p>刚要开口。却看到小伙伴们开心的打起麻将。</p><p>吃着火锅唱着歌。</p><p>并没有人需要他。</p><p>这趟旅程。</p><p>没有回头路。</p><p>他喜欢手里的剑。</p><p>也讨厌手里的剑。</p><img src="brave.png" width="100%" style="margin-top:100px;margin-left:0;">]]></content>
  </entry>
  <entry>
    <title>如果养一只猫，就养加菲猫，如果养一只狗，就养秋田犬。</title>
    <link href="https://t.smallyu.net/#2020-21"/>
    <id>micro:713236063</id>
    <published>2020-10-21T01:36:19Z</published>
    <updated>2020-10-21T01:36:19Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果养一只猫，就养加菲猫，如果养一只狗，就养秋田犬。</p>]]></summary>
    <content type="html"><![CDATA[<p>如果养一只猫，就养加菲猫，如果养一只狗，就养秋田犬。</p>
]]></content>
  </entry>
  <entry>
    <title>最近遇到一个小事情：一个文档需要多人完成，每个人各写各的，然后由一人统一合并。合并之后，如果有改动，就严格按照合并好之后...</title>
    <link href="https://t.smallyu.net/#2020-20"/>
    <id>micro:712535404</id>
    <published>2020-10-20T01:44:18Z</published>
    <updated>2020-10-20T04:13:14Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>最近遇到一个小事情：一个文档需要多人完成，每个人各写各的，然后由一人统一合并。合并之后，如果有改动，就严格按照合并好之后的格式更改、发送到统一合并的人手里。 想起在某微博某书里看到的故事：几十年前，有个外国人来到中国做监工，看着工地上的人干活。监工发现，经常出现很多人合力把一袋水泥从一个地方搬到另一个地方，但没有人会去...</p>]]></summary>
    <content type="html"><![CDATA[<p>最近遇到一个小事情：一个文档需要多人完成，每个人各写各的，然后由一人统一合并。合并之后，如果有改动，就严格按照合并好之后的格式更改、发送到统一合并的人手里。</p>
<p>想起在某微博某书里看到的故事：几十年前，有个外国人来到中国做监工，看着工地上的人干活。监工发现，经常出现很多人合力把一袋水泥从一个地方搬到另一个地方，但没有人会去找一辆推车过来。在有人使用推车的地方，车轮的转轴处长久失修，发出吱呀吱呀刺耳的噪音，但没有人会在上面滴一些润滑油，消除这些声音。</p>
<p>所以关于文档协作产生的问题是：</p>
<ol>
<li>目前多人协同编辑的工具已经很常见，为什么没有人投入使用。</li>
<li>Office 是否有强制限制样式格式的机制，保证样式在各版本、各平台的统一，想改样式都改不了的那种。如果有，为什么没人用？如果没有，为什么没有？</li>
<li>流程上的问题，应该在确保内容不会有更改之后，再严格修正样式。而不是调整好样式之后，让别人按照要求更改。</li>
</ol>
<p>这些都是提议，都是问题，目前并没有答案（以后会有的）。</p>
<p>关于 Office 的样式格式，已知的是：</p>
<ol>
<li>Office 有模板功能，但只是模板，没有强制约束。即使只是模板，也似乎没人用。</li>
<li>Office 提供了 API，可以按照指定格式生成文档。不过少量使用的话成本有点高。</li>
</ol>
<p>另外关于 Office 字体的问题，有点纳闷，在不同平台不同软件编辑过后字体配置就变了。</p>
<p>HTML关于字体的逻辑是，字体由样式文件（CSS）决定，如果字体存在，就按照指定字体显示，如果字体不存在，就显示默认字体。字体是一种配置，仅取决于配置文件，和平台环境无关，这个配置无论用什么编辑都不会自动改变，除非有意识修改这个配置。</p>
<p>Office 的字体问题，是很无聊的问题。</p>
]]></content>
  </entry>
  <entry>
    <title>如果长期被关在一间阴暗潮湿的监狱里。忽然有一天，一束阳光照了进来。 如果请求阳光，是否愿意留在这里？ 如果阳光说愿意，房...</title>
    <link href="https://t.smallyu.net/#2020-19"/>
    <id>micro:706693170</id>
    <published>2020-10-11T11:50:20Z</published>
    <updated>2020-10-12T10:39:04Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>如果长期被关在一间阴暗潮湿的监狱里。忽然有一天，一束阳光照了进来。 如果请求阳光，是否愿意留在这里？ 如果阳光说愿意，房间里将不再潮湿和阴暗。 如果阳光说不愿意。这一束阳光会消失不见，房间里将继续潮湿和阴暗。 如果不请求阳光。这一束阳光会短暂停留，但停留多长时间是未知的。并且阳光不会知道你需要它。</p>]]></summary>
    <content type="html"><![CDATA[<p>如果长期被关在一间阴暗潮湿的监狱里。忽然有一天，一束阳光照了进来。</p>
<ul>
<li><p>如果请求阳光，是否愿意留在这里？</p>
<ul>
<li>如果阳光说愿意，房间里将不再潮湿和阴暗。 </li>
<li>如果阳光说不愿意。这一束阳光会消失不见，房间里将继续潮湿和阴暗。</li>
</ul>
</li>
<li><p>如果不请求阳光。这一束阳光会短暂停留，但停留多长时间是未知的。并且阳光不会知道你需要它。</p>
</li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>高正确率是实力的象征，低正确率是努力的象征。 如果正确率很高 pass 数也很高，说明实力超过水平线，但同时也说明在过程...</title>
    <link href="https://t.smallyu.net/#2020-18"/>
    <id>micro:706470835</id>
    <published>2020-10-10T02:24:10Z</published>
    <updated>2020-10-10T02:24:10Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>高正确率是实力的象征，低正确率是努力的象征。 如果正确率很高 pass 数也很高，说明实力超过水平线，但同时也说明在过程中收获的经验有限。 如果正确率很低但 pass 数很高，说明经历了不断试错的过程，并且最终解决了问题。获取到的经验对于当事人是前所未有的。 因此不应该以正确率低为耻。</p>]]></summary>
    <content type="html"><![CDATA[<p>高正确率是实力的象征，低正确率是努力的象征。</p>
<p>如果正确率很高 pass 数也很高，说明实力超过水平线，但同时也说明在过程中收获的经验有限。<br>如果正确率很低但 pass 数很高，说明经历了不断试错的过程，并且最终解决了问题。获取到的经验对于当事人是前所未有的。</p>
<p>因此不应该以正确率低为耻。</p>
]]></content>
  </entry>
  <entry>
    <title>手机里装了 3 个邮箱软件，QQ邮箱、阿里邮箱和 Gmail 。在IOS 14 的 APP 资源库里直观显示了软件的分类...</title>
    <link href="https://t.smallyu.net/#2020-17"/>
    <id>micro:703395703</id>
    <published>2020-10-05T04:58:12Z</published>
    <updated>2020-10-10T02:26:03Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>手机里装了 3 个邮箱软件，QQ邮箱、阿里邮箱和 Gmail 。在IOS 14 的 APP 资源库里直观显示了软件的分类： QQ Mail 的分类是“工具”，这个分类下的其他 APP 都是系统自带的，APP商店、Safari、寻找、时钟、指南针、系统设置……QQ Mail 何德何能？ Alimail 的分类是”社交“，...</p>]]></summary>
    <content type="html"><![CDATA[<p>手机里装了 3 个邮箱软件，QQ邮箱、阿里邮箱和 Gmail 。在IOS 14 的 APP 资源库里直观显示了软件的分类：</p>
<p>QQ Mail 的分类是“工具”，这个分类下的其他 APP 都是系统自带的，APP商店、Safari、寻找、时钟、指南针、系统设置……QQ Mail 何德何能？</p>
<p>Alimail 的分类是”社交“，“社交”分类下的 APP 只有微信、电话、短信，Alimail 想啥呢？</p>
<p>Gmail 的分类是“效率”。</p>
]]></content>
  </entry>
  <entry>
    <title>刚意识到 Java 的 Functional Interface 其实已经很强大了（始于 2014 年的 Java 8）...</title>
    <link href="https://t.smallyu.net/#2020-16"/>
    <id>micro:698262142</id>
    <published>2020-09-24T10:34:53Z</published>
    <updated>2020-09-24T10:38:53Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>刚意识到 Java 的 Functional Interface 其实已经很强大了（始于 2014 年的 Java 8），但是很少在 Java 里见到回调的写法。 JavaScript 为什么大量使用回调？因为 js 很多场景是异步的网络请求，需要异步处理请求的数据。 Golang 为什么回调也很常见？因为 golan...</p>]]></summary>
    <content type="html"><![CDATA[<p>刚意识到 Java 的 Functional Interface 其实已经很强大了（始于 2014 年的 Java 8），但是很少在 Java 里见到回调的写法。</p>
<p>JavaScript 为什么大量使用回调？因为 js 很多场景是异步的网络请求，需要异步处理请求的数据。<br>Golang 为什么回调也很常见？因为 golang 有显式的引用传值，一个星号的写法比 java 里 new 一个对象简洁很多。</p>
<p>所以虽然 Java 的 Functional Interface 是可用的，但只是补上了 Java 的短板，而不能说明 Java 是足够厉害的。（当然 Java 确实很厉害。）</p>
]]></content>
  </entry>
  <entry>
    <title>阮一峰在 2009 年对闭包的理解《 学习Javascript闭包（Closure） 》是错的。</title>
    <link href="https://t.smallyu.net/#2020-15"/>
    <id>micro:695875076</id>
    <published>2020-09-21T02:27:49Z</published>
    <updated>2020-09-21T02:27:49Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>阮一峰在 2009 年对闭包的理解《 学习Javascript闭包（Closure） 》是错的。</p>]]></summary>
    <content type="html"><![CDATA[<p>阮一峰在 2009 年对闭包的理解《<a href="https://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html">学习Javascript闭包（Closure）</a>》是错的。</p>
]]></content>
  </entry>
  <entry>
    <title>网页技术能实现 3D 建模吗？</title>
    <link href="https://smallyu.net/2020/09/20/%E7%BD%91%E9%A1%B5%E6%8A%80%E6%9C%AF%E8%83%BD%E5%AE%9E%E7%8E%B03D%E5%BB%BA%E6%A8%A1%E5%90%97%EF%BC%9F/"/>
    <id>blog:https://smallyu.net/2020/09/20/%E7%BD%91%E9%A1%B5%E6%8A%80%E6%9C%AF%E8%83%BD%E5%AE%9E%E7%8E%B03D%E5%BB%BA%E6%A8%A1%E5%90%97%EF%BC%9F/</id>
    <published>2020-09-20T14:58:39.000Z</published>
    <updated>2025-11-09T09:22:13.532Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>网页技术（HTML5、CSS3、JavaScript）能实现效果炫酷的 3D 建模甚至是 3D 动画效果吗？我暂时认为是不可以的。比如期望这样的页面效果：</p>
<img src="preview.png" class="no-shadow"]]></summary>
    <content type="html"><![CDATA[<p>网页技术（HTML5、CSS3、JavaScript）能实现效果炫酷的 3D 建模甚至是 3D 动画效果吗？我暂时认为是不可以的。比如期望这样的页面效果：</p><img src="preview.png" class="no-shadow" width="100%"><p>d3.js 是不用考虑的，它仅仅是一个数据可视化的工具，和 3D 建模是两个领域。</p><p>three.js 似乎是目前比较流行的 3D 建模库。假如 three.js 可以做到的话，应该怎么做呢？首先的想法是画这样一个正方体出来：</p><img src="cube_target.png" class="no-shadow" width="20%"><p>3d 建模里的立方体相当于编程世界的 hello world，很容易就能出来：</p><img src="cube_1.png" class="no-shadow" width="20%"><p>给场景加上灯光，正方体就不是黑漆漆的了。然后给正方体加上颜色，改一下场景的背景色，再把灯光调到正方体的上面，正方体就能像样子一点了：</p><img src="cube_2.png" class="no-shadow" width="20%"><p>目标正方体的边缘是发光的，而且是渐变色。怎么给正方体加一个边缘线呢，正方体本身是没有这种属性的，只能用线性材料（three.js 里的 LineBasicMaterial，正方体用的是 MeshPhongMaterial）再画一个正方体出来，套在实体正方体上：</p><img src="cube_3.png" class="no-shadow" width="20%"><p>怎么让线性的正方体发光呢？线性材料（LineBasicMaterial）是不能使用渐变色的，只有着色器材料（ShaderMaterial）可以使用渐变色。着色器材料可以实现多彩的效果，比如这样（来自 <a href="https://stackoverflow.com/questions/52614371/apply-color-gradient-to-material-on-mesh-three-js">StackOverflow</a>），：</p><img src="line_1.png" class="no-shadow" width="20%"><p>但是到这里遇到问题了。在 three.js 里，渲染一个物体需要两个参数，一个是 geometry（几何体），一个是 material（材料），线性材料和着色器材料都是材料的种类。(TorusKnotGeometry 是上图用到的几何形状)</p><pre><code>线条正方体 = EdgesGeometry + LineBasicMaterial渐变曲线条 = TorusKnotGeometry + ShaderMaterial</code></pre><p>现在想要线性材料和着色器材料（LineBasicMaterial 和 ShaderMaterial）组合是不合逻辑的，我没有找到实现发光的正方体边缘效果的方法。把着色器用在正方体的效果是这样的（颜色从 0x215ec9 到 0x000000）：</p><img src="cube_4.png" class="no-shadow" width="20%"><p>所以然后呢？我意识到即使实现了一个好看的正方体，离渲染出整张图还差的太多。比如这样的文字效果怎么做？</p><img src="part_1.png" class="no-shadow" width="30%"><p>three.js 的 Texture 本身效果是不错的，可是怎么把文字安安稳稳的放到正方体上，还带透明的黑色背景框？再比如这五彩斑斓的线条，以及准确的箭头指向：</p><img src="part_2.png" class="no-shadow" width="15%"><p>还有整个图上十多种元素的位置布局、动画效果。</p><p>我相信 three.js （WebGL）在技术能力上是可以实现这样效果的，甚至官方的 example 里网页游戏都有，不过假如要实现一个网页游戏，一定会用到图像素材，素材从哪儿来呢？还是得回到 PS、AI 之类的工具上，如果用上了那样的生产力工具，就没有必要用 js 来写布局和动画了。单纯的网页技术似乎很难完全解决 3D 建模的问题。H5 动画也是类似的情况。</p><p>单纯写代码来 3D 建模的另一个问题是不直观，代码是违反直觉和视觉的，写个网页、APP界面似乎还可以（二维的）。如果可以在一个画布上直接放置正方体和线条，然后鼠标拖动改变位置、调整颜色，以及添加各种其他元素，像玩游戏（比如我的世界）一样操作简便，不就比写代码好多了吗……那不就是 Adobe Animate 吗？</p><p>可惜 Adobe Animate 没有 Linux 版本，而且 Linux 下的替代品 Blender 有点性能问题。</p><img src="blender.png" class="no-shadow" width="100%"><p>回到一开始期望的效果图上，图片出自一个大屏 UI 的 <a href="https://www.zcool.com.cn/work/ZMjg2NTA1Njg=.html">设计演示</a>，其实原效果不是三维的，作者使用的工具是 PS、AI。那么在仅需要二维效果的前提下，网页技术能实现吗？如果要用代码实现各种图形，就依然还是三维建模的问题。最简单的方式是拿个背景图，把文字贴到上面。背景图从哪儿来呢？</p>]]></content>
  </entry>
  <entry>
    <title>有一个老生常谈的词叫 curd boy，指工作内容仅仅是数据库的增删改查、调接口，没有技术含量的码农； 前段时间在脉脉上...</title>
    <link href="https://t.smallyu.net/#2020-14"/>
    <id>micro:693184392</id>
    <published>2020-09-16T05:42:33Z</published>
    <updated>2020-09-18T01:21:09Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>有一个老生常谈的词叫 curd boy，指工作内容仅仅是数据库的增删改查、调接口，没有技术含量的码农； 前段时间在脉脉上看到一个词叫 nginx 工程师，指工作内容是转发领导命令的小领导，把什么样的命令以什么样的形式精确地转发给什么样的人，似乎也是个技术活（手动滑稽）； 刚想起来一个词，叫 demo boy，指工作内容...</p>]]></summary>
    <content type="html"><![CDATA[<p>有一个老生常谈的词叫 curd boy，指工作内容仅仅是数据库的增删改查、调接口，没有技术含量的码农；</p>
<p>前段时间在脉脉上看到一个词叫 nginx 工程师，指工作内容是转发领导命令的小领导，把什么样的命令以什么样的形式精确地转发给什么样的人，似乎也是个技术活（手动滑稽）；</p>
<p>刚想起来一个词，叫 demo boy，指工作内容是售前项目、项目原型的程序员。和 “乙方” 的区别是，需求不明确、不确定，甲方随时会对需求进行改动、代码有可能推倒重来，所以做出来的只能是原型、demo。</p>
<p>类似的词还有 sql boy、rpc boy ……</p>
]]></content>
  </entry>
  <entry>
    <title>“xxx的重要性不言而喻” 是无聊且无用的话术，意味着无知和盲从。不言难喻。</title>
    <link href="https://t.smallyu.net/#2020-13"/>
    <id>micro:692404323</id>
    <published>2020-09-15T01:24:01Z</published>
    <updated>2020-09-15T05:51:01Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>“xxx的重要性不言而喻” 是无聊且无用的话术，意味着无知和盲从。不言难喻。</p>]]></summary>
    <content type="html"><![CDATA[<p>“xxx的重要性不言而喻” 是无聊且无用的话术，意味着无知和盲从。不言难喻。</p>
]]></content>
  </entry>
  <entry>
    <title>在 youtube 上看到两个小视频， 视频1 , 视频2 , 从 lambda calculus 讲到 y combi...</title>
    <link href="https://t.smallyu.net/#2020-12"/>
    <id>micro:690445522</id>
    <published>2020-09-10T16:24:27Z</published>
    <updated>2020-09-11T01:00:21Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>在 youtube 上看到两个小视频， 视频1 , 视频2 , 从 lambda calculus 讲到 y combinator，简洁易懂。</p>]]></summary>
    <content type="html"><![CDATA[<p>在 youtube 上看到两个小视频，<a href="https://youtu.be/eis11j_iGMs">视频1</a>, <a href="https://youtu.be/9T8A89jgeTI">视频2</a>, 从 lambda calculus 讲到 y combinator，简洁易懂。</p>
]]></content>
  </entry>
  <entry>
    <title>英文邮件大多数底部有一个 Unsubscribe 链接，中文邮件几乎都没有。</title>
    <link href="https://t.smallyu.net/#2020-11"/>
    <id>micro:689286223</id>
    <published>2020-09-09T03:59:09Z</published>
    <updated>2020-09-09T03:59:09Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>英文邮件大多数底部有一个 Unsubscribe 链接，中文邮件几乎都没有。</p>]]></summary>
    <content type="html"><![CDATA[<p>英文邮件大多数底部有一个 Unsubscribe 链接，中文邮件几乎都没有。</p>
]]></content>
  </entry>
  <entry>
    <title>昨天深夜看了一个 QCon 的视频 The Why of Go 。看到那么大口气的标题，以为里面会有什么厉害的内容，结果...</title>
    <link href="https://t.smallyu.net/#2020-10"/>
    <id>micro:688016445</id>
    <published>2020-09-07T03:59:53Z</published>
    <updated>2020-09-07T04:48:47Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>昨天深夜看了一个 QCon 的视频 The Why of Go 。看到那么大口气的标题，以为里面会有什么厉害的内容，结果只是讲到了 golang 的3个优点：goroutines、有类型的垃圾回收、简洁的标准库。除了 goroutines，其他两点对程序员甚至没有太大感知。不过视频里提到的 go-is-not-good...</p>]]></summary>
    <content type="html"><![CDATA[<p>昨天深夜看了一个 QCon 的视频 <a href="https://www.infoq.com/presentations/go-concurrency-gc/?itm_source=presentations_about_golang&itm_medium=link&itm_campaign=golang">The Why of Go</a>。看到那么大口气的标题，以为里面会有什么厉害的内容，结果只是讲到了 golang 的3个优点：goroutines、有类型的垃圾回收、简洁的标准库。除了 goroutines，其他两点对程序员甚至没有太大感知。不过视频里提到的 <a href="https://github.com/ksimka/go-is-not-good">go-is-not-good</a> 倒是有点意思，详细列举了 golang 的种种缺点。</p>
<p>感觉视频提到的点并不是很有说服力，就查了一下，原来视频的讲述者 Carmen Andoh 是 google 的员工，可以算是 golang 的布道者了。从 Carmen 的 github 账号 <a href="https://github.com/Lyoness?tab=overview&from=2016-12-01&to=2016-12-31">Lyoness</a> 来看，她的代码能力似乎并不显著，而且在视频里的讲话过程中，她经常有一个捂嘴的小动作，不知道是不是对演讲的内容不够自信呢。</p>
]]></content>
  </entry>
  <entry>
    <title>发现一本书最好看的是前言、序和后记 🙃</title>
    <link href="https://t.smallyu.net/#2020-9"/>
    <id>micro:679055417</id>
    <published>2020-08-24T10:49:38Z</published>
    <updated>2020-08-24T10:54:58Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>发现一本书最好看的是前言、序和后记 🙃</p>]]></summary>
    <content type="html"><![CDATA[<p>发现一本书最好看的是前言、序和后记 🙃</p>
]]></content>
  </entry>
  <entry>
    <title>“做正确的事情，然后等着被解雇”</title>
    <link href="https://b.smallyu.net/2020/08/22/%E2%80%9C%E5%81%9A%E6%AD%A3%E7%A1%AE%E7%9A%84%E4%BA%8B%E6%83%85%EF%BC%8C%E7%84%B6%E5%90%8E%E7%AD%89%E7%9D%80%E8%A2%AB%E8%A7%A3%E9%9B%87%E2%80%9D/"/>
    <id>blog-b:https://b.smallyu.net/2020/08/22/%E2%80%9C%E5%81%9A%E6%AD%A3%E7%A1%AE%E7%9A%84%E4%BA%8B%E6%83%85%EF%BC%8C%E7%84%B6%E5%90%8E%E7%AD%89%E7%9D%80%E8%A2%AB%E8%A7%A3%E9%9B%87%E2%80%9D/</id>
    <published>2020-08-22T08:17:53.000Z</published>
    <updated>2025-12-03T10:02:00.857Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>“做正确的事情，然后等着被解雇”，这句话出自 Google 工程师 Tan Chade-Meng 的博客文章《<a href="http://chademeng.com/me/do-the-right-thing-wait-to-get-fired/">DO THE]]></summary>
    <content type="html"><![CDATA[<p>“做正确的事情，然后等着被解雇”，这句话出自 Google 工程师 Tan Chade-Meng 的博客文章《<a href="http://chademeng.com/me/do-the-right-thing-wait-to-get-fired/">DO THE RIGHT THING, WAIT TO GET FIRED</a>》，一本关于程序员协作的书《<a href="https://book.douban.com/subject/11154471/">Team Geek: A Software Developer’s Guide to Working Well with Others</a>》引用了博客中的内容（P126），然后书里的内容又被 CoolShell 的文章《<a href="https://coolshell.cn/articles/17972.html">我看绩效考核</a>》引用。我在 CoolShell 的文章里第一次看到了这段话。看到之后，念念不忘，现在一定要把它复制过来：</p><blockquote><p>New Google employees (we call “Nooglers”) often ask me what makes me effective at what I do.  I tell them only half-jokingly that it’s very simple: I do the Right Thing for Google and the world, and then I sit back and wait to get fired.  If I don’t get fired, I’ve done the Right Thing for everyone.  If I do get fired, this is the wrong employer to work for in the first place.  So, either way, I win.  That is my career strategy.</p></blockquote><p>得多么强大的自信和力量，才能说出这样的话啊！尽管原作者也说，这是半开玩笑的说法，尽管作者已经有了一些影响力，做过了一些“正确”的事情——没有身份和地位确实很难说出这样的话，但这句话背后的精神会一直鼓励和激励着我们——你知道我说的是谁，经久不衰，生生不息。也有不少文章展开讨论这句话的含义，比如《<a href="https://brendansterne.com/2013/07/11/do-the-right-thing-wait-to-get-fired/">Do the right thing, Wait to get fired</a>》。</p><p>当然，这句话不能反过来说，不是说等着被解雇，就意味着在做正确的事了。这句话也不适用于喜欢混吃等死的人，毕竟努力不一定有结果，但不努力一定很舒服 :-P 我得认真想一下什么是“正确的事”，以及如何做一些“有价值的事”。</p>]]></content>
  </entry>
  <entry>
    <title>应该喜欢作品而不是喜欢创作出作品的人。 关注一个人，往往是因为创作出优秀作品的人，创作出下一个优秀作品的概率比较大。 作...</title>
    <link href="https://t.smallyu.net/#2020-8"/>
    <id>micro:675854483</id>
    <published>2020-08-19T05:09:16Z</published>
    <updated>2020-08-19T05:11:01Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>应该喜欢作品而不是喜欢创作出作品的人。 关注一个人，往往是因为创作出优秀作品的人，创作出下一个优秀作品的概率比较大。 作品和个人属性是无关的。一个作品好是因为作品本身好，而不是因为这是谁的作品。 相信理性的力量，拒绝和避免个人崇拜。</p>]]></summary>
    <content type="html"><![CDATA[<p>应该喜欢作品而不是喜欢创作出作品的人。<br>关注一个人，往往是因为创作出优秀作品的人，创作出下一个优秀作品的概率比较大。<br>作品和个人属性是无关的。一个作品好是因为作品本身好，而不是因为这是谁的作品。<br>相信理性的力量，拒绝和避免个人崇拜。</p>
]]></content>
  </entry>
  <entry>
    <title>习近平主持第十九届中央政治局集体学习并讲话： 序号 时间 主题 十八 2019.10.25 把 区块链 作为核心技术自主...</title>
    <link href="https://t.smallyu.net/#2020-7"/>
    <id>micro:674790794</id>
    <published>2020-08-17T10:09:09Z</published>
    <updated>2020-08-29T06:24:31Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>习近平主持第十九届中央政治局集体学习并讲话： 序号 时间 主题 十八 2019.10.25 把 区块链 作为核心技术自主创新重要突破口，加快推动区块链技术和产业创新发展 …… 九 2018.10.31 加强领导做好规划明确任务夯实基础，推动我国新一代 人工智能 健康发展 参考链接： 第十九届、第十八届 第十七届</p>]]></summary>
    <content type="html"><![CDATA[<p>习近平主持第十九届中央政治局集体学习并讲话：</p>
<table>
<thead>
<tr>
<th>序号</th>
<th>时间</th>
<th>主题</th>
</tr>
</thead>
<tbody><tr>
<td>十八</td>
<td>2019.10.25</td>
<td>把 <strong>区块链</strong> 作为核心技术自主创新重要突破口，加快推动区块链技术和产业创新发展</td>
</tr>
<tr>
<td>……</td>
<td></td>
<td></td>
</tr>
<tr>
<td>九</td>
<td>2018.10.31</td>
<td>加强领导做好规划明确任务夯实基础，推动我国新一代 <strong>人工智能</strong> 健康发展</td>
</tr>
</tbody></table>
<p>参考链接：</p>
<ul>
<li><a href="http://www.12371.cn/special/lnzzjjtxx/">第十九届、第十八届</a></li>
<li><a href="http://www.gov.cn/test/2009-02/25/content_1241784.htm">第十七届</a></li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>Although significant time has passed since the writing of th...</title>
    <link href="https://t.smallyu.net/#2020-6"/>
    <id>micro:673418346</id>
    <published>2020-08-13T11:18:51Z</published>
    <updated>2020-08-13T11:18:51Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>Although significant time has passed since the writing of this book, surprisingly little needs to be changed. Why? Because the emphasis is on people, on how we,...</p>]]></summary>
    <content type="html"><![CDATA[<blockquote>
<p>Although significant time has passed since the writing of this book, surprisingly little needs to be changed. Why? Because the emphasis is on people, on how we, as human beings, interact with the physical objects in the
world. This interaction is governed by our biology, psychology, society,
and culture. Human biology and psychology do not change much with
time: society and culture change very slowly. </p>
</blockquote>
<p>—— 《The Design of Everyday Things》</p>
]]></content>
  </entry>
  <entry>
    <title>CoolShell 文章中出现的文字累赘举例： 所以我对原文进行大量的删减、裁剪、改写和添加， 主要 删除了一些没有信息...</title>
    <link href="https://t.smallyu.net/#2020-5"/>
    <id>micro:671702421</id>
    <published>2020-08-11T03:25:43Z</published>
    <updated>2020-08-11T03:25:43Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>CoolShell 文章中出现的文字累赘举例： 所以我对原文进行大量的删减、裁剪、改写和添加， 主要 删除了一些没有信息的段落， 主要 加入了如何实施计时攻击相关的其它内容。 ——《计时攻击 TIMING ATTACKS》 这篇文章的 主要 内容 主要 是我今年3月份在腾讯做的直播， 主要 是想让一些技术人员对世界有一...</p>]]></summary>
    <content type="html"><![CDATA[<p>CoolShell 文章中出现的文字累赘举例：</p>
<blockquote>
<p>所以我对原文进行大量的删减、裁剪、改写和添加，<strong>主要</strong>删除了一些没有信息的段落，<strong>主要</strong>加入了如何实施计时攻击相关的其它内容。 </p>
<p>——《计时攻击 TIMING ATTACKS》</p>
</blockquote>
<blockquote>
<p>这篇文章的<strong>主要</strong>内容<strong>主要</strong>是我今年3月份在腾讯做的直播，<strong>主要</strong>是想让一些技术人员对世界有一个大体的认识。</p>
<p>—— 《程序员如何把控自己的职业》</p>
</blockquote>
]]></content>
  </entry>
  <entry>
    <title>给区块链一个定义</title>
    <link href="https://smallyu.net/2020/08/09/%E7%BB%99%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%80%E4%B8%AA%E5%AE%9A%E4%B9%89/"/>
    <id>blog:https://smallyu.net/2020/08/09/%E7%BB%99%E5%8C%BA%E5%9D%97%E9%93%BE%E4%B8%80%E4%B8%AA%E5%AE%9A%E4%B9%89/</id>
    <published>2020-08-09T08:06:45.000Z</published>
    <updated>2025-11-09T09:22:13.532Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>一直以来，区块链似乎都没有一个明确的定义，伴随区块链出现的词语经常是去中心化、溯源、不可篡改、以信用为基础、下一代价值互联网之类，这些都是区块链的特性，不是区块链的组成，这些词都在说区块链有什么，没有说区块链为什么会有那些，以及为什么要有那些。</p>
<p>感觉上很多东西]]></summary>
    <content type="html"><![CDATA[<p>一直以来，区块链似乎都没有一个明确的定义，伴随区块链出现的词语经常是去中心化、溯源、不可篡改、以信用为基础、下一代价值互联网之类，这些都是区块链的特性，不是区块链的组成，这些词都在说区块链有什么，没有说区块链为什么会有那些，以及为什么要有那些。</p><p>感觉上很多东西都没有明确的定义，比如，计算机是什么？都知道是那么一个东西，可以打游戏上网，稍微专业点的会说是基于冯诺依曼体系结构的、有 5 个组成部分的什么什么机器。其实计算机可以认为是“做计算的机器”，就这么简单。冰箱是什么？“一个放东西的柜子，有一些冷冻的功能”，就可以了。设计模式是什么？一种软件程序设计的范式。微服务是什么？一种软件架构的模式。所以区块链是什么？奇怪的是，区块链（blockchain）这个词不知从何而起，从来没有人明确提出这个概念，比特币白皮书里也只是提到 “chain of block”。</p><p>我以前对区块链有过一些不成熟的认识，虽然好像也没什么错，但不够清晰，尤其是没搞清楚一个问题，区块链是什么？现在来看，区块链的定义应该是：</p><blockquote><p>区块链是一种数据协同软件，或者说，区块链是一种用来同步数据的软件。</p></blockquote><p>数据协同软件决定用什么样的数据结构通过什么样的通信机制同步哪些数据。区块链不是数据库，区块链不负责储存数据，储存数据的事情会交给真正的数据库来做，区块链并不关心数据是怎么存在磁盘上的，不关心储存结构是否合理，利用率高不高，处理速度快不快。区块链关心数据以什么样的方式同步到其他的机器上，如何及时同步，以及其他机器同步过来的数据有没有问题。可以说，区块链是对数据协同软件的一种实现。</p><p>因为是数据协同软件，所以区块链多节点、去中心化，这显而易见。</p><p>溯源是指交易可溯源，只要数据之间有关联关系就可以，这是数据模型决定的，比如 UTXO。</p><p>链式的数据结构，是为了方便数据协同软件校验数据的完整性，类似用 md5 判断文件是否完整。这种数据结构并不是必要的，数据的全量对比也可以实现目的，只是效率非常低下。所以采用加密算法做摘要然后放到下一部分数据里的做法，相当于保证了一大块数据是完整的，仅此而已。</p><p>至于不可篡改，其实是数据协同软件带来的特性。区块链的不可篡改，并不是数据不能修改，而是改了之后其他节点不认可。这是不一样的，数据不能更改是技术问题，比如不提供更新数据的接口，用户就没有修改数据的渠道，通过技术手段可以控制。改了之后其他节点不接受，是一种机制，这种机制问题已经脱离技术领域。</p><p>区块链目前的发展受技术限制吗？计算机的计算理论包含两个主要部分，可计算性理论和复杂度理论。可计算性理论判断一个问题能不能用算法解决，复杂度理论意在提高算法的效率。和区块链有关系吗？退一步说，区块链需要计算吗？不需要，没有关系，不受限制。有个有趣的脑洞问题，如果把全世界的人都拉到一个微信群里，会发生什么？起码屏幕上的消息肯定刷不过来了。如果全世界的数据共用一条区块链，会发生什么？所以区块链最终还是机制的问题，不是技术问题。</p><p>比特币和区块链是两个概念，比特币是一种使用了区块链做数据同步的交易系统，比特币首先是一个交易系统，其次才需要的数据同步。这也是我以前犯的概念上的错误，把区块链等同于比特币了。很多对区块链概念比较模糊的人，提到区块链也都会往比特币之类的数字货币上想。记得去年参加过一个分享会，主讲人是某知名交易所总监，分享标题是区块链和国家政策什么的，整个会议下来，讲的却全是比特币的趣闻轶事。</p><p>区块链是比特币的组成部分。比特币的作者看到了比特币的价值，把软件和白皮书发布出来了。为什么比特币的作者没有把区块链的概念抽离出来，发个通用软件和说明书？是水平不够没有意识到区块链潜在的巨大价值吗？不是。区块链的提出，是因为人们看到了比特币的价值，想要复制比特币的成功，所以把比特币的技术组成提取出来，叫做区块链。可惜比特币是一个设计巧妙的系统，单独把某些技术特点拿出来难以产生预期的价值，这也是区块链的现状。这是现代版技术圈的东施效颦。</p><p>智能合约（Smart Contract）早在 1997 年由一位金融、法律从业者提出，“智能”是指和纸质合同相比，智能合约达到某一条件时就会自动执行某些操作，确实比纸质合同智能了一点，尤其在那个年代，数字化还没有普及，描述这是一种智能并不为过。而且，作者明确说，智能合约没有用到人工智能。</p><p>智能合约抽象一下，达到某一条件自动执行一些动作，不就类似编程语言的条件语句吗，事实上现在的智能合约大多是用图灵完备的编程语言实现的。用编程语言来描述合约的致命问题在于，编程语言的表达能力比自然语言弱太多了，如果试图用编程语言来重写保险说明书里的所有条文，“发生什么，就赔偿多少……”，这种改写的成本太高了，而且很多时候法律条文需要专业律师、法官解释和判断，现实世界的逻辑远比程序逻辑复杂，编程语言是搞不定的。</p><p>一种数据同步软件不应该被推崇，区块链被神化、妖魔化了。也因此，不能说区块链没有价值，因为区块链是且只是一种工具软件。</p>]]></content>
  </entry>
  <entry>
    <title>租房子遇到一个说话挺实在的东北大姐，当时看了一个我不太满意的房子，大姐好心劝我说，就这儿吧，没必要多花一千块钱非要个窗子...</title>
    <link href="https://t.smallyu.net/#2020-4"/>
    <id>micro:670926311</id>
    <published>2020-08-08T12:58:24Z</published>
    <updated>2020-08-09T05:38:51Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>租房子遇到一个说话挺实在的东北大姐，当时看了一个我不太满意的房子，大姐好心劝我说，就这儿吧，没必要多花一千块钱非要个窗子、阳台，今年挣钱不容易，多出来的几千块钱放在银行卡里不好吗，今年挣钱不容易，姐干这行十年了，找房子就图个人少、安静、干净，睡个觉就行了，你要结婚生孩子了愿意找好点的房子到时候再说，现在省点钱存点钱……...</p>]]></summary>
    <content type="html"><![CDATA[<p>租房子遇到一个说话挺实在的东北大姐，当时看了一个我不太满意的房子，大姐好心劝我说，就这儿吧，没必要多花一千块钱非要个窗子、阳台，今年挣钱不容易，多出来的几千块钱放在银行卡里不好吗，今年挣钱不容易，姐干这行十年了，找房子就图个人少、安静、干净，睡个觉就行了，你要结婚生孩子了愿意找好点的房子到时候再说，现在省点钱存点钱……</p>
<p>突然想起来去年租房子时找的中介也说过类似的话，你租房子就是睡个觉就行了，白天上班晚上回来玩玩手机，要那么大地方干嘛，没必要多花那个钱，这儿就挺好的，这个小区的房子要买的话不得八九万呐……</p>
<p>我去年信了，这次没信。不是因为他们骗人，他们没有骗人，也许说的是实话，是真心话。</p>
<p>似乎我的目的从来都不是存钱。也许他们是有代表性的一类人，几乎完全是在为生计而奔波而工作，也许停留在一线城市仅仅是为了更高的工资，赚更多的钱。相信不会有人说，我热爱中介这个行业，热爱玩弄信息差、玩弄话术，喜欢介绍房子时颠倒黑白，喜欢叫客户哥啊姐啊，能够在工作中和人的来往中自得其乐。</p>
<p>如果工作可以正常双休，每个月就会有 8 天的时间可以自由支配，加上每天下班后几个小时的时间，其实有很多时间可以自己处理。这是非常重要而且丰富的一些时间，尤其今年因为疫情没地方可去，加深了我对蜗居生活的恐惧，而且生活状态不好会占用很多心情，而且……原罪宁有种乎 :)</p>
]]></content>
  </entry>
  <entry>
    <title>北京五环内租房子的行情 🙃 3000+：客厅可以有 2500 、2700：主卧、双人床、大窗户、大空间 2200：常规...</title>
    <link href="https://t.smallyu.net/#2020-3"/>
    <id>micro:670919774</id>
    <published>2020-08-08T11:48:33Z</published>
    <updated>2020-08-08T15:39:39Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>北京五环内租房子的行情 🙃 3000+：客厅可以有 2500 、2700：主卧、双人床、大窗户、大空间 2200：常规次卧，适合一个人住，有一定活动空间 1600、1800：小次卧，装修看运气 1500-：暗间、阁楼、床位</p>]]></summary>
    <content type="html"><![CDATA[<p>北京五环内租房子的行情 🙃</p>
<ul>
<li>3000+：客厅可以有</li>
<li>2500 、2700：主卧、双人床、大窗户、大空间</li>
<li>2200：常规次卧，适合一个人住，有一定活动空间</li>
<li>1600、1800：小次卧，装修看运气</li>
<li>1500-：暗间、阁楼、床位</li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>蓝牙耳机的音质体验递减： 漫步者 Lollipods （￥225） Redmi AirDots（￥99） 小米 Air2...</title>
    <link href="https://t.smallyu.net/#2020-2"/>
    <id>micro:669730552</id>
    <published>2020-08-06T06:29:44Z</published>
    <updated>2020-08-07T05:50:04Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>蓝牙耳机的音质体验递减： 漫步者 Lollipods （￥225） Redmi AirDots（￥99） 小米 Air2 SE （￥138） 高仿 AirPods（￥198） 山寨 AirPods （￥30） 其他（￥50-）</p>]]></summary>
    <content type="html"><![CDATA[<p>蓝牙耳机的音质体验递减：</p>
<ul>
<li>漫步者 Lollipods （￥225）</li>
<li>Redmi AirDots（￥99）</li>
<li>小米 Air2 SE （￥138）</li>
<li>高仿 AirPods（￥198）</li>
<li>山寨 AirPods （￥30）</li>
<li>其他（￥50-）</li>
</ul>
]]></content>
  </entry>
  <entry>
    <title>晚上11点出门溜达刚刚好，天气凉快下来了，路上寥寥几个行人，零星几辆车子，环境里没有杂音，耳机的音效能够完全发挥出来，这...</title>
    <link href="https://t.smallyu.net/#2020-1"/>
    <id>micro:663880886</id>
    <published>2020-07-25T17:33:39Z</published>
    <updated>2020-07-25T17:46:35Z</updated>
    <category term="微博"/>
    <summary type="html"><![CDATA[<p>晚上11点出门溜达刚刚好，天气凉快下来了，路上寥寥几个行人，零星几辆车子，环境里没有杂音，耳机的音效能够完全发挥出来，这个时候精神状态也是正好，不像早上上班还没睡醒，晚上下班累的头晕。☕️</p>]]></summary>
    <content type="html"><![CDATA[<p>晚上11点出门溜达刚刚好，天气凉快下来了，路上寥寥几个行人，零星几辆车子，环境里没有杂音，耳机的音效能够完全发挥出来，这个时候精神状态也是正好，不像早上上班还没睡醒，晚上下班累的头晕。☕️</p>
]]></content>
  </entry>
  <entry>
    <title>宜怀旧 · 近期微博内容归档</title>
    <link href="https://crazy.smallyu.net/2020/06/26/%E5%AE%9C%E6%80%80%E6%97%A7-%E8%BF%91%E6%9C%9F%E5%BE%AE%E5%8D%9A%E5%86%85%E5%AE%B9%E5%BD%92%E6%A1%A3/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2020/06/26/%E5%AE%9C%E6%80%80%E6%97%A7-%E8%BF%91%E6%9C%9F%E5%BE%AE%E5%8D%9A%E5%86%85%E5%AE%B9%E5%BD%92%E6%A1%A3/</id>
    <published>2020-06-26T14:48:25.000Z</published>
    <updated>2025-08-16T03:27:11.427Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>一些简短的想法好像更适合实时记录在新浪微博（简称微博）这样的微博平台上，而不是直接或者总结后发布到博客里，博客对内容的定位似乎稍微有点”重“。</p>
<p>不过微博的内容质量实在是太差了，我尝试过多次打开微博后随便刷一刷，劣质的信息流让人无法忍受。而且微博有两种罪恶，一是]]></summary>
    <content type="html"><![CDATA[<p>一些简短的想法好像更适合实时记录在新浪微博（简称微博）这样的微博平台上，而不是直接或者总结后发布到博客里，博客对内容的定位似乎稍微有点”重“。</p><p>不过微博的内容质量实在是太差了，我尝试过多次打开微博后随便刷一刷，劣质的信息流让人无法忍受。而且微博有两种罪恶，一是能接受的“尺度”太小，我的网名 smallyu 仅仅因为包含”sm”两个字母，在微博的搜索引擎上就无法通过我的用户名搜索到我发布的内容，这很奇怪，也就是说任何包含”smile”、”smart”之类单词的网名都不能正常显示在搜索页面上，这种问题绝对和技术无关。微博的罪恶之二是用户会受到平台的干涉，崔永元在 Youtube 上开通了账号并时不时发布短视频，有一次提到说他在微博有两个账号，两千多万粉丝，但是忽然就不能发布内容了，没有给出任何说明，就是发不了内容，新浪微博不让发，所以现在开始用 Twitter 和 Youtube 了。</p><p>相比之下 Twitter 确实好很多，阮一峰的科技爱好者周刊 111 期里有个故事，Twitter 几乎给了用户最大限度的自由：</p><blockquote><p>一个推特用户做了一个实验，注册了一个帐号，特拉普发什么推特，他就发一样的内容，不是转发，而是原文复制，除此以外不发其他内容。</p><p>结果，推特官方三天就注意到了他，关闭帐号12小时，要求他在这段时间内删除违规言论。同样的话，特朗普可以说，你说就不行。媒体报道这件事以后，推特恢复了这个账号，并说关闭帐号是一个”失误”。</p></blockquote><p>想起来关于工具的选择的另外一个事，deepin 论坛里经常有人推荐360浏览器，我曾经也非常喜欢用360的浏览器，尤其是360极速浏览器，是一个基于 Chromium 内核套壳的浏览器，里面有一个自带的手势操作的功能，按住鼠标右键在浏览器窗口上划拉几下就能便捷的操作页面了，前进、后退、新建标签页、关闭页面、滚屏、滑动到页面顶部，等等，很好玩。直到后来有一天，国产浏览器集体封禁 <a href="https://996.icu/">996.icu</a> ，我决定再也不用国产浏览器了。</p><p>我不希望继续使用新浪微博了，Twitter 对内容几乎没有限制，UE也很好，但是毕竟和我们隔着一堵墙，网络环境总有点差强人意。至于怎么安置内容不是很多的短时间内的想法，得再想想办法了。前段时间本想在微博里“制造”一些看起来“正能量”一点的东西，后来有点跑偏了，不过原则还在，也就是只提”技术无关的话题“。</p><p>这是最近一段时间的微博的内容，按照时间正序归档到这里。</p><div class="cards"><div class="card">    <div class="card-time"><p>5月4日</p></div>    <div class="card-content"><p>亲情是一种糟糕的情绪，它会让人有难过的感觉。</p></div></div><div class="card">    <div class="card-time"><p>5月5日</p></div>    <div class="card-content"><p>租个小房子，都不知道天是几点亮的。</p></div></div><div class="card">    <div class="card-time"><p>5月7日</p></div>    <div class="card-content">        <p>有时候觉得生活糟透了，会不会以后也这样。</p>        <p>有时候觉得生活糟透了，好像前一段时间也这样。</p>    </div></div><div class="card">    <div class="card-time"></div>    <div class="card-content">        <p>第一次听到的让人心情激动的歌，再听就不觉得多好听了，第一次吃到的很好吃的麻辣小龙虾干拌方便面，再吃就没有太大感觉了。这是一种惩罚。</p>    </div></div><div class="card">    <div class="card-time"><p>5月15日</p></div>    <div class="card-content">        <p>我们都习惯于在游戏里做主角，在影视剧里做英雄，但是把我们放回盛唐，我们做不了李白，也成不了捉妖精的白居易，我们只会是一介平民，在历史上不配留下姓名。</p>    </div></div><div class="card">    <div class="card-time"></div>    <div class="card-content">        <p>喊加油的人是比较轻松的，在赛场上拼搏的人压力才最大。所以加个油算什么贡献？</p>    </div></div><div class="card">    <div class="card-time"><p>5月16日</p></div>    <div class="card-content">        <p>王者荣耀删了又下，下了又删。删掉是因为浪费了太多时间，下回来是因为时间浪费在了别的地方，还没有得到好的娱乐体验。</p>    </div></div><div class="card">    <div class="card-time"><p>5月17日</p></div>    <div class="card-content">        <p>现在的人，一旦微信拉黑就是真的绝交了，没有任何再挽回的机会，因为除了微信，没有其他方式可以联系到它了。住址更是无从得知。</p>    </div></div><div class="card">    <div class="card-time"><p>5月18日</p></div>    <div class="card-content">        <p>自得其乐也是一种生活方式，有梦想有追求也是一种生活方式。</p>    </div></div><div class="card">    <div class="card-time"><p>5月20日</p></div>    <div class="card-content">        <p>只有只有你知道，别人不知道的东西，才有价值。</p>    </div></div><div class="card">    <div class="card-time"><p>5月26日</p></div>    <div class="card-content">        <p>“没心没肺的人睡眠质量都高。”</p>    </div></div><div class="card">    <div class="card-time"><p>5月27日</p></div>    <div class="card-content">        <p>听歌的时候，如果突然听到一首好歌，后面会开始逐渐变得不耐烦，期望再遇到一首好歌，切歌变得频繁，但往往再难听到心动的歌。甚至切过很多的歌后，只好回头再去听当初的歌。</p>    </div></div><div class="card">    <div class="card-time"><p>5月28日</p></div>    <div class="card-content">        <p>《像我这样的人》​​​​</p>    </div></div><div class="card">    <div class="card-time"><p>5月29日</p></div>    <div class="card-content">        <p>一局不想赢的游戏，好像就变的不是那么好玩了。​​​​</p>    </div></div><div class="card">    <div class="card-time"></div>    <div class="card-content">        <p>流量限速了，早上听歌的时候，QQ音乐停在开屏页面进不去，因为开屏广告一直加载不出来。加载广告已经成了QQ音乐必需的一部分。相反网易云音乐就好一点。​​​​</p>    </div></div><div class="card">    <div class="card-time"></div>    <div class="card-content">        <p>听到一首好歌的另一面是，提高了对烂歌的鉴别能力，只要听一下前奏，或者一开口，就知道不是自己喜欢的类型。</p>    </div></div><div class="card">    <div class="card-time"><p>6月3日</p></div>    <div class="card-content"><p>百丈怀海有一次陪马祖大师外出，看见一群野鸭飞过。马祖问他：“那是什么？”怀海说：“野鸭子嘛。”马祖又问：“飞哪儿去了？”怀海说：“飞过去了。”马祖闻言上前，使劲拧怀海的鼻子，疼得怀海大叫。马祖说：“叫你还说飞过去了！”怀海当下大悟。</p><p>马祖的意思是：野鸭已经飞走了，你还在心里记挂着。</p><p>因此想起慧海禅师的故事。有人问慧海，他是如何用功的。慧海说：“很简单，饿了就吃，困了就睡。”那人说：“人人都是一样，这算什么用功。”慧海说：“不一样。”那人问：“怎么不一样？”慧海说：“他们思虑重重，吃饭时不肯吃饭，睡觉时不肯睡觉；我不然，我是该吃饭时吃饭，该睡觉时睡觉，这就是不同。”</p><p>——《读者》​​​​</p>    </div></div><div class="card">    <div class="card-time"><p>6月4日</p></div>    <div class="card-content"><p>有时候不好分辨一个人是真的有水平还是只会晃荡，想起以前的一个老师说话，有几个我早就注意到的经典的技巧。</p><p>让人觉得自己厉害的话术（一）：</p><p>1. 谈起自己和某位“有位置”的人的对话、经历，可能只是很简单的对话、很简单的来往，但是一加上什么什么主任的头衔，就感觉高大上了一点，什么时候见到什么主任在干什么，然后说了是什么话，计划要干点什么，让人感觉讲话者和主任的位置是一样的，有来往的关系。</p><p>2. 谈话的时候引用“有位置”人的话，尽管这些话可能很简单甚至没有道理。“我说的大概就是这个意思，就像什么主任说的，xxxxxx”。一方面体现了讲话者和他人来往密集，有观点的交流，另一方面，引用别人的话不好反驳。</p><p>3. “制造”榜样，说自己以前教的某个学生现在如何如何厉害，借用他人能力来抬高自己，让人感觉教出来的学生都那么厉害，这个老师肯定更是厉害多了。</p><p>4. ……</p>    </div></div><div class="card">    <div class="card-time"></div>    <div class="card-content"><p>买过很多次蓝牙耳机，一开始买的都是几十块钱的劣势的那种，几乎都能勉强用用，能听到声音，但也几乎都会存在各种各样的问题，左右音量大小不一样、有杂音、距离稍微远点就没有声音或者断开连接、容易被周围的磁场干扰等等，耳机的音质也很奇怪。后来因为无法忍受这些小问题，就买了一个Redmi的运动蓝牙耳机，虽然也不贵，但那些小问题通通不见了。</p><p>用过之后，很难说Redmi的蓝牙耳机有多好，但明显能感觉到的是，同样很难说有哪儿不好，起码没有那些糟心的问题了。所以其实好用不一定要有多好的体验，能够避开体验差的地方，本身就是一种好了。</p><p>以前用安卓手机，时间长会速度变慢是一方面，各种系统应用无法卸载、系统的操作界面上各种广告、权限无法控制，有的应用随便给你发通知，有的应用想收通知都收不到、屏幕亮度和色调……能够避开这些用户体验不好的地方，就算是一种好了，你可能说不上苹果比安卓好的地方，因为苹果可能确实没有比安卓好多少，只是少了非常多不好的地方。</p>    </div></div><div class="card">    <div class="card-time"><p>6月5日</p></div>    <div class="card-content"><p>不会有两种，一种是学过了，没学会，另一种是没学过，或者还没来得及学。</p><p>解决不了问题也有两种，一种是遇到过，或者正在遇到，解决不了，另一种是还没有遇到过。</p><p>对于没学过和还没遇到过问题的情况，很难直接判断一个人的能力，所以就需要拿以往的一些事例来证实一个人有相应的能力，比如学会过什么东西，解决过什么问题。</p><p>按照这样的思路，学历是事例的一种，有过学历，说明你学会过一些东西，类比推断，你有能力学会其他的一些东西。</p><p>工作经验也是事例的一种，有过解决问题的经验，说明你能够解决一些问题，类比推断，遇到其他问题时，你同样可以解决，所以你能够胜任某些工作。</p>    </div></div><div class="card">    <div class="card-time"><p>6月8日</p></div>    <div class="card-content"><p>PPT 演讲的主要内容有两种，一种是观点，对待某个问题的看法是怎样，原因是什么，为什么会有这样的观点，然后参会者有什么疑问或者不同想法，交流一下。另一种是案例，就是讲故事，背景、起因、过程、结果、总结，让人听故事，自己的事或别人的事，然后得出一个小结论，过渡到下一个观点或者另一个故事。</p><p>第三种内容是在 PPT 上写大段文字、理论、公式、技术方案，然后照着 PPT 读，跟讲课一样，指望能教会别人什么，这种做法显然是不可取的。</p><p>meetup 更像是一种技术交流会，大家平等的参与对话、交流技术问题，主讲者负责提出话题，其他人负责讨论。PPT 只是辅助主讲者表述话题的工具，是次要的，真正的价值还在人身上，看有没有观点，有没有案例，引出的话题是不是有足够的讨论性。</p>    </div></div><div class="card">    <div class="card-time"><p>6月10日</p></div>    <div class="card-content"><p>最近睡眠不好有点头晕，精神恍惚，突然想起来以前的一个大学同学，疯了……起码是有一些精神上的问题的，可能那段时间压力大，也可能那段时间经历了一些失败的事情，也可能那段时间没睡好，成为了精神失常的导火索。在精神状态不好抵抗力薄弱的时候受到精神上的打击，可能很危险。</p><p>精神失常是一种很常见的现象，是在某些特定的场景下很容易陷进的迷沼。回想上初高中的不太光彩的日子，其实也是浑浑噩噩不清不楚，做出来的事情缺乏理智，像未开化的原始人一样凭借原始的冲动说话做事。</p><p>《洛丽塔》、《穆赫兰道》、《Hello！树先生》、《小丑》这种精神分析片，基本上都有一个共同点是把真的和假的混在一起拍，作为观众无法直接区分，但是在有了分析影片的要是之后恍然大悟然后细思极恐。假的事情可以和真的一样，即使没有真的发生，你的意识认为发生了，就是发生了。所以我们是否也是患有精神疾病的人？我们经历的事情是否真的确实发生了？如果我们已经进入了精神世界的迷宫，该如何找到出口？</p>    </div></div><div class="card">    <div class="card-time"><p>6月17日</p></div>    <div class="card-content"><p>前几天吃饭，想起来关于酒桌文化的问题，中国人喜欢喝酒，越醉越好。</p><p>为什么想要别人醉呢，因为想要别人出丑。<br/>可对方是客户、是朋友，为什么想要朋友出丑？<br/>因为大家其实都很丑陋。</p><p>有的人外表光鲜亮丽，金玉其外，但实际上大家都是人，都会有点破事，都半斤八两。<br/>喝酒，就是想让人把这丑陋但真实的一面表现出来。<br/>你也表现，我也表现，互相知根知底，关系就变亲密了，生意就好谈了。</p>    </div></div><div class="card">    <div class="card-time"><p>6月22日</p></div>    <div class="card-content"><p>走在路上听歌，发现一首歌有点好听，但也不是特别好听，歌是好歌，原唱是烟嗓男声，撕裂的感觉，这个翻唱是女声，有点软绵绵的，好像没有原唱那种爆发力了。纠结了很久，从歌一开始直到歌曲快结束，经过一系列痛苦的挣扎和思想斗争，终于决定还是把这首歌添加到收藏列表，点个小红心。打开手机，解锁，进入网易云音乐，点开播放界面，小红心亮闪闪的杵在那里，原来这首歌已经在收藏列表了。</p><p>什么样的歌算是喜欢的歌？列表里的歌随意播放，能够引起你注意的应该就是了。可能是某一段音乐、某几句歌词、某一种声音，或者听的时候想要知道这首歌是什么歌，或者……就是在你走神的时候能把你拉回来，让你把注意力放到歌曲本身上面。</p><p>所以，知道喜欢什么样的东西之后，就能够确保不会错过喜欢的东西，避免永远忘记这个本可能是你喜欢的东西，避免第二次遇到才明白自己喜欢的悲剧。</p><p>包括人。</p>    </div></div><div class="card">    <div class="card-time"><p>6月24日</p></div>    <div class="card-content"><p>上周末和一个同学吃饭，颇有感慨。以前在博客上用一些篇幅提过这个同学的事情，如今我肯定不会主动拒绝别人的好意。这次见面，总的来说没有太多惊喜，想法还是以前的想法，做的事情基本上是意料之中的事情。有时候也想仔细分析一下他的人物性格，但又觉得不应该占用更多篇幅了。提几个点吧：</p><p>1. 感觉没必要过早“成熟”，想着赚钱、买房、结婚……反正我不喜欢。<br/>2. 如果一个人能够经常而不是偶尔带给你启发，那么他的思维能力高过你。<br/>3. 有时候觉得“难”，也许是消费超过了自己的承受能力，重点在于消费的起因，是自己的欲望、外人的压力或者别的什么。</p>    </div></div><div class="card">    <div class="card-time"><p>6月26日</p></div>    <div class="card-content"><p>最近打游戏发现一件好玩的事情，暂且可以把它称为“神秘的鼓励的力量”。</p><p>每次开局后，我都会发一条全局消息：“我们家XXX很厉害，你们小心点”，一开始仅仅是恶作剧，把所谓的队友放在了自己的对立面，感觉自己和对面是一伙的，有一种莫名的快感，卧底、破坏、当坏人。但是后来慢慢发现，也许是错觉，每次我说厉害的人，战绩都不错。</p><p>我消息里说到的厉害的人有两种，一种是真厉害的，（当然我经常挑段位高的说，毕竟匹配到的人从青铜到星耀都有），另一种是真的菜的。真厉害那种，要么是自己好好玩了，要么是对面听到这话不服，故意好好玩针对他了。比较菜的，我发出消息后还会解释自己其实才刚开始玩游戏，战绩不好的甚至会愧疚，自嘲说自己比美团还能送。</p><p>还有刚刚在游戏里发生的一个情况，有人出了三双鞋（演员，不想好好玩的那种），我发全局消息说，“我们家妲己说不买装备也能赢你们，你们不要高兴的太早”（他自然没说这话），本来只是随便调侃一下，结果你猜怎么着？队友们都开始变得团结了，妲己也好好玩了，甚至还道歉了。也许是这话说的太悲壮了？或者……这话里体现出了一种莫名的友善和信任和……？</p><p>我有些感同身受，能够理解这种情况下的心理。虽然懒得分析这种行为本身，但是从这里出发想到了关于“鼓励”、“信任”之类的东西，或许有时候鼓励别人、信任别人的能力，要比命令别人、定个严厉的标准规范别人的行为效果好。当然也得分人。当然还有一个词叫“捧杀”。当然有当然……</p>    </div></div><div class="card">    <div class="card-time"><p>6月28日</p></div>    <div class="card-content">        <p>最后补充一条，以前屡次删除王者荣耀还有个原因，就是对人性的反复失望。希望这次卸载后不要再让历史重演。</p>    </div></div></div>]]></content>
  </entry>
  <entry>
    <title>构造函数为什么没有返回值？</title>
    <link href="https://b.smallyu.net/2020/05/16/%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%B8%BA%E4%BB%80%E4%B9%88%E6%B2%A1%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%9F/"/>
    <id>blog-b:https://b.smallyu.net/2020/05/16/%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%B8%BA%E4%BB%80%E4%B9%88%E6%B2%A1%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%9F/</id>
    <published>2020-05-16T04:19:44.000Z</published>
    <updated>2026-03-02T09:06:05.035Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>刚才同学问了我一个问题，C++里new一个类的成员函数是什么意思？</p>
<p>……我心想，new成员函数？还有这种操作？</p>
<p>后来我问，这个成员函数，名字是不是和类名一样？</p>
<p>他说一样，就是构造函数。</p>
<p>……那不就是new一个对象吗？<]]></summary>
    <content type="html"><![CDATA[<p>刚才同学问了我一个问题，C++里new一个类的成员函数是什么意思？</p><p>……我心想，new成员函数？还有这种操作？</p><p>后来我问，这个成员函数，名字是不是和类名一样？</p><p>他说一样，就是构造函数。</p><p>……那不就是new一个对象吗？</p><p>然后他问了一个深刻的问题，为什么构造函数没有返回值？</p><p>我说new的是类，new后面指的是类名，不是成员函数。</p><p>可是类没有参数啊？</p><p>构造函数有参数。</p><p>但是构造函数没有返回值啊？</p><p>啊？</p><img src="face.jpeg" width="30%" /><p>这是一段简单的代码：</p><pre><code class="C++">#include &lt;iostream&gt;using namespace std;class Test&#123;    public:        Test(int num);&#125;;// 构造函数，有参数没有返回值Test::Test(int num)&#123;    cout &lt;&lt; num &lt;&lt; endl;&#125;int main()&#123;    // 对象赋值给了变量    Test* test = new Test(1);    return 0;&#125;</code></pre><p>其实不看代码也能想到这个场景。new一个对象的时候，new后面的变量，指的的类名，还是方法名？</p><p>如果指的是类名，类本身没有参数，也没有返回值，而且new这个关键字在代码的行为上也会特殊于其他语句。另外，类会有一个默认的无参构造方法，如果new的是类，要默认的构造方法干嘛？</p><p>如果指的是函数名，构造函数没有返回值，像上面的代码里明显就把<code>new Test(1)</code>赋值给了<code>Test* test</code>。</p><p>构造函数为什么没有返回值？因为构造函数在执行的时候，告诉编译器在内存上开辟多大的空间，初始化了成员变量，确定了this的地址，然后干了这些事情之后，就不允许用户自定义返回值的类型了？因为构造函数的返回值一定且必须是它自己，所以就不需要对用户透明了（编译器为什么要“擅自”做这样的事情？）？</p><p>构造函数为什么没有返回值？我并不知道这个问题的答案，也不大有兴趣知道。但这个问题带给我很大的启发，也带给我很大的震撼，“new成员函数”这种说法真是思路清奇。我们对太多东西习以为常，司空见惯，觉得它应该就是那样，却很少问它为什么是那样，很少认真去思考和认识很多事物。</p>]]></content>
  </entry>
  <entry>
    <title>关于人的能力，经验，和……</title>
    <link href="https://b.smallyu.net/2020/05/03/%E5%85%B3%E4%BA%8E%E4%BA%BA%E7%9A%84%E8%83%BD%E5%8A%9B%EF%BC%8C%E7%BB%8F%E9%AA%8C%EF%BC%8C%E5%92%8C%E2%80%A6%E2%80%A6/"/>
    <id>blog-b:https://b.smallyu.net/2020/05/03/%E5%85%B3%E4%BA%8E%E4%BA%BA%E7%9A%84%E8%83%BD%E5%8A%9B%EF%BC%8C%E7%BB%8F%E9%AA%8C%EF%BC%8C%E5%92%8C%E2%80%A6%E2%80%A6/</id>
    <published>2020-05-03T13:50:15.000Z</published>
    <updated>2026-07-25T13:03:58.096Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>最近好像没什么特别的事情，工作内容比起以前变多了，占据了很多时间，工作之外的空隙时间，似乎没有太多精力去关注学习。</p>
<p>这个博客上的内容，大概就那么两三种，一种是想到和学习到的技术方面的东西，再一种是工作和生活方面的事情，遇到的或者想到的引起了一些感悟的事情，第三]]></summary>
    <content type="html"><![CDATA[<p>最近好像没什么特别的事情，工作内容比起以前变多了，占据了很多时间，工作之外的空隙时间，似乎没有太多精力去关注学习。</p><p>这个博客上的内容，大概就那么两三种，一种是想到和学习到的技术方面的东西，再一种是工作和生活方面的事情，遇到的或者想到的引起了一些感悟的事情，第三种也许就是流水账、幻想之类，单纯做记录用，写下发生了什么事情。设想中博客的内容频率大概两周到一个月左右，时间太短没什么可说的，时间太长就有点长了。如果连续很长一段时间没什么可写或者不想写，就意味了发生了危险的事情，要么是松懈于动脑子了，要么是心理产生了不正常的问题。所以博客也可以作为自己的照妖镜。</p><p>最近纠结于的一点事情，问题在于很难得出什么结论。</p><p>(1)</p><p>前段时间周末的时候一个读研的同学问了我一点比较基础的操作问题。一个C++的项目，从Github克隆下来，用VS2012打开后编译报错，说找不到文件。我很少接触C++，不过还是尽快了解了一下。项目叫 <a href="https://www.wxishiko.com/wxCharts/">wxCharts</a>，是一个图表的UI库，编译的时候几乎找不到所有的头文件。他的老师告诉他在常规里把外部依赖库加上，他就加啊加还是找不到头文件。</p><p>我说把找不到的文件随便挑一个，在磁盘里搜一下，搜不到……</p><p>后来我看了一下wxCharts的官网，知道了wxCharts是依赖于 <a href="https://www.wxwidgets.org/">wxWidgets</a> 的。wxWidgets是一个GUI库，wxCharts只是这个GUI库的样式组件。然后我本地测试了一下，编译安装wxWidgets后wxCharts就能编译过了。</p><p>原因找到了，但是他说他已经安装过wxWidgets了。我当时不太确定window下vs的<code>生成</code>和linux的<code>make install</code>是不是一回事，就说有那么几种方案，一是把wxWidgets下面的wx文件夹复制到wxCharts下（wx文件夹是项目默认的依赖文件夹，类似Go项目的src目录），二是把wxCharts的项目源码放到wxWidgets项目里试试能不能编译过，三是重新安装一下wxWidget，一定要全局安装，环境变量里配置一下。</p><p>后来折腾半天总算是能找到头文件了，外部依赖那里配置的路径有问题，用了错误的环境变量作为路径的变量，还重复引用了错误的路径。但是编译还不通过，找不到什么什么文件的，又折腾了一下，就是除了头文件还要引入动态依赖库，而且编译了生产版本的目录位置不一样，后面带d的是debug版本……</p><p>其实整个过程面对的问题很简单，就是找不到项目依赖，如果Java项目必定轻车熟路了（话说其实有工作好几年的同事面对项目依赖这种低级问题有时候还难以搞定的）。这是我一个关系不错的同学，本科时我们天天坐在床上打王者荣耀。他的实力我还是稍微有一些了解，可能学术能力比较强，但计算机方面真是比小白还小白。但要说学术能力多强其实本科成绩还没我好，也就是考研的一年多确实实实在在的努力了。</p><p>稍有感触的一点是，说起来现在他算是一所还不错的211大学的研究生，我的学历依然是双非本科，学历上差了好几个段位。至于能力的话，只能说曾经有一个考研的机会放在我面前，我没有珍惜，直到失去了也没有一丝丝悔意，如果上天给我一个重新来过的机会，我一定会做出和现在相同的决定，如果非要给这个决定加一个期限，我希望是，有生之年。</p><p>(2)</p><p>有一个我以前也提到过的让我感觉充满矛盾的同事，实际的动手能力和对工作的负责程度真是让我感觉理解不了。但是后来遇到几次问题，发现她毕竟还是有丰富开发经验的，经验方面真的难以反驳的超过我。</p><p>当时面对比较简单的一个递归的问题。我之前也确实一直没搞明白，一个对象传到一个函数里面，是值还是引用传递？</p><pre><code class="JavaScript">function a() &#123;    obj = &#123; &quot;a&quot;: 1 &#125;    b(obj)    console.log(obj)&#125;function b(obj) &#123;    // 方式1    obj = 1    // 方式2    obj = &#123; &quot;a&quot;: 2 &#125;    // 方式3    obj.a = 2&#125;</code></pre><p>必须先搞清楚这个问题，才能使用递归解决问题。方式1直接给对象赋值，方式2给了参数一个新的对象，方式3改变了对象的属性。我当时是没有概念的，一心想着是不是能用原型链解决这个问题。我也知道她不太清楚这个问题，但是她疑疑惑惑的提了一句这个和堆栈是不是有关系，然后又很不确定的没再提了。</p><p>我以为没有关系，我以为她是随口说的。我错了。</p><p>对象是引用传递的，这一点没有问题，但对象的属性有没有改变，取决于改变的是对象的栈空间还是堆空间。给对象赋新值，不管是简单值还是复合值，都会将对象的变量指向新的栈地址，所以对象的属性并不会改变。如果直接用方式3的写法，改变的是对象指向的堆里面的内容，原对象的属性就会改变。</p><p>所以其实经验在一定程度上是有用并且难以轻易超越的，经验基本上无法通过捷径获得。</p><p>(3)</p><p>能力通过经验获得，强大的能力可以更快更有效的获取更高级的经验，然后这些经验会使能力更加强大。</p><p>也许能力和经验是相辅相成的，类比所谓的“经验和洞察力”。其实这里的“能力”确实稍微有点“洞察力”的意味。有时候在招聘的时候感觉招聘方一味强调多少多少年经验，好像用工作经验多的人就比用经验少的人占了便宜一样，但是吧，关于能力和经验……</p><p>这两天下了一个编曲的软件，简单尝试一下，感觉编曲这个事情，其实还是很难的，和编程虽然只有一字之差，技能要求却是截然不同而且更高的。现在各种培训班、在线课程，编程已经几乎没有门槛，当“全民编程”的时代来临后，我们改怎么面对这个世界呢。未来的编程也许不会把MVC、ORM什么的渗透到生活中，但一套物联网设备、自动化设备，或者iOS系统快捷指令的未来版本，如何更加适合人类个性化的生活习惯，可能多少也会需要点“编程”的逻辑。</p><p>PS:</p><img src="chortcut.png" width="30%" /><center>iOS 13的快捷指令已经支持基本的语句逻辑</center>]]></content>
  </entry>
  <entry>
    <title>从 Erlang 开始了解 Actor 模型</title>
    <link href="https://smallyu.net/2020/03/31/%E4%BB%8EErlang%E5%BC%80%E5%A7%8B%E4%BA%86%E8%A7%A3Actor%E6%A8%A1%E5%9E%8B/"/>
    <id>blog:https://smallyu.net/2020/03/31/%E4%BB%8EErlang%E5%BC%80%E5%A7%8B%E4%BA%86%E8%A7%A3Actor%E6%A8%A1%E5%9E%8B/</id>
    <published>2020-03-31T04:47:59.000Z</published>
    <updated>2025-11-09T09:22:13.310Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Actor]]></summary>
    <content type="html"><![CDATA[<p>Actor Model是一个宽泛的概念，早在上个世纪就被提出来，它将Actor视作一个整体，可以是原子变量，也可以是一个实体，也可以代表一个线程，Actor之间相互通信，每个Actor都有自己的状态，在接收到其他Actor的消息后可以改变自己的状态，或者做一些其他事情。一般提到Actor，会用Erlang、Elixir或Akka来举例，它们都在一定程度上实现了Actor模型。</p><p>前端的MVVM框架React、Vue等都有各自的数据流管理框架，比如Redux和Vuex，这些数据流管理框架中有几个类似的概念，Action、Reducer、State之类，这些概念有时候会让人感到迷惑。现在前端变得越来越复杂，其中有一些东西可能是借鉴后端的，像TypeScript的类型系统。我好奇这些前端框架里的Action和后端的Actor模型在概念上是否有相似的地方。</p><p>其实Action的本质是简单的，甚至代码的原理也是简单的，reducer里面用switch判断不同的操作类型，去调不同的方法。最简化的形式就是一个方法Action改变了全局变量state的值。Redux文档里说它的设计来自Flux架构，Flux架构的来源暂时不得而知，但也不太可能说是受到了Actor模型的启发。</p><pre><code class="JavaScript">let state = nullfunction action(val) &#123;  state = val&#125;</code></pre><p>Erlang是一门古老的编程语言，也是一门典型的受Actor Model启发的编程语言。单纯去理解概念是空泛的，从具体的、特定的语言入手也许能帮助我们探索这些理论。就像学习FP，选择Haskell要好过Java很多倍。Elixir是基于Erlang虚拟机的一门语言，与Erlang的关系类似Scala和Java的关系，也因此Erlang的语法相对简单和干净一点。</p><h3 id="Erlang"><a href="#Erlang" class="headerlink" title="Erlang"></a>Erlang</h3><p>Erlang的代码块以<code>.</code>结尾，代码块可能只有一行，也可以有多行，<code>.</code>的作用类似于<code>&#125;</code>，只是Erlang里没有<code>&#123;</code>。代码块内的语句以<code>,</code>结尾，意味一个语句的结束，相当于一些语言的<code>;</code>。</p><p>Erlang将一个程序文件定义为一个模块，在命令行中使用<code>c(test).</code>可以加载模块。模块名称必须和文件名称一致：</p><pre><code class="Erlang">-module(test).</code></pre><p>文件头部需要定义程序export的函数，这是模块的出口：</p><pre><code class="Erlang">-export([start/0, ping/3, pong/0]).</code></pre><p>这里导出了3个函数，方括号和其他语言一样表示数组，函数名称后面的<code>/0</code>、<code>/3</code>指函数参数的个数。start函数将作为程序的主入口，负责启动整个程序，ping负责发送消息，pong负责接收消息并做出响应。</p><p>Erlang里面有个<code>process</code>的概念，它不是线程，也不是指计算机层面的进程，它就是<code>process</code>，或者也能把它当做线程，但是要明白它和线程不一样。我们将启动两个process，一个负责ping，一个负责pong，模拟消息的传输和交互。可以类比启动了两个线程，一个负责生产，一个负责消费。</p><pre><code class="Erlang">ping(0, Pong_PID, StartTime) -&gt;     Pong_PID ! &#123;finished, StartTime&#125;;</code></pre><p>这是ping函数的第一部分，是ping函数的一个分支，接收3个参数，如果第一个参数是0，就会执行这个函数中的语句。第二个参数<code>Pong_PID</code>指包含pong的process，第三个参数指程序启动的时间，用于记录程序的运行时长。函数体内只有一个语句，<code>!</code>是发送消息的意思，意为将数据<code>&#123;finished, StartTime&#125;</code>发送到id为<code>Pong_PID</code>的process中，其中finished是一个<code>Atom</code>，作为标识发送到pong那里。Atom是Erlang的数据类型之一，相当于……不需要声明的常量。</p><pre><code class="Erlang">ping(N, Pong_PID, StartTime) -&gt;     Pong_PID ! &#123;ping, self()&#125;,    receive        pong -&gt;             io:format(&quot;~w~n&quot;, [N])    end,    ping(N - 1, Pong_PID, StartTime).</code></pre><p>这是ping函数的第二部分，如果函数接收到的第一个参数不等于0，就会执行这个函数内的语句。这一部分函数在接收到请求后，首先会做和分支一同样的事情，就是把数据<code>&#123;ping, self()&#125;</code>发送给pong，区别在于这里的标识为<code>ping</code>而不是<code>finished</code>，pong那里会根据这个标识做不同的操作，至于第二个参数，<code>self()</code>会返回当前process的id，也就是把ping的id传给了pong，用以pong回复消息。pong会选择性的使用第二个参数。</p><p>把数据发送到pong之后，有一个<code>receive ... end</code>的代码段，这个代码段会阻塞当前程序的执行，直到当前process接收到数据。代码段里是一个简单的模式匹配，<code>pong</code>是一个Atom类型的变量，如果接收到pong这样的标识，就会执行<code>-&gt;</code>后面的语句。<code>io:format</code>是一个简单的格式化输出，把N的值打印到屏幕上。</p><p>receive结束之后，马上又调了一下ping自己，递归……直到N为0，也就是说ping和pong的交互会持续N次，<code>io:format</code>那里会把交互次数打印出来。这是ping函数的两个分支，pong函数和ping函数的程序类似：</p><pre><code class="Erlang">pong() -&gt;    receive        &#123;finished, StartTime&#125; -&gt;             io:format(&quot;The End&quot;);            io:format(&quot;~w~n&quot;, [erlang:timestamp()]);            io:format(&quot;~w~n&quot;, [StartTime]);        &#123;ping, Ping_PID&#125; -&gt;            Ping_PID ! pong,            pong()    end.</code></pre><p>pong函数在入参层面没有分支，但是receive里有两种匹配，如果接收到了结束标识finished，会把开始时间和结束时间都打印出来，然后程序结束。如果接收到的标识是ping而不是finished，首先给Ping_PID也就是ping的process一个pong的响应，然后调了一遍自己，相当于先发了一个消息出去，接着自己等待消息的回复，如果没有收到回复，它就一直等着。</p><pre><code class="Erlang">start() -&gt;    Pong_PID = spawn(test, pong, []),    spawn(test, ping, [10, Pong_PID, erlang:timestamp()]).</code></pre><p>最后是start函数，程序的入口函数，spawn了两个process，这两个process分别单独地运行。当传入ping的第一个参数为10，ping和pong的交互将持续10次。</p><h3 id="交互速率"><a href="#交互速率" class="headerlink" title="交互速率"></a>交互速率</h3><p>以前听到过一个所谓的“大牛”讲，我们现在想要提高计算机的速率，瓶颈是什么呢，我们应该往哪个方向努力呢，应该是CPU的利用率，Actor是很快的，为什么快呢，因为一个Actor就是一个整体，一个Actor只在一个内核中运行，连CPU内核之间的交互都省了……这种说法的正确性可能有待验证，不过Actor是否真的快呢，我有点好奇，也因此萌生了测试一下Actor速度的想法。</p><p>必须要说明的是，我也相当清楚，这种测试方法很不靠谱。</p><p>在Erlang程序里启动两个process，两个process之间相互通信，测试不同数量级的通信次数，记录下程序执行所花费的时间。与Erlang作为对比，在Java里启动两个线程，用线程的睡眠和唤醒实现线程间的通信。同样的，在Go语言里用两个协程通信。至于Akka……其实也是Actor的代表。下表是测试之后的结果，次数从1到1亿，时间单位为毫秒。</p><table class="table"><thead><tr><th style="text-align:right">次数</th><th style="text-align:right">Erlang</th><th style="text-align:right">Java</th><th style="text-align:right">Go</th><th style="text-align:right">Akka</th></tr></thead><tbody><tr><td style="text-align:right">1</td><td style="text-align:right">0</td><td style="text-align:right">0</td><td style="text-align:right">0</td><td style="text-align:right">3</td></tr><tr><td style="text-align:right">10</td><td style="text-align:right">0</td><td style="text-align:right">1</td><td style="text-align:right">0</td><td style="text-align:right">7</td></tr><tr><td style="text-align:right">100</td><td style="text-align:right">3</td><td style="text-align:right">4</td><td style="text-align:right">1</td><td style="text-align:right">17</td></tr><tr><td style="text-align:right">1,000</td><td style="text-align:right">26</td><td style="text-align:right">30</td><td style="text-align:right">4</td><td style="text-align:right">83</td></tr><tr style="background:#ffff0008;"><td style="text-align:right">10,000</td><td style="text-align:right;"><span style="color:#0000ff99;">610</span></td><td style="text-align:right">168</td><td style="text-align:right">42</td><td style="text-align:right"><span style="color:#0000ff99;">225</span></td></tr><tr style="background:#ffff0008;"><td style="text-align:right">100,000</td><td style="text-align:right">2783</td><td style="text-align:right"><span style="color:#0000ff99;">1295</span></td><td style="text-align:right">404</td><td style="text-align:right"><span style="color:#0000ff99;">674</span></td></tr><tr style="background:#ffff0008;"><td style="text-align:right">1,000,000</td><td style="text-align:right">27,085</td><td style="text-align:right">11,300</td><td style="text-align:right"><span style="color:#0000ff99;">4489</span></td><td style="text-align:right;"><span style="color:#0000ff99;">3515</span></td></tr><tr><td style="text-align:right">10,000,000</td><td style="text-align:right">273,912</td><td style="text-align:right">107,673</td><td style="text-align:right">40,335</td><td style="text-align:right">29,368</td></tr><tr><td style="text-align:right">100,000,000</td><td style="text-align:right">2,851,680</td><td style="text-align:right">1,092,879</td><td style="text-align:right">482,196</td><td style="text-align:right">300,228</td></tr></tbody></table><p>本来尝试用Echarts之类渲染一下这些数据，方便对比，后来发现这些数据绘制出来的折线图并不友好。</p><p>总的来看，Erlang的速度是最慢的，这可能和Erlang历史悠久有关，也许是因为没有得到足够的优化，相信Elixir的速度会好一些。相较之下，Java的速度胜过Erlang，Go语言的速度胜过Java，这似乎是意料之中的事情。Java的耗时是Erlang的1&#x2F;3，Go语言的耗时是Java的1&#x2F;2。</p><p>最让人惊讶的在于，Akka的Actor速度竟然比Go语言的协程还要快。在交互1000次之前，Akka的速度比Erlang还要慢，在10K数量级的时候，它的速度超过了Erlang，在100K数量级的时候，速度超过了Java，直到1M数量级的时候，Akka超过了Go语言，并且一直保持领先。这是一个令人难以置信的结果，同样是运行在JVM上，Akka的耗时是Java的1&#x2F;3，可能Java线程间的交互确实带来了很大的开销。</p><p>没有用Elixir做测试是一个遗憾。关于Akka为什快，和Actor模型有没有关系，有多大的关系，还需要进一步探索。</p><p>(The End)</p><h3 id="Akka"><a href="#Akka" class="headerlink" title="Akka"></a>Akka</h3><p>用来做测试的Akka程序是Akka官方的Hello Wrold程序，能看到明显的Actor模型的影子，尤其是<code>!</code>运算符和<code>receive</code>方法。</p><pre><code class="Scala">import akka.actor.typed.ActorRefimport akka.actor.typed.ActorSystemimport akka.actor.typed.Behaviorimport akka.actor.typed.scaladsl.Behaviorsimport GreeterMain.SayHello</code></pre><p>这是导入部分，如果使用VS Code之类的编辑器，这段代码还是很重要的。和Erlang的程序类似，有一个发消息的Greeter和一个接收并回复消息的GreeterBot，另外还有一个主方法。</p><pre><code class="Scala">object Greeter &#123;  final case class Greet(whom: String, replyTo: ActorRef[Greeted])  final case class Greeted(whom: String, from: ActorRef[Greet])  def apply(): Behavior[Greet] =     Behaviors.receive &#123; (context, message) =&gt;      message.replyTo ! Greeted(message.whom, context.self)      Behaviors.same    &#125;&#125;</code></pre><p>这是发消息的Greeter，当Greeter作为函数被调用，会自动执行apply中的代码。apply方法是一个receive，和Erlang的receive一样会阻塞程序直到Actor接收到消息。replyTo是GreeterBot的”pid”，Greeter接收到消息后会回复消息给GreeterBot。</p><pre><code class="Scala">object GreeterBot &#123;  var startTime = System.currentTimeMillis()  def apply(max: Int) = &#123;    bot(0, max)  &#125;  private def bot(greetingCounter: Int, max: Int): Behavior[Greeter.Greeted] =    Behaviors.receive &#123; (context, message) =&gt;      val n = greetingCounter + 1      context.log.info(&quot;&#123;&#125;&quot;, n)      if (n &gt;= max) &#123;        context.log.info(&quot;The End | &#123;&#125;&quot;, System.currentTimeMillis() - startTime)        Behaviors.stopped      &#125; else &#123;        message.from ! Greeter.Greet(message.whom, context.self)        bot(n, max)      &#125;    &#125;&#125;</code></pre><p>这是GreeterBot，和Erlang简洁的代码比起来，Scala冗长的类型声明可能显得有些……烦杂。GreeterBot接收到来自Greeter的消息后，判断n是否为max，如果已经执行够次数了，就停止，否则调用自己进行递归。</p><pre><code class="Scala">object GreeterMain &#123;  final case class SayHello(name: String)  def apply(): Behavior[SayHello] =    Behaviors.setup &#123; context =&gt;      val greeter = context.spawn(Greeter(), &quot;greeter&quot;)      Behaviors.receiveMessage &#123; message =&gt;        val replyTo = context.spawn(GreeterBot(max = 10), message.name)        greeter ! Greeter.Greet(message.name, replyTo)        Behaviors.same      &#125;    &#125;&#125;object AkkaQuickstart extends App &#123;  val greeterMain = ActorSystem(GreeterMain(), &quot;AkkaQuickStart&quot;)  greeterMain ! SayHello(&quot;Charles&quot;)&#125;</code></pre><p>最后是主方法，看着可能也有点……长。继承于App的类是能够运行的主类，向Actor系统中注册了GreetMain，同时GreetMain的apply方法被执行了一次。GreetMain里spawn了两个process，和Erlang的程序行为是类似的。</p><h3 id="Go"><a href="#Go" class="headerlink" title="Go"></a>Go</h3><p>Go语言的程序真的要简洁很多，这是程序头部：</p><pre><code class="Go">package mainimport(  &quot;fmt&quot;  &quot;time&quot;)var maxCount = 100000000var startTime = time.Now().UnixNano() / 1e6</code></pre><p>定义了两个变量，一个是程序执行次数，一个是程序开始时间。</p><pre><code class="Go">func main() &#123;  ch := make(chan bool)  exit := make(chan bool)  go func() &#123;    for i := 0; i &lt; maxCount; i++ &#123;      fmt.Println(i)      &lt;- ch      ch &lt;- true    &#125;  &#125;()  go func() &#123;    defer func() &#123;      timeUsed := time.Now().UnixNano() / 1e6 - startTime      fmt.Println(&quot;The End | &quot;, timeUsed)      close(ch)      close(exit)    &#125;()    for i := 0; i &lt; maxCount; i++ &#123;      ch &lt;- true      &lt;- ch    &#125;  &#125;()  &lt;- exit&#125;</code></pre><p>两个协程，从channel中取数据和向channel中写数据交替。Go语言的程序看着清爽太多了，Scala扎眼睛。</p><h3 id="Java"><a href="#Java" class="headerlink" title="Java"></a>Java</h3><p>Java的冗长程度不比Scala轻。</p><pre><code class="Java">public class Test&#123;    public static void main(String[] args) &#123;        Object lock = new Object();        Thread sender = new Sender(lock);        Thread receiver = new Receiver(lock);        sender.start();        receiver.start();    &#125;&#125;</code></pre><p>主方法里启动了两个线程，锁是共享资源。</p><pre><code class="Java">class Message &#123;    static long MAX_COUNT = 100000000;    static String status = new String(&quot;init&quot;);    static long count = 0;    static long startTime = 0;    public static void send() &#123;        System.out.println(count);        status = &quot;sent&quot;;        count++;        if (count == 1) &#123;            startTime = System.currentTimeMillis();        &#125;        if (count &gt;= MAX_COUNT) &#123;            status = &quot;stop&quot;;            long time = System.currentTimeMillis() - startTime;            System.out.println(&quot;The End | &quot; + time);        &#125;    &#125;    public static void receive() &#123;        status = &quot;received&quot;;    &#125;    public static String getStatus() &#123;        return status;    &#125;&#125;</code></pre><p>Message是临界资源，储存消息的内容。消息内容变更时做了一点其他的事情，把需要的日志打印到屏幕上。</p><pre><code class="Java">class Sender extends Thread &#123;    Object lock = null;    public Sender(Object lock) &#123;        this.lock = lock;    &#125;    @Override    public void run() &#123;        while (!Message.getStatus().equals(&quot;stop&quot;)) &#123;            synchronized (lock) &#123;                if (Message.getStatus().equals(&quot;init&quot;)                   || Message.getStatus().equals(&quot;received&quot;)) &#123;                    Message.send();                    lock.notify();                    try &#123;                        lock.wait();                    &#125; catch (Exception e) &#123;                        e.printStackTrace();                    &#125;                &#125;            &#125;        &#125;    &#125;&#125;class Receiver extends Thread &#123;    Object lock = null;    public Receiver(Object lock) &#123;        this.lock = lock;    &#125;    @Override    public void run() &#123;        while (!Message.getStatus().equals(&quot;stop&quot;)) &#123;            synchronized (lock) &#123;                if (Message.getStatus().equals(&quot;sent&quot;)) &#123;                    Message.receive();                    lock.notify();                    try &#123;                        lock.wait();                    &#125; catch (Exception e) &#123;                        e.printStackTrace();                    &#125;                &#125;            &#125;        &#125;    &#125;&#125;</code></pre><p>Sender和Receiver的程序类似，Sender先发送消息，然后wait，等着接收Receiver的消息，Receiver用while不停地判断有没有收到消息，如果有则回复消息，并且唤醒Sender，通知它该处理消息了，叫醒Sender后自己wait，等着Sender的反馈。</p>]]></content>
  </entry>
  <entry>
    <title>一种侧边导航栏的交互方式</title>
    <link href="https://smallyu.net/2020/03/21/%E4%B8%80%E7%A7%8D%E4%BE%A7%E8%BE%B9%E5%AF%BC%E8%88%AA%E6%A0%8F%E7%9A%84%E4%BA%A4%E4%BA%92%E6%96%B9%E5%BC%8F/"/>
    <id>blog:https://smallyu.net/2020/03/21/%E4%B8%80%E7%A7%8D%E4%BE%A7%E8%BE%B9%E5%AF%BC%E8%88%AA%E6%A0%8F%E7%9A%84%E4%BA%A4%E4%BA%92%E6%96%B9%E5%BC%8F/</id>
    <published>2020-03-21T09:59:37.000Z</published>
    <updated>2025-06-19T03:30:33.027Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>最近看到几个管理系统的演示项目，结合开发过程中不顺手的地方，发现大多数网站的侧边导航栏都是点击展开，点击关闭。</p>
<img src="classical.gif"]]></summary>
    <content type="html"><![CDATA[<p>最近看到几个管理系统的演示项目，结合开发过程中不顺手的地方，发现大多数网站的侧边导航栏都是点击展开，点击关闭。</p><img src="classical.gif" width="20%"><p>感觉这样的交互方式稍微有点繁琐：</p><ul><li>在不知道子菜单位置的情况下，需要一个一个点开才能找到需要的页面</li><li>在知道子菜单位置的情况下，也需要点击一下父级菜单，才能看到想要的子菜单</li><li>不一个一个点开，就无法知道子菜单有些什么</li><li>子菜单展开之后，需要一次一次点击父菜单才能收起</li></ul><p>后来就想，能不能把点击事件换成悬浮事件呢？只要鼠标放上去，菜单就会自动展开，不用点一下的操作了。但是单纯的悬浮展开，需要考虑菜单长度不一致的问题，如果下一个菜单的长度比当前菜单短，鼠标离开当前菜单，当前菜单收回，鼠标所在的位置会直接越过下一长度较短的菜单。</p><img src="problem.gif" width="20%"><p>像图片中这样，栏目二的长度是4，栏目三的长度是2，当鼠标从栏目二向下移动，离开栏目二的瞬间栏目二收回内容，鼠标在没有移动的情况下跳过了栏目三，悬浮在栏目四上，这其实是不合理的，会违背用户的预期。栏目二之后是栏目三，这是最正常的逻辑。</p><p>为了应对这一问题，也许可以将交互设计成这样，当鼠标离开栏目二后，栏目二不收回，直到鼠标离开整个导航栏，子菜单才自动折叠。如果子菜单展开时用户点击了某一父菜单，那这个父菜单即使鼠标离开导航栏也不收回。</p><img src="solution.gif" width="20%"><p>下面是一个demo页面，通过iframe嵌入到这里，可以对比两种侧边导航栏的交互方式（移动端没有鼠标悬浮事件）。我偏爱灵活一点的交互，第二种方式单击父菜单也可以展开收起列表，相当于在方式一的基础上加入了鼠标悬浮自动展开的能力。</p><div align="center"><iframe src="/html/sider_bar_demo.html" width="400px" height="580px" frameborder="0" scrolling="yes" style="border: 5px double #e4e4e4;"> </iframe></div><p>相较于鼠标悬浮自动展开不收回的方式，更进阶一点的做法是，当鼠标从上往下移动时，子菜单自动展开但不收回，当鼠标从下往上移动时，子菜单自动展开并且自动收回。因为子菜单要不要自动收回取决于对用户接下来的操作有没有影响。不过这样的效果实现起来有些复杂了，对于网页上的一个导航栏来说，需要不断监听鼠标的坐标，开发和和维护的成本有点高。</p>]]></content>
  </entry>
  <entry>
    <title>新的征程</title>
    <link href="https://crazy.smallyu.net/2020/03/08/%E6%96%B0%E7%9A%84%E5%BE%81%E7%A8%8B/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2020/03/08/%E6%96%B0%E7%9A%84%E5%BE%81%E7%A8%8B/</id>
    <published>2020-03-07T17:00:29.000Z</published>
    <updated>2026-07-04T17:36:19.117Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>我犹豫了很久，要不要把这些东西写下来，应该什么时候写，现在写合不合适……如果我无法在自己的独立博客上写自己想写的东西，我就被生活上的事情束缚了，博客也变的没有意义。我总是担心，如果我的同事、领导偶然看见我在博客上写想要离开公司，或者原来早就产生离开公司的想法，对公司有什么不]]></summary>
    <content type="html"><![CDATA[<p>我犹豫了很久，要不要把这些东西写下来，应该什么时候写，现在写合不合适……如果我无法在自己的独立博客上写自己想写的东西，我就被生活上的事情束缚了，博客也变的没有意义。我总是担心，如果我的同事、领导偶然看见我在博客上写想要离开公司，或者原来早就产生离开公司的想法，对公司有什么不满之类；或者担心招聘者会偶然看到我对公司的不忠诚，看到我说公司的坏话，会不会对新的公司也产生一大堆意见，毕竟我总是把网址写在简历中。</p><p>也可能世上本无事，我杞人忧天了。</p><h3 id="期望"><a href="#期望" class="headerlink" title="期望"></a>期望</h3><p>我期望的工作，可能需要一点实力，也需要一点运气。当HR问我想要跳槽的原因，我一开始的说辞是想要寻找更好的机会，不是现在的公司不好，而是想要更好。具体说就是想要找更好的发展前景，技术上或者业务上能够有更多的成长……直到HR问我，你现在的平台机会不多，前景不好，工作不饱满吗？</p><p>我重新思考了这个问题，关于为什么想要跳槽。我没有撒谎，现在的公司确实还好，没什么能说得上不好的地方，当然也说不上多好。我想了想，真正的原因应该是我作为开发人员，作为技术支持这样的一个角色，对于目前公司的情况来说，难堪大用。公司更需要的是能拉客户的销售，能写专利的技术研究员（投标的时候要指标），而不是能把脏活干好的熟练的工人。</p><p>我有算不上丰富的开发经验，从还有静态网站和动态网站之分的那个年代，接触到互联网之后对广阔的网络世界充满兴趣。从三极管到模拟电路、数字电路、集成芯片、单片机、汇编语言、树莓派、C语言、Java、JavaScript、MVC、MVVM、FP……除了网站开发，稍微知道一点安卓的玩法、用H5开发原生应用的混合开发、基于Node.js的桌面应用开发……大学读电子类专业并没有阻碍我对计算机的了解，反而知道了一些可能计算机专业不会学的电子电路、通信编码之类。其实我真正懂得东西很少，只是稍微知道一点概念，但内心深处总是充满力量，有一种莫名的热情，让我感觉自以为能够解决更多问题，事实上我也确实希望能有更多机会解决更多的问题，希望在技术上有长足的发展。</p><p>有时候会感觉世界的不公，我无法想象不会处理SVN冲突、搞不清二维数组的前端，没用过Docker、不懂RBAC权限模型的后端，不知道<code>String.valueOf()</code>和<code>(String)</code>区别、可以直接往<code>JSONObject</code>里传<code>Map</code>的Java开发，是合格的程序员。我可以解决同事无法解决的技术问题，有超过同事的技术广度，甚至有更多努力工作的意愿，但仅仅因为我的工作年限较短，别人的工作时间较长，我只能拿与我工作经验相当的工资。实际上我接触Web开发的时间可能比某些小作坊的面试官还要长（真的遇到过）。也许我的同事都是幸运者，在互联网还未退潮的时候上了船。</p><p>我并不是想说我是自大狂，我很清楚自己没有足够的实力，不懂JVM调优、背不下设计模式、没看过Spring或Redis的源码、不懂操作系统原理（看过两本书，抄过一本，没记住），不懂算法（见medium死），没有好的学历（双非）。我也不知道我会点什么。但是当面试官问我ECharts的用法、“事务的隔离级别”、“死锁产生的条件”、“Map的原理”，虽然有点卡壳……我同样有些犹豫，在百度用中文搜的第一条就能找到答案的问题，需不需要记下来呢，世界上的问题那么多，知识那么多。</p><h3 id="面向面试学习"><a href="#面向面试学习" class="headerlink" title="面向面试学习"></a>面向面试学习</h3><p>对于需不需要记下来的问题，我希望自然而然的解决。就像做开发，踩的坑多了，就成了资深程序员，看的报错日志多了，就能瞬间明白异常原因。我可以多面几个试，在面试过程中了解公司会问哪些问题，期望怎么样的回答，不断积累经验，顺便锻炼一下语言表达能力，在面试结束后弥补不足，补充知识。正好最近的疫情提供了绝佳的机会，几乎所有公司都无法现场面试，可以通过电话、视频面试，我在公司连假都不用请，除了稍微在心态上有点影响工作外，但保证不会落下进度。</p><p>到这里我又担心如果新的公司看到这些话，会不会认为我面试是刷经验去了，毕竟我真的会在简历上写下网址，大多数情况不会有人看，但万一呢……</p><p>目前对我来说，发展前景比工资重要太多了。所以最最最理想的情况，是进一家能叫得上名字的公司。折中一点的情况，是公司招牌和目前的公司相当，但是工资比现在高一点，底线是两千，试用期加上跳槽离职入职工作交接之类的成本，两千应该不夸张。再差一点的情况，再差一点，就是我被公司裁了，不得不找其他工作，又没有合适的机会，随便找了一家保证生存。</p><h3 id="最后的稻草"><a href="#最后的稻草" class="headerlink" title="最后的稻草"></a>最后的稻草</h3><p>我想说说目前的公司。当时在学校还是秋招阶段的时候，HR就跟我说，应届生两年后考虑涨工资。其实我从一开始就明白，我不可能等两年。开始实习后，带我的导师告诉我，他们一年涨一次。</p><p>所以在我被迫换部门后（当时公司效益不好，裁了很多人，未入职的应届生走了一半），我想着一定要等过个年，心里还在期望和等待的有两件事，一个是年终奖，一个是涨工资（普调）。倒不是在意能拿到手多少钱，而是想要了解一下公司的运作方式，绩效怎么回事，年终奖怎么发，是否和绩效挂钩，涨工资是怎么谈或者怎么样，还幻想着领导会不会谈个话，聊聊工作情况，表现怎样，未来计划，然后我应该说些什么，怎么表现，让领导看到我的能力。没有经历过那些，就想经历一下。</p><p>事实当然是令人失望的。我了解到部门内有的人三四年都没有涨过工资，暂且接受，但是到过年放假前的最后一天，我感到异常生气，因为没有年终奖。往年都有，就今年没有，这一点也能理解，公司效益不好。问题是公司当天把本季度的绩效工资发了下来（我们下季度发本季度绩效），这不是公司良心发现要发当前季度绩效了，如果想发，就应该和当月工资一起发。我当时瞬间想到的是“朝三暮四”这个词，公司把我们当猴养，我们在人格和尊严上都应该感受到侮辱，我无法继续忍受这种任人宰割的状况，没有公告，没有制度，没有任何形式的通知，关于工资、普调、年终奖，我希望知道规则，我希望知道该如何努力，该如何表现，问题是没有，全部没有，全看领导心情。我无法凭自己的努力改善自己的收入，这就是我在目前公司看不到希望的地方。我甚至都不明白我的直属领导到底是谁，到现在HR系统里还指向一个已经离职的名字，他什么时候来和我谈一谈工资的事情呢？</p><h3 id="区块链不是风口"><a href="#区块链不是风口" class="headerlink" title="区块链不是风口"></a>区块链不是风口</h3><p>最近几天初次知道了“共有知识”和“公共知识”的区别，重新明白了一下《皇帝的新装》里面的道理。提区块链是因为我目前属于区块链团队，公司也把一部分资源押在了区块链上。</p><pre><code class="html">我知道区块链没什么用。你知道区块链没什么用。他知道区块链没什么用。</code></pre><p>这是共有知识。</p><pre><code class="html">我知道 你和他都知道 区块链没什么用。你知道 我和他都知道 区块链没什么用。他知道 我和你都知道 区块链没什么用。</code></pre><p>这是公共知识。</p><p>大家都知道，但不清楚别人知不知道的，叫共有知识。当有人跨越了中间的沟壑，告诉所有人他们的想法是一致的，然后大家都知道了大家的想法是一致的，共有知识就变成了公共知识。目前的区块链就处于共有知识的阶段，因为很多人都说区块链怎样怎样，你无法不认可它的价值，如果你说区块链没有价值，那就是你不懂，你没有智慧，你见识浅薄，你……连位置最高的管理者都发话了，你能说你看不到区块链的价值吗？</p><p>和《皇帝的新装》的故事对比一下，是不是有一些相似之处？</p><h3 id="新的征程"><a href="#新的征程" class="headerlink" title="新的征程"></a>新的征程</h3><p>所以我真的犹豫了很久，要不要写下这些东西，关于当前的公司，关于新的目标，从年前放假的最后一天，直到现在。</p><p>我需要新的机会。</p>]]></content>
  </entry>
  <entry>
    <title>Java 项目开发中的3个小问题</title>
    <link href="https://b.smallyu.net/2020/02/26/Java%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%843%E4%B8%AA%E5%B0%8F%E9%97%AE%E9%A2%98/"/>
    <id>blog-b:https://b.smallyu.net/2020/02/26/Java%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%843%E4%B8%AA%E5%B0%8F%E9%97%AE%E9%A2%98/</id>
    <published>2020-02-26T09:37:42.000Z</published>
    <updated>2026-03-02T09:11:49.056Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p><strong>1.]]></summary>
    <content type="html"><![CDATA[<p><strong>1. mysql需要id自增主键吗</strong></p><p>有些时候我们会使用具有具体含义的字段作为主键，比如用用户名username而不是无意义的自增id。这样做的好处之一是可以利用主键不可重复的特性，保证username的惟一。如果试图写入重复的数据，数据库会抛出”Duplicate entry * for key PRIMARY”的错误。</p><p>利用这个“好处”的问题是，我们能否依赖以及是否需要依赖主键的默认特性（字段不重复）来实现我们业务上的需求（字段不重复），而事实上“不重复”是惟一索引的特性，并不是主键的特性。主键字段会自动加上惟一索引。</p><p>同时，利用这个“好处”的不便之处之一是，数据表缺少一个表示“数据行序列”的字段。oracle还有rownum这样的东西，mysql则没有，得用脚本实现。如果需要分段遍历表的话，没有行的概念就很难操作。</p><p>《阿里巴巴Java开发手册》明确要求表必备id字段，他们不一定是对的，但我相信他们的理由一定足够充分。</p><img src="id.png" width="90%" height="50%" /><p><strong>2. Map还是Bean</strong></p><p>用mybatis查询数据时，返回值类型一种是List<Map>，一种是List<Bean>。这里的Bean指数据对象（DO）。</p><p>使用Bean的好处显而易见，输入对象名再按下一个点，idea会自动弹出bean的getter和setter，表包含的属性一目了然。无论取值还是赋值，都对使用者友好。</p><p>使用Bean有可能存在的问题之一是，如果表结构有改动，比如删除一个字段，Bean类中对应删除了一个属性，同时删除了相应的getter和setter，那么只要是程序中用到了这个bean这个字段的地方，都需要逐一修改，如果不改，程序将无法通过编译。</p><p>我们经常在开发过程中遇到这种情况，调试A类，改了某个公用的COM类，编译的时候BCDEF…都报错了，这很让人抓狂，我只想要也迫切的只需要确认A类的问题是不是由COM类引起，却由于这种依赖关系需要尝试其他方法。</p><p>如果面临系统改造、整合、重构之类的问题，Bean也会暴露出同样的问题。我在最近接触的项目中，为了尽可能多复用原系统，尽可能少做改动，只好用含义不太相同的Bean.username储存实际上内容为Bean.phoneNumber的值。原系统的各种工具类（加解密、本地缓存之类）全都依赖Bean，涉及到Bean的改动之后，要么大批量的全改，要么全不改。</p><p>如果使用的是Map，Bean带来的问题可能会得到稍微的缓解。尤其是在合理处理取值操作后，比如<code>String.valueOf(map.get(&quot;&quot;))</code>可以避免伟大的空指针异常，程序取值为空也可以正常启动，需要变动的地方随心所欲的get、set，不再受Bean类getter、setter方法的限制。</p><p>另外，其实Map和Bean都是对属性的一种封装。</p><p><strong>3. 注解还是xml</strong></p><p>Spring的IOC支持注解也支持xml，mybatis的sql同样支持注解也支持xml。</p><p>在以前的时代，Java项目往往会打包成war或者jar，放在容器tomcat或者resin中运行。容器在运行的时候会将包自动解压成class文件和资源文件，资源文件就包括xml。使用xml配置的好处之一是，线上环境可以直接修改xml重启项目就完成操作，不需要再把java文件编译成class文件，打包解压替换，走一遍项目上线的流程，拉分支、开发、测试、编译、部署、合并基线，一步步发邮件。</p><p>我想现在时代变了，有持续集成，有自动化运维，有properties，有yml，xml似乎显得不是那么重要。</p><p>对于mybatis的sql来说，内部有一个xml的解析器，xml相当于一种dsl，通过配置来实现动态sql语句之类的需求。如果使用注解的方式，把sql写在provider里，我们就失去了xml解析器的功能。不过失去能力的同时，我们也会获得自由。面对字符串形式的sql语句，我们完全可以自己封装一个parser。</p><p>一个有趣的现象是，国外的开发者似乎更喜欢注解的方式，国内的开发者倾向于使用xml，国外的书籍很多作者使用注解做案例，国内的博客文章则大多使用xml配置做教程。这一点有些类似于前端框架react和vue的状况，技术实力较强的企业、开发者更加青睐react，因为jsx更像是编程语言，有更多的发挥空间，vue则受到技术实力较弱的企业和开发者喜爱，因为上手简单，开发简单。如果你用过vue就应该有体会，用那玩意儿开发不叫编程，它只是软件工业化的产物。</p>]]></content>
  </entry>
  <entry>
    <title>程序员的定位</title>
    <link href="https://b.smallyu.net/2020/01/11/%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E5%AE%9A%E4%BD%8D/"/>
    <id>blog-b:https://b.smallyu.net/2020/01/11/%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E5%AE%9A%E4%BD%8D/</id>
    <published>2020-01-11T10:19:45.000Z</published>
    <updated>2026-07-25T13:02:58.692Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>有一件可怕的事情是，程序员不再关注代码、软件、系统、架构，而是关注产品、运营、销售，展望内容不再是提高代码质量、迭代更好的软件、做更好的工程，而是提高文档输出能力、活跃团队气氛。</p>
<h3 id="startup与996"><a]]></summary>
    <content type="html"><![CDATA[<p>有一件可怕的事情是，程序员不再关注代码、软件、系统、架构，而是关注产品、运营、销售，展望内容不再是提高代码质量、迭代更好的软件、做更好的工程，而是提高文档输出能力、活跃团队气氛。</p><h3 id="startup与996"><a href="#startup与996" class="headerlink" title="startup与996"></a>startup与996</h3><p>公司开始倡导创业心态，创业嘛，大家就要一起努力，一起干大事。BOSS说，有天回公司晚了，看到某某和某某10点多还在……大家也要这样，我们也只能这样做，如果因为身体或者其他原因不能适合我们这种节奏了，可能就不太适合我们这个团队了。大家要一起努力，要10106，我们只能这样做，如果不这样做，如果不这样做……公司就会死。</p><p>当时听到这儿，哑然失笑。说句不太符合价值观的话，我明知道这样说不对，如果老板看到这样的想法，我明天就得和HR聊聊了，这是没有责任心的体现，这是没有职业道德的体现，这是……恕我直言，公司死掉，于我何干？</p><p>画饼啊，平时都听人吐槽，老板给画个大饼，入职后发现遥遥无期，然后上网发帖，不要相信老板的鬼话，不要相信什么福利奖金，拿到手的才是真的。我们这画风好像不太一样啊，如果不努力，公司会死掉？以前看到过一句话，所有人都告诉我们要努力，但是从来没有人告诉我们努力之后可以得到什么。公司死掉了，我们换家公司不也照样干活吗？</p><p>年会的问答环节上，大BOSS抓住了“享受红利”这个字眼，大意是红利不是公司给予的，要给公司带来相应的价值。猜想很多时候，公司的想法是，你要先给我干20分的活，我就分你10分的利。员工的想法是，你给我10分的钱，我就干好10分的活，你要再多给我5分，我就再多尽5分力。</p><p>996是类似的问题，我们为什么是10106？因为我们9点半上班，坐到工位上打开电脑、开个晨会大概就10点了，所以是1010，而不是99。关于996，一种说法是有些员工挣表现的心理，从小被奖励小红花的培育文化，造就了认为“只要努力就会有收获”的心态。不过很多老板也确实吃这一套。</p><p>昨天我听到了另一种说法。我们BOSS虽然说出了10106的话，但是并不会发正式的制度通知出来，因为这违反劳动法。我对此感到疑惑，这就不好办了呀，到底要不要10106？请教稍有经验的员工，得到的答案是，老板喜欢“聪明”的员工。也就是说，老板提到这个事了，具体怎么做得自己掂量。</p><h3 id="加班"><a href="#加班" class="headerlink" title="加班"></a>加班</h3><p>有时候项目紧、突发bug、上线、工作失误，偶尔加班很正常，有忙有闲。有的公司要求经常性加班，有干不完的活，也就是所谓996工作制。一般来说965是一个数，996是一个数，对应的薪资水平不同。产生矛盾的点在于，公司希望用965的薪资招996的人，员工希望领996的薪水干965的活。</p><p>存在一种情况是老板没有要求加班，但是有人加班。每个人分工不同，任务量不同，完成速度不同，要看具体情况。如果自己效率低于别人，加班无可厚非。比较坑的是别人因为效率不高整天加班，你完成任务没有加班，老板就在工作时间这件事上做文章。你如果和别人一样的工作时间，是不是就能产出更多了？别人没完成的也可以帮帮忙完成一下……相信明智的领导能够分辨出真正的工作能力，也能够按照工作量而不是工作时间判断产出。不过最可怕的是揣着明白装糊涂。</p><p>另一种情况是老板要求多呆一会儿。可能没有那么紧急的工作需要加班才能完成，但是别人加班了，为什么你到点就走？所有人都加班，就你特殊？……老板为什么会想要多呆一会儿呢，加班总归要多干点活吧，应该是植根于中国劳动人民群众心中占小便宜的心理。</p><p>其实996对工作产出的影响未必是正面的。如果到点大家都下班了，我是不好意思长留加班的（认真），别人都能完成工作，你需要加班完成，是不是你能力不行？所以工作内容会尽量在上班时间紧凑的完成。如果每天需要加班呢，反而会感觉上班稍微拖沓一点也没事，反正要加班，反正到点也走不了，上班时间摸摸鱼，没完成的好好加一把班，还能给老板留个好印象。</p><h3 id="技术人"><a href="#技术人" class="headerlink" title="技术人"></a>技术人</h3><p>公司开始倡导“销售导向”，因为销售是能够直接决定收益的一环，也是老板比较重视的部分。述职会上，我第一次从销售和运营的口中了解到公司的全貌，也是在述职会中，BOSS提到，“像了解机器学习常用的模型和算法是一些很具体的、很普通的事情，我们要……”，那正是我几天前的述职材料中提到的内容。</p><p>其实技术不重要，尤其是销售导向的公司，用到了什么技术真的不重要，重要的是把客户谈下来，把客户忽悠住，给公司挣钱。放在整个社会中，技术要足够领先、足够新，才能有立足的可能，像机器学习这样已经谈了十几年的技术，了解常见的用法确实很普通、很平庸。尤其是并不能带来什么收益。</p><p>从实行OKR开始，我们的绩效计划有两个特点，一是要有目标有结果，二是这个目标和结果不是工作内容方面的，而是自我提升方面的。自我提升主要指输出，就是写内刊、写专利、分享技术等，尤其是要能够给工作带来帮助的。讽刺的是，我们几乎没有技术氛围，真正写代码的只有几个骨干。从绩效管理能体现出的是，领导不太在意工作方面的内容，比如建立项目规范和开发规范，需求、开发、评审、测试之类的，领导更在意个人方面的东西。</p><p>可能很多时候的情况是，公司在意的是“你能给公司带来什么？”员工想的是“公司需要我做些什么？”</p><p>述职也是一样，不得不写一些工作之外，但又和工作相关的内容。深度学习本身是一个值得学习和研究的技术领域，即使是常见的模型和算法，从原理到工程至少也要1年的时间才能有一定了解。另外我目前的工作内容是应用层开发，也就是增删改查的业务之类，部门的技术主题是区块链，所以就把机器学习放在了展望一栏。</p><p>个人而言，机器学习是很大的一步。它本身有一定门槛，以前也多次尝试，看吴恩达的教程放弃了一次，看斯坦福的图像识别课放弃了一次，……有观点说机器学习是微积分在现代计算机技术背景下的发展，它的基础理论是数学，同时观点也提到，区块链是小骗，AI是大骗……不管骗不骗，总归还是要学的。</p><h3 id="程序员"><a href="#程序员" class="headerlink" title="程序员"></a>程序员</h3><p>和销售或者运营相比，程序员的特点之一可能是不那么依赖外部资源，人脉、市场、监管、业务，技术在形式上千变万化，本质上都是操作计算机进行计算。应用层开发的程序员，本职工作应该是按照进度要求完成开发任务，职业素养是保证代码质量，需要提升的是系统架构能力。熟练的Coder可以高效使用工具链，优秀的Coder可以优化算法、提高程序效率和系统性能。</p><p>对不起，I am a Coder，我认为不丢人。（@<a href="https://www.ruanyifeng.com/blog/2011/10/dont_call_yourself_a_programmer.html">不要自称为程序员</a>）</p>]]></content>
  </entry>
  <entry>
    <title>Rust 的 ownership 是什么？</title>
    <link href="https://smallyu.net/2019/12/21/Rust%E7%9A%84ownership%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F/"/>
    <id>blog:https://smallyu.net/2019/12/21/Rust%E7%9A%84ownership%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F/</id>
    <published>2019-12-21T15:06:28.000Z</published>
    <updated>2025-06-30T13:36:00.071Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Rust是内存安全的。Facobook的Libra使用Rust开发，并推出了新的编程语言Move。Move最大的特性是将数字资产作为资源（Resource）进行管理，资源的含义是只能够移动，无法复制，就像纸币一样，以此来保证数字资产的安全。其实Move的这种思想并不是独创的]]></summary>
    <content type="html"><![CDATA[<p>Rust是内存安全的。Facobook的Libra使用Rust开发，并推出了新的编程语言Move。Move最大的特性是将数字资产作为资源（Resource）进行管理，资源的含义是只能够移动，无法复制，就像纸币一样，以此来保证数字资产的安全。其实Move的这种思想并不是独创的，Rust早已使用这样的方式来管理内存，因此Rust是内存安全的。Rust中的内存由ownership系统进行管理。</p><h3 id="Java的引用计数"><a href="#Java的引用计数" class="headerlink" title="Java的引用计数"></a>Java的引用计数</h3><p>垃圾回收有很多种方式，ownership是其中之一。Java使用的是引用计数，引用计数法有一个广为人知的缺陷，无法回收循环引用涉及到的内存空间。引用计数的基本规则是，每次对内存的引用都会触发计数加一，比如实例化对象，将对象赋值给另一个变量，等。当变量引用被取消，对应的计数就减一，直到引用计数为0，才释放空间。</p><pre><code class="Java">class Test &#123;    Test ref = null;&#125;Test a = new Test(); // a的计数加一Test b = new Test(); // b的计数加一// 此时a的计数是1，b的计数是1a.ref = b;           // a的计数加一，因为ref是a的类变量b.ref = a;           // b的计数加一，因为ref是b的类变量// 此时a的计数是2，b的计数是2a = null;            // a的计数减一，因为a的引用被释放b = null;            // b的计数减一，因为b的引用被释放// 此时a的计数是1，b的计数是1</code></pre><p>因此，在a和b的引用被释放时，它们的计数仍然为1。想要a.ref的计数减一，就要将a.ref指向nulll，需要手动操作指定为null吗？当然不需要，Java从来没有手动释放内存空间的说法。一般情况下，a.ref执行的对象也就是b的空间被释放（计数为0）时，a.ref的计数也会自动减一，变成0，但此时因为发生了循环引用，b需要a的计数变为0，b的计数才能变成0，可a要想变成0，需要b先变成0。相当于死锁。</p><p>这和Rust的ownership有关系吗？当然，没有关系……</p><h3 id="ownership"><a href="#ownership" class="headerlink" title="ownership"></a>ownership</h3><p>ownership有三条基本规则：</p><ul><li>每个值都拥有一个变量<code>owner</code></li><li>同一时间只能有一个<code>owner</code>存在</li><li>当<code>owner</code>离开作用域，值的内存空间会被释放</li></ul><p>作用域多数情况由<code>&#123;&#125;</code>界定，和常规的作用域是一样的概念。</p><pre><code class="Rust">&#123;                       // s还没有声明    let s = &quot;hello&quot;;    // s是可用的&#125;                       // s已经离开作用域</code></pre><p>Rust的变量类型分简单类型和复杂类型，相当于普通变量和引用变量，因为ownership的存在，简单类型发生赋值操作是，值是被复制了一份的，但复杂类型是将引用直接重置到新的引用变量上，原先的变量将不可用。</p><pre><code class="Rust">let x = 5;let y = x;                        // y是5，x还是5let s1 = String::from(&quot;smallyu&quot;);let s2 = s1;                      // s2是&quot;smallyu&quot;，s1已经不可用</code></pre><p>赋值过程中，s2的指针先指向string，然后s1的指针被置空，这也就是移动（Move）的理念。如果想要s1仍然可用，需要使用<code>clone</code>复制一份数据到s2，而不是改变指针的指向。</p><pre><code class="Rust">let s1 = String::from(&quot;smallyu&quot;);let s2 = s1.clone();              // s1仍然可用</code></pre><h3 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h3><p>目前提到的有两个概念，一是ownership在离开作用域后会释放内存空间，二是复杂类型的变量以移动的方式在程序中传递。结合这两个特点，会发生这样的情况：</p><pre><code class="Rust">fn main() &#123;    let s = String::from(&quot;smallyu&quot;);    takes(s);             // s被传递到takes函数                          // takes执行结束后，s已经被释放    println!(&quot;&#123;&#125;&quot;, s);    // s不可用，程序报错&#125;fn takes(s: String) &#123;     // s进入作用域    println!(&quot;&#123;&#125;&quot;, s);    // s正常输出&#125;                         // s离开作用域，内存空间被释放</code></pre><p>如果把s赋值为简单类型，比如5，就不会发生这种情况。对于复杂类型的变量，一旦离开作用域空间就会释放，这一点是强制的，因此目前可以使用函数的返回值来处理这种情况：</p><pre><code class="Rust">fn main() &#123;    let s = String::from(&quot;smallyu&quot;);    let s2 = takes(s);     println!(&quot;&#123;&#125;&quot;, s2);&#125;fn takes(s: String) -&gt; String &#123;     println!(&quot;&#123;&#125;&quot;, s);     s&#125; </code></pre><p>takes把变量原封不动的返回了，但是需要一个变量接住takes返回的值，这里重新声明一个变量s2的原因是，s是不可变变量。</p><h3 id="引用变量"><a href="#引用变量" class="headerlink" title="引用变量"></a>引用变量</h3><p>引用变量不会触发ownership的drop方法，也就是引用变量在离开作用域后，内存空间不会被回收：</p><pre><code class="Rust">fn main() &#123;    let s = String::from(&quot;smallyu&quot;);    takes(&amp;s);    println!(&quot;&#123;&#125;&quot;, s);&#125;fn takes(s: &amp;String) &#123;    println!(&quot;&#123;&#125;&quot;, s);&#125;</code></pre><h3 id="可变变量"><a href="#可变变量" class="headerlink" title="可变变量"></a>可变变量</h3><p>引用变量仅属于可读的状态，在takes中，s可以被访问，但无法修改，比如重新赋值。可变变量可以解决这样的问题：</p><pre><code class="Rust">fn main() &#123;    let mut s = String::from(&quot;smallyu&quot;);    takes(&amp;mut s);    println!(&quot;&#123;&#125;&quot;, s);&#125;fn takes(s: &amp;mut String) &#123;    s.push_str(&quot;, aha!&quot;);&#125;</code></pre><p>可变变量也存在限制，同一个可变变量同一时间只能被一个其他变量引用：</p><pre><code class="Rust">let mut s = String::from(&quot;smallyu&quot;);let r1 = &amp;mut s;let r2 = &amp;mut s;println!(&quot;&#123;&#125;, &#123;&#125;&quot;, r1, r2);</code></pre><p>程序会报错，这是容易理解的，为了保证内存安全，一个变量只能存在一个可变的入口。如果r1和r2同时有权力更改s的值，将引起混乱。也因此，如果是<code>r1 = &amp;s</code>而不是<code>r1 = &amp;mut s</code>，程序会没有问题，只能存在一个引用针对的是可变变量的引用变量。</p><h3 id="返回值"><a href="#返回值" class="headerlink" title="返回值"></a>返回值</h3><p>函数的返回值类型不可以是引用类型，这同样和ownership的规则有关，返回普通变量相当于把函数里面的东西扔了出来，如果返回引用变量，引用变量指向的是函数里面的东西，但函数一旦执行结束就会销毁内部的一切，所以引用变量已经无法引用到函数。</p><pre><code class="Rust">fn dangle() -&gt; &amp;String &#123;    let s = String::from(&quot;smallyu&quot;);    &amp;s;&#125; // 到这里s的内容空间已经释放，返回值无法引用到这里</code></pre><h3 id="？"><a href="#？" class="headerlink" title="？"></a>？</h3><p>没有更多内容了。</p><p>最近看了一部能够让人振奋的美剧《硅谷》，编剧给主角挖了很多坑，感觉他们倒霉都是自己作的，编剧也给观众留了很多坑，剧情跌宕起伏到想给编剧寄刀片。抛开那些情节，剧中渲染的geek真的很帅，很帅！当然，神仙打架，凡人也参与不了。</p>]]></content>
  </entry>
  <entry>
    <title>我亲手写出了难以维护的代码</title>
    <link href="https://b.smallyu.net/2019/12/15/%E6%88%91%E4%BA%B2%E6%89%8B%E5%86%99%E5%87%BA%E4%BA%86%E9%9A%BE%E4%BB%A5%E7%BB%B4%E6%8A%A4%E7%9A%84%E4%BB%A3%E7%A0%81/"/>
    <id>blog-b:https://b.smallyu.net/2019/12/15/%E6%88%91%E4%BA%B2%E6%89%8B%E5%86%99%E5%87%BA%E4%BA%86%E9%9A%BE%E4%BB%A5%E7%BB%B4%E6%8A%A4%E7%9A%84%E4%BB%A3%E7%A0%81/</id>
    <published>2019-12-15T12:03:32.000Z</published>
    <updated>2026-07-25T13:04:42.553Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>前段时间尝试了一些线下活动，加上有几天身体异常痛苦，现在稍微静下来感觉恍如隔世。最近有个项目在做最后的验收，于是搬出了一两个月前的代码，需要手动操作更新一些数据。看到这些不久之前写的代码，同样恍如隔世的感觉，如果这是别人写的，我一定会第一时间认为很垃圾，既然是我亲手写的，客]]></summary>
    <content type="html"><![CDATA[<p>前段时间尝试了一些线下活动，加上有几天身体异常痛苦，现在稍微静下来感觉恍如隔世。最近有个项目在做最后的验收，于是搬出了一两个月前的代码，需要手动操作更新一些数据。看到这些不久之前写的代码，同样恍如隔世的感觉，如果这是别人写的，我一定会第一时间认为很垃圾，既然是我亲手写的，客观的说，它确实很垃圾。</p><p>那是一个很好记的日子，从那天开始，2019年才真正开始。我曾经接触的是老系统的代码，不得不在resin里启动项目，编译一次至少要两分钟，难以调试，曾经在测试服务器上开发和调试程序，而不是发布代码，曾经写过一些小任务，比如批量执行sql还踩了坑。我曾经看不起垃圾代码，看不起9102年还在用eclipse的程序员。</p><p>时至今日，我也变成了写出垃圾代码的程序员。</p><h3 id="小需求"><a href="#小需求" class="headerlink" title="小需求"></a>小需求</h3><p>第一次写出垃圾代码，印象比较深的是打印两次日志：</p><pre><code class="java">catch (e) &#123;    System.out.println(&quot;捕获到异常&quot;);    logger.error(&quot;捕获到异常&quot;);&#125;</code></pre><p>logger出现了多少次，println就出现了多少次，这显然是丑陋的做法。因为当时的nohup.out和log文件夹不在同一目录，log文件夹专门配置过放在统一的目录，然后希望nohup.out也有日志输出……具体原因有点模糊了，这应该是第一次恶心到我自己的代码。后来好像再版的时候去掉了，恍恍惚惚。</p><p>同样是这个需求中，当时的老大的代码里，有一处值得借鉴和赞赏的写法，我当时怀着慷慨激昂的心情认为这是冗余的做法，有点想要挑战权威的意味，事情证明还是年轻了。</p><pre><code class="java">代码想不起来了 T_T</code></pre><p>同样还是这个需求，需要实现可以自定义配置sql语句，类似jdbcTemplate中的<code>?</code>，或者mybatis的<code>#&#123;&#125;</code>，我当时用了非常生硬的做法：</p><pre><code class="java">// 需求sql = update set a=&#123;a&#125;, b=&#123;b&#125;, ...// 解决for (i = 0; i &lt; param.num; i++) &#123;    switch(match.group()) &#123;        case &#123;a&#125;: break;        case &#123;b&#125;: break;        ...    &#125;&#125;</code></pre><p>当被问到参数位置是否可以调换，还是放心的，那参数能多能少吗？……</p><h3 id="改需求"><a href="#改需求" class="headerlink" title="改需求"></a>改需求</h3><p>曾经见过一个程序，一个文件里面有一个类，这是理所当然的，这个类里面只有一个方法，方法有一千多行，是个女程序员写的。</p><p>我的任务是原先输出的报表上加几个字段，原先输出了<code>a,b</code>，现在需要<code>a,b,c,d</code>。<code>c,d</code>是我需要实现的部分，大致的程序逻辑和<code>a,b</code>一样，但是来源不同，执行不同的sql查出来的。按理说改个sql不就完了吗，问题是一千多行的方法里面嵌套了三四层循环，包含了从不同银行查数据的业务操作，循环内外的变量名就是<code>list1、list2</code>，最终的结果还会涉及到对<code>a,b</code>的累加操作。</p><p>当时选择的做法是不动原来的程序，复制一份出来，分别执行完后整合一下数据。心高气傲啊，不愿意读垃圾代码。所以后来一个类里面有两个一千行代码的方法了。要命的是bug不断，复制出来的代码仍然需要从头到尾看明白，而且对两部分数据的整合也带来了不少麻烦和意想不到的漏洞……</p><h3 id="完善需求"><a href="#完善需求" class="headerlink" title="完善需求"></a>完善需求</h3><p>另一个需求是接手别人做到一半的项目。9102年了在spring boot里面用模板引擎写页面，我不得不用jquery和基于jquery的移动端样式库完成开发，界面丑先不说了，文档！文档前后对不上！也怪我，小看了需求，应该不明白就问，问清楚了各个环节再动手操作。结果自然好不了，也是反反复复的改……可能不会有人愿意再维护那份代码。</p><h3 id="不断变更的需求"><a href="#不断变更的需求" class="headerlink" title="不断变更的需求"></a>不断变更的需求</h3><p>无法在一开始敲定需求，一定会产生烂代码。在理想情况下做好规划、有充裕的时间和高素质的开发人员完成工作，各种设计、模式自然是好的。现实一定不是那样。</p><p>vue的前端项目里有一种惯用的写法，是对axios的封装，在一个单独的api.js里写各种export，然后在模块中import。据说是为了统一管理api的url还是什么，总之在实际的开发过程中，发现这实在是繁琐的写法，带来了很多开发上的不便。维护更容易了吗？并没有。原因之一就是需求在不断变化，如果api里的注释不够清晰也不够准确，那单独抽出来毫无意义。</p><pre><code>// api.jsexport a = () =&gt; &#123; get(&#39;a&#39;) &#125;// model.jsimport &#123;a&#125; from api.jsa().then(res =&gt; &#123;&#125;)</code></pre><p>如果api中的a函数和路由a不完全对应，需要修改api.js时就不得不到对应的页面中去找是哪个函数，这和直接把路由写在页面中没有区别。或许可以试着把路由访问的函数在每个模块或者每个页面顶部封装一下，让模块或者页面里的api是自治的。</p><p>前端项目里比起api，更让人难过的是随处可见的css！更更让人难过的是项目已经成型了！同样是背景色的配置，index里写一遍，common里写一遍，model里写一遍，甚至内联的写法再来一遍……问题是各个地方的配置内容还不一样。背景色这种样式还好，可怕的是文档流，定位，浮动，边距……css真正的内功是文档流吧，假如完全不懂还撑起了整个项目，这样的代码谁敢动？</p><h3 id="懒得重写的需求"><a href="#懒得重写的需求" class="headerlink" title="懒得重写的需求"></a>懒得重写的需求</h3><p>随着需求的不断变更，会出现的另一个现象是以前的代码能复用就复用，以最快的速度完成现在的需求，反正不知道以后需求会不会变，要是每次都重构出整洁的代码，工作量和工作效率……这绝对是产生烂代码的途径之一。</p><p>后端开发中有个我不太喜欢的东西，bean，也叫entity，不知道是从哪个年代流传下来的做法，包括模板化的dao和service，写个IClass再写个ClassImpl有多大意思呢。bean不利于需求变更，有时候用map反而好一点。回到一开始提到要验收的项目，我写出的烂代码和bean不无关系，大概就是bean的设计包含有很多个字段，后来需求变了，字段也变了，如果要改就要改很多地方，天知道以后需求还会不会变，就强行复用了，导致有些字段含义不明，有些字段完全对不上，仅仅是占用了位置来储存数据。</p><p>当然，框架的选择失误也是产生垃圾代码的原因，这要归因于我经验不足，不得不承认架构师在项目管理中起到的核心作用。</p><h3 id="开发中的困境"><a href="#开发中的困境" class="headerlink" title="开发中的困境"></a>开发中的困境</h3><p>一个是起名字的难题，偶尔写错了接口名称，或者复制粘贴相似的逻辑，懒得改变量名，产出的代码一定难以维护，这就可见code review真是企业开发中不可缺少的一步，不过中小公司可能对代码质量的要求也没那么高，除非是要上线的、会涉及到线上业务的代码，review是必须的，搞不好会出人命的，普通的开发可能就没那么严格。</p><p>另一个是模块划分的问题，比如a页面有文件上传，b页面有文件下载，那么文件上传下载是不是应该放在同一api路径？都是文件操作，好像挺对的。可如果其他api都是按照页面划分，同一个页面的所有接口都在同一路径下，那单独把文件操作拎出来是不是有点突兀？有时也会按照数据表划分模块，一遇到联表的操作就不好约定了。各种规则混着用多半会引起混乱，让代码难堪。</p><h3 id="？"><a href="#？" class="headerlink" title="？"></a>？</h3><p>年终之际，还是要给我的2019画上一个圆满的问号。</p>]]></content>
  </entry>
  <entry>
    <title>Haskell 中的 Monad 是什么？</title>
    <link href="https://smallyu.net/2019/11/26/Haskell%E4%B8%AD%E7%9A%84Monad%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F/"/>
    <id>blog:https://smallyu.net/2019/11/26/Haskell%E4%B8%AD%E7%9A%84Monad%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F/</id>
    <published>2019-11-26T05:34:02.000Z</published>
    <updated>2025-06-30T13:35:47.359Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>第一次听说Monad是在一个Scala Meetup上，后来试着了解Monad的概念，却头疼于Haskell的各种大部头的书和教程。再后来看到阮一峰在2015年发表的《<a]]></summary>
    <content type="html"><![CDATA[<p>第一次听说Monad是在一个Scala Meetup上，后来试着了解Monad的概念，却头疼于Haskell的各种大部头的书和教程。再后来看到阮一峰在2015年发表的《<a href="http://www.ruanyifeng.com/blog/2015/07/monad.html">图解 Monad</a>》，虽然清晰易懂，但是脱离了Haskell，图片的表意和语言中的概念对不上。阮一峰的文章译自《<a href="http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html">Functors, Applicatives, And Monads In Pictures</a>》，我阅读了原文。</p><h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>计算机程序用于控制计算机进行运算，程序操作的对象是各种不同类型的值，比如数值。这是一个简单的值<code>2</code>：</p><img src="1.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>用函数对值进行一些处理，可以返回函数执行的结果，比如：</p><img src="2.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>除了简单的数值类型，值也有可能被包含在一些上下文环境中，组成更复杂的值类型。可以把上下文环境想象成盒子，数值放在盒子里面，这个盒子整体作为一个值，描述为<code>Just 2</code>，也就是带盒子的<code>2</code>：</p><img src="3.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>如果对Java有过了解，可以将这个盒子理解为包装类，比如Integer和int，对应带盒子的2和不带盒子的2。</p><h3 id="Functors"><a href="#Functors" class="headerlink" title="Functors"></a>Functors</h3><p>面对带盒子的<code>2</code>，我们无法直接把<code>+3</code>的函数作用在它上面：</p><img src="4.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>这时需要一个函数<code>fmap</code>来操作。fmap会先从<code>Just 2</code>中取出数值2，然后和3相加，再把结果5放回盒子里，返回<code>Just 5</code>：</p><img src="5.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>fmap怎么知道该如何解析<code>Just</code>？换一个其他像<code>Only</code>之类的类型，还能解析吗？所以就需要Functor（函子）来完成<code>定义</code>的的操作。</p><p>Functor是一种数据类型：</p><img src="6.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>Functor定义了fmap的行为：</p><img src="7.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>fmap有两个入参和一个出参，入参分别是一个函数和一个带盒子的值，出参是一个带盒子的值，可以这样使用：</p><pre><code class="Haskell">fmap (+3) (Just 2)-- Just 5</code></pre><p>回到Haskell，在Haskell的“系统类库”中有一个<code>Functor</code>的实例<code>Maybe</code>，<code>Maybe</code>中定义了<code>fmap</code>的行为，指定了面对<code>Just</code>类型的入参时对值进行操作：</p><pre><code class="Haskell">instance Functor Maybe where  fmap func (Just val) = Just (func val)  fmap func Nothing = Nothing</code></pre><p>表达式<code>fmap (+3) (Just 2)</code>的整个过程类似这样：</p><img src="8.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>同理，从<code>Maybe</code>的定义中能看出，如果传入fmap的第二个参数是<code>Nothing</code>，函数将返回<code>Nothing</code>，事实确实如此：</p><img src="9.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><pre><code class="Haskell">fmap (+3) Nothing-- Nothing</code></pre><p>现在假设一个Java的场景，用户使用工具类Request发起一个向服务器的请求，请求返回的类型是Response，Response是一个实体类，可能包含所需数据data也可能不包含：</p><pre><code class="Java">Response res = Request.get(url);if (res.get(&quot;data&quot;) != null) &#123;  return res.data;&#125; else &#123;  return null;&#125;</code></pre><p>使用Haskell中fmap的写法就变成了：</p><pre><code class="Haskell">fmap (get(&quot;data&quot;)) (Response res)</code></pre><p>当然Haskell不存在<code>get(&quot;data&quot;)</code>这样的写法，可以将由Response获取Response.data的操作封装为函数getData，然后传入fmap作为第一个参数。</p><p>Haskell提供了fmap函数的语法糖<code>&lt;$&gt;</code>简化fmap的写法：</p><pre><code class="Haskell">getData &lt;$&gt; (Response res)</code></pre><p>再来想一个问题，Haskell的函数是如何对列表进行操作的？函数会对列表的每一个元素都进行计算，然后返回列表：</p><img src="10.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>其实列表也是Functions，这是列表的定义：</p><pre><code class="Haskell">instance Functor [] where  fmap = map</code></pre><h3 id="Applicatives"><a href="#Applicatives" class="headerlink" title="Applicatives"></a>Applicatives</h3><p><code>Applicatives</code>是另一个概念，我们之前说数据被放在盒子里，如果函数也被放在盒子里呢？</p><img src="11.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>Haskell的系统提供了操作符<code>&lt;*&gt;</code>用于处理盒子里的函数：</p><img src="12.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>例如：</p><pre><code class="Haskell">Just (+3) &lt;*&gt; Just 2 == Just 5</code></pre><p>使用<code>&lt;*&gt;</code>还可以完成一些有趣的操作，比如分别让列表中的元素*2和+3：</p><pre><code class="Haskell">[(*2), (+3)] &lt;*&gt; [1, 2, 3]-- [2, 4, 6, 4, 5, 6]</code></pre><img src="13.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><h3 id="Monads"><a href="#Monads" class="headerlink" title="Monads"></a>Monads</h3><p>函数的执行是使用<code>带入参</code>的<code>函数</code>处理<code>值</code>，涉及到三个角色。<code>Functors</code>是被处理的<code>值</code>放在盒子里，<code>Applicatives</code>是<code>函数</code>放在盒子里，<code>Monads</code>则是将函数的<code>入参</code>放在盒子里。Monads有一个操作符<code>&gt;&gt;=</code>来实现Monads的功能。假设现在有一个函数<code>half</code>的入参是数值，如果是偶数就除以2，否则返回Nothing:</p><pre><code class="Haskell">half x = if even x  then Just (x `div` 2)  else Nothing</code></pre><img src="14.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>想要给<code>half</code>传一个<code>Just</code>类型的值怎么办？</p><img src="15.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p><code>&gt;&gt;=</code>可以解决这个问题：</p><pre><code class="Haskell">Just 3 &gt;&gt;= half-- Nothing</code></pre><p><code>&gt;&gt;=</code>操作符把<code>Just 3</code>变成了<code>3</code>放在<code>half</code>中进行计算。<code>Monad</code>是一个数据类型，定义了<code>&gt;&gt;=</code>的行为：</p><pre><code class="Haskell">class Monad m where  (&gt;&gt;=) :: m a -&gt; (a -&gt; m b) -&gt; m b</code></pre><img src="16.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><p>这里的<code>Maybe</code>是一个<code>Monad</code>（和上文的Maybe同时存在）:</p><pre><code class="Haskell">instance Monad Maybe where  Nothing &gt;&gt;= func = Nothing  Just val &gt;&gt;= func = func val</code></pre><p><code>&gt;&gt;=</code>还支持链式的操作：</p><pre><code class="Haskell">Just 20 &gt;&gt;= half &gt;&gt;= half &gt;&gt;= half-- Nothing</code></pre><img src="17.png" style="box-shadow: 0 0 0 #fff; margin-left: 0;" /><h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><p>虽然Haskell的Monad比较有名，但实际上涉及到三个概念<code>Functors</code>、<code>Applicatives</code>和<code>Monads</code>，可能Monad的应用比较广泛一点。在数据处理上，FP并不比OOP高级，逻辑是相似的，只是写法不同。面对同样的问题使用不同的思维方式和表达方式去解决，对应了不同的编程思想和编程范式。世界上有很多精妙的理论等待我们探索。</p>]]></content>
  </entry>
  <entry>
    <title>浅析 Libra 背后的区块链技术</title>
    <link href="https://smallyu.net/2019/11/20/%E6%B5%85%E6%9E%90Libra%E8%83%8C%E5%90%8E%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF/"/>
    <id>blog:https://smallyu.net/2019/11/20/%E6%B5%85%E6%9E%90Libra%E8%83%8C%E5%90%8E%E7%9A%84%E5%8C%BA%E5%9D%97%E9%93%BE%E6%8A%80%E6%9C%AF/</id>
    <published>2019-11-20T09:21:18.000Z</published>
    <updated>2025-11-09T09:22:13.451Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<blockquote>
<p>前段时间国家领导人曾公开表示鼓励区块链技术的研究，称要把区块链作为核心技术自主创新的突破口。Libra的发行计划是区块链发展史上一座重要的里程碑，本文从合约语言、数据库协议、逻辑数据模型、数据结构、共识协议等方面简要介绍Libra区块链的技术方案。]]></summary>
    <content type="html"><![CDATA[<blockquote><p>前段时间国家领导人曾公开表示鼓励区块链技术的研究，称要把区块链作为核心技术自主创新的突破口。Libra的发行计划是区块链发展史上一座重要的里程碑，本文从合约语言、数据库协议、逻辑数据模型、数据结构、共识协议等方面简要介绍Libra区块链的技术方案。</p></blockquote><p>2019年5月，Facebook首次确认推出加密货币的意向，“全球币”、“脸书币”的消息不胫而走。6月18日，Facebook正式宣布将推出名为Libra的加密货币，预计2020年上半年针对性发布。Facebook宣称，Libra建立在安全、可靠、可扩展的区块链上，采用链外资产抵押的模式，锚定一篮子法定货币作为资产担保，由独立的Libra协会治理。Facebook在全球拥有27亿用户，Libra的愿景是建立一套简单、无国界的货币，为数十亿人提供金融服务。</p><p>Facebook正式宣布Libra后，同步上线了Libra的官网、白皮书和测试网络等内容。白皮书中提到，Libra网络希望未来以公有链的形式运作，但由于目前没有成熟的技术能在公有链上支撑大规模的交易，Libra将以联盟链的形式起步，计划三到五年内展开由联盟链过渡为公有链的研究。</p><p>Libra官网公布了三篇论文详细说明Libra使用的技术方案，这三篇论文分别是《Libra区块链》、《Move：一种具有可编程资源的语言》和《Libra区块链中的状态机复制》。Libra为满足高度安全、足够灵活、吞吐量极高等要求，设计了新的编程语言Move，选择BTF共识机制，采用广泛使用的Merkle Tree作为数据结构。本文简要介绍Libra区块链的相关技术。</p><h3 id="Move"><a href="#Move" class="headerlink" title="Move"></a>Move</h3><p>当现实世界的资产进入Libra储备，系统会创建相应的数字资产Libra货币，这些数字资产在不同账户之间流通，当现实中的资产离开Libra储备，对应的数字资产也随之销毁。Fackbook设计了新的编程语言Move用于对Libra中的数字资产进行管理，Libra在Move中将数字资产表示为资源（resource）。</p><p>Move是带有类型的字节码语言，资源是Move的类型之一，程序在执行前会先经过字节码验证器检验，然后由解释器执行。Move中的资源仅支持copy和move两种操作，可以理解为copy移出资源，move移入资源，也就是说资源和普通的变量类型不同，资源的值可以赋给普通变量，但资源本身只能在地址间移动，不能复制或丢弃。如果在程序中使用了违反规则的copy和move操作，比如copy一次move两次，程序将无法通过字节码验证器，因为在第一次move后原先的资源就已经不可访问了。</p><p>使用Move可以编写自定义的交易逻辑和智能合约，相比现有的合约语言要更加强大。比特币脚本提供了简洁优雅的设计用于表达花费比特币的策略，但是比特币脚本不支持自定义数据类型和程序，不是图灵完备的。以太坊虚拟机倒是支持流程控制、自定义数据结构等特性，但太过自由的合约让程序的漏洞随之增多，发生过多起安全事件。Move的静态类型系统为数字资产的安全性提供了保障。</p><p>为了配合静态验证工具的验证，Move在设计上采取了一些措施：没有动态调度，让验证工具更容易分析程序；限制可变性，每一次值的变化都要通过引用传递，临时变量必须在单个脚本中创建和销毁，字节码验证器使用类似Rust的”borrow checking”机制保证同一时间变量只有一个可变引用；模块化，验证工具可以从模块层面对程序进行验证而不需要关心具体实现细节，等等。Move的这些特性都使得静态验证工具更加高效可靠。</p><pre><code>public main(payee: address, amount: u64) &#123;  let coin: 0x0.Currency.Coin = 0x0.Currency.withdraw_from_sender(copy(amount));  0x0.Currency.deposit(copy(payee), move(coin));&#125;</code></pre><p>这是一段交易脚本的示例程序，是Move语言的中间表示（IR），IR更适合程序员阅读和编写。程序实现了一个转移资源的函数，main方法是脚本的入口，包含两个入参：目标地址和金额。程序先从0x0地址Currency模块中移出amount个资源暂存到coin变量，然后将coin的资源移动到payee的地址上。</p><p>交易脚本是为Move提供灵活性的一个方面，另一方面来自安全的模块化设计。交易脚本让交易逻辑更加自由，模块化设计则让保证了脚本程序的多样化。模块的类型是<code>module</code>，主要包含Move程序，一个模块可以包含任意个资源，也就是声明另个或多个资源类型的变量，modules&#x2F;resources&#x2F;procedures相当于面向对象语言中的classes&#x2F;object&#x2F;methods，不同的是Move中并没有self、this之类的概念。</p><h3 id="Libra协议"><a href="#Libra协议" class="headerlink" title="Libra协议"></a>Libra协议</h3><p>Libra区块链是一个需要经过密码学认证的分布式数据库，用于储存可编程资源，比如Libra货币就是可编程资源，在Move中表现为资源。Libra协议中有两种实体类型，验证节点（validators）共同参与维护数据库，客户端（client）通常发起向数据库的请求。Libra协议会在执行过程中选举出leader接收客户端的请求，然后leader将请求同步到其他验证节点执行，其他验证节点执行结束后把结果返回给leader，leader再把请求的最终结果返回客户端。</p><p>Libra的交易会经过很多步骤，包括验签、运行先导程序、验证交易脚本和模块程序的正确性、发布模块、执行交易脚本、运行结尾程序等。为了使合约交易的计算能力可计量，Libra吸收了以太坊中Gas的概念，消耗Gas作为交易的费用。</p><img src="a.png" width="100%" style="box-shadow: 0 0 0px #fff;"><p>这张图详细展示了交易请求在Libra的网络组件中流转的过程，客户端发起请求到权限控制层，权限验证后将请求数据转给虚拟机进行预处理，同时数据也会进入内存池中，内存池负责将请求同步到其他节点，共识协议在请求同步的过程中发挥作用，节点同步结束后虚拟机执行真正的交易程序，程序执行完毕对结果持久化，基本流程结束。</p><h3 id="逻辑数据模型"><a href="#逻辑数据模型" class="headerlink" title="逻辑数据模型"></a>逻辑数据模型</h3><p>Libra区块链上所有的数据都保存在有版本号标识的数据库中，版本号是64位无符号整数。每个版本的数据库都包含一个元组 (T, O, S)，T代表交易，O代表交易的输出，S代表账本的状态。当我们说执行了一个Apply操作，表示为Apply(S, T) -&gt; (O, S)，意思是在S状态下执行了T交易，产生了O输出并且账本的状态变为S。</p><p>账户是资源的拥有者，可以使用账户内的资源进行交易。账户地址是一个256位的值，创建新账户需要一个验证&#x2F;签名的键值对（vk, sk），新的账户地址a由vk经过公钥加密计算得到，a &#x3D; H(vk)。具体来说Libra使用SHA3-256实例化哈希函数，使用wards25519椭圆曲线做变量的EdDSA公钥进行数字签名。交易过程中由已经存在的账户调用create_account(a) 指令即可生成新账户。</p><img src="b.png" width="80%" style="box-shadow: 0 0 0px #fff;"><p>上图所示有四个以0x为前缀的账户地址，矩形框表示模块，椭圆形表示资源，箭头表示依赖关系。图中0x12账户中的Currency.T在Currency模块中声明，Currency模块的代码储存在0x56地址上。同理，0x34的StatChannel.T声明自0x78的StateChannel模块。当客户端想要访问0x12下的Currency.T，请求资源的路径应写作0x12&#x2F;resources&#x2F;0x56.Currency.T。</p><h3 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h3><p>Libra交易区块中包含各节点签名的数据，交易前会对签名数据进行校验，根据这一集体签名客户端可以相信请求的数据库版本是完整有效的，也因此客户端可以请求任意节点甚至是第三方数据库副本进行查询。Libra协议中的数据结构主要基于默克尔树。</p><img src="c.png" width="100%" style="box-shadow: 0 0 0px #fff;"><p>如图所示，账本历史数据的根哈希用来验证系统的完整状态，账本数据由默克尔树累加形成，虚线表示数据累积的过程。账本历史数据的每一个节点都包含交易签名、事件树和账本状态，事件树也是基于默克尔树，账本状态则是基于稀疏默克尔树，账本状态的每个叶子节点都包含有账户数据。</p><p>Libra协议中验证节点V会对数据D的根哈希a进行校验。例如不受信任的节点在获取到数据D后使用函数f对数据进行运算，希望得到结果r，同时还需要一个用于验证函数结果正确性的数据π，协议会要求节点把(a, f, r, π)都传到验证节点V处进行验证，如果f(D) &#x3D; r则通过验证。</p><img src="d.png" width="70%" style="box-shadow: 0 0 0px #fff;"><p>在上图中，数据D &#x3D; {0:s0, 1:s1, 2:s2, 3:s3}。假设f是获取第三项数据的函数，也就是要获取h2的数据，期望结果f(D) &#x3D; h2，此时h2就是r，r &#x3D; h2，用于验证计算结果正确性的数据π &#x3D; [h3, h4]，根哈希a &#x3D; H(h4||h5) &#x3D; H(h4 || H(H(2 || r) || h3))，验证节点将执行Verify(a, f, r, π)对计算结果进行验证。</p><h3 id="共识协议"><a href="#共识协议" class="headerlink" title="共识协议"></a>共识协议</h3><p>Libra选择使用的是拜占庭容错共识，实现了一种HotStuff共识的变体LibraBFT，简称LBFT。LBFT协议的主要作用是让提交的块在同一个序列上，或者说避免分叉。每三次提交为一轮操作，每一次提交验证节点都会投票选举出下一轮的leader，同时这些投票的集合形成一个法定证书（QC），每一轮的第一个块记为preferred_round，下一个块写入时对preferred_round的QC进行验证，也就是preferred_round后的第一、二、三个块都与preferred_round校验，第四个块将是第二轮的preferred_round，依次更迭。</p><img src="e.png" width="50%" style="box-shadow: 0 0 0px #fff;"><p>如图所示，k是preferred_round，如果在k处出现了分叉，并且有2f + 1个验证节点投票给了k，k+1将接在k的后面，k+2依次写入，k左侧的分叉失效。这时假如k+3的leader超时了，k+4成为新的leader并写入在preferred_round（k）的后面，会引起新的分叉。如果k+4获得2f+1个投票，k+5会按照规则写入在k+4后面。</p><p>在k+4分叉后，当超时的k+3再次被选为leader并重新提交，验证节点会对k+3的preferred_round（k）的QC进行校验，校验通过，k+3写入在了k+2的后面，这符合规则。再然后，下一个leader（k+6）的preferred_round实际上是k+4，准备提交块到k+3后面时发现QC对不上，k及其后的k+1、k+2、k+3都会被删除，k+4后的链成为主链。</p><p>LBFT基本上是对链式HotStuff的实现，并没有太多创新，Libra团队更多的是在共识协议中做出一种选择，对BFT的选择是好是坏还存在争议，需要时间来验证，LBFT算是Libra从联盟链到公有链过渡前的方案，预计至少支持100个节点，上限大概是1000个左右。和HotStuff一样，LBFT最多容忍三分之一的不诚实节点。</p><h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><p>Libra协议目前还处于比较早期的阶段，性能上并不算惊艳，支持每秒1000笔交易，每次提交的交易确认时间大概是10秒钟。Libra协议在设计上很多也是兼顾了性能，比如每三次提交进行一次共识，每一轮操作内不需要等待就可以进行投票，这减少了客户端和验证节点之间的网络延时；考虑到并行和分片的思想，稀疏默克尔树的使用使得账户的身份数据可以跨数据库进行验证，也支持并行更新等等。</p><p>Libra选择了众多成熟的技术构建Libra系统，使用内存安全的Rust编写核心程序、使用容易验证的Merkle Tree作数据结构、基于Chained HotStuff实现共识协议等等。Move是Libra在技术上最大的亮点之一，在语言层面保证了数字资产的安全性，Move本身是一种字节码语言，难以阅读，所以提供了Move的中间表示IR，用于编写交易脚本和智能合约。Libra作为一种在金融领域的创新实验，基于区块链提出了世界货币的愿景，其社会意义可能要远大于在技术创新上所带来的意义。Libra协会目前拥有16个成员组织，涵盖支付业、电信业、区块链业、风险投资业等领域，已经在世界范围引起广泛关注。</p><p>Libra预计2020年上半年针对性发布，让我们拭目以待！</p>]]></content>
  </entry>
  <entry>
    <title>对区块链的理性认识</title>
    <link href="https://smallyu.net/2019/11/05/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E7%9A%84%E7%90%86%E6%80%A7%E8%AE%A4%E8%AF%86/"/>
    <id>blog:https://smallyu.net/2019/11/05/%E5%AF%B9%E5%8C%BA%E5%9D%97%E9%93%BE%E7%9A%84%E7%90%86%E6%80%A7%E8%AE%A4%E8%AF%86/</id>
    <published>2019-11-05T05:53:58.000Z</published>
    <updated>2025-11-09T09:22:13.447Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>曾以为区块链是革命性的、颠覆性的技术，毕竟区块链和人工智能、大数据并列互联网前沿技术。但是，人工智能达到真正的智能暂时还是梦，大数据也实现不了像《复联》里一样的精准分析。前几天国家领导人对区块链的讲话振奋人心，可过去几年的物联网、互联网+，不也都无疾而终了吗。</p>
<h]]></summary>
    <content type="html"><![CDATA[<p>曾以为区块链是革命性的、颠覆性的技术，毕竟区块链和人工智能、大数据并列互联网前沿技术。但是，人工智能达到真正的智能暂时还是梦，大数据也实现不了像《复联》里一样的精准分析。前几天国家领导人对区块链的讲话振奋人心，可过去几年的物联网、互联网+，不也都无疾而终了吗。</p><h3 id="公有链无法脱离货币"><a href="#公有链无法脱离货币" class="headerlink" title="公有链无法脱离货币"></a>公有链无法脱离货币</h3><p>有的观点认为，核反应最初的目的是建造核弹，而核反应现在也作为电能的来源服务于人民，区块链最初的目的是支持比特币的运作，现在我们想要区块链应用于其他方向。也就是说，观点认为核反应的位置和区块链是对等的。</p><pre><code>核反应 -&gt; 核弹区块链 -&gt; 比特币</code></pre><p>可是仔细想想，到底该如何对比这几乎完全不一样的两种事物。如果你看过几本区块链相关的书，会发现讲的东西并不会特别新鲜，观点也完全够不上所谓革命、创新。比特币诞生至今不过10年左右，并没有克服技术上的难题，只是不同机制的组合，它应该和P2P或者某种电子游戏处在同一地位。比特币的价值在于进行电子交易，而不是货币本身。</p><pre><code>核反应 -&gt; 核能量 -&gt; 大爆炸区块链 -&gt; 比特币 -&gt; 电子交易</code></pre><p>因为核反应，才能产出核能量，有了核能量，才能够产生大爆炸。因为区块链，才有了比特币，有了比特币，才能够进行电子交易。所以这样来看，核能量是离不开核反应的，比特币是离不开区块链的。</p><p>那么，区块链能够离开比特币单独应用于场景吗？或者说，其实区块链和比特币是一体的，就像核反应产生出的核能量，有价值的是能量而不是反应，区块链产出比特币，运作于区块链上的比特币才有所谓匿名、不可篡改、可溯源等特性，有价值的是比特币而不是区块链。</p><p>几天前广州市政府发布补贴区块链企业的细则（<a href="http://www.gz.gov.cn/gzswjk/2.3.6.3/201910/7beb40281dde4fa2beee0da2b16aa6dc.shtml">实施细则</a>），明确要求“无币”公有链项目。这项政策，一方面是国家不允许发币，另一方面，公有链无币其实是区块链最理想的情况，一般来说，理想是难以实现的。</p><p>比特币解决的是交易中的信任问题，解决方式归根结底是数据存在哪儿。两个人进行交易，如果由交易发起方记账，或者交易接受方记账，或者两个人都记账，无论谁记，只要有一方说谎，甚至不说谎，他就是记错了，都会产生争执，不认账怎么办！这时就需要第三方机构介入，通过银行记账，通过律所解决纠纷。要是连银行、政府、法律都不相信，就不用活了。</p><p>如果真的不信任中心化的机构，比特币提出的办法是，让全世界的人都为你记账，全世界的人都会记住两个人的交易记录，谁给谁转账多少，这样无论如何都不再会有差错，除非全世界一半以上的人都犯了同样的错误。所以问题在于，凭什么让全世界的人为两个人的个人交易记账？人家为什么要记？于是将比特币作为奖励，谁记账了，并且被系统认为记的账是有效的，谁就可以得到奖金。</p><p>没有奖励，世界上的人不会主动为你记账，分布式账本还怎么维持运行？</p><h3 id="比特币并非去中心化"><a href="#比特币并非去中心化" class="headerlink" title="比特币并非去中心化"></a>比特币并非去中心化</h3><p>有人认为分布式记账、分布式数据库就已经是去中心化了，但这一定不是去中心化的最终形态。比如，比特币程序的开发、维护和升级？数据确实天下共享，但程序还是要有人制定规则，有人开发，有人发布，出bug了要有人修复，有更好的点子了要迭代升级，分布式的数据全部经由中心化的程序发布中心发布的程序处理。目前解决程序上信任的方式是将程序开源……这一点暂且可行，但是程序升级带来的困难就要大多了，要么确保向下兼容，要么确保所有人更新程序。</p><p>另外，比特币的数据冗余是个极大的问题，每个节点都需要备份全量数据，而且大多数是不相关的历史数据。如果单个节点不保留全部数据，就无法保证分布式数据的可靠性，但如果保留全部数据，又是对资源很大的浪费。中心化系统一份数据就可以解决的问题，为了能够相互信任，就多出来几十亿份数据？就好比我不相信银行，就自己造一个银行，自己管自己？</p><p>可以畅想一下，在牺牲去中心化概念的情况下，能够有哪些可能。</p><p>一、全球共用一个数据库，数据库只承担储存数据的任务，分布式程序只解决共识问题。数据库非常安全，数据容量非常大，但是写入规则严格，需要全球一半以上的人认可，或者通过其他的共识机制准入。任何人可以随意查询，可溯源，历史数据不能修改。共识程序是必要的，决定了哪些数据可以写入，比如判断余额是否足够，而且是全世界的人一起判断，如果有坏人想要写入非法数据，需要买通全球一半以上的人……这样数据冗余最少。</p><p>二、每个节点只保留一半数据，数据拆分为历史的一半和当前的一半。一个人储存最新的一半数据，另一个人储存旧的一半数据，旧数据只需要负责储存，当新数据过多时同步到旧数据这里。新数据负责接收广播、写入数据，功能等同于现在的节点，如果遇到需要查询历史数据的情况，就从旧数据的一半查。相当于两人合作完成一个节点，新旧节点随时随机搭配，节点的新旧由系统平均分配。至于安全性，因为全网的节点随机配对，应该不会低于比特币，最坏的情况是一半的节点全部挂掉。同理，可将两份数据扩展到多份数据的情况。</p><p>三、每个节点只保留一半数据或者更多份，数据对半拆分。就是同一条数据，按照一定规则拆分为多个数据包，分别储存在不同的节点，参考HDFS的储存方式，存在一定冗余，但又节省了不少空间。再激进一点，数据可以实现自验证，网络中的每个节点储存的数据大小是随机的，当用户查询某一条数据时，从全网的节点中搜寻可以组成所需数据的节点，然后从中取出数据。也就是说整个节点网络的数据都混杂在一起，难点变成了如何给数据包设计自验证机制。</p><h3 id="数字货币和区块链没有关系"><a href="#数字货币和区块链没有关系" class="headerlink" title="数字货币和区块链没有关系"></a>数字货币和区块链没有关系</h3><p>有的人谈到区块链的应用，会把央行关于数字货币的研究给扯上，甚至某交易所知名总监，以区块链为主题的演讲，却把比特币和Libra的趣闻轶事说了一遍。很多人都在忽略概念上的区别，这无关紧要，也至关重要。央行说有发行数字货币的计划，也说过区块链可以作为技术选择之一，但区块链从不是必须的技术。区块链对于国家的意义，是“以去中心化之名，行中心化之实”，意在一统国内互联网，方便监管。即使没有区块链，国家也有能力实现各种应用，只是借势上了区块链的船而已。</p><p>过去的区块链指支撑比特币运行的技术体系，未来的区块链将几乎约等于联盟链。</p><p>华为区块链白皮书中的观点很客观，区块链是互联网的补充，它不会脱离传统数据库，离不开TCP，只是在特定场合下发挥独特的作用。对于国家来说，链上的数据清晰可见，没有人能暗箱操作；对于企业来说，可以方便的实现制衡，几家企业合作共享一组数据，区块链则是打开大门的钥匙。如果没有区块链，可能说不上来数据共享是个什么样子，区块链诞生了，并且比特币在世界范围稳定运行了十多年，所以这是可信的、有前途的技术方向，大家都争先恐后创新、落地。</p><p>可以预见，未来区块链的开发会分为两类，一类底层开发，一类应用层开发。底层开发的技术要求更高，开发者素质更高，应用层开发则类似于现在的Web开发。会先后出现一些区块链应用提供商，也会相应的出现一些SDK，开发者调用区块链储存数据、进行交易，类似于现在调用数据库提供的API、请求支付机构的接口。</p><h3 id="所以"><a href="#所以" class="headerlink" title="所以"></a>所以</h3><p>区块链会被广泛应用到我们的网络中，但不足以改变世界。（不要笑）</p><h3 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h3><p>无意间发现了分布式网络 <a href="https://github.com/HelloZeroNet/ZeroNet">ZeroNet</a> ，是一个早在2015年就发布的项目，它几乎满足了所有我对区块链储存系统的想象，而且功能完备，可以基于这个网络搭建博客、论坛、邮箱、共享文件等。当然，我曾想到的、应该存在的问题，ZeroNet也一个都没有解决，算是对我的一些想法的验证，惟一不同的是我希望将分布式网络对接到公网，但ZeroNet的做法是建立了一套自治的网络系统，包括.bit域名也只能作为URI的后缀，这无疑限制了该网络无法被更加广泛传播使用。另外，由于点对点文件系统难以监管，GWF将ZeroNet列入名单，这虽然是特殊现象，但ZeroNet和IPFS等网络似乎可以说明，区块链最适合也只能应用于金融领域或者受限制的互联网中。</p>]]></content>
  </entry>
  <entry>
    <title>来，我们再谈一谈梦想</title>
    <link href="https://crazy.smallyu.net/2019/10/26/%E6%9D%A5%EF%BC%8C%E6%88%91%E4%BB%AC%E5%86%8D%E8%B0%88%E4%B8%80%E8%B0%88%E6%A2%A6%E6%83%B3/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2019/10/26/%E6%9D%A5%EF%BC%8C%E6%88%91%E4%BB%AC%E5%86%8D%E8%B0%88%E4%B8%80%E8%B0%88%E6%A2%A6%E6%83%B3/</id>
    <published>2019-10-26T05:44:35.000Z</published>
    <updated>2025-08-16T03:27:11.437Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>早就想好了标题，可迟迟不知道要写什么，始终无法给内容“定调”。后来一想，其实也没必要强调『基调』，在开头或者结尾说几句概括性的话确实好，少了主题，内容就显得空泛，但这并不影响我“记录”自己的生活，并不影响我表达在不同时期对不同事物的『见解』。</p>
<h3]]></summary>
    <content type="html"><![CDATA[<p>早就想好了标题，可迟迟不知道要写什么，始终无法给内容“定调”。后来一想，其实也没必要强调『基调』，在开头或者结尾说几句概括性的话确实好，少了主题，内容就显得空泛，但这并不影响我“记录”自己的生活，并不影响我表达在不同时期对不同事物的『见解』。</p><h3 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h3><p>最近领导离职了，原因是要去创业。</p><p>领导离职带来的直接影响是，我最近的工作任务少得可怜，上一个项目接近尾声，下一个项目进展缓慢，加上领导离职，谁也不知道部门接下来会怎么发展。也因此，我有了比较多的空闲时间，我开始思考该如何提升自己的实力。在职业生涯上，我曾经有两个『追求』，一是不局限于语言，二是不局限于框架。其实这涵盖了太多的内容。</p><p>我非常不喜欢『面向面试』的学习，有个同事以前鼓动我，说我们互相分享一下最近的项目经验，有什么收获，这样我们以后去面试就有两个项目可以说了。看我不太感兴趣，他继续说，我看你平时也自己做一些小Demo之类的东西，但是你去面试总不能拿这些去面吧，我可以给你讲讲我们这个项目里的东西，像PDF解析、上传下载，还有关于区块链的一些东西……</p><p>对于这件事情，槽点就很多了。</p><p>他一直以和他一样没有经验的『应届生』看待我，其实我对Web开发的理解远超过他。从『人』的角度来看，我并不认为他的项目经验能够给我带来帮助，尤其是什么IO流、网络流之类的基础操作。对了，这个同事之前还鼓动我做另一件事情，就是总结项目里可复用的代码，比如PDF解析，网上可能有很多方案，但是自己总结一个能用的放着，以后遇到类似的需求直接CV就行了……他甚至还说，他的目标就是能够熟练的完成工作。</p><p>我的目标从来不是成为熟练的工人。就像搬砖的工人，从来不会因为搬的又快又多成为包工头。这也是我现在不想离开目前公司的原因，如果去其他公司996，即使工资涨了，也只是因为付出了更多的劳动力。平时一天搬10块砖头挣10块钱，如果加班多搬5块砖头，一天就可以挣15块钱。我目前还不是那个阶段，还没有必要一心赚钱的。</p><p>另外，我相信有能力的面试官，可以分辨出真正有实力的候选人。什么飘来飘去的框架，满口听起来高大上的词汇，微服务还没有过气，中台又炒到天上……另外，规范也不是真理，《代码整洁之道》也不是真理，设定各种条条框框有助于管理者把员工变成机器，但是作为员工如果听信了某种『宗教』，我同样认为不合时宜。</p><h3 id="创业"><a href="#创业" class="headerlink" title="创业"></a>创业</h3><p>领导离职去创业了，原因自然是想赚更多的钱。他说，挣多少钱就可以退休了呢，每年的开销乘以20，也就是说10年以后你的钱就剩一半了，这还不算货币贬值（用钱买基金是不是能够应对货币贬值？）。</p><p>创业是一个经常听到的词了，但是我还未见过创业真正的形态。同样是这段时间，上面提到的那个同事，入职三个月的『应届生』，也辞职了，要去创业了。领导创业我还能理解，基于多年的见识和积累，有能力也有经济实力去尝试创业。这位看起来涉世未深的同事要去创业，就有点匪夷所思了。不过也许人家并不是依靠自己的能力，而是有大佬愿意带着起飞，这就很正常了，和咱也没有关系。</p><p>在领导的酒席上，印象最深的内容是领导说，以前他作为中层管理，员工入职的时候还会帮着员工给HR说，多给点吧。现在他创业，也出资入股，也要招人，感觉就不一样了。能省下来钱，是给自己省钱。你说你拿着工资整天不干活，到点就走。到点就走，真的就是好吗，真的就好吗……我无法生动形象的转述具体内容了，大意如此。</p><p>就这段话来看，我并不赞同。作为中层怎样，作为老板怎样，然后位置不一样有了不一样的观点……然后呢？不同的位置，本就该有不同的观点，但是如果身为老板，想要员工站在老板的角度考虑问题，或者身为员工，想要老板站在员工的角度考虑问题，这不都是耍流氓吗，何必呢，矛盾存在就让它存在好了。</p><p>另一个问题是“到点就走”。到底对不对呢，这同样存在老板和员工的利益冲突。在知乎上看到关于ownership的说法甚是清晰，ownership的前提是owner，然后才有ship。至于提到加班就不得不提的996，相信只要区分开『奋斗』和『压榨』，情况就可以好一点。</p><h3 id="武林外传"><a href="#武林外传" class="headerlink" title="武林外传"></a>武林外传</h3><p>小时候看武林外传，是在看乐子。最近重温武林外传，却发现自己变了。</p><p>以前小郭和秀才组CP，感觉两人挺般配，但现在的想法是，人家小郭是郭巨侠的千金，和四大神捕论兄弟，秀才百无一用，是个没落的知县后辈，年年中不了举。这门不当户不对，好比小郭是北京公安局局长的女儿，秀才是十八线小县城县长的孙子，还没什么功名。现实生活中这可能吗？我们希望并相信生活和爱情的美好，但现实不允许。</p><p>然后是掌柜的和老白，开始越看越不明白，老白怎么就看上佟湘玉了呢，和小郭也挺配，初恋展红绫也回来找过他，无双等了他12年零3天……后来想了想，可能是剧情需要吧，再者佟湘玉也是龙门镖局的千金，龙门镖局也是有名望的大集团，老白并不吃亏。</p><p>无双是最可怜的，见一个爱一个，却落给了小六。无双又单纯又贤惠，主要是那么好看，老白不要，秀才也不要，后来终究没遇到合适的。难道是因为没有背景孤身一人闯荡江湖吗。尤其是和小郭抢秀才那一段，小郭没了秀才要什么有什么，可无双没了秀才就什么都没有了。无双似乎从来就没有融入同福客栈的大家庭。</p><p>武林外传和现实生活的另一个差异是，戏里表现出来的都是真性情。生气了，嫉妒了，吃醋了，记仇了，闹别扭了，和好了，真真实实，像我们小时候一样，还没有长大的时候，敢于将真是的情绪表现出来，上演一出出闹剧。对，放在现实生活中叫『作』，不是我说的，是弹幕里满屏的恶意。</p><p>现在看个电视，也真是多了很多世俗的眼光。有点感慨。</p><h3 id="王者荣耀"><a href="#王者荣耀" class="headerlink" title="王者荣耀"></a>王者荣耀</h3><p>说到家庭，最近王者荣耀周年庆，变身大作战里有一个夜游峡谷、点亮峡谷的活动，水晶、野区、龙坑，到处都挂着彩灯。看到游戏里的这一幕，忽然想到春节。现在想想，过年什么都没有，新衣服还是好吃的根本不重要，但过年的气氛实在弥足珍贵。除了过年，不会再有什么日子可以让一大家子的人都聚在一起了。</p><p>有时候想，一个成年人，如果他生命里乐趣的来源只剩下游戏，那他的人生一定是悲哀的吧。老梁讲到宅男的时候，说你以为宅男宅在家里很无趣，其实宅男的内心是充实的。作为人类，如果在家里没有什么事情可做，那他一定会想着法子和这个搞搞关系，和那个打打招呼。这话不假，也假。常说可怜之人必有可恨之处，相应的，我相信可恨之人，也一定有可怜之处。</p><h3 id="酒"><a href="#酒" class="headerlink" title="酒"></a>酒</h3><p>领导的酒席，自然免不了喝酒。我依然无法融入气氛，甚至没有敬酒的欲望。我和大多数人都没有过“发生关系”，这……不算不合适吧，况且大家都是逢场作戏而已。同事嘛，谈什么感情呢。</p><p>关于酒桌上的礼节，我承认我相当生疏。不过我还是认为，人和人合作的根本原因是互利，而不是多喝了几杯酒，混了个脸熟。我们的目的应该是创造价值，而不是求别人给一点施舍。有个老大不小的同事，每天吃饭都尽量和领导一起，那天也是坐到了老板的一桌，后来没说上几句话就回来了。我不知道工作5年以上还是个小兵算不算失败，但我真的不希望失败。</p><p>酒那么难喝，为什么自古以来还是那么多人喜欢？可能像人开心了就要哈哈大笑，伤心了就要嚎啕大哭一样，有时候不开心，不伤心，但就是不痛快，生活平淡无奇，反反复复，需要用酒来刺激自己的舌头和身体，给自己一些痛觉的反馈。“没什么，至少证明我们还活着”。有人说，父母在路上遇到旧识，喜欢聊聊近况，一说起来就没完，小时候觉得烦，长大了才明白，那是父母难得的开心时光。我稍有感悟。</p><h3 id="食色"><a href="#食色" class="headerlink" title="食色"></a>食色</h3><p>随着年龄的增长，越来越喜欢吃饭，发现吃饭也是一件为数不多令人愉悦的事情。小时候视若不见的炒土豆丝、炒白菜、炒鸡蛋、白馒头，尤其武林外传里每次开饭，老白手里的鸡腿、大嘴手里的花生米，垂涎欲滴。为什么以前从未注意这些，我妈喊着让我吃点零食都懒得吃，现在却控制不住自己的食欲。也许是以前有目标吧，想着考试，想着玩游戏，想着找工作，想着未来，想着某人。</p><p>现在啊，时过境迁，饮食男女，性也。</p>]]></content>
  </entry>
  <entry>
    <title>来，我们谈一谈梦想</title>
    <link href="https://crazy.smallyu.net/2019/09/19/%E6%9D%A5%EF%BC%8C%E6%88%91%E4%BB%AC%E8%B0%88%E4%B8%80%E8%B0%88%E6%A2%A6%E6%83%B3/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2019/09/19/%E6%9D%A5%EF%BC%8C%E6%88%91%E4%BB%AC%E8%B0%88%E4%B8%80%E8%B0%88%E6%A2%A6%E6%83%B3/</id>
    <published>2019-09-19T13:47:25.000Z</published>
    <updated>2025-08-16T03:27:11.437Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>最近租的小隔断被拆了，快国庆节了，查得紧。好像也没什么，找房子，签合同，入住，上班，再习惯。好像一切都很自然，没有什么激动人心的事情，没有什么让人开心的期望。</p>
<h3 id="中介"><a href="#中介" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>最近租的小隔断被拆了，快国庆节了，查得紧。好像也没什么，找房子，签合同，入住，上班，再习惯。好像一切都很自然，没有什么激动人心的事情，没有什么让人开心的期望。</p><h3 id="中介"><a href="#中介" class="headerlink" title="中介"></a>中介</h3><p>这次找房子花了一笔中介费，美曰其名“服务费”。一开始我问是不是中介，有没有中介费，回答是否定的。不过大哥人还算不错，我也没计较。作为服务行业，我为你提供服务，你为此支付一定费用，这是理所应当的事情。</p><p>中介这样的行业存在，本质还是信息不对等。同一城市的中介们会有一个平台，平台里的房源信息是共享的。也就是说，不管房客被哪个中介宰，他们是不介意的。互联网让信息平等了吗？并没有。“互联网的共享精神都是扯淡！”信息共享的前提是，信息提供方愿意将信息分享出来。作为房东，我什么都不想理会，把房子交给你，我每个月就可以收到一大笔钱，何乐而不为？</p><p>中介的房子会被查吗？不会的。这种专门折腾用来出租房子，房东、二房东、中介、物业，已经相当于一条产业链。二房东是给物业送过礼的，即使查，也不会查这几个房子，即使查到了，也不会往上报。也许社会就是这样，在哪儿都一样，不管是十八线小县城，还是一线帝都。</p><h3 id="房子"><a href="#房子" class="headerlink" title="房子"></a>房子</h3><p>刚离开之前的房子，还是非常不舍的。毕竟我记得当时是怎么来的，来了之后遇到了不错的人，遇到了不错的房东，性价比来讲之前的房子已经非常好了。其实很久了，已经过了好几个月，大半年了。其实也没多久。</p><p>焉知非福呢，只是不会再听到隔壁女生的笑声了。同样的生活节奏时间长了，难免会有一些惯性，看不清楚未来的惯性。偶尔发生一些意料之外的事情也好。现在住的房子临近某个大学，而且大学里的操场没有门禁。以前苦于附近的大学有门禁，公园又太远，运动实在不方便。现在反而手到擒来了。现在每天骑行上班，也算发现了新的天地。以前的生活半径以步行的范围为界限，现在可以将范围扩大一倍了。</p><p>焉知非福呢，被举报了的房子，说走就说。我开玩笑的跟同事说，可能今天下班的时候，老板就告诉你明天不用来了，也是说走就走。很正常，不是吗？不过，即使发生那样的事情，焉知非福呢？</p><h3 id="朋友"><a href="#朋友" class="headerlink" title="朋友"></a>朋友</h3><p>前些日子，我主动“放弃”了一个『朋友』。理由很简单，我不想再参与他的任何事情。我绝对不否认今后我们会有互利共赢的可能，但就目前而言，我丝毫不再有兴趣。他可能会是一个成功的商人，有能力赚到很多很多钱。但是能赚钱的人也很多，我知道有的『农民工』攒二三十年的钱，也可以全款买房子。</p><p>但是我的『目标』从来不是赚钱。这个朋友，他是做销售的，在朋友圈整天灌鸡汤，说你要努力，要找专业的人办专业的事，我们懂企业管理，知道最完美的薪酬体系，让你学会如何成功……你很难想象一个大学都不能按时毕业的人，跟你谈努力，谈专业。当然，他并不是要卖课程给我。他的另一个特点是，对技术的迷之崇拜。做一个微信公众号，有成就感，开发一个微信小程序，感觉了不起……这种感觉就像我小时候，刚接触互联网的时候，对网络世界的一切都感到新奇，比如注册一个域名，然后全世界的人都可以通过域名访问到我的个人网站，这是多么酷的事情！</p><p>一个多月前，他找我说想要开发一个H5网站。我问，具体有些什么功能？大概多少个主要的页面？他说，不太确定，就是有一个大概的想法。然后介于『朋友』的这层关系，我和另外两个人，就马马虎虎开始了。说实话，我答应下来做这个东西，完全是出于私心，因为一起共事的另外两个人，算是由我负责，给他们安排任务，把控整个项目的进度。哦，忘了说，这个朋友是我同级的校友，但也是一个小公司的老板，在这个项目的过家家游戏里，他仍然扮演『老板』的角色，给我安排的角色是『技术总监』。</p><p>本来这算是一个绝妙的机会，我可以趁机了解一些团队管理的东西。然而另外两个人的水平真是让我大跌眼镜，vue的项目，一步一步教也不会启动，git从始至终都不会用，后端……也就只能写几个接口了，毕竟他们都是『后端程序员』。然后就在项目过程中，发现到具体设计操作流程的阶段了，这个项目的应用场景、使用流程、盈利模式，都还完全没有概念。“这样能赚钱吗？” “我也不确定能不能赚钱，咱们总得试试。” 我就不奉陪了。</p><h3 id="金钱的价值"><a href="#金钱的价值" class="headerlink" title="金钱的价值"></a>金钱的价值</h3><p>想要认识金钱的『价值』，得了解各种东西的物价，然后侧面对金钱有个认识。以前1块钱就是1块钱，反正学费和生活费都是父母给的，我要多少，他们给多少就是了。最近租的房子没有宽带，我得自己办一个，到这儿就有点犯嘀咕了。</p><p>移动100M宽带一年380，是最便宜的套餐。380多吗，不多，平均一个月38。问题是我需要吗？好像也不太需要。我的手机套餐￥48&#x2F;月，一年下来要超过这个宽带的价。我一顿饭就要吃20多，可是上下班骑行一个月才20左右。网吧￥8&#x2F;小时，38块钱只能上网5个小时不到。然后，我一个月唱歌就要花160，平均￥1&#x2F;分钟。</p><p>买一件衣服50，寿命是一个月，买一双普通的鞋子70，寿命也是一个月。买一双亚瑟士慢跑鞋要380左右，寿命是几个月。一直想要的Redmibook 14是3999，能用3年。一个鼠标20左右，仿机械键盘30左右，真机械键盘100左右，手感有很大差异。两瓶大矿泉水可以喝一周，是10块钱，买一袋怪味胡豆要5块钱，一天就能吃完。一个月的房租是几千块钱，加上押金水电暖气管理服务费，平均下来也不少了。</p><p>我一个月的花销是多少呢，算不过来了，懒得算了。</p><h3 id="编程"><a href="#编程" class="headerlink" title="编程"></a>编程</h3><p>最上层的编程语言是脚本语言，往往没有严格的类型系统，基于其他语言实现的解释器编译执行。同样被广泛应用的是领域模型语言，他们是功能更加具体的语言。然后是高级语言，他们具有悠久的历史，优雅的设计，常常用来构建大型软件系统。高级语言会被编译器编译为汇编语言，汇编语言将载入处理器被执行。计算机的处理器根据指令改变引脚的电平，这些指令以电信号的形式与内存进行交互，完成寻址和计算的操作。</p><p>程序设计是在编程语言之上的应用，有了编程语言作为工具，就要用编程语言来完成一些作品。面向过程、面向对象和函数式编程是主流的程序设计方案。程序设计框架是开发者为了简化软件开发提供的一系列更加上层的工具。 </p><p>常见的网站程序设计方案是前端+后端，前端离不开MVVM框架，后端离不开MVC框架，也可能会将前端程序嵌入到后端程序中。为了加快任务处理，多线程是广为提倡的一个概念，也是对于新手的一个难点。当网站流量增大，需要保证服务能够稳定运行，高并发就成为了老手的难点，随之而来的是缓存、中间件等方案。当网站的数据量非常大，需要加快数据的处理速度，大数据的概念就应运而生，开源基金会提供了一整套大数据处理的框架。</p><p>随着技术的发展，程序员的工作内容逐渐由『开发』变成『组装』。以前是没有这样的东西，需要我们创造一个出来。现在市面上已经有了各种成熟的组件，我们只需要根据业务场景来搭建服务，能够满足业务需求。开源框架的作者们致力于让软件开发变得简单。如果你在开发过程中感觉有不舒服的地方，或许那个地方就差一个好用的框架，你可以试着完成这件事。</p><p>前沿技术一般来说有三个方向，大数据、人工智能和区块链。大数据就是通过集群的方式处理海量数据，一台服务器做起来费劲，就用十台服务器一起来做。大数据框架则是在提供给开发者搭建分布式数据处理集群的能力。人工智能是一个听起来比较高级的方向，我有一个同学，大学的时候C语言都搞不明白，考研上了个比较好的学校，现在也开始搞深度学习了……人工智能的核心并不是计算机技术，而是数学理论借助计算机实现了大量计算。至于区块链，它的核心自然也不是计算机技术，而是使用机制。不过话说回来，计算机技术不也是由各种『机制』结合组成的吗？</p><h3 id="了解更多"><a href="#了解更多" class="headerlink" title="了解更多"></a>了解更多</h3><p>偶尔看看书，世界上其实有很多很多领域，关于群众心理的研究，关于人类语言的研究，关于社会行为的研究，关于简洁设计的研究，关于历史和未来的研究……</p><p>一年前在知乎上看到了一段话，感觉非常喜欢。至今，我仍然非常喜欢。所以我想分享一下：</p><blockquote><p>谁让你读了这么多书，又知道了双水村以外还有个大世界……如果从小你就在这个天地里日出而作，日落而息，那你现在就会和众乡亲抱同一理想：经过几年的辛劳，像大哥一样娶个满意的媳妇，生个胖儿子，加上你的体魄，会成为一名出色的庄稼人。不幸的是，你知道的太多了，思考的太多了，因此才有了这种不能为周围人所理解的苦恼。</p></blockquote>]]></content>
  </entry>
  <entry>
    <title>Rust 基础语法概述</title>
    <link href="https://smallyu.net/2019/08/19/Rust%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95%E6%A6%82%E8%BF%B0/"/>
    <id>blog:https://smallyu.net/2019/08/19/Rust%E5%9F%BA%E7%A1%80%E8%AF%AD%E6%B3%95%E6%A6%82%E8%BF%B0/</id>
    <published>2019-08-19T14:12:25.000Z</published>
    <updated>2025-06-30T13:35:29.557Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Rust是复杂度和应用场景都对标C++的语言，一起学习吧！</p>
<p>最近，我开始思考像本文这样类型的内容算什么，编程语言的教程？内容不全面；对语言的评价？够不着；学习笔记？如果是，那绝非我本意。我倾向于认为这是一个探索的过程，无论对于我自己还是对于别人，我希望可以表现]]></summary>
    <content type="html"><![CDATA[<p>Rust是复杂度和应用场景都对标C++的语言，一起学习吧！</p><p>最近，我开始思考像本文这样类型的内容算什么，编程语言的教程？内容不全面；对语言的评价？够不着；学习笔记？如果是，那绝非我本意。我倾向于认为这是一个探索的过程，无论对于我自己还是对于别人，我希望可以表现出来的是，你看，新的编程语言没什么神秘的，它如此简单！有的程序员终其一生，都将某种语言作为自己职业头衔的前缀，“Java程序员”或是“后端开发”，我们该跳出这种怪圈。</p><h3 id="语句"><a href="#语句" class="headerlink" title="语句"></a>语句</h3><p>Rust必须以<code>;</code>结尾。</p><h3 id="常量和变量"><a href="#常量和变量" class="headerlink" title="常量和变量"></a>常量和变量</h3><p>Rust使用<code>let</code>定义常量，使用<code>let mut</code>定义变量。这样的写法可能稍微有点奇怪：</p><pre><code class="Rust">fn main() &#123;  let x = 1;  println!(&quot;&#123;&#125;&quot;, x);  let mut y = 2;  println!(&quot;&#123;&#125;&quot;, y);  y = 3;  println!(&quot;&#123;&#125;&quot;, y);&#125;</code></pre><p>不同于其他语言的是，Rust允许在同一作用域中多次声明同一常量。也就是说，Rust里的常量虽然不可以被第二次赋值，但是同一常量名可以被多次定义。我们虽然能在系统层面明白常量和变量的区别，但是写法上稍微有点容易引起混淆。我多次给同一组符号赋值，这个符号不就是变量吗？</p><pre><code class="Rust">fn main() &#123;  let x = 1;  println!(&quot;&#123;&#125;&quot;, x);  let x = 2;  println!(&quot;&#123;&#125;&quot;, x);&#125;</code></pre><p>另一个有点奇怪的地方是，Rust的变量不允许重复定义。我们无法推测语言设计者的初衷，这明显不是为了允许重复定义而允许。也许，Rust中只存在常量，<code>mut</code>关键字的作用就是给常量一个可以被多次赋值的接口。没有mut，常量就是个常量，有了mut，常量就有了获得新值的“入口”。至于变量重复定义的问题，要啥自行车？</p><pre><code class="Rust">fn main() &#123;  let mut x = 1;  let mut x = 2;&#125;// warning: variable does not need to be mutable</code></pre><h3 id="控制流"><a href="#控制流" class="headerlink" title="控制流"></a>控制流</h3><p>Rust的条件部分不需要写小括号，和Go语言一样。谁先谁后呢？</p><pre><code class="Rust">fn main() &#123;  let number = 2;  if number == 1 &#123;    println!(&quot;1&quot;)  &#125; else if number == 2 &#123;    println!(&quot;2&quot;)  &#125; else &#123;    println!(&quot;3&quot;)  &#125;&#125;</code></pre><p>由于if语句本身是一个表达式，所以也可以嵌套进赋值语句中，实现类似其他语言三目运算符的功能。（Rust是强类型的语言，所以赋值类型必须一致。）</p><pre><code class="Rust">fn main() &#123;  let number = if true &#123;    3  &#125; else &#123;    4  &#125;;  println!(&quot;&#123;&#125;&quot;, number);&#125;</code></pre><p>与Go语言简洁的多功能for循环相比，Rust支持多种类型的循环：</p><pre><code class="Rust">fn main() &#123;  loop &#123;    // ...  &#125;  while true &#123;    // ...  &#125;  let a = [1, 2, 3];  for item in a.iter() &#123;    println!(&quot;&#123;&#125;&quot;, item);  &#125;&#125;</code></pre><h3 id="函数与值的传递"><a href="#函数与值的传递" class="headerlink" title="函数与值的传递"></a>函数与值的传递</h3><p>Rust似乎不存在值传递与引用传递的区别，因为Rust中全都是引用传递，或者分类为常量的传递与变量的传递。对比Java中字符串的创建，Rust中创建字符串也可以使用“声明对象”的方式：</p><pre><code class="Rust">fn main() &#123;  // 常量传递  let a = String::from(&quot;a&quot;);  testa(&amp;a);  // 变量传递  let mut b = String::from(&quot;b&quot;);  testb(&amp;mut b);  println!(&quot;&#123;&#125;&quot;, b);&#125;fn testa(a: &amp;String) &#123;  println!(&quot;&#123;&#125;&quot;, a);&#125;fn testb(b: &amp;mut String) &#123;  b.push_str(&quot; b&quot;);&#125;</code></pre><p>函数当然也是可以有返回值的，Rust中函数的返回值用<code>-&gt;</code>定义类型，默认将函数最后一行的值作为返回值，也可以手动return提前结束函数流程。需要注意的是，在最后一行用来作为返回值的表达式，记得不要加封号……</p><pre><code class="Rust">fn main() &#123;  let mut a = test();  println!(&quot;&#123;&#125;&quot;, a);  a = test2();  println!(&quot;&#123;&#125;&quot;, a);&#125;fn test() -&gt; u32 &#123;  1&#125;fn test2() -&gt; u32 &#123;  return 2;&#125;</code></pre><h3 id="结构体"><a href="#结构体" class="headerlink" title="结构体"></a>结构体</h3><p>结构体的基本用法比较常规，没有<code>new</code>关键字，直接“实例化”就可以使用：</p><pre><code class="Rust">struct Foo &#123;  a: String,  b: i32&#125;fn main() &#123;  let t = Foo &#123;    a: String::from(&quot;a&quot;),    b: 1,  &#125;;  println!(&quot;&#123;&#125;, &#123;&#125;&quot;, t.a, t.b);&#125;</code></pre><p>同样可以给结构体添加方法：</p><pre><code class="Rust">struct Foo &#123;  a: String,  b: i32&#125;impl Foo &#123;  fn test(&amp;self) -&gt; i32 &#123;    self.b + 1  &#125;&#125;fn main() &#123;  let t = Foo &#123;    a: String::from(&quot;a&quot;),    b: 1,  &#125;;  println!(&quot;&#123;&#125;, &#123;&#125;, &#123;&#125;&quot;, t.a, t.b, t.test());&#125;// a, 1, 2</code></pre><h3 id="列表与模式匹配"><a href="#列表与模式匹配" class="headerlink" title="列表与模式匹配"></a>列表与模式匹配</h3><p>下面的例子创建了包含3个元素的向量，然后将第0个元素赋值给常量one。之后使用模式匹配判断列表的第0个元素是否等于one的值，如果相等则输出字符串”one”，否则为”none”。Rust的模式匹配中，Some()和None都是内置的关键字：</p><pre><code class="Rust">fn main() &#123;  let v = vec![1, 2, 3];  let one = &amp;v[0];  println!(&quot;&#123;&#125;&quot;, one);  match v.get(0) &#123;    Some(one) =&gt; println!(&quot;one&quot;),    Some(2) =&gt; println!(&quot;two&quot;),    None =&gt; println!(&quot;none&quot;),  &#125;&#125;</code></pre><h3 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h3><p>panic函数用于抛出异常：</p><pre><code class="Rust">fn main() &#123;  panic!(&quot;new Exception&quot;);&#125;// thread &#39;main&#39; panicked at &#39;new Exception&#39;, test.rs:4:3// note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.</code></pre><p>针对错误处理，Rust提供了两个简写的方法，用于便捷的处理错误信息。unwrap()函数会自动抛出panic，如果不使用unwrap()，程序则会跳过发生panic的代码。这在某种程度上与Java的异常处理逻辑相反，因为Java如果不对异常进行处理，程序就无法继续运行。而Rust如果使用unwrap()对panic进行处理，程序将不再继续执行，同时打印出错误信息。</p><pre><code class="Rust">use std::fs::File;fn main() &#123;  let f = File::open(&quot;hello.txt&quot;);  println!(&quot;a&quot;);  let f2 = File::open(&quot;hello.txt&quot;).unwrap();  println!(&quot;b&quot;);&#125;// a// thread &#39;main&#39; panicked at &#39;called `Result::unwrap()` on an `Err` value: Os &#123; code: 2, kind: NotFound, message: &quot;系统找不到指定的文件。&quot; &#125;&#39;, src\libcore\result.rs:999:5// ...</code></pre><p>另一个简写的方法是expect()，可用于替代unwrap()。它与unwrap()的区别在于，unwrap()使用系统内置的panic信息，而expect()可以传入参数作为panic的错误信息。仅此而已。</p><pre><code class="Rust">use std::fs::File;fn main() &#123;    let f = File::open(&quot;hello.txt&quot;).expect(&quot;Failed to open hello.txt&quot;);&#125;// thread &#39;main&#39; panicked at &#39;Failed to open hello.txt: ...// ...</code></pre><h3 id="Lambda表达式"><a href="#Lambda表达式" class="headerlink" title="Lambda表达式"></a>Lambda表达式</h3><p>Rust中的Lambda表达式使用<code>|</code>作为入参的界定符，即使用<code>||</code>来代替<code>()</code>。此外Lambda的公用和其它语言是相同的：</p><pre><code class="Rust">fn main() &#123;  let test = |num| &#123;    num == 1  &#125;;  println!(&quot;&#123;&#125;, &#123;&#125;&quot;, test(1), test(2));&#125;// true, false</code></pre><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>Rust的语言特性远不止此，尤其是Rust与众不同的内存管理机制，以及让Rust新手得其门不得其道的概念”ownership”，都需要我们不断前行。</p>]]></content>
  </entry>
  <entry>
    <title>基于 Java 的爬虫框架 WebCollector</title>
    <link href="https://smallyu.net/2019/08/10/%E5%9F%BA%E4%BA%8EJava%E7%9A%84%E7%88%AC%E8%99%AB%E6%A1%86%E6%9E%B6WebCollector/"/>
    <id>blog:https://smallyu.net/2019/08/10/%E5%9F%BA%E4%BA%8EJava%E7%9A%84%E7%88%AC%E8%99%AB%E6%A1%86%E6%9E%B6WebCollector/</id>
    <published>2019-08-10T13:03:41.000Z</published>
    <updated>2026-08-04T11:43:17.000Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Long, Long]]></summary>
    <content type="html"><![CDATA[<p>Long, Long Ago，网络上出现大量Python爬虫教程，各种培训班借势宣扬Python，近几年又将噱头转向人工智能。爬虫是一个可以简单也可以复杂的概念，就好比建造狗屋和建筑高楼大厦都是在搞工程。</p><p>由于工作的缘故，我需要使用WebCollector爬取一些网页上的数据。其实宏观上，爬虫无非就是访问页面文件，把需要的数据提取出来，然后把数据储存到数据库里。难点往往在于，一是目标网站的反爬策略，这是让人比较无奈的斗智斗勇的过程；二是目标网页数量大、类型多，如何制定有效的数据爬取和数据分析方案。</p><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>这是一张简略的概念图，受屏幕宽度限制，可能无法看清内容，请在新标签页打开图片，或者直接点击 <a href="/2019/08/10/%E5%9F%BA%E4%BA%8EJava%E7%9A%84%E7%88%AC%E8%99%AB%E6%A1%86%E6%9E%B6WebCollector/WebCollector.png">这里</a>。这张图片并不是完美的，甚至还包含不完全正确的实现方式，具体内容会在后面阐述。</p><img src="WebCollector.png" width="95%" height="100%"><p>我将目标网页分为4种类型：</p><ol><li>静态的网页文档，curl就可以加载到</li><li>需要自定义HTTP请求的页面，比如由POST请求得到的搜索结果页面，或者需要使用Cookie进行鉴权的页面</li><li>页面中包含由JavaScript生成的数据，而我们需要的正是这部分数据。由于js是加载后才执行的，就像CSS加载后由浏览器进行渲染一样，这样的数据无法直接得到</li><li>页面中包含由JavaScript生成的数据，且需要自定义HTTP请求的页面</li></ol><h3 id="测试环境"><a href="#测试环境" class="headerlink" title="测试环境"></a>测试环境</h3><p>为了便于测试，在本地使用Node.js启动一个简单的服务器，用于接收请求，并返回一个页面作为响应。server.js的内容如下：</p><pre><code class="JavaScript">var http = require(&#39;http&#39;)var fs = require(&#39;fs&#39;)var server = http.createServer((req,res) =&gt; &#123;  // 返回页面内容  fs.readFile(&#39;./index.html&#39;, &#39;utf-8&#39;, (err,data) =&gt; &#123;    res.end(data);  &#125;);  // 打印请求中的Cookie信息  console.log(req.headers.cookie)&#125;)server.listen(9000) </code></pre><p>index.html的内容更加简单，只包含一个title和一个p标签：</p><pre><code class="HTML">&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;    &lt;title&gt;This is a title&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;</code></pre><h3 id="静态页面"><a href="#静态页面" class="headerlink" title="静态页面"></a>静态页面</h3><p>这是一个最简版的爬虫程序，在构造方法中调用父类的有参构造方法，同时添加url到待爬取队列中。visit是消费者，每一个url请求都会进入这个方法被处理。</p><pre><code class="Java">public class StaticDocs extends BreadthCrawler &#123;    public StaticDocs(String crawlPath, boolean autoParse) &#123;        super(crawlPath, autoParse);        this.addSeed(&quot;http://127.0.0.1:9000/&quot;);    &#125;    @Override    public void visit(Page page, CrawlDatums next) &#123;        System.out.println(page.doc().title();        // This is a title    &#125;    public static void main(String[] args) throws Exception &#123;        StaticDocs crawler = new StaticDocs(&quot;crawl&quot;, true);        crawler.start(1);    &#125;&#125;</code></pre><h3 id="Cookie鉴权"><a href="#Cookie鉴权" class="headerlink" title="Cookie鉴权"></a>Cookie鉴权</h3><p>需要在header中带cookie请求同样简单，在构造方法中添加相应配置就可以，node.js的命令行会打印出cookie的内容：</p><pre><code class="Java">public CookieDocs(String crawlPath) &#123;    super(crawlPath, true);    // 设置请求插件    setRequester(new OkHttpRequester() &#123;        @Override        public Request.Builder createRequestBuilder(CrawlDatum crawlDatum) &#123;            return super.createRequestBuilder(crawlDatum)                    .header(&quot;Cookie&quot;, &quot;name=smallyu&quot;);        &#125;    &#125;);    this.addSeed(&quot;http://127.0.0.1:9000/&quot;);&#125;// name=smallyu</code></pre><h3 id="JavaScript生成的数据"><a href="#JavaScript生成的数据" class="headerlink" title="JavaScript生成的数据"></a>JavaScript生成的数据</h3><p>测试js生成数据的情况需要做一点准备，修改index.html，在body标签中加入这样几行代码：</p><pre><code class="JavaScript">&lt;div id=&quot;content&quot;&gt;1&lt;/div&gt;&lt;script&gt;  document.getElementById(&#39;content&#39;).innerHTML = &#39;2&#39;&lt;/script&gt;</code></pre><p>可以预见，请求中直接返回的div内容是1，然后js经由浏览器执行，改变div的内容为2。访问静态页面的爬虫程序只能进行到第1步，也就是直接获取请求返回的内容。修改StaticDocs.java的visit方法，打印出div的内容看一下，可以确信是1：</p><pre><code class="Java">System.out.println(page.select(&quot;div&quot;).text());// 1</code></pre><p>这是一个官方提供的Demo，用于获取js生成的数据。WebCollector依赖于Selenium，使用HtmlUnitDriver运行js：</p><pre><code class="Java">public class JsDocs &#123;    public static void main(String[] args) throws Exception &#123;        Executor executor = (CrawlDatum datum, CrawlDatums next) -&gt; &#123;            HtmlUnitDriver driver = new HtmlUnitDriver();            driver.setJavascriptEnabled(true);            driver.get(datum.url());            WebElement divEle = driver.findElement(By.id(&quot;content&quot;));            System.out.println(divEle.getText());            // 2        &#125;;        //创建一个基于伯克利DB的DBManager        DBManager manager = new RocksDBManager(&quot;crawl&quot;);        //创建一个Crawler需要有DBManager和Executor        Crawler crawler = new Crawler(manager, executor);        crawler.addSeed(&quot;http://127.0.0.1:9000/&quot;);        crawler.start(1);    &#125;&#125;</code></pre><p>如果你看过WebCollector的主页，一定可以注意到这个Demo和其他Demo的明显不同。在不需要js生成的数据时，新建的类继承自BreadthCrawler，而BreadthCrawler继承自AutoParseCrawler，AutoParseCrawler又继承自Crawler。现在获取js数据的Demo，直接跳过BreadthCrawler和AutoParseCrawler，实例化了Crawler。</p><img src="uml.png" width="50%" height="100%"><p>为什么要这样做呢？再次强调，这是官方提供的Demo。</p><h3 id="Cookie鉴权后JavaScript生成的数据"><a href="#Cookie鉴权后JavaScript生成的数据" class="headerlink" title="Cookie鉴权后JavaScript生成的数据"></a>Cookie鉴权后JavaScript生成的数据</h3><p>根据官方提供的用例，显然是无法设置cookie的，因为Crawler类并没有提供自定义Header的方法。这个自定义Header的方法继承自AutoParseCrawler类。那么如何做到既可以添加Cookie又可以使用HtmlUnitDriver？</p><p>其实结果很简单，我在看过WebCollector的代码后发现AutoParseCrawler实现了Executor接口，并且在构造方法中将this赋值给了父类的executor。也就是说，AutoParseCrawler本身就是一个Executor。下面的代码用以表示它们的关系：</p><pre><code class="Java">public class Crawler &#123;    protected Executor executor;    public Crawler(DBManager dbManager, Executor executor) &#123;        // ...    &#125;&#125;public class AutoParseCrawler extends Crawler implements Executor &#123;    public AutoParseCrawler(boolean autoParse) &#123;        // 这里的executor指向父类        this.executor = this;    &#125;&#125;</code></pre><p>new Crawler时传入一个executor，相当于直接new一个AutoParseCrawler。BreadthCrawler继承自AutoParseCrawler，所以BreadthCrawler本身也是个Executor。再看官方关于自定义Cookie的Demo，如何在其中使用HtmlUnitDriver呢？重写Executor的execute方法。</p><p>所以，在定义cookie后获取js生成的数据，使用继承BreadthCrawler的类，然后重写execute就可以。这是一个完整的Demo：</p><pre><code class="Java">/** * @author smallyu * @date 2019.08.11 12:18 */public class JsWithCookieDocs extends BreadthCrawler &#123;    public JsWithCookieDocs(String crawlPath) &#123;        super(crawlPath, true);        // 设置请求插件        setRequester(new OkHttpRequester() &#123;            @Override            public Request.Builder createRequestBuilder(CrawlDatum crawlDatum) &#123;                return super.createRequestBuilder(crawlDatum)                        .header(&quot;Cookie&quot;, &quot;name=smallyu&quot;);            &#125;        &#125;);        this.addSeed(&quot;http://127.0.0.1:9000/&quot;);    &#125;    // 直接重写execute即可    @Override    public void execute(CrawlDatum datum, CrawlDatums next) throws Exception &#123;        super.execute(datum, next);        HtmlUnitDriver driver = new HtmlUnitDriver();        driver.setJavascriptEnabled(true);        driver.get(datum.url());        WebElement divEle = driver.findElement(By.id(&quot;content&quot;));        System.out.println(divEle.getText());        // 2        // 同时，node.js的命令行中打印出cookie内容    &#125;    // 重写execute就不需要visit了    public void visit(Page page, CrawlDatums crawlDatums) &#123;&#125;    public static void main(String[] args) throws Exception &#123;        JsWithCookieDocs crawler = new JsWithCookieDocs(&quot;crawl&quot;);        crawler.start(1);    &#125;&#125;</code></pre><h3 id="外部代理"><a href="#外部代理" class="headerlink" title="外部代理"></a>外部代理</h3><p>也许还没有结束。在一开始概述的图片上，同时定义cookie以及获取js生成的数据，实现方式是内部Selenium + 外部browsermob-proxy。假设没有上述重写execute的方法（官方也确实没有提供类似的Demo），该如何实现想要的效果？一种实践是本地启动一个代理，给代理设置好cookie，然后让Selenium的WebDriver通过代理访问目标页面，就可以在带header的情况下拿到js生成的数据。这是在JsDocs.java的基础上，使用代理的完整实现：</p><pre><code class="Java">public class JsWithProxyDocs &#123;    public static void main(String[] args) throws Exception &#123;        Executor executor = (CrawlDatum datum, CrawlDatums next) -&gt; &#123;            // 启动一个代理            BrowserMobProxy proxy = new BrowserMobProxyServer();            proxy.start(0);            // 添加header            proxy.addHeader(&quot;Cookie&quot; , &quot;name=smallyu&quot;);            // 实例化代理对象            Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);            // 由代理对象生成capabilities            DesiredCapabilities capabilities = new DesiredCapabilities();            capabilities.setCapability(CapabilityType.PROXY, seleniumProxy);            // 内置，必须设置            capabilities.setBrowserName(&quot;htmlunit&quot;);            // 使用capabilities实例化HtmlUnitDriver            HtmlUnitDriver driver = new HtmlUnitDriver(capabilities);            driver.setJavascriptEnabled(true);            driver.get(datum.url());            WebElement divEle = driver.findElement(By.id(&quot;content&quot;));            System.out.println(divEle.getText());   // 2        &#125;;        //创建一个Crawler需要有DBManager和Executor        Crawler crawler = new Crawler(new RocksDBManager(&quot;crawl&quot;), executor);        crawler.addSeed(&quot;http://127.0.0.1:9000/&quot;);        crawler.start(1);    &#125;&#125;</code></pre><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>对于WebCollector我已经没有兴趣了解更多，倒是在注意到框架的包名<code>cn.edu.hfut</code>后有种豁然开朗的感觉。凌乱的代码风格，随处可见不知所以的注释，毫无设计美感的代码架构，倒也符合国内不知名大学的开源软件水平，距离工业级的框架，可能还需要N个指数倍的时间。至于使用过程中遇到depth含义不明、线程非法结束、next.add失效等问题，就这样吧，也在情理之中，整个框架都像是赶工的结果，或者说是学生们拿来练手的项目。我在WebCollector的GitHub上PR了关于重写execute的问题，从开发者回复的只言片语中，我怀疑开源者自己都没有把里面的东西搞清楚 :P</p>]]></content>
  </entry>
  <entry>
    <title>工作能力低下的表现</title>
    <link href="https://b.smallyu.net/2019/07/25/%E5%B7%A5%E4%BD%9C%E8%83%BD%E5%8A%9B%E4%BD%8E%E4%B8%8B%E7%9A%84%E8%A1%A8%E7%8E%B0/"/>
    <id>blog-b:https://b.smallyu.net/2019/07/25/%E5%B7%A5%E4%BD%9C%E8%83%BD%E5%8A%9B%E4%BD%8E%E4%B8%8B%E7%9A%84%E8%A1%A8%E7%8E%B0/</id>
    <published>2019-07-24T16:05:30.000Z</published>
    <updated>2025-12-03T10:02:00.865Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>现在是零点零五分左右，本来是应该睡觉的时间，却突然想写点东西。</p>
<ul>
<li><p><strong>抱怨</strong> </p>
<p>时时刻刻在抱怨，这个不对，那个不好，并且将不满实实在在的挂在脸上，从嘴里说出来，生怕别人不知道有意见]]></summary>
    <content type="html"><![CDATA[<p>现在是零点零五分左右，本来是应该睡觉的时间，却突然想写点东西。</p><ul><li><p><strong>抱怨</strong> </p><p>时时刻刻在抱怨，这个不对，那个不好，并且将不满实实在在的挂在脸上，从嘴里说出来，生怕别人不知道有意见 :)</p></li><li><p><strong>无法承受工作压力</strong></p><p>抱怨的根源是工作内容，工作量稍微多一些就会开始抱怨，活好多，我好烦，我做不完，我做不过来，我没有时间。其实只不过是正常的工作量而已，其实不用加班，其实摸鱼晒网谁都喜欢 :)</p></li><li><p><strong>情绪化</strong></p><p>面对同事提出的问题，常见做法是不予理睬，稍加严重的做法是争锋相对。最让人诧异的是，生气的原因竟然可以是“他不尊重我的劳动成果”。打工而已，劳动哪有成果 :)</p></li><li><p><strong>自我为中心</strong></p><p>正常工作中的分工合作感觉像是去政府求人办事，要在适当的时候，方便的时候，有时间的时候，心情好的时候，不然可能会看到不太好的脸色。我曾以为众生平等 :)</p></li><li><p><strong>你的错，我的错</strong></p><p>盼天盼地盼月亮盼星星，是你的错，不是我的错，这个问题需要你改，而不是需要我改，有事找你别找我，你能解决的就尽量不要让我动手 :)</p></li><li><p><strong>专业能力不足</strong></p><ul><li><p><strong>模块化能力欠缺</strong></p><p>功能组件化，模块抽象化。不懂后端架构的前端工程师不是好码农，由于缺乏对整个项目结构的思考，复用能力太差，导致需求变更带来大的工作量，大的工作量会引起第一点 :)</p></li><li><p><strong>编程能力欠缺</strong></p><p>会写代码，但不会编程。缺乏基本的计算机常识，遇到功能点显得盲目、无力，由于自身能力的限制导致工作难度增大，工作时间加长，也就是工作量增大，大的工作量会引起第一点 :)</p></li><li><p><strong>对自己认知不足</strong></p><p>会做什么，不会做什么？ :)</p></li><li><p><strong>思想上的巨人</strong></p><p>思想上的巨人，行动上的矮子。即使知道自己有欠缺，口口声声说甚至有行动作出改变，但是收效甚微。一般来说，造成这种现象的原因是，没动脑子 :)</p></li></ul></li><li><p><strong>盲目要强</strong></p><p>拒绝别人的帮助，希望别人以更加友善、符合自己能力的方式迁就合作。在意“自己”完成任务，而不是自己“完成”任务。</p></li><li><p><strong>目的不明确</strong></p><p>工作是为了什么？既然如此痛苦，为什么不换个行业？ :)</p></li><li><p><strong>……</strong></p></li></ul><p>我没有任何恶意，只是描述一些客观现象。我可怜能力不足的人，面对超出自己能力范畴的工作时会感到无助，但我也难受，和这样的人合作也许是噩梦。我会尽量避开那些我不太喜欢的点，告诫自己不要也变成那样。让自己变好，然后拥有讨厌别人的资格。现在一点零五分左右，我要睡觉了。</p><h3 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h3><p>时间过去了将近一个月，我似乎开始理解某些行为和现象。</p><p>事情是这样，最近，我试着使用 C# 开发一个简单的桌面应用程序，我的想法很简单，自定义几个快捷键，然后让快捷键代替重复多次的退格键。比如，全局热键 <code>Ctrl-5</code> 相当于按下退格键 <code>Backspace</code> 5 次，<code>Ctrl-6</code> 则相当于按 6 次。</p><p>这个想法产生于我日常敲键盘的过程，由于双手打字速度较快，类似于多线程的无序执行，经常出现拼音中字母错位的现象，然后手快又按下了空格键，就会有一长串错误的词组上屏。每次都按 N 次退格键是一件比较让人不爽的事情，尤其是流畅的思路被打断，感觉啪啪啪的退格键既影响了正常打字的顺畅，又有一种不得不为自己之前犯下的小错误负责任的愤恨。</p><p>原先以为只要向系统注册一组全局按键，然后模拟键盘的输入，整个过程就这么简单。然而，在实际的开发过程中，我遇到了很多困难，一开始连 WPF 中的 Window 和 Form 都没有区分清楚，Google 到的教程提到了多种注册快捷键的方法，但是真正可用的少之又少，对于按键的模拟也只能依靠搜索引擎，因为官方文档中提到的 <code>Keys.send()</code> 之类的方法并不起作用（也许是事件等级太低）。</p><p>在能够实现基本的注册快捷键和模拟按键功能后，我遇到了新的问题。快捷键是基于 <code>Ctrl</code>，在按下快捷键的同时，程序就会执行，也就是模拟 <code>Backspace</code>，这个时候 <code>Ctrl</code> 键还没有松开，系统会认为我按下了 <code>Ctrl-Backspace</code>，这显然不是预期的效果。然后我将 <code>Ctrl</code> 换为 <code>Alt</code>，最终确定 <code>Shift</code> 键和 <code>Backspace</code> 组合没有冲突。但是新的问题又来了，程序模拟的按键最多触发两次，所以实际效果最多退两格，无论我循环多少次或者改变 <code>nInPints</code> 参数的值，都没有解决这个问题。</p><p>所以，我并没有在表达开发一个那样的东西很难，只是说遇到了一些我不太擅长解决的问题。也是在那个过程中，我体会到了“我好烦”、“这个好难”、“真闹心”、“没那么简单”之类的情绪。</p><p>也许，我们应该多一些理解。</p>]]></content>
  </entry>
  <entry>
    <title>Kotlin：简化版的 Scala</title>
    <link href="https://smallyu.net/2019/07/06/Kotlin%EF%BC%9A%E7%AE%80%E5%8C%96%E7%89%88%E7%9A%84Scala/"/>
    <id>blog:https://smallyu.net/2019/07/06/Kotlin%EF%BC%9A%E7%AE%80%E5%8C%96%E7%89%88%E7%9A%84Scala/</id>
    <published>2019-07-06T02:18:22.000Z</published>
    <updated>2025-07-19T15:57:56.734Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>行走江湖的剑客，必然要有一柄趁手的宝剑。好的程序语言就像一把好剑，重量合适，拿着舒服，挥舞起来优雅，杀伤力过关。Kotlin官方对待Kotlin和Scala的关系是，“如果你玩Scala很happy，那你就不需要Kotlin。”</p>
<h3 id="脚本化"><a]]></summary>
    <content type="html"><![CDATA[<p>行走江湖的剑客，必然要有一柄趁手的宝剑。好的程序语言就像一把好剑，重量合适，拿着舒服，挥舞起来优雅，杀伤力过关。Kotlin官方对待Kotlin和Scala的关系是，“如果你玩Scala很happy，那你就不需要Kotlin。”</p><h3 id="脚本化"><a href="#脚本化" class="headerlink" title="脚本化"></a>脚本化</h3><p>Scala执行的基本单位和Java一样是类，而Kotlin允许文件中的main方法直接运行，不需要类。Java的入口函数定义在类中：</p><pre><code class="Java">public class Java &#123;    public static void main(String[] args) &#123;&#125;&#125;</code></pre><p>Scala的入口函数定义在样本类而不是普通的类中：</p><pre><code class="Scala">object Scala &#123;  def main(args: Array[String]): Unit = &#123;&#125;&#125;</code></pre><p>Kotlin的入口函数则直接定义在.kt文件中，相应的，Kotlin的类仅相当于一种数据结构，类中无法定义入口函数：</p><pre><code class="Kotlin">fun main(args: Array&lt;String&gt;) &#123;&#125;</code></pre><h3 id="构造函数与单例模式"><a href="#构造函数与单例模式" class="headerlink" title="构造函数与单例模式"></a>构造函数与单例模式</h3><p>Kotlin的构造函数同Scala一样写在类定义处，因此也无法像Java的构造函数一样直接写入初始化代码。Kotlin中使用init代码块来执行初始化程序：</p><pre><code class="Kotlin">class Test(arg: String) &#123;    init &#123;        println(&quot;This string is $&#123;arg&#125;&quot;)    &#125;&#125;fun main(args: Array&lt;String&gt;) &#123;    val test = Test(&quot;smallyu&quot;)&#125;// This string is smallyu</code></pre><p>如果需要第二个构造函数，就要使用类似ES6的constructor函数，或者类似Scala的辅助构造器。这实在是丑陋的写法，相比之下Java真的友善多了。</p><pre><code class="Kotlin">class Test(arg1: String) &#123;    init &#123;        println(&quot;This string is $&#123;arg1&#125;&quot;)    &#125;    constructor(arg2: Int): this(&quot;smallyu2&quot;) &#123;        println(&quot;This int is $&#123;arg2&#125;&quot;)    &#125;&#125;fun main(args: Array&lt;String&gt;) &#123;    val test = Test(1)&#125;// This string is smallyu2// This int is 1</code></pre><p>Kotlin的构造函数是需要用constructor关键字定义的，默认可以省略，但如果要加权限修饰符自然就不能省了。在Kotlin中实现单例模式的思路与Java相同，让构造器私有，然后通过静态方法暴露实例：</p><pre><code class="Kotlin">class Test private constructor() &#123;    companion object Factory &#123;        fun create(): Test = Test()    &#125;&#125;fun main(args: Array&lt;String&gt;) &#123;    val test = Test.Factory.create()&#125;</code></pre><p>Kotlin中的object定义静态代码块，companion允许在类内部定义静态代码块，因此compaion object定义了类外部可以访问的方法create()。</p><h3 id="getter和setter"><a href="#getter和setter" class="headerlink" title="getter和setter"></a>getter和setter</h3><p>Kotlin另一个有趣的玩意儿是getter和setter。前端框架React或Vue实现数据双向绑定的原理即使用Object.defineProperty()定义对象的getter和setter，使得对象的变化可以实时同步到页面上。Kotlin提供了对属性getter和setter的支持：</p><pre><code class="Kotlin">var test: Int    get() &#123;        println(&quot;There is test getter&quot;)        return 2    &#125;    set(arg) &#123;        println(&quot;The setter arg is $&#123;arg&#125;&quot;)    &#125;fun main(args: Array&lt;String&gt;) &#123;    println(test)    test = 3&#125;// There is test getter// 2// The setter arg is 3</code></pre><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>开始对Kotlin感兴趣是因为发现Kotlin竟然支持协程，如果Kotlin真的有语言级别的协程支持，加上运行在Jvm上的特点，以及能够开发多平台应用包括Server Side、Android、JavaScript、Native，那Kotlin无疑是异常强大的编程语言。然而事实上Kotlin的协程只是一个扩展包，甚至还需要使用编译工具来引入，对协程的支持还是Go语言独大。用于JavaScript平台也是个幌子，并没有比TypeScript好用，至于Android和Native本身也是Java的应用场景……</p><p>Kotlin提供了许多语法糖，看似可以简化程序员的代码量，但是为了熟练应用Kotlin的特性，使用者又不得不搞清楚类似data class的概念，就像Scala的case class一样。Kotlin的学术性弱于Scala，工程能力又不比Java有大的优势。Go语言虽然另辟蹊径，语言特性上有广为诟病的地方，但是看着爽，写着也爽。所以Kotlin和Scala一样，并不会有广泛的应用前景。也就是说，它并不会是下一个很流行的编程语言。</p>]]></content>
  </entry>
  <entry>
    <title>大学毕业是什么体验</title>
    <link href="https://crazy.smallyu.net/2019/06/30/%E5%A4%A7%E5%AD%A6%E6%AF%95%E4%B8%9A%E6%98%AF%E4%BB%80%E4%B9%88%E4%BD%93%E9%AA%8C/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2019/06/30/%E5%A4%A7%E5%AD%A6%E6%AF%95%E4%B8%9A%E6%98%AF%E4%BB%80%E4%B9%88%E4%BD%93%E9%AA%8C/</id>
    <published>2019-06-30T12:27:07.000Z</published>
    <updated>2026-07-04T17:36:19.116Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>李诞写的一本书《笑场》的序言里有一句话：“人生确实没有意义，但人生有美”。</p>
<h3 id="相同的错误"><a href="#相同的错误" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>李诞写的一本书《笑场》的序言里有一句话：“人生确实没有意义，但人生有美”。</p><h3 id="相同的错误"><a href="#相同的错误" class="headerlink" title="相同的错误"></a>相同的错误</h3><p>其实我早就“毕业”了，只是现在才领证书。当我没有挂科记录的时候，当我开始实习的时候，我的学生时代就已经结束了，虽然好像不曾开始过。学业上，可能唯一的遗憾是英语四级（CET 4）没过。也许你会觉得可笑，我也感觉可笑。临近毕业，学校有一个大学四年的综测成绩，我期末考试从没考过第一，但四年下来的综测竟然可以在班里排第一。当然，我们班成绩整体很差，但这不重要，重要的是将近1&#x2F;2的人可以考过425，我却只有423。</p><p>大学刚入学的几天，我曾在笔记本上写过几天日记，整理东西的时候翻开，其中有一句话让我感到吃惊：“我是来学习的，不是来娱乐的”。我自然可以理解当时是什么心情，高三的一年时间里，只有我自己知道我做了什么。高三开学摸底考，我考班里倒数十几，直到后来各种模拟考高考，我可以保持班里前三。不要对这样的排名感到诧异，这就是小县城的真实情况。也正因为这样的经历，我怀着不那么正规的求学的心，开始了大学生活。</p><p>就在前段时间，我陷入了同样的思维困境：“我不是来娱乐的，我是来工作的”。因为没有带着游玩的心上大学，所以大学的时光里，我的成绩可能不那么差，技术能力也有所增长，总体而言，是远超部分同学的。但也正因如此，我错过了很多娱乐的机会，甚至我大学所在的城市，都完全不了解，景点、场所等。更重要的是，我错过了非常重要的人，错过了曾经弥足珍贵的机会。现在我已经学会如何爱一个人，可是没有人再需要我去爱了。</p><p>所以你可以理解标题“相同的错误”是指什么。我从半个月前开始规划要写的内容，原标题是“关于职业生涯的规划”，后来觉得职业生涯这个范围太小了，无非是认真工作、好好生活、工作和生活平衡。事实上生活本就不需要规划，规划了也没用，我们应该时刻保持清醒，现状如何，未来会怎样，想要的是什么。总的来说，该有的想法是：“我不是来混日子的”。</p><h3 id="一拳超人"><a href="#一拳超人" class="headerlink" title="一拳超人"></a>一拳超人</h3><p>我换了个头像。他说，“我变秃了，也变强了”。琦玉因为感兴趣而当英雄，不是为了被更多人认识和崇拜，也不是为了英雄协会的丰厚待遇，仅仅是因为想当英雄所以当了英雄。可以说，我从事某个职业，也不是为了别人眼中的各种评价标准，仅仅是因为我从初中就开始积累的某些兴趣，让我想要在这条路上继续探索前行。</p><p>琦玉的强大是莫名其妙的，即使他把变强的过程全盘托出，你也无法达到他的高度。就好比学霸告诉你他上课如何听讲，作业如何完成，你也无法成为下一个学霸。一拳超人变强大唯一的代价，就是头发变秃了，直接变成了光头。我发现这一点和程序员类似，如果一个程序员因为工作把头发搞秃了，那他往往是大牛，并且即使他把方法告诉你，你也无法轻易超越。不过即便如此，也并不应该阻碍我们对强大能力的向往。</p><img src="avatar_origin.jpg" width="50%" height="50%"><h3 id="毕设和微服务"><a href="#毕设和微服务" class="headerlink" title="毕设和微服务"></a>毕设和微服务</h3><p>我的毕设以微服务为标题，但由于我们学校对毕设和论文的要求之低，我并没能完成自己心里的目标，只是应付老师，蒙混过关了。微服务本身是一个很简单的概念，难点往往在于如何在大型系统中实现微服务。在大型系统中进行任何操作都步履维艰，微服务并不特殊，因此，微服务是简单的。关于注册中心、配置中心、负载均衡、断路器什么的，可能在不久的将来，这个博客上就会出现关于它们的文章。</p><p>学习应该关注本质，是抽象的，我更希望从高的层面去理解技术，如果只是学习Kafka怎么使用而不关心像Kafka这样的中间件都在解决什么问题，这个世界就太无聊了。结合实际工作的内容，我的下一步计划会聚焦在中间件、区块链和算法上。</p><h3 id="博客存在的意义"><a href="#博客存在的意义" class="headerlink" title="博客存在的意义"></a>博客存在的意义</h3><p>（写到这里，发现自己没有耐心继续写下去。有些内容的输出需要同理心，也就是“当时是什么想的”。这半个月来发生了很多事情，但是现在已经结束了，并且我将面临新的生活和挑战。我的心态回不到过去，也不愿停留在过去。可能剩下的内容将无法完成。）</p><p>（这个附件 <a href="./%E5%85%B3%E4%BA%8E%E8%81%8C%E4%B8%9A%E7%94%9F%E6%B6%AF%E7%9A%84%E8%A7%84%E5%88%92.pdf">关于职业生涯的规划</a> 是之前写的大纲。）</p>]]></content>
  </entry>
  <entry>
    <title>JavaScript 有关联数组吗？</title>
    <link href="https://smallyu.net/2019/05/18/JavaScript%E6%9C%89%E5%85%B3%E8%81%94%E6%95%B0%E7%BB%84%E5%90%97%EF%BC%9F/"/>
    <id>blog:https://smallyu.net/2019/05/18/JavaScript%E6%9C%89%E5%85%B3%E8%81%94%E6%95%B0%E7%BB%84%E5%90%97%EF%BC%9F/</id>
    <published>2019-05-18T10:50:32.000Z</published>
    <updated>2025-06-30T13:35:02.794Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>如果你接触过PHP，那你对关联数组一定不陌生。C或Java中数组下标都是从0开始的数值，而PHP除了数值，还可以用字符串作为数组的下标。用数值做下标的数组叫做索引数组，用字符串做下标的数组叫做关联数组，他们都是合法的数组。</p>
<pre><code]]></summary>
    <content type="html"><![CDATA[<p>如果你接触过PHP，那你对关联数组一定不陌生。C或Java中数组下标都是从0开始的数值，而PHP除了数值，还可以用字符串作为数组的下标。用数值做下标的数组叫做索引数组，用字符串做下标的数组叫做关联数组，他们都是合法的数组。</p><pre><code class="PHP">&lt;?php$arr[0] = 1;        // 索引数组$arr[&quot;a&quot;] = &quot;b&quot;;    // 关联数组echo $arr[0];       // 1echo $arr[&quot;a&quot;];     // b</code></pre><p>在JavaScript中，同样可以使用字符串来作为数组的下标：</p><pre><code class="JavaScript">let arr = []arr[0] = 1arr[&#39;a&#39;] = &#39;b&#39;</code></pre><p>昨天，我和漂亮同事在使用JavaScript中用字符串做下标的数组时，遇到了令人困惑的问题。</p><h3 id="缘起"><a href="#缘起" class="headerlink" title="缘起"></a>缘起</h3><p>在Express.js框架的路由处理中，用res.json()返回数组，下标为数值的数组可以正常返回，下标使用字符串的数组却始终返回空。这是一段最简代码，可以用来描述该过程：</p><pre><code class="JavaScript">app.get(&#39;/&#39;, (req, res) =&gt; &#123;  let arr = []  arr[&#39;a&#39;] = &#39;b&#39;  console.log(arr)  // [a: &#39;b&#39;]  res.json(arr)     // []&#125;)</code></pre><p>预期返回的数组arr包含1个元素，console.log()直接在命令行打印的文本内容是<code>[a: &#39;b&#39;]</code>，和预期一致，然而如果通过页面请求路由，返回的内容是<code>[]</code>，这是匪夷所思的，也就是说res.json()把数组的内容吞掉了。</p><h3 id="探寻"><a href="#探寻" class="headerlink" title="探寻"></a>探寻</h3><p>为了寻找问题的真实原因，我在框架的中找到res.json()方法的定义：</p><pre><code class="JavaScript">res.json = function json(obj) &#123;  var val = obj;  // ...  var body = stringify(val, replacer, spaces, escape)  // ...  return this.send(body);&#125;;</code></pre><p>返回内容body经过了stringify()方法处理，stringify()方法调用的是JavaScript中JSON标准库的方法JSON.stringify()：</p><pre><code class="JavaScript">function stringify (value, replacer, spaces, escape) &#123;  var json = replacer || spaces    ? JSON.stringify(value, replacer, spaces)    : JSON.stringify(value);  // ...&#125;</code></pre><p>那么就说明，JSON.stringify()方法的返回值，会忽略用字符串做下标的数组。为了证实这一现象，用简单的Demo测试一下：</p><pre><code class="JavaScript">let arr1 = [], arr2 = []arr1[0] = 1arr2[&#39;a&#39;] = &#39;b&#39;JSON.stringify(arr1)    // &quot;[1]&quot;JSON.stringify(arr2)    // &quot;[]&quot;</code></pre><p>所以问题又来了，JavaScript标准库中的JSON.stringify()方法，为什么要忽略数组中下标为字符串的元素？是有意为之，官方不赞成使用字符串做下标，还是无奈之举，存在不可抗拒的原因无法实现？为了找到问题的根源，我试着从Chrome解析JavaScript的 <a href="https://github.com/v8/v8">V8引擎</a> 中寻找JSON.stringify()的定义。</p><p>V8引擎是用C++写的，关于JSON.stringify()的定义应该是这一段代码：</p><pre><code class="JavaScript">// ES6 section 24.3.2 JSON.stringify.BUILTIN(JsonStringify) &#123;  HandleScope scope(isolate);  JsonStringifier stringifier(isolate);  Handle&lt;Object&gt; object = args.atOrUndefined(isolate, 1);  Handle&lt;Object&gt; replacer = args.atOrUndefined(isolate, 2);  Handle&lt;Object&gt; indent = args.atOrUndefined(isolate, 3);  RETURN_RESULT_OR_FAILURE(isolate,                           stringifier.Stringify(object, replacer, indent));&#125;</code></pre><p>可以推测出，object即JSON.stringify()处理并返回的内容，返回之前使用args.atOrUndefined()方法进行包装。这里atOrUndefined()被反复调用，传入两个参数，可以理解为，第一个参数isolate保存有完整的参数信息，第二个参数是数据的索引，结合起来便是atOrUndefined()方法要处理的完整数据。</p><p>然后看atOrUndefined()的定义，在下面的代码中，tOrUndefined()调用了at()方法，at()方法又调用了Arguments的at方法：</p><pre><code class="C++">Handle&lt;Object&gt; atOrUndefined(Isolate* isolate, int index) &#123;  if (index &gt;= length()) &#123;    return isolate-&gt;factory()-&gt;undefined_value();  &#125;  return at&lt;Object&gt;(index);&#125;Handle&lt;S&gt; at(int index) &#123;  DCHECK_LT(index, length());  return Arguments::at&lt;S&gt;(index);&#125;</code></pre><p>Arguments::at()方法中，指针value获取了待处理参数的内存地址，然后使用reinterpret_cast对value的值进行类型强转。</p><pre><code class="C++">Handle&lt;S&gt; at(int index) &#123;  Object** value = &amp;((*this)[index]);  // This cast checks that the object we&#39;re accessing does indeed have the  // expected type.  S::cast(*value);  return Handle&lt;S&gt;(reinterpret_cast&lt;S**&gt;(value));&#125;</code></pre><p>到这里值就返回了，但是并没能解释为什么使用字符串做下标的数组内容会被忽略。只要是同一个数组，它的值就会保存在一段连续的地址空间中，即使reinterpret_cast处理的是指针变量，也应该无论多少都照常输出才是。</p><h3 id="真相"><a href="#真相" class="headerlink" title="真相"></a>真相</h3><p>最后，通过Google找到了一个关于数组使用字符串做下标的问题和答案（<a href="https://stackoverflow.com/questions/10326635/string-index-in-js-array">String index in js array</a>），我才明白为什么字符串做下标的数组如此特殊，因为JavaScript里压根就没有关联数组！</p><pre><code class="JavaScript">let arr1 = [], arr2 = []arr1[0] = 1arr2[&#39;a&#39;] = &#39;b&#39;arr1.length     // 1arr2.length     // 0</code></pre><p>给一个数组使用字符串作为下标赋值后，数组的长度不会改变，赋的值并没有作为数组元素储存到数组里。使用字符串作为下标能够正常对数组取值赋值的原因是，JavaScript将字符串作为数组的属性进行了储存。</p><pre><code class="JavaScript">let arr = []arr[&#39;a&#39;] = &#39;b&#39;arr.hasOwnProperty(&#39;a&#39;)   // true</code></pre><p>因此，JSON.stringify()处理的是数组的内容，reinterpret_cast也只是基于指针对数组内容进行类型转换，属性什么的，当然不会有输出！</p><h3 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h3><ol><li><p>为什么console.log()可以将数组的属性也输出？对于要输出的内容，它是怎么定义的？</p></li><li><p>为什么JavaScript中<code>typeof []</code>的值是<code>&quot;object&quot;</code>，也就是数组的类型是对象，但对象的属性会被处理，而数组不会？</p></li></ol>]]></content>
  </entry>
  <entry>
    <title>主流编程语言的异常处理机制</title>
    <link href="https://smallyu.net/2019/04/24/%E4%B8%BB%E6%B5%81%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E7%9A%84%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6/"/>
    <id>blog:https://smallyu.net/2019/04/24/%E4%B8%BB%E6%B5%81%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E7%9A%84%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6/</id>
    <published>2019-04-24T02:19:04.000Z</published>
    <updated>2025-06-19T03:30:33.084Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>学习编程语言应该从语言特性入手，而不是编程语言本身。这里尝试对各种编程语言的异常和错误处理机制做一个横向的、简单的了解。涉及到的编程语言包括C、C++、Go、Java、Scala、Kotlin、Ruby、Rust、JavaScript、PHP、Python、Lisp。</p]]></summary>
    <content type="html"><![CDATA[<p>学习编程语言应该从语言特性入手，而不是编程语言本身。这里尝试对各种编程语言的异常和错误处理机制做一个横向的、简单的了解。涉及到的编程语言包括C、C++、Go、Java、Scala、Kotlin、Ruby、Rust、JavaScript、PHP、Python、Lisp。</p><h3 id="C"><a href="#C" class="headerlink" title="C"></a>C</h3><p>C语言没有异常捕获机制。程序在发生错误时会设置一个错误代码errno，该变量是全局变量。C语言提供了perror()和strerror()函数来显示与errno相关的描述信息。perror()函数可以直接调用，入参是一个字符串，输出<code>入参: 错误文本</code>。strerror()函数入参是一个数字（错误码），返回一个指针，指针指向错误码对应的文本。</p><pre><code class="C">#include &lt;stdio.h&gt;#include &lt;errno.h&gt;#include &lt;string.h&gt;void main ()&#123;  // 打开一个不存在的文件，会发生错误  fopen (&quot;unexist.txt&quot;, &quot;rb&quot;);  // 2  printf(&quot;%d\n&quot;, errno);  // No such file or directory  perror(&quot;&quot;);  // No such file or directory  printf(&quot;%s\n&quot;, strerror(errno));&#125;</code></pre><h3 id="C-1"><a href="#C-1" class="headerlink" title="C++"></a>C++</h3><p>C++支持异常捕获机制。C++可以抛出或捕获两种内容，一种是int或char*之类的内容，程序可以捕获并抛出，这一点和Java相比有差异，因为Java并不支持直接抛出基本类型的异常：</p><pre><code class="C">#include &lt;iostream&gt;#include &lt;exception&gt;using namespace std;int main () &#123;    try    &#123;        throw &quot;error&quot;;    &#125;    catch(const char* msg)    &#123;        cout &lt;&lt; msg &lt;&lt; endl;    &#125;&#125; // error</code></pre><p>另一种内容就是类，可以是内置的标准异常类，或是自定义的异常类：</p><pre><code class="C">#include &lt;iostream&gt;#include &lt;exception&gt;using namespace std;int main () &#123;    try    &#123;        throw exception();    &#125;    catch(std::exception&amp; e)    &#123;        cout &lt;&lt; e.what() &lt;&lt; endl;    &#125;&#125; // std::exception</code></pre><h3 id="Go"><a href="#Go" class="headerlink" title="Go"></a>Go</h3><p>Go语言作为非OOP派系的编程语言，并不支持try-catch的语法，但仍然具有类似抛出和捕获的特性。Go语言有3个错误相关的关键字，panic()、recover()和defer。可以理解为，panic()函数抛出异常，recover()函数捕获异常，defer关键字定义最后也就是finally执行的内容：</p><pre><code class="Go">package mainimport &quot;fmt&quot;func main() &#123;  defer func() &#123;    err := recover()    fmt.Println(err)  &#125;()  panic(&quot;error&quot;)&#125;// error</code></pre><h3 id="Java"><a href="#Java" class="headerlink" title="Java"></a>Java</h3><p>Java是纯粹的OOP语言，仅支持对象的抛出和捕获：</p><pre><code class="Java">public class ErrorTest &#123;    public static void main(String[] args) &#123;        try &#123;            throw new Exception();        &#125; catch (Exception e) &#123;            System.out.println(e);        &#125;    &#125;&#125;// java.lang.Exception</code></pre><h3 id="Scala"><a href="#Scala" class="headerlink" title="Scala"></a>Scala</h3><p>Scala和Java是一个流派，同样仅支持对象的抛出和捕获，除了语法上和Java稍有差异，概念上基本是一jian样rong的：</p><pre><code class="Scala">object ErrorTest &#123;  def main(args: Array[String]): Unit = &#123;    try &#123;      throw new Exception()    &#125; catch &#123;      case e: Exception =&gt; print(e)    &#125;  &#125;&#125;// java.lang.Exception</code></pre><p>另外，Scala抛出的是Java的异常，也许Scala不能算作是独立的编程语言，而是依附于Java、为Java提供语法糖的编程语言。这一点值得深入思考和探究。</p><h3 id="Kotlin"><a href="#Kotlin" class="headerlink" title="Kotlin"></a>Kotlin</h3><p>Kotlin和Scala是一种性质的语言，默认抛出的同样是Java的异常：</p><pre><code class="Kotlin">fun main(args: Array&lt;String&gt;) &#123;  try &#123;    throw Exception()  &#125; catch (e: Exception) &#123;    print(e)  &#125;&#125;// java.lang.Exception</code></pre><h3 id="Ruby"><a href="#Ruby" class="headerlink" title="Ruby"></a>Ruby</h3><p>Ruby使用关键字raise和rescue代替try和catch来实现异常的抛出和捕获。Ruby同样支持try-catch关键字，这里暂不讨论，因为我没搞清楚它的用法。</p><pre><code class="Rbuy">begin  raise &quot;error&quot;   rescue Exception =&gt; e    puts eend// error</code></pre><h3 id="Rust"><a href="#Rust" class="headerlink" title="Rust"></a>Rust</h3><p>Rust没有try-catch的语法，也没有类似Go的错误处理函数，而是用对错误处理进行过包装的<code>Option&lt;T&gt;</code>或Option的加强版<code>Result&lt;T, E&gt;</code>进行错误处理。Rust的模式匹配和Scala类似：</p><pre><code class="Rust">fn main() &#123;  match find() &#123;    None =&gt; println!(&quot;none&quot;),    Some(i) =&gt; println!(&quot;&#123;&#125;&quot;, i),  &#125;&#125;fn find() -&gt; Option&lt;usize&gt; &#123;  if 1 == 1 &#123;    return Some(1);  &#125;  None&#125;// 1</code></pre><h3 id="JavaScript"><a href="#JavaScript" class="headerlink" title="JavaScript"></a>JavaScript</h3><p>脚本语言在变量类型上不做强制约束，捕获时也就不能按照异常类型来做区分。抛出错误的内容还是相对自由的：</p><pre><code class="JavaScript">try &#123;  throw 1&#125; catch (e) &#123;  console.log(e)&#125;// 1try &#123;  throw new Error(&#39;&#39;)&#125; catch (e) &#123;  console.log(e)&#125;// Error</code></pre><h3 id="PHP"><a href="#PHP" class="headerlink" title="PHP"></a>PHP</h3><p>PHP的try-catch和Java类似，并没有特殊之处：</p><pre><code class="PHP">&lt;?php  try &#123;      throw new Exception(&quot;error&quot;);  &#125; catch (Exception $e) &#123;      echo $e-&gt;getMessage();  &#125;</code></pre><h3 id="Python"><a href="#Python" class="headerlink" title="Python"></a>Python</h3><p>Python在语法上能找到Ruby的影子，raise触发异常，execpt捕获异常：</p><pre><code class="Python">try:  raiseexcept:  print(&quot;error&quot;)</code></pre><h3 id="Lisp"><a href="#Lisp" class="headerlink" title="Lisp"></a>Lisp</h3><p>Lisp整体较复杂，Lisp捕获处理异常的内容暂时留坑。以下是Common Lisp触发错误的情形之一，declare会声明函数入参类型，传入错误参数将引发错误：</p><pre><code class="Lisp">(defun df (a b)  (declare (double-float a b))  (* a b))  (df &quot;1&quot; 3)// *** - *: &quot;1&quot; is not a number</code></pre><h3 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h3><p>原先想梳理这些语言的大部分异常和错误处理相关概念，然而真正开始后发现比较困难，并且之前我没能区分”exception”和”checked exception”，以致从立意到标题到内容可能都有偏差。这次就先提及”exception”，之后讨论关于”checked exception”的内容。</p>]]></content>
  </entry>
  <entry>
    <title>实习 3.5 个月之际</title>
    <link href="https://b.smallyu.net/2019/04/21/%E5%AE%9E%E4%B9%A03.5%E4%B8%AA%E6%9C%88%E4%B9%8B%E9%99%85/"/>
    <id>blog-b:https://b.smallyu.net/2019/04/21/%E5%AE%9E%E4%B9%A03.5%E4%B8%AA%E6%9C%88%E4%B9%8B%E9%99%85/</id>
    <published>2019-04-21T09:47:49.000Z</published>
    <updated>2026-07-25T13:01:29.366Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>想用《卧虎藏龙》里的台词来描述心情：“被一种寂灭的悲哀环绕”。</p>
<h3 id="工作"><a href="#工作" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>想用《卧虎藏龙》里的台词来描述心情：“被一种寂灭的悲哀环绕”。</p><h3 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h3><p>最近实际的工作产出很少，大多时间用在了熟悉业务上。不出所料，工作中用到的技术并不会超出想象，因此可以安心地认为目前还在及格线上。倒是业务比较复杂，对没有经验的人显得不太友好。线上的交易系统，生产上的数据库字段，真真切切对应具体的业务流程和操作。毫不知情地开发一时爽，等到上线就火葬场。</p><p>有经验的程序员做事细致谨慎，也确实是给我上了一课。在学校曾有人问我一些问题，我觉得很简单，然后直截了当的解决问题。现在到工作岗位上，我就是被解决问题的那个人。我之前思考过，我的同学技术水平如何？我的技术能力是否真的高过他们？如果有好过他们的地方，是什么？有核心竞争力吗？这些问题的答案，基本上都聚焦在“经验”上。经验是无法快速获得的，我的同学不行，我也不行。</p><p>我的经验来自爱好和习惯，也许是碰巧接触互联网较早，仅此而已。王垠提到过 <a href="http://www.yinwang.org/blog-cn/2017/04/14/experience-and-insight">经验和洞察力</a> 的问题，观点精辟，值得深思。我没有所谓的洞察力，并且洞察力类似于学习能力、理解能力，是一个人综合素养的体现，无法轻易获得。没有足够的阅历，怎么能透过现象看到本质？郭德纲说的很好，让人成长的不是时间，是经历。可以理解为，时间助长经验，经历助长洞察力。</p><h3 id="人际"><a href="#人际" class="headerlink" title="人际"></a>人际</h3><p>有件事情带给我一些思考。我请假几天，但有工单提测了没有测完。我说要离开几天时，测试同事问怎么要走云云，我说过几天就回来了，他说，“我不关心这个，我关心的是我工单怎么测……”倒不是他说这句话会让人伤心，我们本就毫无交集，认识没几天，同事之间往往只有工作关系，我也是清楚的。我在意的是，他竟然可以直截了当直击要害地说出自己的需求，这是一种需要能力也需要胆量的做法。</p><p>对话发生在几秒钟的时间里，能够快速组织语言描述清楚自己的想法，是我现在不具备的能力。需要胆量的说法是指，这样的做法稍微有点不符合国人的行事风格，客套话、顾面子、话里有话、笑里藏刀，都是中华民族的传统品德。</p><h3 id="比金钱更重要的东西"><a href="#比金钱更重要的东西" class="headerlink" title="比金钱更重要的东西"></a>比金钱更重要的东西</h3><p>看到朋友圈晒工作晒起薪，各种酸。但是就目前而言，我没有丝毫寻找新机会的冲动。融洽的工作氛围，压力并不大的工作内容，能让人有成长的业务需求，现在的工作足够让我满意，除了工资。我曾经的老师个性签名是，成长比成就重要。这句话并不绝对，但有道理。对于刚参加工作的情况来说，有多少挣钱的能力比能挣到多少钱重要，能力可以持续转化为金钱，一时的金钱却无法保正能力的持续增长。</p><p>996是一种选择。罗辑思维有过一种观点，就是大脑处于空闲状态的时候，会不自觉的考虑各种人际关系，因此一些现象可以这样解释：聪明人往往易怒、情商低，是因为他们把大量时间用在了目的性较强的问题，留给大脑的空闲时间少了，也就没有太多关于人际关系的思考；某个一线互联网公司内流行冥想活动，就是坐那儿什么也不干，此时虽然没有明确的想法，但大脑会不自主的东想西想，谁对我怎么样，我对谁怎么样，等等。这也正好是修福报之余衍生出来的、可能人类本身就需要的活动。</p><p>我开玩笑的和同学说，我的公司是996，同学反问，真的？你们公司是996？我能在言语之前感受到他开心的情绪。因为他在某N线城市找了一份工作，工资不高，但除去开销，能剩下的和我差不多。抛开五险一金的额度不谈，生活质量、圈子、眼界，以及上面提到的成长空间，都是我所在乎的。我突然对单纯的薪资比较感到厌恶，不要再用某种“小气”的思维方式推测我的处境了，我们需求不同，理想不同。我对某个世界充满兴趣，会亲身去探索，麻雀怎么会知道凤凰的志向呢？</p><h3 id="获取有效信息的途径"><a href="#获取有效信息的途径" class="headerlink" title="获取有效信息的途径"></a>获取有效信息的途径</h3><p>N年前，很多人努力读书上更好的学校，为的是更好的教育资源，甚至是结识更多“高端人才”。如今，因为互联网的存在，某些各种维度的距离已经不再遥远。你想要获取的很多信息，都可以通过网络得到，而且不只是书本书面知识，还包括在某些领域长期的经验和对一些问题独特的见解。</p><p>所以我能更加信任自己的决策而不是父母或者其他长辈，因为我和他们相比，虽然有年龄和人生经历上的不足，但由于我可以利用互联网来不断获取各种信息，我对某些事情的决策可能比他们更加正确。</p><p>当然，也并非所有会上网的人，都可以有效利用互联网来获取信息。从广泛的信息网络中搜查、筛选、分析、推断出自己想要的东西，很重要。</p>]]></content>
  </entry>
  <entry>
    <title>电梯楼层显示屏的设计失误</title>
    <link href="https://b.smallyu.net/2019/03/27/%E7%94%B5%E6%A2%AF%E6%A5%BC%E5%B1%82%E6%98%BE%E7%A4%BA%E5%B1%8F%E7%9A%84%E8%AE%BE%E8%AE%A1%E5%A4%B1%E8%AF%AF/"/>
    <id>blog-b:https://b.smallyu.net/2019/03/27/%E7%94%B5%E6%A2%AF%E6%A5%BC%E5%B1%82%E6%98%BE%E7%A4%BA%E5%B1%8F%E7%9A%84%E8%AE%BE%E8%AE%A1%E5%A4%B1%E8%AF%AF/</id>
    <published>2019-03-27T14:29:49.000Z</published>
    <updated>2026-03-02T09:06:02.334Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>每次上楼的时候都感到困惑，有一个问题我注意很久了。</p>
<h3 id="电梯"><a href="#电梯" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>每次上楼的时候都感到困惑，有一个问题我注意很久了。</p><h3 id="电梯"><a href="#电梯" class="headerlink" title="电梯"></a>电梯</h3><p>其实没什么大不了的，目前某座楼里的电梯是这样的情况。电梯从楼上到1楼的过程中，楼层显示屏会显示向下的箭头<code>↓</code>，当电梯到达1楼，电梯门已经开了，箭头仍然向下。这时不少人会认为，电梯将要向下运行，到达地下室。</p><img src="f1.png" width="50%" height="50%"><p>这种想法很正常，因为电梯存在另一个设计失误。当有人等待电梯想要从10楼到达1楼，同时正好有人乘坐电梯从1楼到达20楼，电梯会在10楼停下并开门。此时无论想到1楼的人是否上电梯，电梯都会继续向20楼行驶。在10楼会开门单纯是因为，在10楼想要到达1楼的人按下了电梯的按钮。</p><img src="f10.png" width="50%" height="50%"><p>正因为电梯向上行驶的这种行为，很容易让人推测，电梯向下行驶也会存在这样的行为。在1楼看到箭头向下，以为电梯本是要到地下室，因为按了电梯的按钮，或正好有人在这一层出电梯，门就开了。然而事实是，箭头只是保留了之前电梯运行的状态（向下），至于接下来是向上还是向下，要看第一个进入电梯的人按了哪个楼层。</p><p>并非（绝不是）所有的电梯都这样。正确的做法应该是，当电梯没有运行任务时，显示屏不显示箭头，或者显示置空（–）之类的内容。</p><h3 id="程序"><a href="#程序" class="headerlink" title="程序"></a>程序</h3><p>当一个任务执行结束（电梯运行结束），应该把任务的标志位重置到初始状态（箭头置空）。这样的逻辑在程序里很常见，不管是UI还是内存，用户不可信，GC亦不可信，手动回收大法好。今天就踩了一个坑 :(</p><p>坑很简单，一句话就能表达：循环里执行SQL语句，Statement对象没关闭。</p><p>坑虽然简单，但在生产环境上影响了正常的业务操作。DB2的默认限制为1400-，之后就会报错。开发的时候要小心，自测的时候也应该注意大量数据的情况。此类错误，希望以后不要再犯！</p>]]></content>
  </entry>
  <entry>
    <title>Go 语言基本语法</title>
    <link href="https://smallyu.net/2019/03/15/Go%E8%AF%AD%E8%A8%80%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95/"/>
    <id>blog:https://smallyu.net/2019/03/15/Go%E8%AF%AD%E8%A8%80%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95/</id>
    <published>2019-03-15T13:18:11.000Z</published>
    <updated>2025-06-30T13:34:55.278Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Go语言虽然在语言设计上不被王垠看好，但它如此简洁的代码结构确实让人着迷。</p>
<h3 id="语句"><a href="#语句" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>Go语言虽然在语言设计上不被王垠看好，但它如此简洁的代码结构确实让人着迷。</p><h3 id="语句"><a href="#语句" class="headerlink" title="语句"></a>语句</h3><p>Go语言语句结尾不需要<code>;</code>。</p><h3 id="变量和常量"><a href="#变量和常量" class="headerlink" title="变量和常量"></a>变量和常量</h3><p>使用<code>var</code>声明变量。当变量需要初始化时，可以使用赋值符号<code>:=</code>代替<code>=</code>以省略var关键字。</p><pre><code class="go">var a intvar b stringvar c int = 10var d = &quot;golang&quot;  // 编译器自动推断类型d := 10</code></pre><p>与C语言或Java不同，Go语言的类型声明在变量右侧。需要注意的是，如果程序中声明的变量未经使用，程序将无法通过编译。Go语言是一种工程化的语言，因此它的一些特性让人感觉不可理喻，但又会在实际工程中提高效益。</p><p>Go语言的变量赋值支持一些炫酷的写法，比如要交换变量x和y的值，可以使用这种违反直觉的写法：</p><pre><code class="go">x, y = y, x</code></pre><p>Go语言中使用<code>const</code>定义常量，<code>true</code>、<code>false</code>和<code>iota</code>是预定义常量。其中iota稍显特殊，iota会在每一个const关键字出现时重置为0，然后在下一次const出现前，每出现一次iota，iota的值加1。</p><pre><code class="go">const a = iota   // 0const b = iota   // 0const (  c = iota       // 0  d = iota       // 1)</code></pre><h3 id="数组和切片"><a href="#数组和切片" class="headerlink" title="数组和切片"></a>数组和切片</h3><p>声明一个元素个数为3的数组，并初始化：</p><pre><code class="go">array := [3]int&#123;0, 1, 2&#125;array[0] = 3fmt.Println(array)</code></pre><p>和其他语言一样，Go语言在声明数组后并不能改变数组的大小。所以Go语言提供了像Python一样的切片。切片可以从数组中产生，也可以使用make()函数新建。</p><pre><code class="go">array := [3]int&#123;0, 1, 2&#125;slice1 := array[:2]       // 从数组中创建slice2 := make([]int, 3)  // 直接创建fmt.Println(slice1)       // [0 1]fmt.Println(slice2)       // [0 0 0]</code></pre><p>除切片外，映射也是使用make函数创建，映射的类型全称是<code>var myMap map[string] int</code>，意为声明变量myMap，key为string，value为int。</p><h3 id="流程控制"><a href="#流程控制" class="headerlink" title="流程控制"></a>流程控制</h3><p>Go语言允许if-else语句的条件表达式不加小括号，当然加上也无妨。</p><pre><code class="go">a := 1if a == 1 &#123;  print(1)&#125; else if (a == 2) &#123;  print(2)&#125; else &#123;  print(3)&#125;</code></pre><p>选择语句的条件表达式同样不需要小括号，另外也不需要break，其他匹配项并不会执行，这一点和Scala相同。对选择语句的优化貌似已经是不约而同的做法。</p><pre><code class="go">i := 0switch i &#123;case 0:  print(0)case 1:  print(1)&#125;</code></pre><p>循环结构的条件表达式依然不需要小括号。Go语言只支持for循环。同时对无限循环的场景也做了优化，不再需要for(;;)的写法。</p><pre><code class="go">for &#123;  print(1)&#125;</code></pre><h3 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h3><p>Go语言诞生自C语言的派系，因此Go语言从一开始就不是OOP或FP的语言，没有类、对象等概念。函数是程序中的一等公民。和C语言相同，（main包下的）main函数是整个程序的入口。</p><pre><code class="go">func add(a int, b int) (int, int) &#123;  return a + b, a - b&#125;func main() &#123;  x, y := add(1, 2)  print(x, y)&#125;</code></pre><p>Go语言的语句简洁高效，函数名后的第一个括号为入参，第二个括号是出参。函数支持多返回值。如果参数类型相同，可以将类型声明合并到一起，如<code>(a, b int)</code>。</p><h3 id="结构体"><a href="#结构体" class="headerlink" title="结构体"></a>结构体</h3><p>刚才提到Go语言没有类、对象等概念，但是Go语言有类似C语言的结构体，并且能力强大。这里定义一个Person结构体，包含两个属性name和age，并为Person添加一个方法getInfo，用于输出Person对象的信息：</p><pre><code class="go">type Person struct &#123;  name string  age int&#125;func (p Person) getInfo() &#123;  print(p.name, p.age)&#125;func main() &#123;  smallyu := new(Person)  smallyu.name = &quot;smallyu&quot;  smallyu.age = 1  smallyu.getInfo()&#125;</code></pre><p>用OOP的思想理解这样的程序并不违和。除了结构体，Go语言还保留有指针的概念。Java程序员对指针可能稍感陌生，关于指针在结构体方法中的应用，可以通过一个简单的例子来了解：</p><pre><code class="go">type Person struct &#123;  name string&#125;func (p Person) setName() &#123;  p.name = &quot;set name&quot;&#125;func (p *Person) setName2() &#123;  p.name = &quot;set name&quot;&#125;func main() &#123;  smallyu := &amp;Person&#123;&quot;smallyu&quot;&#125;  smallyu.setName()  fmt.Println(smallyu)        // &amp;&#123;smallyu&#125;  bigyu := &amp;Person&#123;&quot;bigyu&quot;&#125;  bigyu.setName2()  fmt.Println(bigyu)          // &amp;&#123;set name&#125;&#125;</code></pre><p>使用值类型定义的结构体方法，入参为形参；使用引用类型定义的结构体方法，入参为实参。<code>&amp;&#123;&#125;</code>是初始化对象的方法之一，等同于<code>new()</code>。</p><h3 id="匿名结合"><a href="#匿名结合" class="headerlink" title="匿名结合"></a>匿名结合</h3><p>Go语言中匿名结合的概念，相当于OOP语言的继承。一个结构体可以继承另一个结构体的属性和方法，大致是这样。</p><pre><code class="go">type Father struct &#123;  name string&#125;func (f Father) getName() &#123;  print(f.name)&#125;type Son struct &#123;  Father&#125;func main() &#123;  smallyu := &amp;Son&#123;&#125;  smallyu.name = &quot;smallyu&quot;  smallyu.getName()       // smallyu&#125;</code></pre><p>Son并没有定义name属性，也没有定义getName()方法，它们均继承自Father。</p><h3 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h3><p>Go语言的接口是非侵入式的，结构体只要实现了接口中的所有方法，程序就会认为结构体实现了该接口。</p><pre><code class="go">type IPerson interface &#123;  getName()&#125;type Person struct &#123;  name string&#125;func (p Person) getName() &#123;  print(p.name)&#125;func main() &#123;  var smallyu IPerson = &amp;Person&#123;&quot;smallyu&quot;&#125;  smallyu.getName()&#125;</code></pre><h3 id="协程"><a href="#协程" class="headerlink" title="协程"></a>协程</h3><p>使用协程的关键字是<code>go</code>，从命名就能看出协程对于Go语言的重要性、协程是轻量级的线程，启动一个协程非常简单：</p><pre><code class="go">func f(msg string) &#123;  println(msg)&#125;func main() &#123;  f(&quot;直接调用方法&quot;)  go f(&quot;协程调用方法&quot;)&#125;</code></pre><p>运行程序，你会发现程序只打印出”直接调用方法”几个字。这种情况是不是似曾相识？go启用了另一个”线程”来打印消息，而main线程早已结束。在程序末尾加上<code>fmt.Scanln()</code>阻止main线程的结束，就能看到全部的打印内容。</p><h3 id="通道"><a href="#通道" class="headerlink" title="通道"></a>通道</h3><p>通道即协程之间相互通信的通道。</p><pre><code class="go">func main() &#123;  message := make(chan string)  go func() &#123;    message &lt;- &quot;ping&quot;  &#125;()  msg := &lt;-message  println(msg)&#125;</code></pre><p>make函数返回一个chan string类型的通道，在匿名函数中将字符串”ping”传入通道，之后将通道中的数据输出到变量msg，最后打印出msg的值为”ping”。</p><h3 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h3><p>Go语言在错误处理部分有两个函数较为常用，panic函数和defer函数。panic函数会打印错误消息，并终止整个程序的执行，类似Java的Throw Exception；defer函数会在当前上下文环境执行结束前再执行，类似try catch后的finally；panic函数虽然会终止整个程序，但不会终止defer函数的执行，可以将defer函数用于打印日志。这是一个简单的例子：</p><pre><code class="go">func main() &#123;  println(&quot;beginning&quot;)  defer func() &#123;    println(&quot;defer&quot;)  &#125; ()  println(&quot;middle&quot;)  panic(&quot;panic&quot;)  println(&quot;ending&quot;)&#125;</code></pre><p>来分析一下程序的执行结果。首先beginning被打印；然后遇到defer，暂不打印；middle在defer之前被打印；遇到panic，程序将终止，打印defer和panic。</p><p>这里要注意，defer是在程序结束前执行，而不是在其他语句结束后执行，这是有区别的。就像这里，panic函数引起了当前程序的结束，所以defer会在panic函数前执行，而不是panic后。程序的执行结果如下：</p><pre><code class="Go">beginningmiddledeferpanic: panicgoroutine 1 [running]:main.main()    D:/go/src/awesomeProject/main.go:12 +0x7f</code></pre><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>除此之外Go语言还有很多语言特性，也提供了非常多实用的工具包。Go语言是一种值得我们尝试去使用的语言。关于协程和通道，后续会单独探讨这一重要特性。</p><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ul><li><p>《Go语言编程》</p></li><li><p><a href="https://gobyexample.com/">Go by Example</a></p></li></ul>]]></content>
  </entry>
  <entry>
    <title>我为什么想要“行万里路”</title>
    <link href="https://crazy.smallyu.net/2019/03/14/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E6%83%B3%E8%A6%81%E8%A1%8C%E4%B8%87%E9%87%8C%E8%B7%AF/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2019/03/14/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E6%83%B3%E8%A6%81%E8%A1%8C%E4%B8%87%E9%87%8C%E8%B7%AF/</id>
    <published>2019-03-14T03:24:19.000Z</published>
    <updated>2026-07-04T17:36:19.116Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<img src="mayun.png" width="90%" height="90%">

<h3 id="微信朋友圈"><a href="#微信朋友圈" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<img src="mayun.png" width="90%" height="90%"><h3 id="微信朋友圈"><a href="#微信朋友圈" class="headerlink" title="微信朋友圈"></a>微信朋友圈</h3><p>首先这不是一个正确的想法，是典型的做什么决定想什么，而不是想什么就去做什么。</p><p>我在朋友圈发过一些景点的照片，这件事情会持续下去，大概1年左右的时间。按1个月3个景点算，1年大概30个景点。帝都稍微知名的、免费的景点也就差不多了。这些景点信息收集自网络，是网友关注并推荐的地点。1年后收入有增长时，会考虑收费（￥19.9以上）的景点。</p><p>在某个过渡期间，我的三观开始崩坏，也需要重塑。其实“观”有很多，除了世界观、人生观、价值观，还可以有事业观、婚姻观、饮食观、出行观、打游戏观等。我想见到更多的人，看到更多的事。看看国内顶尖的建筑，看看上万人趋之若鹜的风景。想想身边的人为何而来，会怀着怎样的心情离去。我还记得在太原市图书馆见到的志愿者队伍，都是老大不小的工人，虽然穿着制服，但看得出来他们的出身，猜得到他们的工作，因为那真是熟悉的身影，在宽敞明亮的大厅里不知所措、唯唯诺诺、格格不入，如果你在农村生活过，就会明白。我也记得在道馆里认真参拜神仙的香客，烧香、磕头、许愿、捐钱，让我不得不思考宗教信仰的力量，因为我想许愿，却发现没有愿望可许。我还发现外国大叔见到你真的会点头微笑。</p><p>我曾在QQ空间发过一些观点鲜明的内容，不知道有什么好的坏的影响，也无所谓知不知道。一方面不想再维护QQ空间的内容，二是我赞同“谦虚不是美德”的观点，所以有些内容可能不够谦虚，但都是实话 :p</p><p>我认为作为接受过高等教育的90后，应该有并且能够容忍甚至接纳新的、奇怪的、特立独行的想法。我们只是独立的、渺小的个体，有可能下一秒钟就会发生意外，也有可能我们会做出在别人眼里是异类的行为，或者我们原本就是别人眼中的异类。几百年前一只跳蚤或一滴水就可以传播瘟疫，贸易船只上每个奴隶身上都可能携带致命的细菌，人们对此类疾病一无所知，求助于僧侣和医生，洗冷水澡、用柏油擦拭身体或是将黑甲虫碾碎涂抹在伤口，却毫无功效。疾病从个体感染到整个家族，蔓延到整座城市，成千上万尸体腐烂在街头，人们将原因归于神灵发怒、恶魔作祟，寄希望于天使或仙女，政府对疾病束手无策，只能组织大规模祈祷和游行。死去或幸存的人，他们也都是有思想的、独立的个体，和我们一样。</p><p>微信好友的群体与QQ不同，也曾想过目前朋友圈的内容是不是很low，于是在虚荣心和真实之间犹豫。显然现在选择了后者，并且这里的内容也将作为外链第一次被分享到朋友圈。</p><h3 id="博客"><a href="#博客" class="headerlink" title="博客"></a>博客</h3><p>我的博客经历过多次建立和销毁，上一次的数据还有备份，但是主机因为科学上网被墙了。每次都想写一些值得写的东西，后来发现要写出不让人后悔的东西太难了，就像看到QQ空间以前的说说，会感到脸红想要立刻删掉一样。有些比较无聊但又想写写的东西，像“在XX平台运行一个XXX”、“XX框架&#x2F;工具的Hello World级demo”之类，会发到另一个平台 <a href="https://www.yuque.com/smallyu/">语雀</a> 上。</p><p>博客主题仿自王垠的博客 <a href="http://www.yinwang.org/">当然我在扯淡</a> ，我在 <a href="/2019/02/12/%E7%94%9F%E8%80%8C%E4%B8%BA%E4%BA%BA%EF%BC%8C%E5%8D%B4%E6%83%B3%E6%88%90%E7%A5%9E/">生而为人，却想成神？</a> 中有提到过对王垠的敬佩，除了极高的学术修养外，他对很多事情都有独到、精辟的见解，是真正有独立思考能力的人，光是这一点就远超常人，那也是我努力追求的可贵品质。</p><p>从 <a href="/2019/01/06/%E5%8C%97%E4%BA%AC%EF%BC%8C%E5%8C%97%E4%BA%AC/">北京，北京</a> 开始，似乎很多技术无关、也没有明确观点的内容。当时多次提到独居的概念，独居并不意味着孤独，而是你可以变成任何你想变成的样子，做任何想做的事请，是一种机会。技术相关的问题会连同其他问题一起重新被审视。技术能力的好坏取决于你有没有用过React或Spring Cloud吗？绝对不是。那又是什么呢？</p><p>如果现在一心关注技术，就像在学校临近毕业的一年，技术一定可以有增长，但那样就没时间也没心情做其他事情了。就像当时我如果懂得其他事情，而不是只关心技术的学习，某些事情一定可以处理的更好，但就不会有超过同学的技术能力，可能现在还在这互联网寒冬之际跑金三银四的招聘会。二者不可兼得，不同的选择会面临不同的人生，这也正是我在 <a href="/2019/03/03/%E8%A6%81%E6%98%AF%E8%83%BD%E9%87%8D%E6%9D%A5%EF%BC%8C%E4%BD%A0%E4%BC%9A%E6%80%8E%E4%B9%88%E6%B4%BB/">要是能重来，你会怎么活？</a> 想要探讨却没有具体阐述的主题。那么，现在该怎么选择？</p><h3 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h3><p>这里是我的博客，网址是 <a href="http://www.smallyu.net/">www.smallyu.net</a> ，会更新一些和任何人无关的内容（如果你认为和你有关，请屏蔽我）。smallyu可以理解为中英混拼，也可以将YU理解为专有名词，在域名中小写，所以有了smallyu的英文拼写。其他文章页面并没有返回首页的链接，但是这次你可以点击这里 <a href="/">返回首页</a> 。</p>]]></content>
  </entry>
  <entry>
    <title>要是能重来，你会怎么活</title>
    <link href="https://crazy.smallyu.net/2019/03/03/%E8%A6%81%E6%98%AF%E8%83%BD%E9%87%8D%E6%9D%A5%EF%BC%8C%E4%BD%A0%E4%BC%9A%E6%80%8E%E4%B9%88%E6%B4%BB/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2019/03/03/%E8%A6%81%E6%98%AF%E8%83%BD%E9%87%8D%E6%9D%A5%EF%BC%8C%E4%BD%A0%E4%BC%9A%E6%80%8E%E4%B9%88%E6%B4%BB/</id>
    <published>2019-03-03T13:29:59.000Z</published>
    <updated>2025-08-16T03:27:11.459Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>如果能够带着现有的记忆重新活一次，我的人生将……</p>
<p>人生道路上，有些事情可以改变，有些事情受生长环境制约。我们面临过很多次选择，有的选择由长辈代劳，有的选择由自己的意愿左右。如果当时做出了不同的选择，我们的人生会发生哪些变化？</p>
<p>夏洛特烦恼算是重新“]]></summary>
    <content type="html"><![CDATA[<p>如果能够带着现有的记忆重新活一次，我的人生将……</p><p>人生道路上，有些事情可以改变，有些事情受生长环境制约。我们面临过很多次选择，有的选择由长辈代劳，有的选择由自己的意愿左右。如果当时做出了不同的选择，我们的人生会发生哪些变化？</p><p>夏洛特烦恼算是重新“活过”的故事，武林外传也有一集，讲各自满足自己的幻想，重新“活过”的情景。这两部影视作品中关于重新“活过”的桥段，结局是相似的，认为在经历了种种之后，还是现状比较好。也不知如此的结局，是真实的，还是两位作者都不约而同向生活妥协，本就无法改变，倒不如让自己接受的痛快，活的自在。</p><p>回想自己以前做的事情，在最优的选择下，能够获得些什么，便可以知道自己荒废了多少时光；整理现在自己做的事情，在完成度最高的情况下，可以达到怎样的高度，就能知道自己以后的时光该如何努力。</p><p>像单机RPG游戏，每升一级就有新的技能点，但技能树上的节点繁多，满级也只能走到某一个分支的尽头。我们必须在低等级，不了解游戏的情况下，选择一个分支，然后等分支到头了，我们就知道加哪些技能好玩了。不过可惜仅此一次，因为游戏已经玩过了。</p><p>时隔（仅仅）两个月回到学校，却有了物是人非、恍若隔世的感觉。变了吧，也都没变。遗憾呐，确实有遗憾。</p>]]></content>
  </entry>
  <entry>
    <title>生而为人，却想成神</title>
    <link href="https://crazy.smallyu.net/2019/02/12/%E7%94%9F%E8%80%8C%E4%B8%BA%E4%BA%BA%EF%BC%8C%E5%8D%B4%E6%83%B3%E6%88%90%E7%A5%9E/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2019/02/12/%E7%94%9F%E8%80%8C%E4%B8%BA%E4%BA%BA%EF%BC%8C%E5%8D%B4%E6%83%B3%E6%88%90%E7%A5%9E/</id>
    <published>2019-02-12T15:02:20.000Z</published>
    <updated>2025-08-16T03:27:11.437Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>从哪儿说起呢？</p>
<h3 id="生而为人"><a href="#生而为人" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>从哪儿说起呢？</p><h3 id="生而为人"><a href="#生而为人" class="headerlink" title="生而为人"></a>生而为人</h3><p>打开各类新式社交APP，匿名聊天、剧情推理、角色扮演，花样很多，如果投入进去，也能找到些许乐趣。然而这些应用的使用者，大多是00后。想起当年90后还未长大，飞信还活着的年代，各种WAP网站，资讯、论坛、自助、文字页游，社区里还充斥着所谓家族的群体，大家热衷于讨论在线浏览器、免流方法。那个时代已经过去了。</p><p>赞叹《忠犬八公》里狗的演技，《一条狗的使命》也另辟蹊径，从狗的视角阐述它一生的经历。有人提到，影片中狗的四次生命，分别对应人生的四个阶段。一开始单纯懵懂，快快乐乐；之后进入工作，生活枯燥，像是失去了一些东西，空空落落；然后是无言的陪伴，生活平淡，身边是家人、朋友；最后生活进入绝境，变得绝望，返璞归真，开始寻找最初的……</p><p>《洛丽塔》是一部讲述少女与大叔禁忌之恋的影片。大叔租了一所公寓，公寓中只有单身母女，大叔喜欢上了未成年的女儿，母亲则喜欢上了大叔。母亲是房东，威胁大叔，要么和自己结婚，要么离开公寓。大叔为了能再见到女儿，和母亲结婚了。名义上，大叔已经是女儿的父亲。然而大叔和儿女发生了各种不可描述的关系……</p><p>修养有限，在今年的贺岁电影《疯狂的外星人》里没有看出某些深刻含义，本来就是荒诞喜剧。但却在观影过程中，诧异于两个屌丝主角没能把外星人的能力变现，他们明知头环拥有力量，却没想过自己占有那份力量。可能是我太自私，只想到自己。不过从结局来看，经历过一系列波折，起起落落，外星人走了，开着飞船，把一仓库的酒都带走了。然后呢？卖酒的卖酒，耍猴的耍猴，生活还是要继续。</p><h3 id="何必成神"><a href="#何必成神" class="headerlink" title="何必成神"></a>何必成神</h3><p>王垠是我钦佩的程序员。前段时间，他在博客中提到，他正试着做一些改变，比起“垠神”，现在更乐意别人叫他“老王”。很庆幸可以通过网络，了解到这样一位有思想的技术专家。</p><p>一个表哥在帝都生活工作多年，最近打算回老家发展。在亲戚朋友眼中，他算混的不错的一类人。早已成家，女儿很可爱。几次接触来看，情商很高，因为是销售出身，会来事，但某些专业能力稍有欠缺。也因为身后庞大的负担，一些小事上表现的不是很慷慨。“北漂的结局有哪些？”也许有上限，没下限。</p><p>一个表姐嫁到某二线城市。第一次到家里做客，是在较偏远的旧式楼房里，没有电梯。表姐的家里人，在十八线县城租房子住着。也许是便宜，没我目前租的房子好……</p><p>平庸的人始终平庸。正因为能看到未来，所以才惧怕未来。知道努力也改变不了什么，但仍然需要努力。</p><p>或许若干年后，我可以向某个人讲述我的所有经历，好的坏的，我希望的，我绝望的，我讨厌我的生活，我也喜欢我的生活。</p><h3 id="你若盛开"><a href="#你若盛开" class="headerlink" title="你若盛开"></a>你若盛开</h3><p>为什么我不再迷信技术？因为我发现，技术无法成就一个“完整”的人。</p><p>关注生活，学会生活，因为活着，就是生活，可以精彩，可以失败。</p><p>最近脑海里闪现“自我救赎”四个字。生活可能有惊喜，但不会有奇迹。让人难过的是，惊喜也往往是人为制造的。</p><p>很久以前有的一些情绪，现在已忘记很多……</p>]]></content>
  </entry>
  <entry>
    <title>实习 0.5 个月复盘</title>
    <link href="https://b.smallyu.net/2019/01/25/%E5%AE%9E%E4%B9%A00.5%E4%B8%AA%E6%9C%88%E5%A4%8D%E7%9B%98/"/>
    <id>blog-b:https://b.smallyu.net/2019/01/25/%E5%AE%9E%E4%B9%A00.5%E4%B8%AA%E6%9C%88%E5%A4%8D%E7%9B%98/</id>
    <published>2019-01-25T13:28:28.000Z</published>
    <updated>2026-07-25T13:01:29.359Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>0.5个月，2个星期，共经手2个工单。</p>
<h3 id="第1个工单"><a href="#第1个工单" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>0.5个月，2个星期，共经手2个工单。</p><h3 id="第1个工单"><a href="#第1个工单" class="headerlink" title="第1个工单"></a>第1个工单</h3><p>第1个工单内容较简单，需求为原先某字段为空时不允许记录重复写入，变更为允许。解决方式也简单，判断字段为空时不做重复校验，一律通过就行。刚开始主要还是熟悉开发流程。</p><ol><li>确认需求，OA出工单；</li><li>新建分支，进行开发；</li><li>自测；</li><li>代码评审；</li><li>提测；</li><li>收到测试报告，申请上线；</li><li>上线完成，代码合并基线。</li></ol><p>事实上沟通有一定成本，其他较复杂的需求可能沟通成本会更高。</p><h3 id="第2个工单"><a href="#第2个工单" class="headerlink" title="第2个工单"></a>第2个工单</h3><p>第2个工单需求为修复平台漏洞，1个SQL注入的漏洞，1个反射型XSS攻击的漏洞。解决思路也是常规。</p><p>代码评审后改正的第1个问题，也是带给我的第1个教训是，程序里if-else不可以嵌套过多。修复SQL注入漏洞需要对多个参数做校验，我一开始的做法是：</p><pre><code class="Java">if (param1) &#123;&#125; else if (param2) &#123;&#125; else &#123;&#125;</code></pre><p>这样的做法太糟糕了！而且明显是规范里不推荐的写法。经导师提醒，将代码改为扩展性更好的这种写法：</p><pre><code class="Java">Map&lt;String, String&gt; paramMap = new ConcurrentHashMap&lt;&gt;();map.put(param1);map.put(param2);if (map) &#123;&#125;</code></pre><p>乍一看没有问题，然而这段代码有bug潜伏，第2个给我带来教训的正是这里。ConcurrentHashMap不允许传入null！和HashMap相比，有非常大的NPE风险，因为这里传入的参数来自页面（或者参数传入时就应该做非空校验？）。生产环境的代码不允许差错。</p><p>第3个教训关于配置文件。程序的配置文件，应该达到的效果是，没有这几行配置，程序就像没上线的版本一样，所更改添加的功能都依赖这个配置文件。当然同时也就要求，程序在没有添加配置时做出相应的默认处理。我自然是没能提前考虑到，配置不存在，直接NPE。</p><p>第4个教训是，画蛇添足。程序前一天晚上上线，第二天早上8点接到异常报告，上班之后马上回滚。产生异常的原因是，我改了需求之外部分的代码。上下两个一模一样的方法，看到上面的方法加上参数校验了，虽然需求里面没写，也索性给下面那个方法加上参数校验吧。然后NPE。因为在需求之外，自测没测出来，代码评审没看出来，提测没测出来，上线就出来了。</p><p>程序回滚的损失大概就是，线上系统一晚上的异常，涉及到的各部分人员再走一次工单流程，去修复bug。就两行代码。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ol><li>要对代码负责，从需求到上线。</li><li>积极处理其他事情，反应要快，沟通要顺畅，注意力要集中。</li></ol>]]></content>
  </entry>
  <entry>
    <title>北京，北京</title>
    <link href="https://b.smallyu.net/2019/01/06/%E5%8C%97%E4%BA%AC%EF%BC%8C%E5%8C%97%E4%BA%AC/"/>
    <id>blog-b:https://b.smallyu.net/2019/01/06/%E5%8C%97%E4%BA%AC%EF%BC%8C%E5%8C%97%E4%BA%AC/</id>
    <published>2019-01-06T12:06:19.000Z</published>
    <updated>2026-07-25T13:08:23.926Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>初到北京，有很多新奇体验。这也意味着，真正的独立生活，开始了。</p>
<h3 id="租房"><a href="#租房" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>初到北京，有很多新奇体验。这也意味着，真正的独立生活，开始了。</p><h3 id="租房"><a href="#租房" class="headerlink" title="租房"></a>租房</h3><p>半个多月前着手看房子，当时对这汪深水知之甚少。市面上的房子大概分三类：中介、公寓和房东直租。</p><p>多数人建议租房子不要找中介，并且各大网站如58同城大量充斥的信息源均来自中介。亲身确认像蘑菇租房、贝壳找房之类的APP确实中介居多。中介除了要一个或半个月房租的中介费外，在退房时也会有各种理由克扣押金。中介说了，不扣点押金回去是要挨骂的。中介在租房过程中扮演介绍人的角色，最后合同还是要和房东签。所以在签合同的环节也有机可趁，要注意房东是不是真房东，有可能是二房东或中介。</p><p>公寓和中介类似，不过算是“正规”中介，像8090公寓、自如、蛋壳，没有中介费，有年租8 ~ 10%的服务费（相当一个月房租），算下来也不比小中介花的少。不过品牌公寓的房子大多统一装修，不算好，但能保证在合格线上。就收费来说，中介多收一个月房租的中介费或服务费，加上押金也大概率是退不到手的，三个月就相当于交五个月房租，假设2000&#x2F;月，则实际是3333&#x2F;月，已经远超预期。</p><p>房东直租推荐<code>合租找室友</code>小程序，豆瓣小组也有，听说住多多APP也可以，房源不算多，但真实。</p><p>运气比较好，联系到一个很nice的央财研究生小姐姐，前两个月房子算是转租给我，没有押金，没有其他费用，房东是北师大的老师，可信度较高，不会乱收一些杂七杂八的费用，合租的其他人，有北师大的研究生，之前还有北大的……总之环境不错，性价比高（感激小姐姐</p><img src="huaban.jpg" width="50%" height="50%"><p>住进来后注意到缺一些生活必需品，才开始有独自一人生活的感觉，好在附近的超市非常方便，这是北京啊。</p><h3 id="饮食"><a href="#饮食" class="headerlink" title="饮食"></a>饮食</h3><p>北京的物价没有想象中可怕，楼下的小饭馆大概一顿饭￥15 ~ 20，已经不算贵，毕竟我们十八线小县城的盖饭还要￥10 ~ 12，在太原也要￥12 ~ 16。</p><img src="jituifan.jpg" width="50%" height="50%"><h3 id="出行"><a href="#出行" class="headerlink" title="出行"></a>出行</h3><p>任何地铁站都可以办理市政交通一卡通。太原的交通卡办理点，每天6点30准时下班，一分不多呆，办理交通卡需要身份证，只能用银行卡刷POS机，整个办理过程在10分钟以上；北京的一卡通就容易多了，7点30左右去的时候当然还是有人在的，小姐姐说话也客气，我没带太多现金，把一堆零钱递过去，不到1分钟就把卡拿出来了，没有各种繁琐的步骤。</p><p>刚拿到卡，好奇地铁是怎么坐的，该什么时候刷卡交钱，跟着别人从入口刷卡进去了。看了半天，乘坐地铁的人直接上车，也没有刷卡，下车的人也就下来了。怎么回事呢（哈）然后出站时刷卡发现少了3块钱。</p><img src="ditie.jpg" width="50%" height="50%"><p>每次出门都要提醒自己钥匙、眼镜、钱必带，也再次加深了独自生活的感觉。</p><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>刚来的第一天住100&#x2F;天的宾馆，环境那个差。租房时也看过便宜一点的合住房，环境没比100块的宾馆好多少，而且合住的麻烦之处在于，如果其中一个人突然不住了，该怎么办呢。</p><p>正好有同学在帝都培训几天，通了电话，可能没有机会出去，不过也挺好的，不至于特别落寞。像我这样的人啊，一个人挺好的。</p><img src="jiejing.jpg" width="50%" height="50%"><h3 id="2019计划"><a href="#2019计划" class="headerlink" title="2019计划"></a>2019计划</h3><p>年初计划里把某件事情放到了重要位置。当时想到大概三个途径，显然其中一个几乎已经失败了，这就是现实。不过在变动中不断调整规划生活，不也正是生活的乐趣之一么。</p><h3 id="次日"><a href="#次日" class="headerlink" title="次日"></a>次日</h3><p>入职前一天还是出去了，先到王府井落脚看了看小吃街，然后在天安门附近逛逛，各个景点周一闭馆，无奈去中山公园转了一圈，3块钱的门票（笑哭</p><img src="zhongshangongyuan.jpg" width="50%" height="50%"><p>公园出来再次回到王府井，灯光下的小吃街算是很美。</p><img src="meishijie.jpg" width="50%" height="50%"><p>在北京这个陌生的环境，能机缘巧合下有这样的机会，让我有些特殊的心情，或许和人一起就开心，或许看到认识的人就不慌，恍惚间感觉自己不是孤身一人，生活还有很多希望，它给我的2019开了个好头。该感谢上天呢，还是该感谢……</p><img src="liangren.jpg" width="50%" height="50%">]]></content>
  </entry>
  <entry>
    <title>Scala 语法基础</title>
    <link href="https://smallyu.net/2018/12/17/Scala%E8%AF%AD%E6%B3%95%E5%9F%BA%E7%A1%80/"/>
    <id>blog:https://smallyu.net/2018/12/17/Scala%E8%AF%AD%E6%B3%95%E5%9F%BA%E7%A1%80/</id>
    <published>2018-12-17T03:06:03.000Z</published>
    <updated>2025-06-30T13:34:43.044Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>Scala语法较复杂，参考软件的增量开发，学习一门编程语言也应先找到一种能够驾驭的表达方式，之后再逐步添枝加叶。Scala同时支持面向对象和函数式编程，是其语法复杂的原因之一。一些教程非常全面，但也因为全面，导致难以抽丝剥茧，抓住主干。</p>
<p>以下内容关注最简单的基]]></summary>
    <content type="html"><![CDATA[<p>Scala语法较复杂，参考软件的增量开发，学习一门编程语言也应先找到一种能够驾驭的表达方式，之后再逐步添枝加叶。Scala同时支持面向对象和函数式编程，是其语法复杂的原因之一。一些教程非常全面，但也因为全面，导致难以抽丝剥茧，抓住主干。</p><p>以下内容关注最简单的基础语法，希望根据这些内容，可以尝试编写面向对象风格的Scala代码。</p><h3 id="语句"><a href="#语句" class="headerlink" title="语句"></a>语句</h3><p>Scala允许语句结尾不加<code>;</code>，这一点类似JavaScript。</p><h3 id="变量定义"><a href="#变量定义" class="headerlink" title="变量定义"></a>变量定义</h3><p>val定义不可变变量（常量），var定义可变变量：</p><pre><code class="Scala">val msg1 = &quot;Hello World&quot;var msg2 = &quot;Hello Wrold&quot;val msg3: String = &quot;Hello World&quot;</code></pre><p>定义变量时，类型声明在变量右侧，而且是可选的，可以不声明，编译器会自动推断。Scala中的基本类型包括：</p><blockquote><p>Byte、Short、Int、Long、Char、String、Float、Double、Boolean</p></blockquote><h3 id="函数定义"><a href="#函数定义" class="headerlink" title="函数定义"></a>函数定义</h3><p>函数即方法，下面是定义函数的例子：</p><pre><code class="Scala">def max(x: Int, y: Int): Int = &#123;  if (x &gt; y) &#123;    return x  &#125; else &#123;     return y  &#125;&#125;</code></pre><p>与Java中方法定义的显著区别有三处：一是使用def关键字定义函数；二是类型声明在变量右侧，上文已提及；三是函数声明和函数体中间使用<code>=</code>连接。</p><p>注意函数声明的参数必须明确定义类型，编译器无法自动推断入参类型。返回类型则是可选的，除非函数使用了递归。另外，return关键字也是可选的，如果没有显式的返回语句，程序会将最后一次运算结果作为返回。</p><p>当然if后是单个语句也可以不使用大括号，因此该函数还可以这样描述：</p><pre><code class="Scala">def max2(x: Int, y: Int) = if (x &gt; y) x else y</code></pre><h3 id="选择结构"><a href="#选择结构" class="headerlink" title="选择结构"></a>选择结构</h3><p>上面的示例已经用到了if语句，Scala的if语句并无特殊之处，不过与其他语言相比，Scala用模式匹配的概念代替传统的switch结构：</p><pre><code class="Scala">val a = 1a match &#123;  case 1 =&gt; println(1)  case 2 =&gt; println(2)  case _ =&gt;&#125;</code></pre><p><code>_</code>通配符匹配所有值，用于捕获默认情况。匹配表达式中，备选项永远不会掉到下一个case，因此不需要break或return。（如果将_放到首句，程序不会继续向下执行）。但是要小心，如果程序没有匹配到选项，会抛出MatchError。</p><h3 id="循环结构"><a href="#循环结构" class="headerlink" title="循环结构"></a>循环结构</h3><p>while循环并不是Scala推荐的代码风格：</p><pre><code class="Scala">var i = 0while (i &lt; 5) &#123;  println(i)  i += 1&#125;</code></pre><p>似乎并没有难以理解的地方，这就是典型的while循环。与指令式语言相比，Scala没有<code>++</code>运算符，只能使用<code>i += 1</code>这样的语句。</p><p>提起while，就一定会想到for。Scala中的for循环与指令式语言有一些差异，简单的示例如下，程序会从0打印直到5（不包括5）。</p><pre><code class="Scala">for (i &lt;- 0 until 5) &#123;  println(i)&#125;</code></pre><p>Scala不推荐while循环，而更倾向于函数式的编程风格，用于遍历的foreach方法就是其一：</p><pre><code class="Scala">&quot;abc&quot;.foreach(c =&gt; println(c))</code></pre><p>程序会依次换行打印出a b c三个字符。如果函数体只有一行语句并只有一个参数，这行代码还可以更简洁：</p><pre><code class="Scala">&quot;abc&quot;.foreach(println)</code></pre><h3 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h3><p>Scala的数组并不在语言层面实现，可以实例化Array类来使用。相应的，数组下标使用小括号（也就是方法参数）表示：</p><pre><code class="Scala">val greet  = new Array[String](3)greet(0) = &quot;a&quot;greet(1) = &quot;b&quot;greet(2) = &quot;c&quot;greet.foreach(println)</code></pre><p>实例化对象时，也可以直接传入默认参数。Array确实只是一个普通的类，下面的书写方式并没有黑魔法，只是用到了样本类。关于样本类，后文有提及。</p><pre><code class="Scala">val greet2 = Array(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;)greet2.foreach(println)</code></pre><h3 id="类"><a href="#类" class="headerlink" title="类"></a>类</h3><p>类使用class关键字定义，类中也包含字段和方法，即典型的面向对象。与Python不同，Scala仍然支持权限控制：</p><pre><code class="Scala">class Accumulator &#123;  private var sum = 0  def add(b: Byte): Unit = &#123;    sum += b    println(sum)  &#125;&#125;</code></pre><h3 id="单例对象"><a href="#单例对象" class="headerlink" title="单例对象"></a>单例对象</h3><p>单例对象（Singleton对象）相当于Java中的静态类，使用object替代class关键字定义。单例对象由程序共享，可直接调用。单例对象可以作为程序入口，即将main方法定义在单例对象中。下面的程序从上面定义的Accumulator类中实例化出对象c，并调用其add方法，最终程序打印1：</p><pre><code class="Scala">object Run &#123;  def main(args: Array[String]): Unit = &#123;    val a = new Accumulator    a.add(1)  &#125;&#125;</code></pre><p>在同一源文件中，当单例对象和类同名时，称单例对象为类的伴生对象，类为单例对象的伴生类。类可以访问其伴生对象的私有属性和方法。</p><h3 id="构造方法"><a href="#构造方法" class="headerlink" title="构造方法"></a>构造方法</h3><p>Scala中构造方法的规则比Java要严格。Scala通过类参数的概念来实现构造方法：</p><pre><code class="Scala">class Accumulator(a: Int, b: Int)</code></pre><p>如果类没有主体，大括号是可以省略的。实例化这个类时，就需要传入参数。在Java中的构造方法重载，对应Scala中的辅助构造器，它看起来像这样：</p><pre><code class="Scala">class Accumulator(a: Int, b: Int) &#123;  def this(c: Int) = this(c, 1)&#125;</code></pre><p>这时类拥有两个构造方法：</p><pre><code class="Scala">val a1 = new Accumulator(1)val a2 = new Accumulator(1, 2)</code></pre><p>Scala构造器的严格之处就在于，第二个构造器只能借助第一个或超类的构造器。</p><h3 id="继承与重写"><a href="#继承与重写" class="headerlink" title="继承与重写"></a>继承与重写</h3><p>Scala的继承与Java没有明显差异，只是方法重写必须要使用override关键字：</p><pre><code class="Scala">class A(a: Int) &#123;  def test = println(&quot;a&quot;)&#125;class B(b: Int) extends A(b) &#123;  override def test = println(&quot;b&quot;)&#125;</code></pre><h3 id="特质"><a href="#特质" class="headerlink" title="特质"></a>特质</h3><p>特质（trait）和单例对象相像，除了定义时使用的关键字不同，其余和普通的类一样，可以包含字段和方法。特质的意义在于，支持混入（Mixins），并且允许混入多个特质。这一特性经常和多重继承进行对比。</p><pre><code class="Scala">trait A &#123;  def aMethod = println(&quot;A&quot;)&#125;trait B &#123;  def bMethod = println(&quot;B&quot;)&#125;class C extends A with B</code></pre><p>这样C的实例就可以调用aMethod和bMethod：</p><pre><code class="Scala">val c = new Cc.aMethodc.bMethod</code></pre><h3 id="样本类"><a href="#样本类" class="headerlink" title="样本类"></a>样本类</h3><p>样本类的定义要在class前加case关键字，即类在定义时用case修饰。这种修饰可以让Scala编译器自动为类添加一些便捷设定：1. 实例化可以省略new关键字；2. 自动将参数作为类字段；3. 自动为类添加toString、hashCode和equals：</p><pre><code class="Scala">case class A(a: Int) &#123;  def aMethod = println(a)&#125;object Run &#123;  def main(args: Array[String]): Unit = &#123;    val a = A(1)    a.aMethod     // 1    println(a)    // A(1)    println(a.a)  // 1  &#125;&#125;</code></pre><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>与Java相比，Scala支持抽象类，但不支持接口，抽象类使用abstract定义，接口则由特质代替。Scala同样支持泛型、注解等语法。</p><h3 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h3><p>以上内容并不全面，也许并不够用。使用一种编程语言，除了掌握它的基本语法外，还要熟悉它的惯用写法，尤其像Scala这种多范式的编程语言。之后会持续修改完善此篇内容，也将继续讨论Scala的其他语言特性。</p>]]></content>
  </entry>
  <entry>
    <title>用 Scala 改写 Java 浅度实践</title>
    <link href="https://smallyu.net/2018/12/14/%E7%94%A8Scala%E6%94%B9%E5%86%99Java%E6%B5%85%E5%BA%A6%E5%AE%9E%E8%B7%B5/"/>
    <id>blog:https://smallyu.net/2018/12/14/%E7%94%A8Scala%E6%94%B9%E5%86%99Java%E6%B5%85%E5%BA%A6%E5%AE%9E%E8%B7%B5/</id>
    <published>2018-12-14T04:36:36.000Z</published>
    <updated>2025-06-30T13:34:34.273Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<h3 id="起源"><a href="#起源" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<h3 id="起源"><a href="#起源" class="headerlink" title="起源"></a>起源</h3><p>想要用Java实现Markdown解析器，目前只完成了多级标题的解析。其实也就是正则匹配之后替换掉相应内容，程序暂时比较简单，大致流程如下：</p><img src="mainProcess.png" width="80%"><h3 id="改写"><a href="#改写" class="headerlink" title="改写"></a>改写</h3><p>按照同样的流程，用Scala来实现该功能，之后也将使用Scala继续完成开发。首先读取文件内容，IO操作参考《Scala Cookbook》，只需一行代码即可：</p><pre><code class="scala">var srcLines = Source.fromFile(srcFile).getLines().toList</code></pre><p>与冗长的Java相比，Scala确实精简了不少。这是之前使用Java读取文件封装的方法：</p><pre><code class="java">/**  * 读取文件内容  *  * @param src 读取文件路径  * @return 读取文件内容  */private static String readFile(String src) throws IOException &#123;    StringBuffer content = new StringBuffer();    InputStream is = null;    BufferedReader reader = null;    is = new FileInputStream(src);    reader = new BufferedReader(new InputStreamReader(is));    String line = reader.readLine();    while (line != null) &#123;        content.append(line);        content.append(&quot;\n&quot;);        line = reader.readLine();    &#125;    if (reader != null) &#123;        reader.close();    &#125;    if (is != null) &#123;        is.close();    &#125;    return content.toString();&#125;</code></pre><p>至于Scala版本将字符串改为列表操作的原因在于，Scala和Java在使用正则匹配替换的API上有差异。Java使用Matcher对象进行迭代，Matcher对象拥有查找、替换等方法：</p><img src="replaceProcess.png" width="80%"><p>而Scala的Regex对象虽然拥有findAllMatchIn、replaceAllIn等方法，但在find中的对象仅用于查找，replace方法中又无法定位匹配项的内容。因此在Scala中，将文件读入列表，使用如下方式带索引遍历文本内容：</p><pre><code class="scala">List.range(0, srcLines.size).foreach(index =&gt; &#123;  srcLines = srcLines.updated(index, regexReplace)&#125;)</code></pre><p>无论是否含有匹配项，循环内都对列表执行一次updated，更新原内容为正则替换后的内容。这样做可能稍微欠妥，关于性能问题将持续关注并整改。可以看到的是，Scala的程序思想与Java典型的OOP确实存在些许差异。</p><p>最后关于文件写入，SDK中没有提供专门的操作对象，可使用JDK中的PrintWriter：</p><pre><code class="scala">val pw = new PrintWriter(new File(outFile))pw.write(outString)pw.close()</code></pre><h3 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h3><p>“Scala是一门会伴随开发者成长的语言”，我将用它完成我的毕业设计。</p>]]></content>
  </entry>
  <entry>
    <title>吹牛和装逼的区别</title>
    <link href="https://crazy.smallyu.net/2018/12/12/%E5%90%B9%E7%89%9B%E5%92%8C%E8%A3%85%E9%80%BC%E7%9A%84%E5%8C%BA%E5%88%AB/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2018/12/12/%E5%90%B9%E7%89%9B%E5%92%8C%E8%A3%85%E9%80%BC%E7%9A%84%E5%8C%BA%E5%88%AB/</id>
    <published>2018-12-12T09:04:32.000Z</published>
    <updated>2025-08-16T03:27:11.405Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>吹牛是天马行空的、不切实际的想象，而装逼则类似于，先定个小目标。</p>
<p>区别就在于讲话者的实力，是打肿脸充胖子，还是能让听众都变成柠檬怪]]></summary>
    <content type="html"><![CDATA[<p>吹牛是天马行空的、不切实际的想象，而装逼则类似于，先定个小目标。</p><p>区别就在于讲话者的实力，是打肿脸充胖子，还是能让听众都变成柠檬怪 &gt;_&lt;</p>]]></content>
  </entry>
  <entry>
    <title>PDL 的概念</title>
    <link href="https://crazy.smallyu.net/2018/12/04/PDL%E7%9A%84%E6%A6%82%E5%BF%B5/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2018/12/04/PDL%E7%9A%84%E6%A6%82%E5%BF%B5/</id>
    <published>2018-12-04T03:51:12.000Z</published>
    <updated>2025-08-16T03:27:11.333Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>类比TDD（Test-driven development，测试驱动开发），这里适当提出提出PDL（Problem-driven]]></summary>
    <content type="html"><![CDATA[<p>类比TDD（Test-driven development，测试驱动开发），这里适当提出提出PDL（Problem-driven learning，问题驱动学习）的概念。</p><p>这一概念似乎容易理解，我暂时无法将其完整阐述，会在之后逐步完善。这种学习方式对有一定基础的人有效，还不能确定是否可以推广到没有任何基础的人群。</p><h3 id="更新（2025-06-30）"><a href="#更新（2025-06-30）" class="headerlink" title="更新（2025.06.30）"></a>更新（2025.06.30）</h3><p>6 年过去了，偶然看到以前写的如此短篇的文字。其实当时想要表达的学习方法，是真实存在的，叫 “费曼学习法”。</p>]]></content>
  </entry>
  <entry>
    <title>Python 获取海贼王更新信息</title>
    <link href="https://smallyu.net/2018/12/02/Python%E8%8E%B7%E5%8F%96%E6%B5%B7%E8%B4%BC%E7%8E%8B%E6%9B%B4%E6%96%B0%E4%BF%A1%E6%81%AF/"/>
    <id>blog:https://smallyu.net/2018/12/02/Python%E8%8E%B7%E5%8F%96%E6%B5%B7%E8%B4%BC%E7%8E%8B%E6%9B%B4%E6%96%B0%E4%BF%A1%E6%81%AF/</id>
    <published>2018-12-02T10:08:00.000Z</published>
    <updated>2025-06-30T13:34:19.282Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<p>12月2日，晴，海贼王停更。</p>
<h3 id="问题"><a href="#问题" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>12月2日，晴，海贼王停更。</p><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>做为一个合格的肥宅，海贼王和妖精的尾巴每周必追。这两部动漫播放源都在爱奇艺，都是VIP内容。每周末看动漫，都要在YouTube或其它网站上找资源。问题是，资源网站的更新往往不及时，常常需要Google“动漫名称 + 最新集数”，比如“海贼王 864”。</p><p>每个星期都精确的记住一部动漫应该更新的最新一集集数是多少，恐怕不是正常肥宅会做的事情，况且两部。这样，每次搜索资源前，都需要进入爱奇艺，搜索海贼王，看到最新的一集集数，关闭页面，进入Google搜索。妖精的尾巴也要同样的操作来一次。</p><p>而且，在爱奇艺里看到最新一集集数的瞬间，无法判断它是否停更，还需要在复杂的PC页面中找到“更新时间”这一标签，看更新状态是否正常，才可以做出判断。至于手机页面或APP，更是没有途径可以查看动漫的更新状态。</p><p>另一个获取动漫最新集数的方式是，百度直接搜索动漫名称，首页就倒序显示最新几集的列表（这一点百度好于谷歌），但也无法判断更新是否正常。再者，浏览器默认为Google，百度搜索需要先输入baidu，按TAB切换至百度搜索引擎，再输入要搜索的内容敲回车，步骤同样繁琐。</p><h3 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h3><p>写一段简单的Python脚本，从爱奇艺页面上抓取信息，自己直接访问程序便能知晓动漫的更新情况。引入工具包：</p><pre><code class="python">import urllib.requestfrom bs4 import BeautifulSoupfrom wsgiref.simple_server import make_server# 海贼王页面链接url = &quot;http://www.iqiyi.com/a_19rrhb3xvl.html?vfm=2008_aldbd&quot;</code></pre><p>urllib用于发送http请求，并接收页面数据；bs4用于解析页面，更轻易获取内容；wsgiref用于建立http服务器，提供网络服务。url是全局变量，储存海贼王页面的链接地址。</p><pre><code class="python"># 从页面获取数据def reciveData(url):  # 获取页面内容  response = urllib.request.urlopen(url)  html = response.read()  # 解析器  soup = BeautifulSoup(html, &quot;html.parser&quot;, from_encoding=&quot;utf-8&quot;)  # 更新时间  p = soup.find(&#39;p&#39;, class_=&quot;episodeIntro-update&quot;)  # 最新集数  i = soup.find(&#39;i&#39;, class_=&quot;title-update-num&quot;)  return p, i</code></pre><p>这几行代码发送了请求，并从页面中获取信息。这里更新时间和最新一集集数的信息就已经拿到了。接着要创建一个http服务器，让程序输出内容到页面：</p><pre><code class="python"># 服务器环境的处理函数def application(environ, start_response):  # 获取数据  p, i = reciveData(url)  # 拼接出页面内容  start_response(&#39;200 OK&#39;, [(&#39;Content-Type&#39;, &#39;text/html&#39;)])  content = (&#39;&lt;h3&gt;海贼王&lt;/h3&gt;&#39;            + &#39;msg: &#39; + p.contents[2].get_text().strip()             + &#39;&lt;br&gt;&#39;            + &#39;num: &#39; + i.get_text())  return [bytes(content, encoding = &quot;utf-8&quot;)]</code></pre><p>最后启动一个本地服务器，访问8010端口即可看到页面。可将程序部署到服务器，之后直接访问服务器：</p><pre><code class="python"># 启动服务器httpd = make_server(&#39;&#39;, 8010, application) httpd.serve_forever()</code></pre><p>运行结果如图：</p><img src="preview.png" width="30%"><h3 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h3><p>从这一想法出发，可以扩展程序。一种是从各大网站获取全面的动漫更新信息，主动提供服务；再一种是根据用户的输入，提供自定义的动漫更新信息；或者将两者结合，提供一种大而全的、可收藏、可定制的服务。虽然这种想法毫无意义。</p><h3 id="更正"><a href="#更正" class="headerlink" title="更正"></a>更正</h3><p>之前的代码犯了一个低级错误，程序只会在首次运行时发起网络请求，之后由于网络服务一直处于启动状态，返回网页的内容始终都是初始数据。解决这个问题也很容易，将请求网络的操作封装到一个函数中，再到application函数中调用该函数即可。（代码已更正，为保证简洁，去掉了妖尾部分的代码和控制台的日志输出）</p>]]></content>
  </entry>
  <entry>
    <title>为什么习惯说“是”而不是“对”</title>
    <link href="https://crazy.smallyu.net/2018/11/28/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B9%A0%E6%83%AF%E8%AF%B4%E6%98%AF%E8%80%8C%E4%B8%8D%E6%98%AF%E5%AF%B9/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2018/11/28/%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B9%A0%E6%83%AF%E8%AF%B4%E6%98%AF%E8%80%8C%E4%B8%8D%E6%98%AF%E5%AF%B9/</id>
    <published>2018-11-28T00:45:14.000Z</published>
    <updated>2025-08-16T03:27:11.368Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>原因在于，“对”含有较多评判性的意味，“是”相对弱一些。我们从小接受的教育，对错太鲜明，对即1，错即0，全对即100，全错即0。当对话的两者没有明显的上下级关系、师从关系，可能将“对”用作口头禅会引起别人的小小不满，尽管这种不满不会表现出来，更不会说出口。“你为什么理所当然]]></summary>
    <content type="html"><![CDATA[<p>原因在于，“对”含有较多评判性的意味，“是”相对弱一些。我们从小接受的教育，对错太鲜明，对即1，错即0，全对即100，全错即0。当对话的两者没有明显的上下级关系、师从关系，可能将“对”用作口头禅会引起别人的小小不满，尽管这种不满不会表现出来，更不会说出口。“你为什么理所当然评判我的对错？”心里想想还是有的，虽然也许时间非常短暂，一瞬而过，之后便忘记了。</p><p>另一原因是，回答“对”往往发生在“是……吗？”的疑问句或“是……吧？”的反问句中。“Java中的int是基本类型吗？” “对” “Java中的int是基本类型吧？” “对” 好像是再正常不过的对话，但是不是的问句为什么要用“对”来回答？更可笑的是，如果答案是否定的，回答的内容往往就变成了“不是”，而不是“不对”。有的人说话，连自己都毫无逻辑。</p><p>或许支持说“对”的观点在于，“对”可以给人带来微小的认可感，听到“对”的回答，也能感觉自己被认可。事实上，优秀的人不需要这种认可。</p><p>同理，常见口语中还有“好”和“行”之间的微小差异，等等。</p>]]></content>
  </entry>
  <entry>
    <title>PHP 7，让代码更优雅（译）</title>
    <link href="https://b.smallyu.net/2018/11/01/PHP7%E8%AE%A9%E4%BB%A3%E7%A0%81%E6%9B%B4%E4%BC%98%E9%9B%85/"/>
    <id>blog-b:https://b.smallyu.net/2018/11/01/PHP7%E8%AE%A9%E4%BB%A3%E7%A0%81%E6%9B%B4%E4%BC%98%E9%9B%85/</id>
    <published>2018-11-01T14:19:31.000Z</published>
    <updated>2026-03-02T09:11:49.071Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>PHP 7已发布很久，它可以让代码更加简洁，让我们一睹其风采。</p>
<h3 id="标量类型声明"><a href="#标量类型声明" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>PHP 7已发布很久，它可以让代码更加简洁，让我们一睹其风采。</p><h3 id="标量类型声明"><a href="#标量类型声明" class="headerlink" title="标量类型声明"></a>标量类型声明</h3><p>标量指string、int、float和bool。PHP 7之前，如果要验证一个函数的参数类型，需要手动检测并抛出异常：</p><pre><code class="php">&lt;?phpfunction add($num1, $num2) &#123;    if (!is_int($num1)) &#123;        throw new Exception(&quot;$num1 is not an integer&quot;);    &#125;    if (!is_int($num2)) &#123;        throw new Exception(&quot;$num2 is not an integer&quot;);    &#125;    return ($num1 + $num2);&#125;echo add(2, 4);     // 6echo add(1.5, 4);   // Fatal error: Uncaught Exception</code></pre><p>现在，可以直接声明参数类型：</p><pre><code class="php">&lt;?phpfunction add(int $num1, int $num2) &#123;    return ($num1 + $num2);&#125;echo add(2, 4);     // 6echo add(&quot;2&quot;, 4);   // 6echo add(&quot;sonething&quot;, 4);   // Fatal error: Uncaught TypeError</code></pre><p>由于PHP默认运行在coercive模式，所以”2”被成功解析为2。可以使用declare函数启用严格模式：</p><pre><code class="php">&lt;?phpdeclare(strict_types=1);function add(int $num1, int $num2) &#123;    return ($num1 + $num2);&#125;echo add(2, 4);     // 6echo add(&quot;2&quot;, 4);   // Fatal error: Uncaught TypeError</code></pre><h3 id="返回类型声明"><a href="#返回类型声明" class="headerlink" title="返回类型声明"></a>返回类型声明</h3><p>像参数一样，现在返回值也可以指定类型：</p><pre><code class="php">&lt;?phpfunction add($num1, $num2):int &#123;    return ($num1 + $num2);&#125;echo add(2, 4);     // 6echo add(2.5, 4);   // 6</code></pre><p>2.5 + 4返回了int类型的6，这是隐式类型转换。如果要避免隐式转换，可以使用严格模式来抛出异常：</p><pre><code class="php">&lt;?phpdeclare(strict_types=1);function add($num1, $num2):int&#123;    return ($num1 + $num2);&#125;echo add(2, 4); //6echo add(2.5, 4); //Fatal error: Uncaught TypeError</code></pre><h3 id="空合并运算符"><a href="#空合并运算符" class="headerlink" title="空合并运算符"></a>空合并运算符</h3><p>在PHP5中，检测一个变量，如果未定义则为其赋初值，实现起来需要冗长的代码：</p><pre><code class="php">$username = isset($_GET[&#39;username]&#39;) ? $_GET[&#39;username&#39;] : &#39;&#39;;</code></pre><p>在PHP 7中，可以使用新增的”??”运算符：</p><pre><code class="php">$username = $_GET[&#39;username&#39;] ?? &#39;&#39;;</code></pre><p>这虽然仅仅是一个语法糖，但能让我们的代码简洁不少。</p><h3 id="太空船运算符"><a href="#太空船运算符" class="headerlink" title="太空船运算符"></a>太空船运算符</h3><p>也叫组合运算符，用于比较两表达式的大小。当$a小于、等于、大于$b时，分别返回-1、0、1。</p><pre><code class="php">echo 1 &lt;=&gt; 1;   // 0echo 1 &lt;=&gt; 2;   // -1echo 2 &lt;=&gt; 1;   // 1</code></pre><h3 id="批量导入声明"><a href="#批量导入声明" class="headerlink" title="批量导入声明"></a>批量导入声明</h3><p>在相同命名空间下的类、函数、常量，现在可以使用一个use表达式一次导入：</p><pre><code class="php">&lt;?php// PHP 7之前use net\smallyu\ClassA;use net\smallyu\ClassB;use net\smallyu\ClassC as C;use function net\smallyu\funA;use function net\smallyu\funB;use function net\smallyu\funC;use const net\smallyu\ConstA;use const net\smallyu\ConstB;use const net\smallyu\ConstC;// PHP 7use net\smallyu\&#123;ClassA, ClassB, ClassC&#125;;use function net\smallyu\&#123;funA, funB, funC&#125;;use const net\smallyu\&#123;ConstA, ConstB, ConstC&#125;;</code></pre><h3 id="生成器相关特性"><a href="#生成器相关特性" class="headerlink" title="生成器相关特性"></a>生成器相关特性</h3><p>PHP中Generator函数和普通函数的形式相同。生成器使用在foreach的迭代中，比数组占用内存更少，效率更高。这是一个生成器的例子：</p><pre><code class="php">&lt;?php// 返回一个生成器function getValues($max) &#123;    for ($i = 0; $i &lt; $max; $i++) &#123;        yield $i * 2;    &#125;&#125;// 使用生成器foreach(getValues(99999) as $value) &#123;    echo &quot;Values: $value \n&quot;;&#125;</code></pre><p>代码中出现了yield表达式，它就像return一样，在函数中返回一个值，每次只执行一次，并且会从上一次停止的位置开始执行。</p><p>PHP 7之前不允许生成器函数使用return返回值，现在允许了，return不会影响yield的正常迭代，return的值也可以使用$gen-&gt;getReturn()来获取：</p><pre><code class="php">&lt;?php$gen = (function() &#123;    yield &quot;First Yield&quot;;    yield &quot;Second Yield&quot;;    return &quot;return Value&quot;;&#125;)();foreach ($gen as $val) &#123;    echo $val, PHP_EOL;&#125;echo $gen-&gt;getReturn();</code></pre><p>PHP 7还支持生成器委派，可以在一个生成器函数中调用另一个生成器：</p><pre><code class="php">&lt;?phpfunction gen() &#123;    yield &quot;yield 1 from gen1&quot;;    yield &quot;yield 2 from gen1&quot;;    yield from gen2();&#125;function gen2() &#123;    yield &quot;yield 3 from gen2&quot;;    yield &quot;yield 4 from gen2&quot;;&#125;foreach (gen() as $val) &#123;    echo $val, PHP_EOL;&#125;</code></pre><h3 id="匿名类"><a href="#匿名类" class="headerlink" title="匿名类"></a>匿名类</h3><p>PHP 7也有匿名类啦。</p><h3 id="闭包"><a href="#闭包" class="headerlink" title="闭包"></a>闭包</h3><p>PHP 7对闭包的支持更加友好：</p><pre><code class="php">&lt;?phpclass A &#123; private $x = 1; &#125;// PHP 7之前$getAFun = function() &#123;return $this-&gt;x;&#125;;$getA = $getAFun-&gt;bindTo(new A, &#39;A&#39;); // 中间层闭包echo $getA();// PHP 7之后$getA = function() &#123; return $this-&gt;x; &#125;;echo $getA-&gt;call(new A);</code></pre><h3 id="可为空类型"><a href="#可为空类型" class="headerlink" title="可为空类型"></a>可为空类型</h3><p>Nullable types是PHP 7.1的新特性之一，在参数类型声明前加上一个问号，约定该参数只能是指定类型或者NULL。可以用在返回类型上：</p><pre><code class="php">&lt;?phpfunction testReturn(): ?string &#123;    return &#39;testing&#39;;&#125;var_dump(testReturn());     // string(7) &quot;testing&quot;function testReturn2(): ?string &#123;    return null;&#125;var_dump(testReturn2());    //NULL</code></pre><p>也可以用在参数类型上：</p><pre><code class="php">&lt;?phpfunction test(?string $name) &#123;    var_dump($name);&#125;test(&#39;testing&#39;);    // string(7) &quot;testing&quot;test(null);         // NULLtest();     // Fatal error: Uncaught ArgumentCountError</code></pre><h3 id="数组解构"><a href="#数组解构" class="headerlink" title="数组解构"></a>数组解构</h3><p>list()函数的简化写法：</p><pre><code class="php">&lt;?php$records = [    [1, &#39;smallyu&#39;],    [2, &#39;bigyu&#39;],];// list() 风格list($firstId, $firstName) = $records[0];// [] 风格，PHP 7.1[$firstId, $firstName] = $records[0];var_dump($firstId);     // int(1)var_dump($firstName);   // string(7) &quot;smallyu&quot;</code></pre><p>另一个新特性是list()和[]都支持keys了：</p><pre><code class="php">&lt;?php$records = [    [&quot;id&quot; =&gt; 1, &quot;name&quot; =&gt; &#39;smallyu&#39;],    [&quot;id&quot; =&gt; 2, &quot;name&quot; =&gt; &#39;bigyu&#39;],];// list() 风格list(&quot;id&quot; =&gt; $firstId, &quot;name&quot; =&gt; $firstName) = $records[0];// [] 风格，PHP 7.1[&quot;id&quot; =&gt; $firstId, &quot;name&quot; =&gt; $firstName] = $records[0];var_dump($firstId);     // int(1)var_dump($firstName);   // string(7) &quot;smallyu&quot;</code></pre><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ul><li><p>《Building REATful Web Services with PHP 7》 Chapter 2: PHP 7, To Code It Better</p></li><li><p><a href="http://php.net/manual/zh/migration70.new-features.php">PHP: 新特性 - Manual</a></p></li></ul>]]></content>
  </entry>
  <entry>
    <title>Java 11 教程（译）</title>
    <link href="https://b.smallyu.net/2018/10/31/Java11%E6%95%99%E7%A8%8B/"/>
    <id>blog-b:https://b.smallyu.net/2018/10/31/Java11%E6%95%99%E7%A8%8B/</id>
    <published>2018-10-31T02:20:56.000Z</published>
    <updated>2026-03-02T09:11:49.049Z</updated>
    <category term="B 面"/>
    <summary type="html"><![CDATA[<p>Java 11已经发布，很多人还在使用Java 8。这篇教程讲述一些重要的语言特性和API。</p>
<h3 id="局部变量类型推断"><a href="#局部变量类型推断" class="headerlink"]]></summary>
    <content type="html"><![CDATA[<p>Java 11已经发布，很多人还在使用Java 8。这篇教程讲述一些重要的语言特性和API。</p><h3 id="局部变量类型推断"><a href="#局部变量类型推断" class="headerlink" title="局部变量类型推断"></a>局部变量类型推断</h3><p>局部变量指在方法体内声明的变量。Java10就已经引进一个新的关键字var，用于代替在声明局部变量时候的类型声明。</p><p>在Java 10之前，你必须这样声明一个变量：</p><pre><code class="java">String text = &quot;Hello Java 9&quot;;</code></pre><p>现在你可以使用var代替String。编译器会自动从变量的赋值推断出正确的类型。如文本的类型为String：</p><pre><code class="java">var text = &quot;Hello Java 10&quot;;</code></pre><p>使用var声明的变量仍然是静态变量，不可以在声明后赋值为其它类型：</p><pre><code class="java">var text = &quot;Hello Java11&quot;;text = 23;  // 编译错误，不兼容的类型</code></pre><p>同样可以使用final声明变量为常量：</p><pre><code class="java">final var text = &quot;Banana&quot;;text = &quot;Joe&quot;;   // 编译错误</code></pre><p>当然，在编译器无法推断出类型的场景下，不可以使用var，比如这些情况：</p><pre><code class="java">var a;var nothing = null;var lamdba = () -&gt; System.out.println(&quot;Pity!&quot;);var method = this::someMethod;</code></pre><p>当变量声明包含泛型时，var的优势尤为突出，下面的示例就用var来代替冗长的Map&lt;String, List<Integer>&gt;：</p><pre><code class="java">var myList = new ArrayList&lt;Map&lt;String, List&lt;Integer&gt;&gt;&gt;();for (var current : myList) &#123;    // current 的类型会被推断为 Map&lt;String, List&lt;Integer&gt;&gt;    System.out.println(current);&#125;</code></pre><p>Java 11的var关键字同样支持在lamdba表达式的参数中使用，并且支持为这些参数添加注解：</p><pre><code class="java">Predicate&lt;String&gt; predicate = (@Nullable var a) -&gt; true;</code></pre><blockquote><p>小技巧：在Intellij IDEA中按住CTRL键可以查看变量的推断类型。</p></blockquote><h2 id="HTTP-Client"><a href="#HTTP-Client" class="headerlink" title="HTTP Client"></a>HTTP Client</h2><p>从Java 9开始引进试用新的API HttpClient，用于处理HTTP请求。现在Java 11将其标准化，我们可以从模块java.net中获取使用。</p><p>新的HttpClient在同步和异步场景下都可以使用。同步请求会阻塞线程，直到获取到响应。BodyHandlers定义了响应数据的类型（如String、Byte[]、File）。</p><pre><code class="java">var request = HttpRequest.newBuilder()        .uri(URI.create(&quot;https://blog.smallyu.net&quot;))        .GET()        .build();var client = HttpClient.newHttpClient();var response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.body());// 记得在module-info.java中导入java.net.http模块</code></pre><p>同样可以使用异步的方式实现请求，调用sendAsync方法并不会阻塞当前线程，它会构建异步操作流，在接收到响应后执行相应操作：</p><pre><code class="java">var request = HttpRequest.newBuilder()        .uri(URI.create(&quot;https://blog.smallyu.net&quot;))        .build();var client = HttpClient.newHttpClient();client.sendAsync(request, HttpResponse.BodyHandlers.ofString())        .thenApply(HttpResponse::body)        .thenAccept(System.out::println);// 线程睡眠，防止在返回响应前当前线程就结束Thread.sleep(3000);</code></pre><blockquote><p>.GET()方法会作为默认的请求方式。</p></blockquote><p>下一个示例通过POST方式发送请求到指定URL。与BodyHandlers相似，使用BodyPublishers定义要发送的数据类型：</p><pre><code class="java">var request = HttpRequest.newBuilder()        .uri(URI.create(&quot;https://postman-echo.com/post&quot;))        .header(&quot;Content-Type&quot;, &quot;text/plain&quot;)        .POST(HttpRequest.BodyPublishers.ofString(&quot;Hi there!&quot;))        .build();var client = HttpClient.newHttpClient();var response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.statusCode());      // 200</code></pre><p>最后一个示例演示了如何使用BASIC-AUTH执行权限验证：</p><pre><code class="java">var request = HttpRequest.newBuilder()    .uri(URI.create(&quot;https://postman-echo.com/basic-auth&quot;))    .build();var client = HttpClient.newBuilder()    .authenticator(new Authenticator() &#123;        @Override        protected PasswordAuthentication getPasswordAuthentication() &#123;            return new PasswordAuthentication(&quot;postman&quot;, &quot;password&quot;.toCharArray());        &#125;    &#125;)    .build();var response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println(response.statusCode());      // 200</code></pre><h3 id="集合框架"><a href="#集合框架" class="headerlink" title="集合框架"></a>集合框架</h3><p>集合框架如List、Set和Map都增加了新的方法。List.of方法根据给定参数创建一个不可变列表，List.copyOf创建一个已存在列表的副本。</p><pre><code class="java">var list = List.of(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;);var copy = List.copyOf(list);System.out.println(list == copy);   // true</code></pre><p>因为列表已经不可变，所以拷贝出的列表和原列表是同一实例。如果拷贝了一个可变列表，拷贝出的列表会是一个新的实例，不会对原列表产生副作用：</p><pre><code class="java">var list = new ArrayList&lt;String&gt;();var copy = List.copyOf(list);System.out.println(list == copy);   // false</code></pre><p>创建不可变映射不必自己创建映射实体，只需要将key和value交替传入作为参数：</p><pre><code class="java">var map = Map.of(&quot;A&quot;, 1, &quot;B&quot;, 2);System.out.println(map);    // &#123;B=2, A=1&#125;</code></pre><blockquote><p>Java 11中的不可变列表和旧版本的列表使用相同的接口，但是如果你对不可变列表进行修改，如添加或移除元素，程序会抛出java.lang.UnsupportedOperationException异常。幸运的是，当你试图修改不可变列表，Intellij IDEA会检查并给出警告。</p></blockquote><h3 id="Streams"><a href="#Streams" class="headerlink" title="Streams"></a>Streams</h3><p>Streams从Java 8开始引进，现在新增了三个方法。Stream.ofNullable从单个元素构建流：</p><pre><code class="java">Stream.ofNullable(null)    .count()   // 0</code></pre><p>dropWhile和takeWhile方法都是用于放弃流中的一些元素：</p><pre><code class="java">Stream.of(1, 2, 3, 2, 1)    .dropWhile(n -&gt; n &lt; 3)    .collect(Collectors.toList());  // [3, 2, 1]Stream.of(1, 2, 3, 2, 1)    .takeWhile(n -&gt; n &lt; 3)    .collect(Collectors.toList());  // [1, 2]</code></pre><h3 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h3><p>String类也新增了一些方法：</p><pre><code class="java">&quot; &quot;.isBlank();                // true&quot; Foo Bar &quot;.strip();          // &quot;Foo Bar&quot;&quot; Foo Bar &quot;.stripTrailing();  // &quot; Foo Bar&quot;&quot; Foo Bar &quot;.stripLeading();   // &quot;Foo Bar &quot;&quot;Java&quot;.repeat(3);             // &quot;JavaJavaJava&quot;&quot;A\nB\nC&quot;.lines().count();    // 3</code></pre><h3 id="其他JVM特性"><a href="#其他JVM特性" class="headerlink" title="其他JVM特性"></a>其他JVM特性</h3><p>Java 11包含许多新特性，以上只提及冰山一角，权作抛砖引玉，更多内容等待你探索……</p><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ul><li><a href="https://winterbe.com/posts/2018/09/24/java-11-tutorial/">Java 11 Tutorial</a></li></ul>]]></content>
  </entry>
  <entry>
    <title>Z-Blog插件：站点信息统计</title>
    <link href="https://old-blog.smallyu.net/indexf8d4.html?id=65"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=65</id>
    <published>2017-08-30T16:00:00.000Z</published>
    <updated>2017-08-30T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>在系统原有的站点信息的基础上，增加了文章总字数和页面总字数统计；可自定义显示条目。 后台配置页面，1为显示，0为不显示，提交后保存，属性同其它系统模块。 前台显示效果会受到主题样式影响。 附件： SiteInfoCount.zip 偶然想到要统计一下自己博客上文章的总字数，几经辗转，还是新建一个插件，开始看着官方文档，试图实现这个功能。 这是smallyu尝...</p>]]></summary>
    <content type="html"><![CDATA[<p style="white-space: normal;">在系统原有的站点信息的基础上，增加了文章总字数和页面总字数统计；可自定义显示条目。<br/></p><p style="white-space: normal;"><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708311504159671197077.png" title="搜狗截图20170831140253.png"/></p><p style="white-space: normal;">后台配置页面，1为显示，0为不显示，提交后保存，属性同其它系统模块。</p><p style="white-space: normal;"><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708311504159671696231.png" title="搜狗截图20170831140134.png"/></p><p style="white-space: normal;">前台显示效果会受到主题样式影响。</p><p style="white-space: normal;">附件：<a href="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708311504162009746764.zip" title="SiteInfoCount.zip" style="line-height: 16px; font-size: 12px; color: rgb(0, 102, 204);">SiteInfoCount.zip</a></p><p style="white-space: normal;"><br/></p><hr/><p style="white-space: normal;"><br/></p><p style="white-space: normal;">偶然想到要统计一下自己博客上文章的总字数，几经辗转，还是新建一个插件，开始看着官方文档，试图实现这个功能。</p><p style="white-space: normal;">这是smallyu尝试开发的第一个zblog插件。</p><p style="white-space: normal;">插件目录使用系统默认的结构，插件嵌入页include.php和插件管理页main.php。<br/></p><p style="white-space: normal;">经过一整天+的探索时间，smallyu渐渐明白了zblog插件的运行机制，最终实现了包括但不限于文章总字数统计的功能。<br/></p><p style="white-space: normal;">因为之前smallyu就受限于系统自带的站点信息不能定制化显示，于是这次在插件上添加了这样的功能。<br/></p><p style="white-space: normal;">也因为smallyu比较懒，可能代码的实现形式比较low，也没有考虑插件给系统性能带来的影响，如果有机会，也许smallyu会重构这个插件的代码。</p><p style="white-space: normal;">同时因为zblog后台并不支持直接提交插件到官方审核，然后smallyu对这个插件也非常没有信心，不认为能够通过审核，就不掺和了。</p><p style="white-space: normal;"><br/></p><p style="white-space: normal;">在插件嵌入页include.php，一共挂载了5个接口，当这些接口事件发生时，模块内容就会被更新（但前台页面需要重新编译）。</p><pre class="prism-highlight prism-language-php">function&nbsp;ActivePlugin_SiteInfoCount()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;Add_Filter_Plugin(&#39;Filter_Plugin_Zbp_BuildTemplate&#39;,&#39;updateSIC&#39;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;模板重新编译接口
&nbsp;&nbsp;&nbsp;&nbsp;Add_Filter_Plugin(&#39;Filter_Plugin_PostArticle_Succeed&#39;,&#39;updateSIC&#39;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;文章编辑成功接口
&nbsp;&nbsp;&nbsp;&nbsp;Add_Filter_Plugin(&#39;Filter_Plugin_DelArticle_Succeed&#39;,&#39;updateSIC&#39;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;文章删除成功接口
&nbsp;&nbsp;&nbsp;&nbsp;Add_Filter_Plugin(&#39;Filter_Plugin_PostPage_Succeed&#39;,&#39;updateSIC&#39;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;页面编辑成功接口
&nbsp;&nbsp;&nbsp;&nbsp;Add_Filter_Plugin(&#39;Filter_Plugin_DelPage_Succeed&#39;,&#39;updateSIC&#39;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;页面删除成功接口
}</pre><p style="white-space: normal;">插件的ID定义为SiteInfoCount，简写为SIC。官方定义了插件接口的挂载函数ActivePlugin_ID，在该函数里可以使用Add_Filter_Plugin函数挂载系统接口。</p><p style="white-space: normal;">当文章或页面被编辑，统计字数就会发生改变，所以在这些事件发生时，需要更新模块内容，这里定义更新模块内容的函数为updateSIC，也就是接管系统接口之后会被执行的函数。</p><pre class="prism-highlight prism-language-php">function&nbsp;updateSIC()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;global&nbsp;$zbp;
&nbsp;&nbsp;&nbsp;&nbsp;$config&nbsp;=&nbsp;configInit();
&nbsp;&nbsp;&nbsp;&nbsp;if(isset($zbp-&gt;modulesbyfilename[&#39;SICMoudle&#39;])){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$zbp-&gt;modulesbyfilename[&#39;SICMoudle&#39;]-&gt;Content&nbsp;=&nbsp;cttBycof($config);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;$zbp-&gt;AddBuildModule(&#39;SICMoudle&#39;,&nbsp;&#39;updateSIC&#39;);
}</pre><p style="white-space: normal;">这是updateSIC函数的内容。先声明使用全局变量$zbp，然后获取配置信息到变量$config，其中configInit函数是自定义的函数。if语句判断模块是否存在，如果存在则更改模块内容。最后面的语句<strong>可能</strong>是用于执行更新，samllyu并没有完全了解zblog的函数。<br/></p><p style="white-space: normal;">理论上更新模块有两种方式，一种是if语句内的样子，直接更改模块内容，另一种是使用下面的AddBuildMoudle函数执行更新模块的操作，函数内的两个参数分别表示要更新的模块是执行更新的用户函数。</p><p style="white-space: normal;">smallyu懒得测试模块到底是怎样更新的了，就把两句都写上，反正程序可以正常执行……即使是更新了两次模块，也并不会给系统带来太大额外开销。</p><pre class="prism-highlight prism-language-php">function&nbsp;configInit($config&nbsp;=&nbsp;array()){
&nbsp;&nbsp;&nbsp;&nbsp;global&nbsp;$zbp;
&nbsp;&nbsp;&nbsp;&nbsp;$configFileName&nbsp;=&nbsp;&quot;config.sic&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;文件不存在、没有参数
&nbsp;&nbsp;&nbsp;&nbsp;if(!is_file($configFileName)&nbsp;&amp;&amp;&nbsp;count($config)&nbsp;==&nbsp;0)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$config&nbsp;=&nbsp;array(1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5,&nbsp;6,&nbsp;7,&nbsp;8);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configInput($config);
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;文件存在
&nbsp;&nbsp;&nbsp;&nbsp;if(is_file($configFileName))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;有参数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(count($config)&nbsp;!=&nbsp;0)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;configInput($config);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;没有参数，读取文件
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$configText&nbsp;=&nbsp;file_get_contents($zbp-&gt;host.&quot;zb_users/plugin/SiteInfoCount/&quot;.$configFileName);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$config&nbsp;=&nbsp;explode(&quot;|&quot;,&nbsp;$configText);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$config;
}</pre><p style="white-space: normal;">这是上面用到的configInit函数。函数接收一个数组类型的参数，用于处理插件管理页面提交并需要保存的配置。</p><p style="white-space: normal;">没错，配置信息是写入到文件里的，读取分别使用explode和implode将字符串分割为数组。</p><p style="white-space: normal;">至于为什么，smallyu之前不知道zblog系统提供了选项机制，可以使用类似$zbp-&gt;Config(&quot;ID&quot;)-&gt;test的形式储存数据，然后就没有改。虽然代码量不大，但要把数据从文件储存全部换成使用选项机制储存，也相当于重构整个插件了。</p><p style="white-space: normal;">文件储存也并不影响使用，就是看起来新手一点。</p><p style="white-space: normal;">其它使用到的函数还有：</p><pre class="prism-highlight prism-language-php">moudleInit();&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;初始化模块，也就是新建模块，函数内配置了模块的一些信息
configInput();&nbsp;&nbsp;&nbsp;//&nbsp;细化的配置写入函数，在postInit函数里调用
cttBycof();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;根据config检出content，接收数组参数
postInit();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;处理提交的配置信息</pre><p style="white-space: normal;">每个函数的代码量都不大。其中站点信息截取了ModuleBuilder类的Statistics方法，直接获取到了字符串形式的站点信息。</p><p style="white-space: normal;">插件管理页面main.php则只是把数据填充过来，其中也用到了看起来不太好的for循环，还把循环次数写死了，像这样：<br/></p><pre class="prism-highlight prism-language-php">//&nbsp;数组转存
foreach($config&nbsp;as&nbsp;$value)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;$config[$value]&nbsp;=&nbsp;$value;
}
//&nbsp;获得显示数组
for($i&nbsp;=&nbsp;1;&nbsp;$i&nbsp;&lt;=8;&nbsp;$i++)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;$cofValue[$i]&nbsp;=&nbsp;$config[$i]&nbsp;==&nbsp;$i&nbsp;?&nbsp;1&nbsp;:&nbsp;0;
}</pre><p style="white-space: normal;">从代码上看，好像不明所以。是的，仅仅过了一个小时，smallyu现在也不明所以……</p><p style="white-space: normal;">-------------------------------------</p><p style="white-space: normal;">刚才zblog社区有人说插件改0后会出错</p><p style="white-space: normal;">应该是全部改0后，会写入配置文件空的内容，然后取配置的时候没能得到参数，程序就报错了，这个bug之前好像也遇到过</p><p style="white-space: normal;">全部改0意思就是不显示任何内容，那么……也许可以试着直接把模块撤掉……这样就可以不显示任何内容了</p><p style="white-space: normal;">好吧，我懒……得改</p><p style="white-space: normal;"><br/></p>]]></content>
  </entry>
  <entry>
    <title>我的世界，你做主</title>
    <link href="https://old-blog.smallyu.net/index3221.html?id=63"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=63</id>
    <published>2017-08-28T16:00:00.000Z</published>
    <updated>2017-08-28T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>我要带你去绿色生态园看风景 看高大的树木进幽谧的森林 坐在丛林里板凳上休息 我要带你去文化生态园看灯展 看炫丽的灯光拍好看的照片 站在熙攘的人群里说笑 我要带你去旅游 去任意的地方 只要和你在一起 去哪里都可以 我要和你一起参加活动 也许是好多人的聚会 也许是两个人的约会 虽然要去很多地方 但不是我开车 因为我不想开车 我要和你一起坐在车的后排 也许是别人的...</p>]]></summary>
    <content type="html"><![CDATA[<p><br/></p><p>我要带你去绿色生态园看风景</p><p>看高大的树木进幽谧的森林</p><p>坐在丛林里板凳上休息</p><p><br/></p><p>我要带你去文化生态园看灯展</p><p>看炫丽的灯光拍好看的照片</p><p>站在熙攘的人群里说笑</p><p><br/></p><p>我要带你去旅游</p><p>去任意的地方</p><p>只要和你在一起</p><p>去哪里都可以</p><p><br/></p><p>我要和你一起参加活动</p><p>也许是好多人的聚会</p><p>也许是两个人的约会</p><p><br/></p><p>虽然要去很多地方</p><p>但不是我开车</p><p>因为我不想开车</p><p>我要和你一起坐在车的后排</p><p>也许是别人的车</p><p>也许是自己的车</p><p><br/></p><p>我想到过很多和你在一起的场景</p><p><br/></p><p>比如一起奋斗</p><p>可能是准备一场考试</p><p>可能是寻找一份工作</p><p>可能是做一次失败的生意</p><p><br/></p><p>比如一起购物</p><p>买两张周末的电影票</p><p>买两张回老家的车票</p><p>买新房子里装修用的瓷砖</p><p><br/></p><p>比如一起无聊</p><p>你在房间里无所事事</p><p>我就看着你无所事事</p><p>和你在一起又怎么会无聊</p><p><br/></p><p>好像我经历过的回忆中，都有你</p><p><br/></p><p>最近天在下雨</p><p>变凉了</p><p>注意身体</p><p>也要注意安全</p><p><br/></p><p>其实我没有想你</p><p>但我还是忍不住关心你</p><p>虽然我联系不到你</p><p><br/></p><p>也没有你</p><p><br/></p><hr/><p><br/></p><p>欢迎来到我的世界。</p><p><br/></p><p>入坑我的世界好多天，经历了各种生生死死，游戏一次又一次地安装卸载。</p><p>刚进入游戏，到了晚上会被僵尸杀死，被拿弓箭的白色僵尸射死，被蜘蛛咬死，被末影人打死，还遇见不知名的拿药水瓶的人，把你毒死。</p><p>自作孽的时候，被爬行者炸死，从高处掉到地上摔死，泡水里淹死，跑岩浆里被火烧死，饿死。</p><p>直到慢慢的，收集地上的泥土，垒起两格高的围墙，把自己围在中间，晚上就在里面等啊等，等到白天再继续活动。</p><p>随着圈起围墙的地盘越来越大，开始学会收集木块，然后知道了最最最最关键的一个步骤：用木块合成木板，这是一切一切的开始。</p><p>有了木板，就能有木棍，就能有工作台，就能有木锹、木槁、木锄、木剑，用木锹挖土，用木槁挖圆石，用木锄种小麦，用木剑打怪兽。</p><p>有了木槁，就能有圆石，就能有熔炉，就能有木炭，就能有火把，火把用来把自己的地盘照亮，照亮的地方就不会有僵尸出生了。</p><p>然后学会挖矿，铁矿、银矿、金矿、钻石矿，还有至关重要的黑曜石，并且用黑曜石搭建地狱门，可以进入地狱。</p><p>……</p><p>我的世界已近神作，自由度太高了，它是给真正体验游戏的玩家玩的游戏。</p><p><br/></p><p>虽然时间不长。</p><p>我并没能完成在游戏里想要完成的操作，比如建一座城堡。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504020835168711.jpg" title="javaw 2017-08-29 21-18-52-441.jpg" alt="javaw 2017-08-29 21-18-52-441.jpg" width="641" height="345" style="width: 641px; height: 345px;"/></p><p>这个是我的圈地用的城墙，目前四个面只留了这么一个入口，一扇木门。原想在城堡的四周都开一个入口，这样每次回家都不用跑到这个面找这个门。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504020861370867.jpg" title="javaw 2017-08-29 21-19-21-753.jpg" alt="javaw 2017-08-29 21-19-21-753.jpg" width="642" height="344" style="width: 642px; height: 344px;"/></p><p>这个是改造中的城墙，原想把泥土搭的城墙全部换成圆石墙，地面全部换成圆石。可是我圈地比较大，没能来得及换完。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504020904758447.jpg" width="643" height="351" style="width: 643px; height: 351px;"/></p><p>这只狗是在很远的森林里遇到，喂了两根骨头就从良的，一直跟在身边。遇到僵尸攻击的时候，小狗也会积极配合上前攻击。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504020942112737.jpg" title="javaw 2017-08-29 21-19-44-978.jpg" alt="javaw 2017-08-29 21-19-44-978.jpg" width="646" height="353" style="width: 646px; height: 353px;"/></p><p>这个长长的杵上天的柱子，是暂时用来当信号灯用的。如果离开城堡，到了旁边的森林，又不是特别远，有这根柱子，一眼就能看出城堡的方向。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504020971931782.jpg" width="648" height="342" style="width: 648px; height: 342px;"/></p><p>这些是在城堡里圈养的动物，有羊、鸡、兔子、狗。游戏中只要喂这些动物食物，它们就会繁殖了，羊吃小麦，鸡吃小麦种子，兔子吃萝卜，狗吃肉。</p><p>在城堡里如果放一些水用来种小麦和萝卜，那这个城堡里的生态圈就可以无限循环啦！以前是有的，后来为了城堡里面的地面平坦一点，加上准备把泥土地面全换成圆石的，就先撤掉了。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504020995103342.jpg" title="javaw 2017-08-29 21-20-18-033.jpg" alt="javaw 2017-08-29 21-20-18-033.jpg" width="653" height="346" style="width: 653px; height: 346px;"/></p><p>这个东西，里面是岩浆，外面是一圈玻璃。仅仅只是为了好玩放在那儿，岩浆晚上会发光，也能起到一点照明的作用。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504021016855166.jpg" title="javaw 2017-08-29 21-20-22-380.jpg" alt="javaw 2017-08-29 21-20-22-380.jpg" width="655" height="355" style="width: 655px; height: 355px;"/></p><p>这些箱子就是用来放物品的地方。除了工作台和熔炉，有六个箱子。东西太多了，很难分类分清楚，有建筑石块、矿石、装饰块、食物、杂物、工具……</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504021029298290.jpg" title="javaw 2017-08-29 21-20-32-655.jpg" alt="javaw 2017-08-29 21-20-32-655.jpg" width="656" height="349" style="width: 656px; height: 349px;"/></p><p>这个，就是地狱之门了。用十块黑曜石搭成的2x3的门，图中用玻璃把紫色的传送门挡住了，因为地狱里面的僵尸猎人太厉害，每次进去都被秒杀，把门堵住，防止自己误进，也防止门里面的僵尸猎人出来，还有偶尔小狗也会自己跳进去。</p><p>游戏里黑曜石很难天然形成，必须得自己，把水倒在岩浆上，然后用钻石镐挖。感觉钻石很难找。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504021046188132.jpg" title="javaw 2017-08-29 22-40-44-725.jpg" alt="javaw 2017-08-29 22-40-44-725.jpg" width="657" height="378" style="width: 657px; height: 378px;"/></p><p>这个留空的没有城墙的角落，是用来钓鱼的，而且很安全，僵尸们上不来，因为下面只铺了踩着的那一层，再下面就是悬空的了。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708291504021070646815.jpg" width="660" height="386" style="width: 660px; height: 386px;"/></p><p>最后是一张不算全景照的全景照。其实地方蛮大的，还有不少能想到的想做的工作没做完。截图是在晚上，没能白天，也算是遗憾吧。</p><p><br/></p><p>没做完，以后接着做？</p><p>单机游戏，实在不愿花费过多时间。</p><p>尽管和已经弃坑的王者荣耀比，我的世界用的时间一点都不多。王者荣耀，永远也不会有我的世界这么精彩的游戏内容。</p><p>而且要开学了，刚放假的时候，对学校还是很不陌生的感觉。</p><p>转眼暑假过去了。</p><p>很陌生。</p><p>现在想想，当时依旧是浑浑噩噩不知所以。</p><p>现在也依旧是浑浑噩噩不知所以。</p><p>平凡才是常态？</p><p>“连自己都找不到，还怎么找另一半？”</p><p>值得思考的，思考不出来的，思考出来做不到的，能做到但又不想做的，种种</p><p><br/></p><p>拿起酒杯敬自己</p><p>敬明天</p><p>敬未来</p><p><br/></p><p>未知的路才要前行</p><p><br/></p>]]></content>
  </entry>
  <entry>
    <title>轻舟虽过万重山，心到桥头自然沉</title>
    <link href="https://old-blog.smallyu.net/index619c.html?id=62"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=62</id>
    <published>2017-08-21T16:00:00.000Z</published>
    <updated>2017-08-21T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>欢迎来到欢乐场。 今天8月22，星期二，天气，阴，心情，糟 CET4是有及格线的，425，因为只有425以上，才有资格报考CET6，是一条约定俗成的及格线，虽然官方并没有这样的说法。 本来向从各个途径找一点点哪怕一点聊以自慰的理由，实在找不到。 CET4重要吗？太不重要了，因为没人过不了。 会在乎425，是因为，我考了420，幸好，不是424。 上一次考38...</p>]]></summary>
    <content type="html"><![CDATA[<p><strong><span style="text-decoration: none;">欢迎来到欢乐场。</span></strong></p><p><br/></p><p>今天8月22，星期二，天气，阴，心情，糟</p><p><br/></p><p>CET4是有及格线的，425，因为只有425以上，才有资格报考CET6，是一条约定俗成的及格线，虽然官方并没有这样的说法。</p><p>本来向从各个途径找一点点哪怕一点聊以自慰的理由，实在找不到。</p><p>CET4重要吗？太不重要了，因为没人过不了。</p><p>会在乎425，是因为，我考了420，幸好，不是424。</p><p>上一次考382的时候，也没怎么在意，并没有伤心，毕竟差得很远。</p><p><br/></p><p>呃</p><p>smallyu很菜对不对</p><p>上大学以来，CET4是smallyu唯一没有通过的考试，连续两次。</p><p>四次期末考试，GPA最低3.2，最高3.7，目前平均不到3.5，不过没关系。</p><p>计算机二级</p><p>计算机三级</p><p>很想说服自己，CET4证书没用，所以过不了也没关系。</p><p><br/></p><p>计算机等级证书有用吗？虽然不愿相信这个事实，但确实没用，尤其对于找工作来说。</p><p>非计算机相关类工作，自然没用。计算机相关类工作，那点水平又远不够用。</p><p><br/></p><p>那CET4证书有用吗？</p><p>英语相关类工作，那点水平同样远不够用。但非英语相关类工作，才是CET4发挥作用的地方。</p><p><br/></p><p>过了，不能说明什么，过不了，说明你很差啊。就像企业招人都会招985、211，不是说人才一定都在那些院校，只是在那些院校招到的人，是人才的概率大。企业在节省招人的成本。</p><p><br/></p><p>想要考NCRE，也只是随便考考，找点乐子……</p><p><br/></p><p>计算机相关考试，目前只有NCRE。</p><p>软考？PAT？嗯……</p><p><br/></p><p>下面引用的这段是逻辑很不清的随便写写，注释掉：</p><p>/**</p><p>为什么NCRE会沦为完全没用的这样一个考试？</p><p>可能NCRE和CET的性质不同。</p><p>对于英语，多会一句，少会一句，多懂一句，少懂一句，运气稍微好以下，运气稍微差一下，都会产生一些影响。</p><p>真正的工作场景中，除了英语相关专业，使用英语的场景，以及对英语的要求并不高。</p><p>那么这里的问题在于，你怀揣CET证书，要应聘的并不是英语相关类的工作，像英语教师、人工翻译、同声传译。</p><p>要想找英语专业相关工作，CET4也远远不够。</p><p>而NCRE没用的说法是对于计算机相关专业类的工作而言。</p><p>应聘程序猿、攻城狮，一张证书不能说明什么。</p><p>面试官不会在意你二级了解了C语言，三级学会了局域网组网，四级学过了操作系统原理。</p><p>Android软件会开发吗？eclipse用熟了吗？Spring会吗？多线程、高并发了解多少？</p><p>技术相关的问题，会就是会，不会就是不会。</p><p>*/</p><p><br/></p><p>计算机技术的道路，可以走下去吗？</p><p>一方面，大量的计算机人，和大量冲着程序猿这个金字招牌，以及火热的人工智能、大数据，入行IT。</p><p>另一方面，大把的IT人呼叫着35岁危机，复制粘贴，增删改查，单身，加班。</p><p>现在的码农，劳苦程度不亚于几十年前坐在缝纫机上的裁缝阿姨，和工厂流水线上工作的工人大叔。</p><p>码农，还是在打工啊。</p><p>要想赚钱，得经商。</p><p>无奸不商啊。</p><p><br/></p><p>那要不要考研？</p><p>考研大概有这么几种原因：</p><p>1.爱学习，爱生活，为知识而拼搏</p><p>&nbsp; &nbsp; 这样的人高考成绩一定炸，已经与我无关</p><p>2.认为高学历就能够找到好工作</p><p>&nbsp; &nbsp; 考研：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 成本：3年的读研时间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1年以上复习、准备考研的时间，大量精力</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 回报：研究生学历</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 知识、技能成长</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 认识更多厉害的人，包括导师</p><p>&nbsp; &nbsp; 就业:</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 成本：3年的工作时间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 回报：工作经历</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 薪水</p><p>&nbsp; &nbsp; <strong>老梁</strong>的观点是，研究生无用，因为目前大多数基层工作岗位需要的技能，本科学历足够。</p><p>&nbsp; &nbsp; 读研，企业需要付给你更高的薪水。但是，你能带来比本科学历的人更高的价值吗？</p><p>&nbsp; &nbsp; 研究生三年，国内学校的尿性是人尽皆知的，尤其是实战操作能力，三年不一定能够学到太多东西，反而本科毕业有整整三年工作经历的人，工作能力上的提高，不见得比三年学院生活少。</p><p>&nbsp; &nbsp; <strong>卿未离</strong>，知乎上最近在关注的很厉害的一个人，他对读研的观点是，如果想要在一线城市北上广深从事技术性强的相关工作，就可以选择读研，否则，该干嘛干嘛。</p><p>&nbsp; &nbsp; 也就是说，只要不在一线城市，无论从事什么工作，都不要读研。</p><p>&nbsp; &nbsp; 当然，事业单位除外，什么公务员、老师，甚至从政。</p><p>&nbsp; &nbsp; <strong>张雪峰</strong>是考研神嘴，提倡考研，比较关键的一个观点是，考研，可以让你认识一个非常牛的人物，那就是你的导师，甚至如果你将来的就业可以用上那么一点他的人脉资源，那就赚大了。</p><p>&nbsp; &nbsp; 这些观点，都很难取舍。</p><p>3.想要逃避现实生活，再在学校呆3年</p><p>&nbsp; &nbsp; 当然不可取</p><p>4.随大流</p><p>&nbsp; &nbsp; 也不可取</p><p>有的人的观点是，你考研先考上再说，再去问要不要读研。</p><p>这样的观点，有一定道理，但也站不住。</p><p><br/></p><p><br/></p><p><strong><span style="text-decoration: none;">当你背上所有的梦与想。</span></strong></p><p><br/></p><p>上大学了，我要好好学习，因为努力就有回报，因为我仅用高三一年的时间，就可以达线，就可以考上大学。</p><p>有很多很多日夜不眠，拼死奋战的人，也就将将达线，甚至没有达线。</p><p>我的努力是有成效的。</p><p>因为高三之前，实在荒废了太多时间，高中期间回家从没有写过作业。于是考上大学，高三一年学了高中三年的东西，再甚包括初中两年的。</p><p>这么容易！</p><p>吃到甜头，还想再吃。</p><p><br/></p><p>于是，大学，上课第一排，虽然不爱写作业。做事积极尝试，虽然明知道自己不行，但也要尝试。试过了，才配说不行。</p><p><br/></p><p>工作？是，工作了，一定要出人头地，光，宗，耀，祖，你们都赚不到的钱，我一定要赚到，你们不敢想的薪水，我一定要拿到。钱钱钱！你们都在乎钱，你们都没有钱，我要有！</p><p>赚钱？是本科就业好，还是读研再就业好？</p><p><br/></p><p>对了，越来越喜欢教育行业，尤其是老师，工作量不大，铁饭碗，社会地位高，赚的不多，但稳定的一塌糊涂。越来越崇尚，越来越，懒惰？是啊，懒又怎么样，我可不想毕业就失业，也不想整天加班，增删改查做CMS，不想找不到女朋友，不想35岁就被开除。</p><p><br/></p><p>家里就我一个孩子，可惜，我完全没有信心，做出为人杰的事情。</p><p><br/></p><p><br/></p><p><strong>当你看到，各色的脸上，各色的妆。</strong></p><p><br/></p><p>他们都变了，我的小学同学们，女生学会画浓妆，学会打麻将，男生抽烟，当保安挣钱。</p><p>初中时候不懂事的她，追求你的她，陪在你身边的她，要结婚了？</p><p>高中时候单纯的她，你心疼的她，让你失望的她，曾决心一起度过一生的她，让你奋发图强，努力奋斗的她，好吧，你已经不认识了。</p><p>大学同学们，来自全国各地，家庭背景不一样，社会背景不一样，成长环境不一样，经济条件不一样，未来的前景不一样。</p><p>大学同学，只不过是按照当初随便报的专业，按照学号，机缘巧合被分在一起，去完成四年的学业任务而已。</p><p>情？</p><p>宿舍舍友？坐火车的时候，如果是软卧，也不得不和，来自不同地方，有着不同目的地的人，在同一间屋子里，睡上几觉。</p><p>我说不出更多东西忘了。</p><p><br/></p><p><br/></p><p><strong>没人会记得，你的模样。</strong></p><p><br/></p><p>我始终一个人。</p><p><br/></p><p>拿起酒杯，</p><p>对自己说，</p><p><br/></p><p>一杯敬你，另一杯还敬你。</p><p><br/></p><p>人生苦短何必念念不忘？</p><p><br/></p><p>说得容易。</p><p><br/></p><p>清醒的人不荒唐，一点都不荒唐。</p><p><br/></p><p>这首歌明明不好听，曲不如摄影艺术，词不如雅俗共赏，人不如VAE。</p><p><br/></p><p>可是念念不忘。</p><p><br/></p><p><br/></p><p>你的大学是否也会遇见，让你心烦意乱的人？</p><p><br/></p><p>第一次四级考不过，所以她不是你应该依靠的人。</p><p>第二次四级考不过，因为第一次的考试结果伤透了你的心。</p><p><br/></p><p>第二次四级考不过，因为你还在等一个可以依靠的人。</p><p>第二次四级考不过，因为你还在等一个给你信念让你考过的人。</p><p><br/></p><p>考研犹豫不决，是因为对她的态度还毫无所知。</p><p><br/></p><p>但，我是外人，我管你有什么理由考试不过？我管你有什么理由停滞不前？</p><p><br/></p><p>我是外人，你不比我强，我不比你差。</p><p><br/></p><p>是，我比你差，没有你强。</p><p><br/></p><p>你过了四级，人们会说，啊，他四级竟然过了！</p><p>我没过四级，人们会说，啊，你四级竟然没过！</p><p><br/></p><p>smallyu是不是很自恋。</p><p>smallyu是不是有假想敌。</p><p>smallyu是不是心理有问题。</p><p><br/></p><p>生而为人，而已。</p><p><br/></p><p><br/></p><p>总在盼望，总在失望，日子还不都这样。</p><p><br/></p><p><br/></p><p>天亮之后，不要离场，不要潦草。</p><p><br/></p><p><strong>我送你。</strong></p><p><strong><br/></strong></p>]]></content>
  </entry>
  <entry>
    <title>NCRE4 · 网络工程师《计算机技术》概要</title>
    <link href="https://old-blog.smallyu.net/index2fc6.html?id=61"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=61</id>
    <published>2017-08-08T16:00:00.000Z</published>
    <updated>2017-08-08T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>前言——2013年下计算机等级考试四级新标准 一、开考类别 科目名称 科目代码 考核课程代码 网络工程师 41 401、403 数据库工程师 42 404、405 软件测试工程师 43 401、405 信息安全工程师 44 401、403 嵌入式系统开发工程师 45 401、402 二、专业核心课程 课程代码 课程名称 401 四级操作系统原理 402 四级...</p>]]></summary>
    <content type="html"><![CDATA[<p><strong><span style="font-size: 18px;">前言——2013年下计算机等级考试四级新标准</span></strong><br/></p><p>&nbsp; &nbsp; 一、开考类别</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 科目名称 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;科目代码 &nbsp; &nbsp;考核课程代码</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 网络工程师 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 41 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;401、403&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 数据库工程师 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;42 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;404、405 &nbsp; &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 软件测试工程师 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 43 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;401、405</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 信息安全工程师 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 44 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;401、403 &nbsp; &nbsp;&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 嵌入式系统开发工程师 &nbsp; &nbsp; 45 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;401、402</p><p>&nbsp; &nbsp; 二、专业核心课程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 课程代码 &nbsp; &nbsp;课程名称</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 401 &nbsp; &nbsp; &nbsp; &nbsp; 四级操作系统原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 402 &nbsp; &nbsp; &nbsp; &nbsp; 四级计算机组成与接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 403 &nbsp; &nbsp; &nbsp; &nbsp; 四级计算机网络</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 404 &nbsp; &nbsp; &nbsp; &nbsp; 四级数据库原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 405 &nbsp; &nbsp; &nbsp; &nbsp; 四级软件工程</p><p>&nbsp; &nbsp; 三、获证条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 通过四级科目考试，并已经（或同时）获得三级相关证书。</p><p>&nbsp; &nbsp; 四、考试形式：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.考试环境：采用无纸化考试的形式；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.考试时间：两门专业核心课程总时间为90分钟；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.合格标准：满分100分，两门课程分别同时达到30分；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.题型及分值：单选题30分，多选题20分。</p><p>&nbsp; &nbsp; 五、题型分析</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.总体难度分析</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由于两门课程合计考试时间为90分钟，总体难度不会太大。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.考核能力分析</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 题型为单选题与多选题，对课程大纲要求的知识点考核以理论基础的理解与判断为主，设计到复杂计算的内容较少。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.单选题应试方法分析与学习建议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 单选题以概念理解为主。考前学习中注意知识的理解，尽量减少死记硬背的内容。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 应试中建议利用排除法。类比法快速确定答案，所以在考前学习中注意概念的理解，和概念的对比记忆。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）单选题常见题型1</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基本网络技术名词、概念的考核。多个名词的功能与原理的区别。难易度不大。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）单选题常见题型2</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 某个网络技术相关概念、名词的理解，从选项中判断正误。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 学习中注意概念的理解，应试中善于利用排除法。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）单选题常见题型3</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 某个网络技术相关参数的简单计算。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于通过固定公式计算的知识点主要记牢计算公式；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于网络中常见的数值进制转换、子网计算等在学习中掌握计算方法，提高计算时间与准确率。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.多选题应试方法分析与学习建议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多选题以概念理解为主。考前学习中注意知识的理解，加强知识点的归纳总结，和概念的对比记忆。</p><p><br/></p><p><strong><span style="font-size: 18px;">计算机网络课程（课程代码403）介绍</span></strong></p><p>&nbsp; &nbsp; 基本要求：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一、理解计算机网络的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二、掌握局域网的基本工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三、掌握TCP/IP及相关协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四、掌握Internet基本服务类型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五、掌握较为新型的网络技术应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 六、理解网络管理与网络安全原理</p><p>&nbsp; &nbsp; 考试内容：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一、网络技术基础</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.计算机网络的形成与发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.计算机网络的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.分组交换技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.网络体系结构与网络协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.互联网应用的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二、局域网技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.局域网与城域网的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.共享式局域网的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.高速局域网的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.交换式局域网与虚拟局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.无线局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三、Internet基础</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.Internet的构成与接入</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.IP协议与服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.IP地址与IP数据报</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.差错与控制报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.路由与路由选择</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.组播技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7.IPv6协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 8.TCP协议和UDP协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 9.NAT的基本原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四、Internet基本服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.应用进程通信模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.域名系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.远程登录服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.FTP服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.电子邮件系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.Web服务系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五、新型网络应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.即时通信系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.文件共享系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.IPTV</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.VoIP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.网络搜索技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.社交网络应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 六、网络管理与网络安全</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.网络管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.网络安全基础</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.加密技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.认证技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.安全技术应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.入侵检测与防火墙</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7.计算机病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 总体分析：考察内容与原三级网络技术的内容大部分相同，提出部分章节的老旧内容，新增部分前沿知识。90%以上内容相同。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 应试建议：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.学习上以教材为主，配合网课。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.习题上以原三级网络技术的历年真题为主，多做试题。</p><p><br/></p><p><strong><span style="font-size: 18px;">第1章 网络技术基础</span></strong></p><p>&nbsp; &nbsp; 学习目标：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.了解计算机网络的形成与发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.掌握计算机网络的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.掌握分组交换技术与包交换技术的基本原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.掌握网络体系结构与网络协议的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.了解互联网应用的发展</p><p>&nbsp; &nbsp; 一、计算机网络的形成与发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）计算机网络的发展阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第一阶段：20世纪50年代，将独立的计算机技术与通信技术结合；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第二阶段：20世纪60年代，美国的APRANET与分组交换技术开始；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第三阶段：20世纪70年代，ISO推动系统参考模型与网络协议；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第四阶段：20世纪90年代，互联网、高速通信网络、无线网络与网络安全技术的发展，基于P2P的网络应用成为互联网产业与信息服务业的新增长点。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）计算机网络的形成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.有一台中央主机通过通信线路连接大量的地理上分散的终端，构成面向终端的通信网络，终端分时访问中心计算机的资源，中心计算机将处理结构返回终端。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.世纪60年代中期，出现了多天计算机通过通信系统互连的系统，开创了“计算机——计算机”通信时代，这样分布在不同地点且具有独立功能的计算机就可以通过通信线路，彼此之间交换数据、传递信息。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.ARPANET的发展以及OS的规定，使各种不同的网络互联、互相通信变为现实，实现了更大的范围内的计算机资源共享。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.Internet是覆盖全球的信息基础设施之一，用户可以利用Internet实现全球范围的信息传输、信息查询、电子邮件、语音与图像通信服务等功能。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）网络体系结构与协议标准化</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在计算机网络发展的第三阶段，出现了很多网络，导致网络之间的通信困难。迫切需要统一的网络体系结构和统一的网络协议。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ISO制定了OSI参考模型，作为国际认可的标准模型。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP/IP协议以及体系结构早于OSI参考模型，因此TCP/IP协议与体系结构也是业内公认的标准。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）互联网应用与高速网络技术发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.互联网高速发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 互联网不仅是一种资源共享、数据通信和信息查询的手段，主键成为了人们了解世界、讨论问题、休闲、学术研究、商贸、教育甚至军事活动等重要领域。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.信息高速公路</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 高速网络技术主要体现在：异步传输模式（ATM），宽带综合业务数字网（B-ISDN）,高速局域网，交换局域网，虚拟网络与无线网络。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.基于WEB技术的互联应用的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Web技术的出现使网站的数量和网络的通信量呈指数增长。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.基于P2P技术的应用技术发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 区别于C/S结构，对等（P2P）网络淡化了服务提供者和服务使用者的界限，扩大了网络资源的范围和深度。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.网络安全技术的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计算机及网络犯罪，使得网络必须具备足够的安全机制，防止信息被非法窃取、破坏与泄露。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 搜索引擎是一种运行在Web上的应用软件系统；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P2P以“非中心化”方式使更多的用户同时身兼客户机与服务器的双重身份，达到信息共享最大化的目标。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五）宽带城域网的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 宽带城域网与传统的通信网络在概念和技术上发生了很大的变化，主要体现在以下几个方面：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传统局域网、城域网与广域网在技术上的界限模糊。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传统的电信传输技术与计算机网络技术的界限越来越模糊。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传统的电信服务与互联网应用的界限越来越模糊。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 电信传输网。计算机网络与广播电视网络技术的界越来越模糊。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.宽带城域网应该包括核心交换网与接入网；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.目前，可作为用户接入网的主要有三类：计算机网络、电信通信网与广播电视网；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.从技术角度来看，互联网的用户接入方式主要分为五类：地面有线通信系统、无线通信和移动通信网、卫星通信网、有线电视网和地面广播电视网。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.三网融合：计算机网络、电信通信网与电视传输网。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 六）无线网络的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.无线局域网（WLAN）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 以微波、激光与红外等无线电波作为传输介质，IEEE 802.11工作组专门从事WLAN标准的研究。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 无线局域网主要有四个应用领域：传统局域网的扩充、建筑物之间的互联、漫游访问与特殊网络。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 无线局域网的传输技术：红外线、扩频、窄带微波。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.无线自组网（Ad hoc）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 是一种自组织、对等式、多跳的无线移动网络，无线自组网技术的发展趋势：一是向军事和特定行业发展的无线传感器网络，二是向民用的接入网领域发展的无线网状网。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.无线传感器网（WSN）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将Ad hoc与传感器技术相结合，WSN的三个要素是传感器、感知对象和观察者。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.无线网状网（WMN）：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由无线路由器构成骨干网，用于大范围的信号与节点连接。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WMN作为WLAN、WiMax技术的补充，成为解决无线接入“最后一公里”问题的新技术方案。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802.11S工作组专门为WMN制定了MAC与PHY层协议。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.蓝牙技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802.15工作组制定了蓝牙通信标准。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 七）操作系统的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 操作系统包括两部分：客户机操作系统与服务器操作系统。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 带网络功能的操作系统的基本任务：用屏蔽本地资源与网络资源的差异性，为用户提供各种网络服务功能，并提供网络系统的安全服务。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.Windows操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.Unix</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 原本为小型机环境开发的操作系统。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要用C语言写成。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 符合易移植操作系统环境（POSIX）标准。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX系统是一种多用户、多任务的分时操作系统。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX系统结构分为两大部分：操作系统内核和外壳。内核原语可以直接对硬件起作用，使得系统易读、易修改、易移植。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX提供了强大的shell语言（外壳语言）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX采用树状目录结构具有良好的安全性、保密性和可维护性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX提供多种通信机制，如管道、软中断通信等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX采用进程对换的内存管理机制和请求调页的存储管理方式。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 常用的UNIX系统有SUN公司的solaris，IBM公司的AIX，HP公司的HP-UX等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.Linux</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基于Intel硬件、在微型机上运行，类似于Unix的操作系统。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 编写内核效仿Unix，兼容Unix工具与外壳。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 符合POSIX标准，开放源代码。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Linux的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Linux操作系统是自由软件，具有开放性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Linux操作系统支持多用户、多任务。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Linux操作系统能把CPU的性能发挥到极限，具有出色的高速度。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Linux操作系统具有良好地用户界面。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Linux操作系统具有丰富的网路功能。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Linux操作系统采用了许多安全措施，为网络多用户提供了安全保障。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 具有可移植性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 具有标准的兼容性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 八）我国互联网的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; 二、计算机网络的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）计算机网络的定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.三类定义观点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广义、资源共享、用户透明性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 符合网络特征的是资源共享的观点。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.资源共享观点定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; “以能够相互共享资源的方式互联起来的自治计算机系统的集合”，主要表现在以下方面：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 建立计算机网络的主要目的是实现计算机资源的共享、</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 互联计算机是分布在不同地理位置的多台独立的“自治计算机”。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 联网计算机之间的通信必须遵循共同的网络协议。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）计算机网络的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 按网络的覆盖范围可以分为：局域网、城域网、广域网、个人区域网。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 局域网：balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 城域网：balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广域网：balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 个人区域网：balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）计算机网络的拓扑结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.网络拓扑的定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 抽象</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; “点”：工作站、服务器、通信设备等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; “线”：通信介质。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络拓扑结构：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通过网络中节点与通信线路之间的几何关系表示网络结构，反应出网络中各个实体间的结构关系。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.网络拓扑的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 按通信子网中的通信信道类型分为：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广播信道通信子网的拓扑与点到点线路的通信子网。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广播信道通信子网的拓扑结构包括4种：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 总线型、树型、环型、无线与卫星通信。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 点到点线路的通信子网的拓扑结构包括4种：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 星型、环型、树型、网状型。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）星型拓扑</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 结点通过点对点线路与中心结点连接，结构简单、易于实现、便于管理，中心结点是整个网络的可靠性瓶颈。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）环型拓扑</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 结点通过点对点线路连接成闭合环路，结构简单、传输延时确定，但环中每条通信线路都会成为网络可靠性的瓶颈。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）树形拓扑</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 结点按层次进行连接，是星型拓扑的扩展，适用于汇聚数据的应用需求。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）网状拓扑</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 结点之间的连接是任意的，主要优点是可靠性高，目前广域网主要用网状拓扑构型。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）描述计算机网络传输特性的参数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.数据传输速率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数据传输速率是每秒钟传输二进制比特数，单位比特/秒，计作bps</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 公式：S=1/T（bps）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; T为发送每个比特所需的时间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数据传输速率与带宽</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 带宽：某个信号具有的频率宽度，单位是赫兹（Hz）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; “带宽”和“速率”几乎成了同义词</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通信信道最大传输速率与信道带宽之间存在着明确的关系</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 奈圭斯特准则</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 香农定理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）奈圭斯特准则</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 描述了有限带宽、无噪声信道的最大数据传输速率与信道带宽的关系。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 二进制数据信号的最大数据传输速率Rmax与通信信道带宽（B=f，单位Hz）的关系为：Rmax=2f</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）香农定理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 描述了有限带宽、有随机热噪声信道时，最大传输速率与信道带宽、信号噪声功率比之间的关系：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Rmax = Blog2( 1 + S / N )</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其中Rmax：数据最大传输速率。单位是bps</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; B：信道带宽，单位是Hz</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S/N：信号与噪声功率比</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 香农定理给出了一个有限带宽、有热噪声信道的最大数据传输速率的极限值</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.误码率的定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 误码率是指二进制码在数据传输系统中被传错的概率，它在数值上近似等于：Pe=Ne/N</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其中N指传输二进制码元总数，Ne为被传错的元数。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于当前使用的电话线路，传输速率在300~2400ps之间时，平均误码率在10^4~10^6之间；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传输速率在4800~9600bps之间时，平均误码率在10^2~10^4之间；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计算机通信的平均误码率要求低于10^(-9)。</p><p>&nbsp; &nbsp; 三、分组交换与包交换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 早期的广域网通信子网中，数据交换分为两类：线性交换、存储转发交换。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）线路交换的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 线路交换的通信过程分为3个阶段：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.线路建立阶段：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 两台主机要传输数据，首先通过子网建立两台主机之间的线路连接。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.数据传输阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 线路连接后，可以实现实时、双向的交换数据。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.线路释放阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数据传输结束后，源点向目的主机发送释放请求，目的同意后逐步释放连接。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 线路交换方式的优点是：通信实时性强，适用于交互式会话类通信。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 线路交换方式的缺点是：对突发性通信不适应，系统效率低，同时不具备数据存储能力和差错控制能力，不能平滑通信量，也无法发现和纠正传输过程中发送的差错。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）存储转发交换的特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.发送的数据中包含目的地址、源地址与控制信息，按一定的格式组成一个数据单元；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.通信子网中的节点是通信控制处理剂，负责完成数据单元的接收、差错校验、存储、路由选择和转发功能。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储转发交换方式可以分为两类：报文交换和报文分组交换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 报文交换中不控制数据的长度，在发送数据时，只把数据当作一个逻辑单元，在数据中加上目的地址、源地址与控制信息后，按一定格式打包后组成一个报文。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分组交换则限制数组的最大长度，源节点需要将一个长报文分成多个分组，由目的结点将多个分组按顺序重新组织成报文。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储转发交换方式，它克服了电路交换方式的缺点，具有明显的优点。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通信子网的路由器可以存储分组，因此多个分组可以共享通信信道，线路利用率高。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器具有路由选择功能，可以动态选择分组通过通信子网的最佳路径，同时可以平滑通信量，提高系统的效率。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分组在通过通信子网的每个路由时，都需要进行差错检查和纠错处理，因此可以减少传输错误，提供系统的可靠性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器可以对不同通信速率的线路进行速率转换，也可以对不同的数据代码格式进行转换。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）数据报方式与虚电路方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.数据报方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 即分组存储转发的一种形式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 同一报文的不同分组可以经过不同的传输路径通过通信子网；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 同一报文的不同分组到达目的节点时可能出现乱序、重复与丢失现象；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每个报文在传输过程中都必须带有目的地址与源地址；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数据报方式的传输延迟较大，适用于突发性通信、不适合于长报文、会话式通信。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.虚电路方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 虚电路方式视图将数据报和电路交换方式结合起来，发挥其各自的优点，以达到最佳的数据交换效果。主要特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每次传输分组之前，在源节点与目的结点之间建立一条逻辑连接；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一次通信的所有分组都通过虚电路顺序传输，分组中不必携带目的地址、源地址等信息，不会出现乱序、重复和丢失现象</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分组通过虚电路上的每个结点只需进行差错检测，不许进行路由选择</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通信子网中的每个结点可以与任何结点建立多条虚电路连接</p><p>&nbsp; &nbsp; 四、网络体系结构与网络协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）网络体系结构的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络协议的定义：为网络数据交换而定义的规则、约定与标准。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络协议三个要素：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 语法：用户数据与控制信息的结构和格式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 语义：需要发出何种控制信息，以及完成的动作与做出的响应</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 时序：对事件实现顺序的详细说明</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络层次模型和各层协议的集合定义为网络体系结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计算机网络体系结构采用层次结构，好处是：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 各层之间是独立的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设计灵活</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 结构上可分割开</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 易于实现和维护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 能促进标准化工作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第一个计算机网络体系结构：IBM公司的SNA</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）ISO/OSI参考模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.OSI参考模型的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由ISO定义开放系统互联（OSI）模型定义了网络互联的七层框架，OSI定义了各层提供的服务，服务和实现无关。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分层的体系结构、三级抽象：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第一级抽象：体系结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第二级抽象：服务定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第三级抽象：协议规格说明</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OSI/RM并不是一个标准，而只是一个概念性的框架</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.ISO/OSI参考模型结构和各层功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OSI参考模型结构的划分基本原则：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络中各结点都具有相同的层次；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不同结点的同等层具有相同的功能；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 同一结点内相邻层之间通过接口通信；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每层可以使用下层提供的服务，并向其上层提供服务；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不同结点的同等层通过协议来实现对等层之间的通信。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）物理层（Physical layer）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 利用物理传输介质为数据连链路层提供物理连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 透明地传送比特流</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）数据链路层（Data link layer）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在通信的实体之间建立数据链路连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传送以“帧”为单位的数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 采用差错控制、流量控制方法，使有差错的物理线路变成无差错的数据链路</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）网络层（Network layer）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通过路由算法，为分组通过通信子网选择一条最佳路径</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络层要实现路由选择、拥塞控制与网络互连等功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）传输层（Transport layer）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 向用户提供可靠的端到端（End-to-End）服务，透明地传送报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 向高层屏蔽了下层数据通信的细节</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计算机通信体系结构中最关键的一层</p><p><br/></p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）会话层（Session layer）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组织两个会话进程之间的通信，并管理数据的交换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 建立传输错纠正与保证数据完整性的控制机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6）表示层（Presentation layer）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理在两个通信系统中交换信息的表示方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数据格式变换、数据加密与解密、数据压缩与恢复等功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7）应用层（Application layer）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为应用程序提供了网络服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 应用层需要识别并保证通信对方的可用性，使得协同工作的应用程序之间的同步</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 建立传输错误纠正与保证数据完整性的控制机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）TCP/IP参考模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.TCP/IP参考模型与协议的发展过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP/IP——Transmission Control Protocol/Internet Protocol，传输控制协议/互联网协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 最早在ARPANET中使用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP/IP特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 开放的协议标准，可以免费使用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 独立于特定的网络硬件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 统一的网络地址分配方案</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 标准化的高层协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.TCP/IP参考模型与层次结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP/IP的主机-网络层实现了OSI模型中物理和链路层的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP/IP的互联层功能主要体现在3个方面：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理来自传输层的分组发送请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理接受的数据报</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理互联的路径、流控与拥塞问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要协议：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP、ICMP、IGMP、ARP、RARP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传输层实现应用进程间的端到端通信，具有两个协议：TCP和UDP协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）TCP：是一种可靠面向连接的协议，允许将一台主机的字节流无差错地传送到目的主机。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）UDP：不可靠的无连接协议。不要求分组顺序到达目的地。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 应用层的主要协议有：远程登录协议（Telnet），文件传输协议（FTP），简单邮件传输此而已（STMP），域名服务（DNS），路由信息协议（RIP），网络文件协议（NFS），超文本传输协议（HTTP）等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.OSI与TCP/IP参考模型比较</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）共同点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 层次结构的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传输层功能相似</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）OSI参考模型的主要缺陷</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 模型的层次数量与内容不是最佳的选择</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 把“服务”与“协议”的定义结合起来使得模型变得很复杂，寻址、流量控制与差错控制在每一层重复出现，效率低</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 受到通信思想的支配，不适合计算机与软件的工作方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）TCP/IP参考模型主要缺陷:</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在服务、接口与协议的区别上不清楚</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在某些层次的划分上不够合理</p><p>&nbsp; &nbsp; 五、互联网应用的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）基于WEB应用的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WEB技术的出现使互联网从最初的主要由计算机专家和大学生使用，变为一种广泛使用的信息交流工具，使得网站的数量和网路的通信量呈指数增长，已经广泛用于电子政务、电子商务、远程教育与信息服务等领域，并有继续扩大的趋势。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）搜索引擎技术发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 搜索引擎是运行在WEB上的应用系统软件，是对网络上大量资源建立索引并提供检索服务的应用软件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）博客技术的应用&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 博客是基于互联网的数字广播技术之一。balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）博客技术的应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五）网络电视的应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络电视（IPTV）通过宽带IP网络传输，可以实现与用户的互动点播，同时能够方便地将传统电视与WWW、E-MAIL等互联网结合起来。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 六）P2P技术的应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.P2P网络的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 是信息达到最大化为目的而设计的“非集中式”的网络结点之间的结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不依赖与互联网的DNS，并具有使用网络拓扑动态变化的独立自制系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可以与网络中已有的“集中式”共享网络资源的结构共存于互补</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P2P网络中的每一台计算机既可以作为网络服务的使用者，又可以作为网络服务的提供者</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.典型的P2P应用：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p><br/></p><p><strong><span style="font-size: 18px;">第2章 局域网技术</span></strong></p><p>&nbsp; &nbsp; 学习目标</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一、了解以太网与城域网的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二、掌握共享式以太网技术特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三、掌握告诉局域网的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四、掌握交换式局域网与虚拟局域网的技术特点与原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五、掌握无线局域网工作原理</p><p>&nbsp; &nbsp; 一、局域网与城域网的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）决定局域网与城域网的三要素：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络拓扑、传输介质与介质访问</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）局域网网络拓扑结构类型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 局域网覆盖范围是“有限地址范围”，所以基本通信机制与广域网不同，从存储转发方式改变为共享介质交换方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 局域网网络拓扑主要为：总线型、环型、星型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 局域网传输介质主要为：双绞线、同轴电缆与光纤</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.总线型拓扑</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 总线型局域网的介质访问控制方法采用“共享介质”方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 所有结点都通过网卡连接到公共传输介质总线上</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 总线通常采用双绞线或同轴电缆作为传输介质</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 所有结点可以通过总线发送或接受数据，但在同一段时间内只允许一个结点通过总线发送数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可能出现冲突而造成传输失败</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 结构简单、容易实现、易于扩展，可靠性较好</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不易管理，故障诊断和隔离比较困难</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.环型拓扑</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 环型拓扑是共享介质局域网的主要拓扑结构之一，环型拓扑结构中，节点之间通过网卡利用点-点线路连接构成闭合的环型，数据在环中按一个方向绕环逐站传输，通常采用令牌环控制方式实现介质访问控制。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要优点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 初始安装比较容易，传输线路较短</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 故障诊断定位比较准确</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 适用于光纤连接，例如FDDI</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要缺点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可靠性较差</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 重新配置较为困难</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）传输介质类型与介质访问控制方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 局域网的传输介质类型常用的有同轴电缆、双绞线、光缆、无线信道</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE802.2标准定义的共享介质局域网有三类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 带有冲突检测的载波侦听多路访问（CSMA/CD）的总线型局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 令牌总线（Token Bus）方法的总线型局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 令牌环（Token Ring）方法的环型局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）IEEE 802参考模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802参考模型研究重点是OSI参考模型中的数据链路层与物理层</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.IEEE 802标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802参考模型将数据链路层划分为两个子层：逻辑链路控制子层（LLC）与介质访问控制子层（MAC），不同局域网在MAC子层和物理层可以采用不同的协议，但在LLC子层必须采用相同协议。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.IEEE 802标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802标准主要有四个：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802.3标准：定义CSMA/CD总线介质访问MAC子层与物理层标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802.11标准：定义无线局域网介质访问MAC子层与物理层标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802.15标准：定义近距离个人无线网络介质访问MAC子层与物理层标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IEEE 802.16标准：定义快带无线局域网介质访问MAC子层与物理层标准</p><p>&nbsp; &nbsp; 二、共享式以太网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）Ethernet技术的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1976年7月，Bob在ALOHA网络的基础山，提出总线型局域网的设计思想，并提出冲突检测、载波侦听与随机后退延迟算法，将这种局域网命令为以太网（Ethernet）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 以太网的核心技术是：介质访问控制方法CSMA/CD</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这种方法解决了多结点共享公用总线的问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 早期以太网的传输介质是同轴电缆，后用双绞线，再后来用光纤</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）Ethernet工作过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.发送流程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 载波侦听过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 冲突检测方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 发现冲突、停止发送</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 随机延迟重发</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 载波侦听过程：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 发送数据前侦听总线是否空闲，如果线上已有数据在传输，总线电平将按曼切斯特编码规律出现跳变，则可判断此时“线路忙”</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 冲突检测方法：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 载波侦听不能完全消除冲突，在节点A发送数据到结点B时，数据传输时需要时间的，在此过程中如果结点B也发送数据，则可能发生冲突</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 以太网标准规定冲突窗口长度为51.2us，以太网数据传输速率为10Mbps，冲突窗口51.2us可以发送64B的数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 发现冲突、停止发送</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果检测到冲突，发送结点要进停止发送数据、随机延迟后重发数据，随机延迟重发的第一步是发送“冲突加强信号”，目的是让网中的所有结点能检测出冲突。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 随机延迟重发</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 最大重发次数为16次，如果超过16，则认为线路故障，进入“冲突过多”的结束状态。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CSMA/CD后退延迟算法：截止二进制指数后退延迟</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; （TBEB）：r=2^k*R*a</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其中r为重新发送所需的后退延迟时间：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a为冲突窗口值</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; R为随机数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; K=min[重传次数n, 10]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.Ethernet接收流程分析</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第一步：判断接收帧是否小于最小长度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第二步：判断目的地址是否自己可以接收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第三步：CRC校验</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC校验正确，进行帧长度检测，如果长度不对，报告“帧长度错”，长度正确，数据交给LLC子层，报告“成功接收”</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC校验错误，判断该帧是否8的整数倍。若是，则报告“帧校验错”，若否，则报告“帧比特错”</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.Ethernet帧结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 前导码与帧定界符：用于接收同步阶段，比特序列101010...11，不计入帧头长度。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目的地址和源地址：目的地址第一位为0表示单播，为1表示多播，全1为广播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 类型：表示网络层使用的协议类型，如0x0800表示IP，0x8137表示IPX</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数据字段：46-1500B，所以帧长度范围为64-1518B</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 帧校验：多项式为 G(x)=x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+1</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.Ethernet实现方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从现实的角度来看，构成以太网网络连接的设备包括网卡、收发器和收发器电缆</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从功能角度来看，包括发送与接收信号的收发器、曼切斯特编码器与解码器、以太网数据链路控制、帧装配及主机的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从层次的角度来看，这些功能覆盖了IEEE 802.3标准的MAC子层与物理层</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.Ethernet物理地</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 物理地址按照48位编码（EUI-48），计作12个十六进制，两两一组，“-”分割，前三组（字节）为公司表示，后三组生产商自行分配，例如006008为3com公司的一个机构唯一标识符（OUI），生产的某一网卡地址为00-A6-38，则网卡的物理地址为00-60-08-00-A6-38</p><p>&nbsp; &nbsp; 三、高速局域网的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.高速局域网的发展</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 局域网的规模不断的扩大，网络通信负荷加重时，冲突和重发现象将大量发生，网络效率急剧下降，网络传输延迟增长，网络服务质量下降</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了克服传统网络规模与性能之间的矛盾，高速局域网的解决方案：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）提高带宽</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）将大型局域网划分成多个用网桥或路由器互联的子网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）将共享介质方式改为交换方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.Fast Ethernet - 802.3u标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有关传输介质的标准：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 100BASE-TX：使用2对5类非屏蔽双绞线或2对1类屏蔽双绞线，1对用于发送，1对用于接收，支持全双工</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 100BASE-T4：使用4对3类非屏蔽双绞线，3对用于传输，一对用于检测，不支持全双工</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 100BASE-FX：支持2芯的单模或多模光纤，传输距离达2km，支持全双工</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.Gigabit Ethernet - 802.3z标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有关传输介质的标准：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1000BASE-T：使用5类非屏蔽双绞线，长度可达100m</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1000BASE-CX：使用5类屏蔽双绞线，长度可达25m</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1000BASE-LX：使用波长1300nm的单模光纤，长度可达3000m</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1000BASE-SX：使用波长850nm的多模光纤，长度可达300~550m</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.10 Gigabit Ethernet - 802.3ae标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 与10M/100M/1Gbps以太网的帧格式相同</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 保持802.3对以太网最小和最大帧长度的规定</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不再使用双绞线，而使用光纤作为传输介质</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 只有全双工工作方式，传输距离不受冲突检测的限制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 物理层标准：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 局域网物理层（LAN PHY）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广域网物理层（WAN PHY）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.40/100 Gigabit Ethernet</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 40Gbps网络使用波分复用技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 100 Gigabit Ethernet物理接口类型：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 10X10Gbps短距离互联的LAN接口技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4X25Gbps中短距离互联的LAN接口技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 10m的铜缆接口和1m的系统背板互联技术</p><p>&nbsp; &nbsp; 四、交换式局域网与虚拟局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）交换式局域网的基本结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.交换机的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 典型的交换式局域网是交换式以太网，它的核心设备是以太网交换机</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 共享端口-&gt;专用端口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 端口之间可有多个并发连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.交换机的技术特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 低交换传输延迟</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从传输延迟时间的量级来看，局域网交换机延迟为几十us，网桥为几百us，路由器为几千us。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 高传输带宽</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于10Mbps的端口，半双工端口带宽为10Mbps，而全双工端口带宽为20Mbps；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于100Mbps的端口，半双工端口带宽为100Mbps，而全双工端口带宽为200Mbps。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 允许不同速率的端口共存</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 采用了自动侦测（Autosenese）技术时，交换机端口可以同时支持10Mbps/100Mbos、全双工/半双工两种工作方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持虚拟局域网服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）局域网交换机的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.交换机的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.端口号/MAC地址映射表 &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 交换机利用“端口/MAC地址映射表”进行数据交换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 交换机的“地址学习”是通过读取帧的源地址并记录帧进入交换机的端口，如果端口与地址的对应关系不存在则加入映射表中，如果已经存在则更新表中对应关系</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每次更新或新加入的映射表表项，会被赋予一个计时器（生命），计时器到达时没有得到该表项的对应关系，则删除</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.交换机的帧转发方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 直接交换方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 交换机只要接受一个帧并检测到目的地址，就立即转发该帧。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点是交换延迟短，缺点是缺乏差错检测能力你，不支持不容速率端口之间的帧转发。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储转发交换方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 交换机完整接受一个帧并进行差错检测，然后转发</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点是具有差错检测能力，支持不同速率端口之间的帧转发，缺点是交换延迟增大</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 改进的直接交换方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 接收到一个帧的前64自节后，检测帧头字段是否正确，如果正确则转发。这种方法对于短的Ethernet帧，交换延迟与直接交换方式相近；对于长的Ethernet帧，由于它只检测的地址字段与控制字段，因此交换延迟将会减少。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）虚拟局域网（WLAN）的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.虚拟网络的概念：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 虚拟网络建立在交换式技术的基础上，如果网络中的结点按工作性质与需要换分为若干个“逻辑工作组”，则一个逻辑工作组就是一个虚拟网络。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 虚拟网络以软件方式实现逻辑工作组的换分与管理，工作组的结点不受物理位置的限制（相同工作组的结点不一定在相同的物理网段，只要能够通过交换机互联）。从一个工作组到另一个工作组时，只要通过软件设定，无需改变结点在网络中的物理位置。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.虚拟局域网的组网方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）用交换机端口定义虚拟局域网：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 虚拟局域网从逻辑上将交换机的端口划分为不同的虚拟子网，各个虚拟子网相对独立</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不允许不同虚拟网包含相同的物理网段或端口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：当结点转移到另一个端口时，管理者必须重新配置虚拟局域网的成员。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）用MAC地址定义虚拟局域网：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由于MAC地址是与硬件相关的地址，结点将自动保持原来的虚拟局域网成员划分，因此允许结点移动到其他物理网段，是一种基于用户的虚拟局域网。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 建立局域网阶段需要将用用户配置到虚拟局域网中。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：在大规模的网络环境中，人工完成这么多用户的初始配置非常麻烦。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）用网络层地址定义虚拟局域网：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用结点的网络层地址来定义虚拟局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：用户可以按照协议类型来组建虚拟局域网，用利于组建基于服务或应用的虚拟局域网；用户可以随意移动结点，而无需重新配置网络地址，对基于TCP/IP的用户特别有利。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：性能比较差，因为检查网络层地址比检查MAC地址更加费时。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）基于广播组的虚拟局域网：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当有广播包要发送到多个目的结点时，就需要动态建立虚拟局域网的代理，代理通过广播信息通知各个结点，如果结点响应信息就可以加入广播组，并成为基于广播组的虚拟局域网成员。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：可以根据服务灵活地组建，并可以跨越与广域网互联。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.虚拟局域网的优点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）方便网络用户管理，减少网络管理开销</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）提供更好的安全性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）改善网路服务质量</p><p>&nbsp; &nbsp; 五、无线局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）无线局域网的应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.传统局域网的扩充</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.建筑物之间的互联</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.漫游访问</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.特殊无线网络结构（如无线自组网）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）无线局域网的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.红外无线局域网（IR）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 按视距方式传输，发送点与接收点中间必须无阻挡</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 红外无线局域网的数据传输技术：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 定向光束红外传输</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 全方位红外传输——需要在天花板安装一个基站</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 漫反射红外传输</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：通信安全性好，抗干扰性强，系统安装简单，易于管理，但是传输距离受一定限制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.扩频无线局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 扩频通信是军事电子对抗中经常使用的一种方法，它是将数据基带信号频谱扩展几倍或几十倍，以牺牲通信的频带宽度为代价，来提高系统的抗干扰性与安全性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 扩频技术主要有2种：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）跳频扩频通信</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将利用的频带分为多个子频带，子频带称为信道。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每个信道带宽相同，中心频率有伪随机数发生器的随机数确定，变化频率叫跳跃系列。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 发送端和接收端采用相同的跳跃系列。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）直接序列扩频通信</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将发送数据经过伪随机数发生器产生的伪随机码进行异或操作，再将异或操作的结果调制后发送</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 所有接受结点使用相同频段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 发送端与接收端使用相同的伪随机码</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.窄带微波无线局域网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 窄带微波是指使用微波无线电频带进行数据传输，其带宽刚好能容纳信号。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）无线局域网标准IEEE 802.11</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.IEEE 802.11协议结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该协议采用的是层次模型结构，其中物理层定义了红外、跳频扩频与直接序列扩频的数据传输标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAC层主要功能是对无线环境的访问控制，可以在多个接入点上提供漫游支持，同时提供数据验证与保密服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAC层支持无争用服务与争用服务两种访问方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 无争用服务：系统中存在中心控制结点。中心控制结点具有点协调功能（PCF）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 争用服务：类似以太网的随机争用访问控制方式，成为分布协调功能（DCF）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAC层采用冲突避免的方法是CSMA/CA（载波侦听多路访问/冲突避免）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.IEEE 802.11的MAC层工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CSMA/CA方法要求每个发送结点在发送帧之前先侦听信道。如果信道空闲，结点可以发送帧，在发送完一帧后，必须再等待一个短的时间间隔，检查接收站是否发回帧的确认ACK。如果接收到确认，则说明此次发送没有出现冲突，发送成功；如果在规定时间内没接收到ACK，表明出现冲突，发送失败，并重发该帧。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.IEEE 802.11协议的帧结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.IEEE 802.11网络的结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 端站STA</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 接入点AP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 接入控制器AC</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AAA服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.IEEE 802.11协议族组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 标准名称 &nbsp; &nbsp;标准描述</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 802.11a &nbsp; &nbsp; 5G Hz波段，速率54Mbps</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 802.11b &nbsp; &nbsp; 2.4G Hz波段，速率11Mbps</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 802.11g &nbsp; &nbsp; 2.4G Hz波段，速率54Mbps</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 802.11n &nbsp; &nbsp; 5G Hz波段，速率100Mbps</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 802.11i &nbsp; &nbsp; 增强无线通信安全的规范</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 802.11e &nbsp; &nbsp; 服务质量QOS</p><p><br/></p><p><strong><span style="font-size: 18px;">第3章 Internet基础</span></strong></p><p>&nbsp; &nbsp; 学习目标</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一、了解Internet的构成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二、掌握Internet不同接入方式的原理和特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三、掌握IP服务的特点和IP层的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四、掌握IP地址、IP数据包的基本知识</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五、掌握基本的路由选择算法并运用算法进行计算</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 六、掌握RIP和OSPF协议的基本原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 七、了解组播的概念和特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 八、掌握组播的相关协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 九、了解IPv6协议的基本特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 十、掌握IPV6地址表示和数据报格式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 十一、掌握TCP和UDP协议的特点和提供的服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 十二、掌握TCP的可靠性和流量控制的实现fagnfa</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 十三、掌握NAT技术的基本工作原理和技术特点</p><p>&nbsp; &nbsp; 一、Internet的构成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 从设计者角度看：Internet是计算机互联网的一个实例；从使用者角度看：Internet是一个信息资源网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）Internet的主要组成部分</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.通信线路：Internet的基础设施，包括有线线路和无线线路</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.路由器：网络互联的桥梁。主要任务是数据从一个网络到另一个网络时，路由器为它选择最佳路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.主机：是信息资源和服务的载体。所有连接Internet的计算机统称为主机</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.信息资源：信息资源是用户最关注的问题之一。用户方便、快捷获取资源一直是Internet的研究方向。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）Internet的接入方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.通过电话网接入</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.利用ADSL（非对称数字用户线路）接入</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 下行数据传输速率远远大于上行数据传输速率（非对称）。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.使用HFC（有线电视网）接入</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HFC采用非对称数据传输速率。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.通过数据通信线路接入 &nbsp; &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 种类有：DOM，ATM，帧中继等，用户可以租用。</p><p>&nbsp; &nbsp; 二、IP协议与IP层服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）IP互联网的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Internet是将提供不同服务的、使用不同技术的、具有不同功能的网络互联起来形成的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP协议精确定义了IP数组格式、并且对数据寻址和路由、数据报分片和重组、差错控制和处理等作出了具体规定。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 工作原理：假设主机A发送数据到主机B</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主机A的应用层形成的数据传输层送互联层处理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 互联层将数据封装成IP数据报，并决定发送给最近的路由器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主机A把IP数据报利用以太网控制传送到路由器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 经由路由器对数据报进行拆封和处理；如果仍需传输，再封装后利用互联层的广域网控制程序传输</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 经由通信子网传输到主机B</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）IP服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 运行IP协议的互联层可为其高层用户提供的服务有三个特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.不可靠的数据投递服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.面向无连接的传输服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.尽最大努力投递服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）IP互联网的特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.IP互联网隐藏了底层物理网络细节，向上为用户提供通用的、一致的网络服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.IP互联网不制定网络互联的拓扑结构、也不要求网络之间全互联</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.IP互联网在物理网络之间转发数，信息可以跨网传输</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.IP互联网平等的对待互联网中的每一个网络</p><p>&nbsp; &nbsp; 三、IP地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）IP地址的作用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 以太网中利用MAC地址（物理地址）标识网络中的一个结点，两个以太网结点需要知道对方的MAC地址才能通信</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 以太网不是唯一的网络，各种网络技术互不相同，它们之间通信是需要解决的问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 统一物理地址的方法不现实。在互联网层将各种物理地址统一必须通过上层软件完成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 屏蔽各种物理地址的差异，使用IP协议规定的地址（IP地址）。IP地址中管理机构统一管理和分配，保证在网络中的每台计算机不会发生冲突</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP地址的作用是标识网络连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; （严格地说，IP地址指定的不是一台计算机，而是计算机到一个网络的连接，例如一台计算机有块网卡，有两条连接，有两个IP地址；或多个IP地址绑定在一条物理连接上）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP地址由32比特的二进制数表示</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）IP地址的层次结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP地址有两层：网络层和主机号</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络号：标识互联网中一个特定的网络；而主机号标识该网络中主机的一个特定连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP地址含有主机的信息和网络的地址信息，所以主机从一个网络移动到另一个网络时，IP地址必须重新分配，否则不能与其他计算机通信</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）IP地址的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; A、B、C、D、E五类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; A类地址的前一个字节表示网络地址，且最前端的1个二进制位固定是0，表示的地址范围是从1.0.0.0~126.255.255.255</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; B类地址的前两个字节表示网络地址，且最前端的2个二进制位固定是10，表示的地址范围是从128.0.0.0~191.255.255.255</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; C类地址的前三个字节表示网络地址，且最前端的3个二进制位是110，表示的地址范围是从192.0.0.0~223.255.255.255</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）IP地址的直观表示法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 点分十进制：32位的二进制，8个一组，形式4组，魅族二进制转换成十进制，计作w.x.y.z的格式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五）特殊的IP地址形式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.网络地址：网络位不变，主机位全0</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.广播地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 直接广播：网络位不变，主机位全1</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有限广播：网络位全1，主机位全1</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.回送地址：127.0.0.1</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.本地地址：即私有地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 六）子网编址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.子网编址的方法 &nbsp;&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 标准的IP地址分为网络号和主机号两部分，为了避免IP地址的浪费，子网编制将IP地址的主机号部分进一步划分成子网部分和主机部分</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在一个IP网络中划分子网使我们能将一个逻辑上单一的大型网络分成若干个小小的网络，即允许将网络划分成许多个部分供内部使用，但是对于外部网络仍像一个网络一样。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 子网编制将IPv4地址分为三部分：网络部分、子网部分和主机部分</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.子网表示法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 子网掩码采用了和IP地址一样的编码方式，用32位二进制数值。其二进制数值必须是连续的1+连续的0组成。其中1位数对应IP地址的网络号部分，0位数对应IP地址的主机号部分。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.子网编址思路：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）你所选的子网掩码将会产生多少个子网？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2的x次方-2（x代表借位部分掩码位，即2进制为1的部分）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）每个子网能有多少主机？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2的y次方-2（y代表主机位，即2进制为0的部分）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）每个子网的广播地址？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广播地址=下个子网号-1</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）每个子网的有效主机分别是？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 忽略子网内全为0和全为1的地址剩下的就是有效主机地址：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 最后有效1个主机地址=下个子网号-2（即广播地址-1）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.可变长子网掩码VLSM子网编址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VLSM（Variable Length Subnet Mask，可变长度子网掩码），是在标准掩码上面再划分的子网的网络号码，无类路由选择网络可以使用VLSM，而有类路由选择网络中不能使用VLSM。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.CIDR（无类域间路由技术）地址规划方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）CIDR的技术特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 表示为“网络前缀+主机号”的二级地址结构。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络前缀相同的连续的IP地址形成了一个CIDR地址块，它是由块起始地址决定的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）CIDR的应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 超网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持路由聚合</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 七）地址解析协议ARP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.ARP协议的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 互联网中高层软件通过IP地址来指定源地址和目的地址，而低层的物理网络通过物理地址发送和接收信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ARP就是以太网中使用的将IP地址映射到物理地址的实现方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.ARP实现中采用的高速缓存技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了避免ARP请求与相应信息的频繁发送与接收对网络产生的影响，每一个主机都设有一个ARP高速缓存（ARP cache）。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.其他提高ARP效率的技术&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; 四、IP数据报</p><p>&nbsp; &nbsp; &nbsp; &nbsp; IP数据报是IP协议使用的数据单元</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）IP数据报的格式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP数据报的格式可以分为报头区和数据区两大部分。其中数据区包括高层需要传输的数据，报头区包含了源IP地址、目的IP地址等控制信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP数据报各字段的功能：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.版本与协议类型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.长度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.服务类型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.生存周期</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.头部校验和</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）IP封装、分片、重组</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP数据报在互联网上传输，可能跨越多个网络，IP数据报最终需要封装成帧进行传输</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器只在内存中保留IP数据报而没有附加帧头信息，只有IP数据报通过一个物理网络时，才会被封装进帧中，接受路由器会解封装帧</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.MTU与分片</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 根据网络使用的技术不同，每种网络都规定了一个帧最多能够携带的数据量，这一限制称为最大传输单元（MYU）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.重组</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在所有段的基础上重新产生原数据报的过程叫重组</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.分片控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在IP数据报报头中，标识、标志和片偏移三个字段与控制分片和重组有关</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）标识：发送方将一个惟一的标识放进每个输出数据报的标识域中，接收方就可利用收到的分片的标识数和IP源地址来确定该分片属于哪个数据报，以便于数据报重组</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）标志：标识该数据是否已经分片，是否是最后一个分片</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）片偏移：用来指出本片数据在初始IP数据区中的位置，以8字节为单位。目的是提供重组的分片顺序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）IP数据报选项</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP数据报选项主要目的：控制和测试</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP数据报选项：选项码、长度、选项数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 选项数据：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.源路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP数据报穿越互联网所经过的路径由源主机指定，分为严格源路由选项和松散路由选项</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.记录路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 记录IP数据报经过路径上各个路由器的IP地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.时间戳</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 经过每个路由器时的当地时间</p><p>&nbsp; &nbsp; 五、差错与控制报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; IP层使用的控制与差错协议是ICMP（互联网控制报文协议）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; ICMP报文是作为IP数据报的数据部分而传输的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; ICMP协议的两种典型应用：ping和traceroute</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）ICMP差错控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ICMP最基本的功能是提供差错报告</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每一个ICMP报文的产生总是对应与一个数据报，要么这个数据报遇到了问题，要么这个数据报携带者一个ICMP请求报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一个路由器从输入的数据报的头部中取出源地址，然后放到携带ICMP报文的数据报的头部中的目的地域中</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ICMP差错报文的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.携带ICMP报文的数据报并没有什么特别优先权——它们像其他数据报一样转发</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.ICMP差错报告数据中包含故障IP数据报报头之外，还包含IP数据报数据区的前64比特数，目的是了解高层协议信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.ICMP差错报告时伴随着抛弃出错IP数据报而产生的，一旦发现传输错误，先把出错报文抛弃</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ICMP出错报告种类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.目的地不可达报告</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.超时报告（存活周期TTL）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.参数出错报告</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用ICMP报文测试可达性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ping程序可以测试一个给定的目的地是否可达</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它发送一个包含ICMP回应请求的报文给目的地，然后等待一段很短的时间如果没有收到应答，则重新传送请求如果重传的仍没有收到应答（或收到一个ICMP目的不可达报文），ping声称该远程机器为不可达</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用ICMP跟踪路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）ICMP控制报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP层控制主要包括：拥塞控制、路由控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.拥塞控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器的处理速度太慢，不能完成IP数据报排队等日常工作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器传入数据速率大于传出数据速率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 最终没有足够的缓冲区存放大量涌入的IP数据报</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 解决方案：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 利用ICMP源抑制报文抑制源主机发送IP数据报的速率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.拥塞控制与源抑制报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ICMP源值报文的方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果路由器的某输出队列已满，那么缓冲区空出之前，该队列将抛弃新来的IP数据报，并向源主机发送ICMP源和抑制报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为路由器的输出队列设置一个阈值，当队列的数据报超过阈值后，如果再有新的数据报到来，向源主机发送ICMP源抑制报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.路由控制与重定向报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）ICMP控制报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ICMP控制报文包括源抑制报文和重定向报文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 源抑制报文——用于拥塞控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 重定向报文——用于路径控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）ICMP请求/应答报文对</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ICMP请求/应答报文对可以获取的信息：回应请求/应答</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.回应请求与应答</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 回应请求/应答ICMP报文对用于测试目的主机或路由器的可达性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.时戳请求与应答</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 同步时钟</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.掩码请求与应答</p><p>&nbsp; &nbsp; 六、路由器与路由选择</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 在IP互联网中，路由选择（routing）是指选择一条路径发送IP数据报的过程，而进行这种路由选择的设备叫路由器（Router）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）表驱动IP选路</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在需要路由选择的设备中保存一张IP路由表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP路由表村塾着有关可能的目的地址及怎样到达目的地址的信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在转发IP数据报时，查询IP路由表，决定把数据报发往何处</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由表中的目的地址如何表示？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）大型互联网（如因特网）中可能存在成千上万台主机</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）路由表中不可能包括所有目的主机的地址信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 内存资源占用巨大</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由表搜索时间很长</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）隐藏主机信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP地址：网络号（netid）和主机号（hostid）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP路由表中保存相关的目的网络信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.标准路由选择算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）下一站选路的基本思想</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由表仅指定从该路由器到目的路径上的下一步，而该路由器并不知道到达目的完整路径</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）标准的IP路由表包含许多（N，R）对序偶</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; N：目的网络的IP地址（使用目的主机IP地址的较少）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; R：到N路径上的“下一个”路由器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.子网选路——标准路由选择算法的扩充</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.路由表中的特殊路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）默认路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）特定主机路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.统一的路由选择算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）特定主机路由表项</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）默认路由表项</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）标准网络路由表项</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）子网路由表项</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）路由表的建立与更新</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.静态路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 什么是静态路由？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 静态路由是由人工建立和管理的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 静态路由不会发生变化</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 静态路由必须手工更新以后反应到互联网拓扑结构或连接方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 静态路由的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优势</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 安全可靠、简单直观，避免了动态路由选择的开销</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 适用环境</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不太复杂的互联网结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 劣势</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不适用于复杂的互联网结构：建立和维护工作量大，容易出现路由环；互联网出现故障，静态路由不会自动做出更改</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.动态路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 动态路由可以通过自身学习，自动修改和刷新路由表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 动态路由要求路由器之间不断的交换路由信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优势：更多的自主性和灵活性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 适用环境：拓扑结构复杂、网络规模庞大的互联网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 自动排除错误路径</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 自动选择性能更优的路径</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 适用动态路由的基本条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器运行相同的路由选择协议，执行相同的路由选择算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广泛采用的路由选择协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由信息协议RIP：利用向量-距离算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 开放式最短路径优先协议OSPF：利用链路-状态算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由收敛（convergence）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 含义：互联网中的所有路由器都运行着相同的。精确的、足以反映当前互联网拓扑结构的路由信息。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 快速收敛是路由选择协议最希望具有的特征</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）RIP协议与向量-距离算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.向量-距离路由算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器周期性地向其相邻路由器广播自己知道的路由信息，用于通知相邻路由器自己可以到达的网络以及到达该网络的距离</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 相邻路由器可以根据收到的路由信息修改和刷新自己的路由表更改</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 向量-距离路由算法执行过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）路由器启动时初始化自己的路由表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）各路由器周期性地向其相邻的路由器广播自己的路由表信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）路由器收到其他路由器广播的路由信息后，刷新自己的路由表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 向量-距离路由算法更新过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 收到对方（发送路由表的路由器）的路由表后是否学习总体原则</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 比我原有的表目好的判断原则：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对方的距离+1&lt;本身原有的距离</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 学习的计算：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 距离+1 &nbsp; &nbsp;路径为对方</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;向量-距离路由算法的特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）优点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 算法简单、易于实现</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）缺点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 慢收敛问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 需要交换的信息量巨大</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）适用环境</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由变化不剧烈的中小型互联网&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.RIP协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）RIP协议是向量-距离选择算法在局域网上的直接实现</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）RIP协议规定了路由器之间交换路由信息的时间、交换信息的格式、错误的处理等内容</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 相邻的路由器之间每30s交换一次路由信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由信息来源与本地路由表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器到达目的网络的距离以“跳数”计算</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RIP协议的实现问题：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 相同开销路由：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 先见为主</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 过时路由：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用计时器超时时间一般为180s，相当于6个RIP刷新周期</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 慢收敛问题与对策</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 慢收敛问题的产生原因</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 慢收敛问题的解决对策</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）限制路径最大“距离”对策</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RIP协议规定，当路由表目“距离”等于或大于16为不可达路由，从路由表中删除</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）水平分割对策</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由器从某个接口发送路由刷新报文时，不能包含该接口原有获取的信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）保持对策</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RIP协议规定在得知目的网络不可能到达后的一定时间内（60秒），不接受关于此网路的任何可达信息。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）带触发刷新的毒性逆转对策</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当某路径崩溃后，最早广播比路由的路由器将原路由保留在更新报文中，并距离置位无限长，同时使用触发刷新技术，立即广播，不等待更新周期到来</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.RIP协议与子网路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）RFC颁布第一个版本之前，RIP协议已经被写成各种程序并被广泛使用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要原因：配置和部署简单</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）RIP Version 1</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用标准的IP地址，不支持子网路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）RIP Version 2</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持子网路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持身份验证</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持多播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）OSPF协议与链路-状态算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 链路-状态（L-S）路由选择算法的基本思想：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 互联网上的每个路由器周期性地向其他路由器广播自己与相邻路由器的连接关系</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 互联网上的每个路由器利用收到的路由信息画出一张互联网拓扑结构图</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 利用画出的拓扑图和最短路径优先算法，计算自己到达各个网络的最短路径</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OSPF路由选择协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OSPF路由选择协议以链路-状态算法为基础</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要优势</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 收敛速度快</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 支持服务类型选路</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 提供负载均衡和身份认证</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用环境</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 规模庞大、环境复杂的互联网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要缺陷</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 要求较高的路由器处理能力</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一定的带宽需求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要解决方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分层（区域）--骨干区域为area0，区域标识按IP地址格式指派路由器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 向量-距离算法与链路-状态算法的原理性差异</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五）部署和选择路由协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.静态路由</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 适用于小型、单路径、静态IP互联网环境</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传输只能通过一条路径进行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.RIP路由协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.OSPF路由协议</p><p>&nbsp; &nbsp; 七、组播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）单播、广播与组播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1。单播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 单播的特点是一对一地传输数据，数据发送方发出的信息包只能传送到一个接收方</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 若发送方同时给多个接收方传输相同的数据包，发送方必须发送多份的相同数据包</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当客户机数量大、单机流量包也大时，服务器将不堪重负，发生延迟长、网络拥塞现象</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.广播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广播的特点是路由器和交换机将同一个信息包无条件地发往每一条分支路径，由接收方自行决定接下来还是将其丢弃</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务器不用向每个用户单独发送数据，流量负载低，如有线电视网</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 但这种方式对于路由器而言，有多少分支就要重复发送多少次，而不论这些主机是否乐于接受该数据包，无法针对每个用户的要求和时间及时提供个性化服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.组播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组播是一种允许一个或者多个发送方发送单一数据包到多个接收方的网络传输方式，它采用组播地址，只向需要数据包的主机和网络发送数据包</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 采用这种方式，需要相同数据流的客户端可以加入相同的组，共享一条数据流，节省了服务器的负载，提高了网络传输速率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 与单播协议相比，组播协议可根据接收者的需要对数据流进行复制转发，服务器端的服务总带宽不受客户机接入带宽的限制，单组播协议没有纠错机制，发生丢包、错包后难以弥补</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP组播的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用组地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 动态的组地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 底层硬件支持</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.单播、广播、组播比较</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）单播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通信模式：一对一</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目的地址：单播地址（A、B、C类地址）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务器及时响应客户机的请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务器针对每个客户不同的请求发送不同的数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：在客户数量大、每个客户机流量大的流媒体应用中服务器不堪重负</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 应用举例：网络浏览</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）广播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通信模式：一对所有</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目的地址：广播地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）组播</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通信模式：一对一组</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目的地址：组播地址（D类地址）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）组播技术基础</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.组播的相关协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 根据协议的作用范围，组播协议分为组播管理协议和组播路由协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组播管理协议是主机和路由器之间的协议，又包括Internet组管理协议（IGMP）和Ciso专用的组管理协议（CGMP）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组管理协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IGMP协议运行于主机和主机直接连接的组播路由器之间，其功能是：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一方面通过协议，主机通知本地路由器希望加入并接收某个特定组播组的消息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 另一方面，...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IGMP协议的发展经过了IGMPv1、IGMPv2、IGMPv3、IGMPv4.目前通用的是IGMPv3.</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组播路由协议是路由器与路由器之间的协议，又分为域内组播路由协议以及域间组播路由协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IP组播路由协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组播路由协议是IP组播协议体系中最核心的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组播路由由源地址、组地址、入接口列表和出接口列表4部分组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组播路由协议分为域内组播路由协议以及域间组播路由协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 域内组播路由协议又分为密集模型（适用于带宽充裕的网络）和稀疏模型（适用于带宽未必有充裕的网络）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络上使用较多的域内组播协议有DVMRP、MOSPF协议和PIM协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于域间组播路由的协议主要有多协议便捷网关协议（MBGP）和组播源发现协议（MSDP）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 各种组播协议都需要获得网络的单播拓扑结构</p><p>&nbsp; &nbsp; 八、IPv6协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）IPv6的局限性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.地址空间的局限性：IP地址空间耗尽制约了互联网的发展，子网划分、无类域间路由（CIDR）等方法虽使IP地址得到有效的利用，但也仅仅是缓解了地址短缺的矛盾</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.IP协议的性能问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.IP协议的安全性问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.自动配置问题：IP协议涉及初没有考虑自动配置问题。后来最优DHCP（动态主机配置协议）在一定程度上解决了地址自动配置问题，但需要对DHCP服务器配置，比较麻烦。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.服务质量（QoS）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）IPv6地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.IPv6的地址表示：128位地址长度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基本表示法：按16位一段，每个位段转换为4位十六进制数，并用冒号隔开。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 零压缩法：在有多个零出现时，用一位0标识一个位段。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果几个连续的段位的值都为0，那么这些零可以简写为::，称为双冒号表示法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在使用零压缩法时，不能把一个位段内部的有效0也压缩掉</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 双冒号在一个地址中只能出现一次</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.IPv6前缀：与无类域间路由类似，IPv6采用前缀表示法形如“地址/前缀长度”。前缀是IPv6的一部分，用来表示路由或子网标识。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.IPv6地址类型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 单播地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 组播地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 任播地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特殊地址：全0地址（地址不存在），回送地址（0::1），IPv4兼容的IPv6地址，映射到IPv4的IPv6等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）IPv6数据报格式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IPv6的数据报由一个IPv6的基本头、多个扩展头和一个高层协议数据单元组成。基本头固定的40字节长度。一些可选的内容放在扩展头部分实现，此种设计方法可提高数据报的处理效率。IPv6数据报格式对IPv4不向下兼容。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.IPv6数据报各域段含义：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 版本：取值为6，意思是IPv6协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通信类型：表示IPv6的数据报类型或优先级，以提供区分服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 流标记</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 载荷长度：有效载荷长度，包含扩展头和高层数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 下一个报头：存在扩展头，该域段的值指明下一个扩展头的类型；如果无扩展头，该域段的值指明高层数据的类型，如TCP、UDP或ICMPv6等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 跳数限制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 源地址：源IPv6</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.IPv6扩展头</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IPv6的基本报头固定40字节长，一些可选头信息由IPv6扩展头实现。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）IPv6数据报</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 扩展头包含的内容</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 逐跳选项头：类型为0</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目的选项头：类型为60</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 路由头：类型43</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分片头：类型44</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 认证头：类型51</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 封装安全有效载荷报头：类型52</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）IPv6地址自动配置</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分为两类：有状态和无状态两种形式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 无状态地址配置：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 128的IPv6地址由64位前缀和64位网络接口标识符组成。如果主机与本地网络的主机通信可以直接通信，主机之间可以利用该地址直接通信；如果与其他网络互联时，主机需要从网络中的路由器中获得该网络使用的网络前缀，然后与64位网络接口标识符结合形成有效的IPv6的地址。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有状态地址配置：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 自动配置需要DHCPv6服务器的支持，主机向DHCPv6服务器发多播“DHCP请求信息”，DHCPv6返回“DHCP应答消息”中将分配的地址返回请求主机，主机利用该地址作为自己的IPv6进行配置。</p><p>&nbsp; &nbsp; 九、TCP与UDP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 可靠性是一个计算机系统的基础，在网络数据传输中用户希望互联网能够提供迅速、准确、可靠的通信功能，保证不发生丢失、重复、错婿等可靠性问题。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 传输层是TCP/IP体系结构中至关重要的一层。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）端对端通信</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP：传输控制协议；UDP：用户数据报协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传输层需要提供从一台主机到另一远程主机的端对端通信控制。传输层利用互联层发送数据，每一传输层都需要封装在一个互联层的数据报中通过互联网，到达目的地后，互联层再将数据提交给传输层。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）传输控制协议TCP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 保证可靠性是传输层的主要责任</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.TCP提供的服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从TCP用户的角度看，TCP可以提供面向连接、可靠的、全双工的数据流传输服务，保证数据在数据连接关闭之前被可靠地投递到目的地</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 面向连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 完全可靠性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 流接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 连接的可靠性与优雅关闭</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.TCP的可靠性实现</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可靠性问题即包括数据丢失后的恢复问题，又包括连接的可靠性建立问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.数据丢失与重发</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 发送方利用重发技术补偿数据报的丢失，需要通信双方协同解决。（确认机制）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP选择重发等待时间具有适应性（如利用KARN算法计算）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.连接的可靠建立与优雅关闭</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为确保连接建立和终止的可靠性，TCP使用了“三次握手”法。简答说在建立和终止过程中，通信双方需要交换3个报文。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.TCP缓冲、流控与窗口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP使用窗口机制进行流量控制，当连接建立时，连接的每一端分配一块缓冲区存储接收的数据，并将缓冲区的尺寸（大小）发送另一端。当数据到达时，接收方发送确认，其中包含自己剩余的缓冲区尺寸。将剩余的缓冲区空间的数量称为窗口。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 窗口和窗口通告可以有效控制TCP的流量，使发送方的数据不会溢出接收方的缓冲空间。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.TCP连接与端口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一个TCP连接的两端称为端口，端口用16位的二进制数表示</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP可利用端口提供多路复用功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）用户数据协议UDP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从用户角度看，UDP虽处于传输层，但UDP提供了面向非连接，不可靠的传输服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UDP面向非连接，它可以将数据直接封装在IP数据报中进行发送。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：运行高效和实现简单</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）端口号的分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目的：区分不同的应用程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 三种端口组：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 熟知（著名）端口：0~1023</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 注册端口：1024~49151</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 动态或私有端口：49152~65535</p><p>&nbsp; &nbsp; 十、NAT的基本工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）为何使用网络地址转换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NAT是为了在现阶段解决IP地址短缺和不足的问题而设计的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 根据NAT技术的分类，主要分为：静态NAT，动态NAT和网络地址端口转换NAPT</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.静态NAT</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.动态NAT</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当NAT地址池中的全局地址被全部占用后，NAT设备将拒绝再来的地址转换申请</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.网络地址端口转化NAPT</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NAPT是目前最常使用的一种NAT类型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 外部网络的主机不能主动访问内部网络中的主机</p><p><br/></p><p><strong><span style="font-size: 18px;">第4章 Internet基本服务</span></strong></p><p>&nbsp; &nbsp; 学习目标</p><p>&nbsp; &nbsp; &nbsp; &nbsp; ...</p><p>&nbsp; &nbsp; 一、应用进程通信模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）客户机/服务器模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.什么是客户机/服务器模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 客户机和服务器分别是指两个应用程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务器处于守候状态，并监视客户机的请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当客户机向服务器发出服务请求时，服务器做出响应</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.客户机与服务器的特性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）服务器程序特性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一种专门用途的、享有特权的应用程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 能够同时处理多个远程客户机的请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在一台共享计算机上运行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 被动的等待客户机的通信请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）客户机程序特性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一个非常普通的应用程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一个用户服务可以随即开始和停止</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在用户计算机上本地运行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主动地与服务器程序进行联系</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）实现中需要解决的主要问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&gt;标识一个特定的服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 互联网TCP或UDP通常使用端口号作为自己特定的标识</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;响应并发请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 客户机发出的请求是随机的，可能很多客户机同时请求不同服务，因此服务器必须具备多个并发处理能力，服务器有两种实现方案：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 重复服务器：服务器包含请求队列，按照先进先出原则处理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 并发服务器：是一个守护进程，没有请求时，它处于等待状态；客户机每来请求，服务器立即创建一个子进程，然后回到等待；并发服务器称主服务器，而子进程称从服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3&gt;服务器程序的安全问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）对等计算模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.什么是对等计算模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对等计算模型（P2P）通过直接交换来共享计算机资源和服务。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.P2P网络的基本结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）集中目录式结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Napster是一种典型的代表软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 要求服务器要持续运转</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）分布式非结构化P2P网络结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 采用随机图的组织方式形成一个松散的网络</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有较好的容错能力，支持复杂查询（多关键词、模糊查询）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多采用洪泛方式查询和定位资源（网络负载重）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可扩展性差</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 典型代表：Gnuella，没有中心服务器，用TTL机制决定是否继续转发信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）分布式结构化P2P网络</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 采用基于分布式散列表（DHT）的分布式发现资源路由算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DHT是由广域范围的大量节点共同维护的巨大散列表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DHT的节点是动态的，且数量巨大，非中心化和自组织成为两个重要的指标</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 典型代表：pastry，tapestry，chord，CAN</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）混合式结构P2P网络</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在分布式模式的基础上，将用户结点按能力进行分类，包括用户结点、搜索结点和索引结点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 典型代表：skype、pplive、BT</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.P2P网络的应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分布式科学计算</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 协同工作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分布式搜索引擎</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 流媒体直播</p><p>&nbsp; &nbsp; 二、域名系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）互联网的命名机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 互联网利用IP地址识别主机，不便于记忆，使用字符串记忆主机好读易记（域名系统诞生）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 命名机制遵循的原则：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 全局唯一性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 名字便于管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 高效地进行映射</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.无层次命名机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在无层次命名机制中，主机名简单地由一个字符串组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 无层次名字的管理与映射很简单</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 但随着互联网中主机的增加，这种命名机制的缺点就明显得表现出来</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目前，无层次命名机制已被层次型命名机制所取代</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.层次型命名机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 名字中加入结构，而这种结构是层次型的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 层次命名机制对名字的管理非常有利。类似树状结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主机的名字就是从树叶到树根路径上各结点标识符的有序序列</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.TCP/IP互联网域名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在TCP/IP互联网中的层次型名字管理机制是由域名系统DNS（Domain Name System）来实现的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.Internet域名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DNS把整个因特网划分成多个顶级域，并为每个顶级域规定了国际通用的域名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 顶级域的划分采用了两种划分模式，即组织模式和地理模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）域名解析</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 域名解析</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将域名翻译为对应IP地址的过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 域名解析器 &nbsp;&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 请求域名解析服务的软件，运行在客户端</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 域名服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 负责对域名的解析工作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 域名体系具有层次型，因此域名服务器也有不同的级别</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 最靠近用户的是本地域名服务器，最顶层为根域名服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.域名解析方式和解析过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 域名解析采用自顶向下的算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在域名解析时，首先是向本地域名服务器提出域名请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 两种方式：可一次性完成全部名字地址变换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 反复解析：每次请求一个服务器，不行再请求别的服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.提高域名解析效率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 解析从本地服务器开始</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 域名服务器的高速缓存技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主机上的高速缓存技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.对象类型与资源记录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对象类型与类别</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 资源记录</p><p>&nbsp; &nbsp; 三、远程登录服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）远程登录协议（Telnet）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户使用Telnet命令，使自己的计算机成为远程计算机的一台仿真终端</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 远程登录允许任意类型的计算机之间进行通信，具体实现的功能有：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 本地用户与远程计算机上运行的程序交互</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 远程登录后，可以运行远程计算机上的任何应用程序（有权限），屏蔽不同型号计算机之间的差异</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）远程登录的工作原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Telnet采用客户机/服务器模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通过Tcp连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络虚拟终端NVT格式将不同的用户本地终端格式统一起来，是的各个终端只与虚拟终端NVt打交道</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）使用远程登录</p><p>&nbsp; &nbsp; 四、FTP服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）FTP客户机/服务器模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCP建立双重连接：一个控制连接和一个数据连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 建立数据连接的方式有两种：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主动模式（默认模式）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 被动模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）FTP命令与响应</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FTP命令和应答采用7位ASCII码</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FTP命令有30多种</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）FTP文件格式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FTP协议支持两种文件传输方式：文本文件传输和二进制文件传输</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文本文件传输</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 二进制文件传输（图像文件类型）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）用户接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传统FTP命令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 浏览器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 下载工具</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五）FTP访问控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FTP服务器利用用户账号来控制用户对服务器的访问权限</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户名：Anonymous</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 口令：guest</p><p>&nbsp; &nbsp; 五、电子邮件系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）电子邮件系统的基本知识</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.电子邮件系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 电子邮件系统采用客户机/服务器工作模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 电子邮件应用程序的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.TCP/IP电子邮件的传输过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 利用SMTP（简单邮件传输协议）协议向邮件服务器发送邮件，使用POP3（邮局协议）或IMAP协议从邮件服务器邮箱中读取邮件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.电子邮件地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）电子邮件传递协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.SMTP协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SMTP协议负责邮件从一个邮局传送到另一个邮局，分为3个阶段：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 连接建立：连接建立后，客户机与服务器互通自己的域名，同时确认对方域名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 邮件传递：将邮件源地址、目的地址和邮件内容传递到SMTP服务器，SMTP服务器进行相应的相应并接收邮件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 连接关闭：SMTP客户机发出QUIT命令，服务器处理命令后相应，随后关闭TCP连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.POP3协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3指第3个版本。一旦建立TCP连接，POP3客户机向服务器发送命令，下载和删除邮件。分为3个阶段：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 认证阶段：邮箱具有权限，客户机将用户名和密码传递给服务器，服务器判断是否合法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 事务处理阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 更新阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）电子邮件的报文格式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.RFC822</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 邮件头</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 邮件体</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.MIME协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对RFC822作了补充</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 添加了一些邮件头字段，主要有：MIME-Version、Content-Type、Content-Transfer_Encoding等</p><p>&nbsp; &nbsp; 六、Web服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）WWW服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.WWW服务系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WWW（world wide web）或WEB服务，以超文本标记语言（HTML）和超文本传输协议（HTTP）为基础。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 以超文本方式组织网络多媒体信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可在世界范围内任意查找、检索、浏览及添加信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 提供生动直观、易于使用、统一的图形用户界面</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务器之间可相互连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可访问图像、声音、影像和文本信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.WWW服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WWW服务器上以web页方式组织文档，还包含指向其他页面的指针。利用超链接将分布在网络中的服务器建立关联。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 超文本可利用引用链接其他不同类型的文件，这些具有多媒体操作的超文本，称为超媒体</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.WWW浏览器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WWW客户机程序称为WWW浏览器，是用来浏览服务器中WEB页面的软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 过程：WWW浏览器负责接收用户的请求，利用HTTP协议将用户的请求传送给WWW服务器。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.页面地址——URL</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WWW服务器中的页面很多，通过URL（统一资源定位器）指定什么协议、哪台服务器和哪个文件等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; URL由三部分组成：协议类型、主机名和路径及文件名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）WWW系统的传输协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 超文本协议是建立在TCP连接基础上，面向对象的协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HTTP将一次请求/服务的全过程定义为一个简单事务处理，它由一下四个步骤组成：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 连接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 应答</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 关闭</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）WWW系统的页面标识方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）Web的安全性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.浏览器的安全性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.Web服务器的安全性</p><p><br/></p><p><strong><span style="font-size: 18px;">第5章 新型网络应用</span></strong></p><p>&nbsp; &nbsp; 学习目标</p><p>&nbsp; &nbsp; &nbsp; &nbsp; ...</p><p>&nbsp; &nbsp; 一、即时通信系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）即时通信系统的概述</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 即时通信（IM）是一种基于Internet的通信服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.应用软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）即时通信的基础通信模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.P2P通信模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.中转通信模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）即时通信实例</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.QQ用户登录过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.QQ聊天通信过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.QQ文件传输过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）即时通信系统的通信协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.SIP协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户代理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 代理服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 重定向服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 注册服务器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.SIMPLE &nbsp; &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 是SIP协议的扩展，支持即时通信服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.XMPP</p><p>&nbsp; &nbsp; 二、文件共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）网络文件系统NFS</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）Windows LAN文件共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.NetBIOS协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.CIRS协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）P2P文件共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.P2P文件共享历史</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.P2P文件共享的理论基础</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.P2P文件共享系统示例——Maze</p><p>&nbsp; &nbsp; 三、IPTV</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）IPTV系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.视频点播（VOD）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.直播电视</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.时移电视</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）IPTV系统关键技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IPTV基本技术形体可概括为视频数字化、传输IP化、播放流媒体化</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 关键技术包括：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 媒体内容分发技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数字版权管理技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IPTV运营支撑管理系统</p><p>&nbsp; &nbsp; 四、VOIP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）VOIP实现方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PC-to-PC</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PC-to-Phone</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Phone-to-Phone</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）VOIP系统的组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 终端设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网关</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多点控制单元</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网守</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）Skype</p><p>&nbsp; &nbsp; 五、网络搜索技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）网络搜索引擎</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）搜索引擎的原理与组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.全文搜索引擎功能模块的组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 搜索器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 索引器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 检索器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.目录导航和网页搜索引擎组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.Google和百度搜索引擎</p><p>&nbsp; &nbsp; 六、社交网络</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）社交网络的概念与历史</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）社会网络的基本模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）社会网络应用实例</p><p><br/></p><p><br/></p><p><strong><span style="font-size: 18px;">第6章 网络管理与网路安全</span></strong></p><p>&nbsp; &nbsp; 一、网络管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）网络管理的基本概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.网路管理的定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.网络管理对象：硬件资源和软件资源</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）网络管理的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 配置管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 故障管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计费管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 性能管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 安全管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）网络管理模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.网络管理的基本模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 集中式管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分布式管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）网络管理协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.发展简史</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.SNMP协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从被管理设备中收集数据有轮询和基于中断两种方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.CMIP协议</p><p>&nbsp; &nbsp; 二、信息安全技术概述</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）安全信息的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要目标：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 真实性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 保密性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可用性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不可抵赖性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可控制性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可审查性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）信息安全策略</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 信息安全的实现要靠先进的技术、严格的安全管理、法律约束与安全教育</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）信息安全等级</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络安全性标准（DoD5200.28_STD），即可信任计算机标准评估准则。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; A1、B1、B2、B3、C1、C2、D1</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在我国，以《计算机信息系统安全保护等级划分准则》（GB17859-1999）位指导，将信息和信息系统的安全系统分为5个等级：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 自主保护级</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 指导保护级</p><p>&nbsp; &nbsp; 三、网络安全问题与安全策略</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）网络安全的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.安全的目的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对网络系统而言主要有信息的存储安全和信息的传输安全</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传输安全则需要预防：网上信息的监听、用户身份的认证、网络信息的篡改、发出信息的否认、信息重放</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.安全措施</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 社会法律政策、企业规章以及网络安全教育</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 技术方面措施</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 审计与管理措施</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）OSI安全框架（X.800）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OSI安全框架关注三个方面：安全攻击、安全机制和安全服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.安全攻击</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 被动攻击</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主动攻击</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务攻击和非服务攻击</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.安全机制 &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分为两类：特定协议层实现的和不输于任何的协议层的安全服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.安全服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）网络安全模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对发送信息的相关安全变换，如消息加密</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 双方共享某些秘密信息，并希望这些消息不为攻击者所知，如加密密钥</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 安全服务主要包含4个方面：安全传输、信息保密、分配和共享秘密信息、通信协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由程序引起的威胁有2种：信息访问威胁和服务威胁</p><p>&nbsp; &nbsp; 四、加密技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）密码学基本术语</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 明文：原始的消息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 密文：加密后的消息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 加密：从明文到密文的变换过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 解密：从密文到明文的变换过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 密码编辑学：研究各种加密方案的学科</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 密码分析学：研究破译密码获得消息的学科</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 密码学</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.密码编码学</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 转换明文为密文的运算类型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 所用的秘钥数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理明文的方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.密码分析学</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 密码分析攻击、穷举攻击</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.无条件安全与计算上的安全</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.代换与置换技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 代换法：将明文字母替换成其他字母、数字或符号的方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 置换法：通过置换而形成新的队列</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）对称密码</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.对称密码的模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 明文：作为算法的输入</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 加密算法：对明文进行各种代换和置换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 密钥：加密算法的输入，不同于明文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 密文：算法的输出</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 解密算法：加密算法的逆</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.数据加密标准</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广泛使用的加密体制是数据加密标准（DES）采用64位明文初始置换重新排列后和64位密钥进行一系列变换得到64位输出密文</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1977年被美国的NIST，即国家标准和技术研究所采纳为联邦信息处理标注46（FIPS PUB 46）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.其他常见的对称加密算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 三重DES</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2001年NIST将Rijndarl作为AES算法，它的密钥长度为128、/12或256位，分组长度为128位</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Blowfish算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RC5</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）公钥密码</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.公钥密码体制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.公钥密码体制的应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 加密/解密</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数字签名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 密钥交换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.RSA算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RSA既能用于加密，也能用于数字签名的算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 选取密钥的过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 解密过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.其他的公钥加密算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Elgama算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基于离散对数的公钥密码体制和椭圆曲线加密体系</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 背包加密算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基本原理：背包问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）密钥管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.密钥的分发</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.密钥的验证</p><p>&nbsp; &nbsp; 五、认证技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）消息认证</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.消息认证的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.消息认证的方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.消息认证的模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.认证函数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）数字签名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.数字签名的需求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.数字签名的创建</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.数字签名的验证</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）身份认证</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.口令认证</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.持证认证</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.生物识别</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）常用的身份认证协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目前满足条件的协议主要有：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一次一密机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 请求应答机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 询问应答方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; X.509认证协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Kerberos认证协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Kerberos基于对称密钥体制，一般采用DES</p><p>&nbsp; &nbsp; 六、安全技术应用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）安全电子邮件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.PGP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 鉴别、机密性、压缩、电子邮件的兼容性和分段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数字签名：采用DSS/SHA或RSA/SHA</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 报文加密：CAST或DEA，或3DES或RSA</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 压缩：ZIP</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 兼容：64-BASE转换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分段：支持分段和重新分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.S/MIME</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 功能：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 加密数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 签名的数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 透明签名的数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 签名并且加密的数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）网络层安全：IPSEC</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要协议：身份认证头（AH）协议和封装安全负载（ESP）协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.AH协议（身份认证头协议）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AH协议提供源身份认证和数据完整性，但没有提供秘密性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AH头在原有IP数据报数据（例如TCP或UDP段）和IP头之间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.ESP协议</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ESP协议提供了数据完整性、身份认证和秘密性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ESP协议不但提供了源主机身份认证，而且提供了网络层秘密性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）WEB安全</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.Web所面临的威胁</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.Web流量安全性方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络级、传输级、应用级</p><p>&nbsp; &nbsp; 七、入侵检测技术与防火墙</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）入侵者</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.假冒者</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.非法者</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.秘密用户</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）入侵技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 统计异常检测</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基于规则的检测</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.审计记录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 原有的审计记录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 专门用于检测的审计记录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.统计异常检测</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 阈值检测和基于轮廓的检测</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.基于规则的入侵检测</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基于规则的异常检测方法是基于对过去行为的观察</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基于规则的渗透鉴别采用了基于专家系统技术的方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.分布式入侵检测</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分布式入侵检测是要保护居于网内或内部互联网络内所有的主机安全</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三）防火墙的特性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 防火墙的定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.防火墙的设计目标</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 所有从内到外和从外到内的通信量都必须经过防火墙</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 只有被授权的通信才能通过防火墙</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 防火墙对于渗透是免疫的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.用来控制访问和执行站点安全策略的4中常用技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务控制（确定可以访问的Internet服务类型）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 方向控制（决定哪些特定方向上服务请求可以被发起并通过防火墙）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户控制（根据哪个用户尝试访问服务来控制对一个服务的访问）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 行为控制（控制怎样使用特定的服务）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.防火墙的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四）防火墙的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 包过滤防火墙、应用级网关、电路级网关、堡垒主机</p><p>&nbsp; &nbsp; 八、计算机病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一）计算机病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计算机病毒的定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.病毒的生命周期</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 潜伏阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 繁殖阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 触发阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 执行阶段</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.病毒的结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.病毒的种类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 寄生病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储器驻留病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 引导区病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 隐形病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多态病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.几种常见的病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 宏病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 电子邮件病毒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特洛伊木马</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计算机蠕虫</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二）计算机病毒的防治策略</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 反病毒软件分为四代：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 简单的扫描程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 启发式的扫描程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 行为陷阱</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 全方位的保护</p>]]></content>
  </entry>
  <entry>
    <title>用你的魔法和勇气，与小伙伴们一起勇闯《西方世界》</title>
    <link href="https://old-blog.smallyu.net/index011a.html?id=60"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=60</id>
    <published>2017-08-07T16:00:00.000Z</published>
    <updated>2017-08-07T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>章节一 追逐父亲 一位父亲和他的四个女儿相约去某个神秘的地方，由于种种原因，章节一的女主来晚了，还没等见到父亲，父亲就已经出发了。 女主在追逐父亲的途中，遇到了她的姐妹们，她的姐妹们也没能和父亲一起前去。但她们找到一个传送装置，可以通过传送装置直接到达父亲所在的神秘地方。 不过这个装置很危险，它并不一定能够准确到达目的地，而有可能传送到达任何地方。女主一进入...</p>]]></summary>
    <content type="html"><![CDATA[<p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502186363869142.png"/></p><p><br/></p><p><strong><span style="font-size: 18px;">章节一 追逐父亲</span></strong></p><p><span style="font-size: 16px;">一位父亲和他的四个女儿相约去某个神秘的地方，由于种种原因，章节一的女主来晚了，还没等见到父亲，父亲就已经出发了。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502186460176045.png"/></p><p><span style="font-size: 16px;">女主在追逐父亲的途中，遇到了她的姐妹们，她的姐妹们也没能和父亲一起前去。但她们找到一个传送装置，可以通过传送装置直接到达父亲所在的神秘地方。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502186547159716.png"/></p><p><span style="font-size: 16px;">不过这个装置很危险，它并不一定能够准确到达目的地，而有可能传送到达任何地方。女主一进入传送装置，装置就被一个不明所以傻傻分不清的姐妹启动了。然后女主来到了这个不知道什么地方的地方。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502186622177148.png"/></p><p><span style="font-size: 16px;">女主属性：</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 武器：魔法杖</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 技能：使用魔法杖短距离攻击，使用魔法球，魔法球可反弹</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 远程：瞬移一段距离，可以穿过薄栅栏</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 特技：能够驱动魔法井 &nbsp; </span>&nbsp;</p><p><br/></p><p><strong><span style="font-size: 18px;">章节二 一个孩子和他的铁铲</span></strong></p><p><span style="font-size: 16px;">这小子被困在了地下，回不去地表。在这儿看到了这么一棵树，就推测，树是需要阳光的，阳光从正上方照射下来，所以这里一定有出口。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502186740696895.png"/></p><p><span style="font-size: 16px;">哦不，上面的内容是第一映像得到的剧情。真实剧情是，男主所在是一个挖矿工团伙。团伙中每个人都深信不疑他们现在是在月球上挖月岩。男主看到了地表穿透下来的阳光，怀疑这里根本不是月球是地球，然后把这一消息告诉了团伙老大。</span></p><p><span style="font-size: 16px;">然后被团伙老大赶了出来。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502186839438370.png"/></p><p><span style="font-size: 16px;">所有人都开始厌恶男主，认为男主是卑鄙的。男主不服，开始了证明他的猜疑之旅。</span></p><p><span style="font-size: 16px;">男主属性：</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 武器：铁锹、溜冰鞋、炸药</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 技能：使用铁锹短距离攻击，扔炸弹远距离攻击</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 远程：溜冰</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 特技：能够穿过低矮的洞穴，能够使用铁锹潜入土质松软的地下，使用溜冰鞋在水面上行走能够</span></p><p><br/></p><p><strong><span style="font-size: 18px;">章节三 魅惑雇佣兵</span></strong></p><p><span style="font-size: 16px;">女主奉老板之命到西部区域的一处圣地取一块价值不菲的宝石。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502187087413734.png"/></p><p><span style="font-size: 16px;">任务途中女主遇到了老巫师和章节二中的铁铲小子，还看到了具有神秘力量的石柱，石柱上画着四个人的脸，包括女主的和铁铲小子的。</span></p><p><span style="font-size: 16px;">老巫师告诉女主，石柱上的四人将结为同伴，共同做一些不可描述的事情，她已经在石柱旁等了很长很长时间，石柱上的四人相遇是先前预言家预言过的。石柱还拥有让人瞬移的能力，在地图多处都有这样的石柱。</span></p><p><span style="font-size: 16px;">女主不信，继续找宝石。</span></p><p><span style="font-size: 16px;">寻找宝石的过程中，女主偶尔遇到困难，和铁铲小子合作通过了难关。</span></p><p><span style="font-size: 16px;">终于在西部区域的圣地拿到了宝石。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502187412265589.png"/></p><p><span style="font-size: 16px;">女主回到老板处交付宝石，并索取报酬。没想到老板背叛了她，不但没有给付报酬，还将她关押在地牢。</span></p><p><span style="font-size: 16px;">女主属性：</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 武器：罩巾、催眠术士的面具</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 技能：使用罩巾中距离攻击，敌人被击中会眩晕。催眠术士的面具让女主可控制被眩晕到的敌人</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 远程：移动加速</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 特技：使用罩巾拉动远方木桩，将自己拉送木桩所在位置</span></p><p><br/></p><p><strong><span style="font-size: 18px;">章节四 呔嗬</span></strong></p><p><span style="font-size: 16px;">呔嗬是一位探险家，驾着船只从远方而来。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502187489142561.png"/></p><p><span style="font-size: 16px;">探险途中遇到了老巫师，以及章节一寻找父亲会使用魔法的女主。</span></p><p><span style="font-size: 16px;">男主属性：</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 武器：拳套</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 技能：拳击</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 远程：公牛冲锋</span></p><p><span style="font-size: 16px;">&nbsp; &nbsp; 特技：击碎石头</span></p><p><br/></p><p><strong><span style="font-size: 18px;">章节五 勋爵和白鼬</span></strong></p><p><span style="font-size: 16px;">现在呔嗬和卢米纳（会魔法的章节一女主）要合力前进了。</span></p><p><span style="font-size: 16px;">呔嗬追寻的是一只可与自己匹敌的野兽，卢米纳想要的则是回家的方法。</span></p><p><span style="font-size: 16px;">呔嗬打败了一直体型庞大的凶猛野兽，实现了愿望。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502187564145932.png"/></p><p><span style="font-size: 16px;">不过卢米纳却落空了。她要找的正是章节三女主拿走的宝石。卢米纳不得不去找她。</span></p><p><span style="font-size: 16px;">卢卡纳依旧落空了，宝石在老板那里。卢卡纳救出了被老板押禁的女主，然后一起乘飞行器前往沙漠，追寻老板和宝石。</span></p><p><br/></p><p><strong><span style="font-size: 18px;">章节六 追击</span></strong></p><p><span style="font-size: 16px;">两个人来到了沙漠。</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502187615135058.png"/></p><p><span style="font-size: 16px;">在一个下着雪的神秘洞穴，遇到了这一章节的BOSS</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/08/201708081502187730115963.png"/></p><p><span style="font-size: 16px;">没错，宝石依旧不在这里</span></p><p><br/></p><p><span style="font-size: 16px;">宝石不在沙漠，在哪里呢？故事还远没有结束。</span></p><p><span style="font-size: 16px;">游戏剧情还是比较简陋的，大多是没有开头的故事，看的时候会不禁想问为什么，毕竟游戏没有把主人公的背景交代清楚</span></p><p><span style="font-size: 16px;">不过游戏很好玩，冒险解谜类游戏，尤其是好几个主人公在同一张地图中利用不同的技能穿过特性，真心想如果这是一款多人合作游戏该多好</span></p><p><span style="font-size: 16px;">但就单机游戏，它可以让人体会不同的人物情节，人物能力，以及合作的乐趣</span></p><p><span style="font-size: 16px;">画面也非常漂亮</span></p><p><span style="font-size: 16px;">尤其是你用一个人物第一遍走过了地形，第二遍还是同样的地方，却不得不因为人物的特殊能力另寻方法的时候，会感觉到游戏设计的精妙</span></p><p><span style="font-size: 16px;">人物和怪物都是Q版</span></p><p><span style="font-size: 16px;">难度不高，也不低，有些地方可能需要重复不止10次才能通过</span></p><p><span style="font-size: 16px;">游戏过程会有能力的提升，使用魔法的小女孩在到达天空（之城）后会学会使用可反弹的魔法球，后来在打败沙漠里的女BOSS后，学会了瞬移到魔法球所在位置的能力，位移距离大大增加，铁铲小子的炸药也是在后面的章节找到的</span></p><p><span style="font-size: 16px;">糙大叔之前只能爬矮墙，到后面高墙也能直接爬上去了</span></p><p><span style="font-size: 16px;">到之后相信那罩巾的和那铲子的也会学到新的能力</span></p><p><span style="font-size: 16px;">还会有更多的游戏内容</span></p><p><span style="font-size: 16px;">但是我不想再玩了</span></p><p><span style="font-size: 16px;">游戏整体稍（太）显（TM）幼（难）稚（了）</span></p><p><br/></p><p><span style="font-size: 16px;">如果再年轻几岁，一定要死命玩通关</span></p>]]></content>
  </entry>
  <entry>
    <title>NCRE4 · 网络工程师《操作系统原理》概要</title>
    <link href="https://old-blog.smallyu.net/index37ab.html?id=59"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=59</id>
    <published>2017-08-01T16:00:00.000Z</published>
    <updated>2017-08-01T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>前言 考试方式： 上机考试，总分50分，与四级其他一门课程合计考试时间长90分钟。 题型： 单选题 10道题 30分 多选题 10道题 20分 基本要求 1.掌握操作系统的基本概念、基本结构及运行机制。 2.深入理解进程线程模型，深入理解进程同步机制，深入理解死锁概念及解决方案。 3.掌握存储管理基本概念，掌握分区存储管理方案，深入理解虚拟页式存储管理方案。...</p>]]></summary>
    <content type="html"><![CDATA[<p><strong><span style="font-size: 18px;">前言</span></strong><br/></p><p>&nbsp; &nbsp; 考试方式：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 上机考试，总分50分，与四级其他一门课程合计考试时间长90分钟。</p><p>&nbsp; &nbsp; 题型：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 单选题 10道题 30分</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 多选题 10道题 20分</p><p>&nbsp; &nbsp; 基本要求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.掌握操作系统的基本概念、基本结构及运行机制。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.深入理解进程线程模型，深入理解进程同步机制，深入理解死锁概念及解决方案。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.掌握存储管理基本概念，掌握分区存储管理方案，深入理解虚拟页式存储管理方案。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.深入理解文件系统的设计、实现，以及提高文件系统性能的各种方法。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.了解I/O设备管理的基本概念、I/O软件组成，掌握典型的I/O设备管理技术。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 6.了解操作系统的演化过程、新的设计思想和实现技术。</p><p><br/></p><p><span style="font-size: 18px;"><strong>第一章 操作系统概论</strong></span></p><p>&nbsp; &nbsp; 考试内容：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.操作系统基本的概念、特征、分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.操作系统主要功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.操作系统发展演化进程，典型操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.操作系统结构设计，典型的操作系统结构</p><p>&nbsp; &nbsp; 操作系统基本的概念：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; 操作系统的特征：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.并发性：在多道程序环境下，并发性是指两个或多个时间在同一时间间隔内发生，即宏观上有多道程序同时执行，而微观上，在单处理机系统中每一个时刻仅能执行一道程序。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.共享性：共享指系统中的资源可供多个并发执行的进程使用。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 涉及资源：中央处理器、内存储器、外存储器、外部设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 共享方式：互斥共享、同时共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.随机性：也称异步性，不确定性，是指多道程序环境下，允许多个进程并发执行，由于资源的限制，进程的执行不是“一气呵成”的，是“走走停停”的。</p><p>&nbsp; &nbsp; 操作系统的功能：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.进程管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程管理、进程同步、进程间通信、调度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.存储管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 内存的分配与回收、存储保护、内存扩充</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.文件管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件存储空间的管理、目录管理、文件系统的安全性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.设备管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缓冲管理、设备分配、设备处理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.用户接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 命令接口、程序接口</p><p>&nbsp; &nbsp; 操作系统分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 按照用户界面的使用环境和功能特征，分为三种：批处理系统、分时系统、实时系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 随着计算机体系结构的发展，出现的多类型操作系统：个人操作系统、网络操作系统、分布式操作系统、嵌入式操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一、批处理操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.基本工作方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户将作业交给操作员，在受到一定数量的作业后，由操作员把这批作业输入到计算机，最后将结果交给用户</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.特点与分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 成批处理作业，</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：用户不直接与计算机交互，不适合调试程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：自动化较高，资源利用率高，作业吞吐量大，提高整个系统效率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分类：简单批处理系统、多道批处理系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 单道批处理系统：主要特征：自动性、顺序性、单道性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多道批处理系统：引入的好处：提高CPU的利用率；可提高内存和I/O设备的利用率；增加系统吞吐量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.设计思想</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 先把一个作业调入内存，等这个作业运行完毕，再调入下一个作业，如此反复，直到作业处理完毕</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 作业及作业的衔接都有监控程序自动控制，提高了作业运行效率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.作业控制说明书</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由作业控制语言编写的一段程序，通常放在程序前面，执行师，由程序读入作业控制说明书，按照说明书中的语句执行。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; STEP1 ASM A</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; STEP2 FTN B</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; STEP3 LINK A,B,C</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; STEP4 RUN C</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5.一般指令和特权指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特权指令：输入输出指令、停机指令等。只要监控程序才能执行特权指令。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户只能执行一般指令，如需执行特权指令，处理器会将控制权移交给监控程序。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.假脱机技术（SPOOLing）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.1假脱机的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 假脱机技术（SPOOLing）是指在联机情况下实现的同时外围操作，也称假脱机输入输出操作，它是操作系统中的一项将独占设备改为共享设备的技术。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.2假脱机技术的组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 假脱机技术由输入井和输出井、输入缓冲区和输出缓冲区、输入进程和输出进程、请求打印队列组成。SPOOLing系统的组成如下图所示。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6.3假脱机技术的特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; （1）提高了输入输出速度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; （2）将独占设备改造为共享设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; （3）实现了虚拟设备的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二、分时系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.基本工作方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户通过终端交互式地向系统提出命令，系统接受命令后，采用时间片轮转方式处理服务请求</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.设计思想</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将CPU的时间划分为若干个时间段、操作系统以时间片为单位，轮流为每个终端用户服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多路性：多个用户在同时使用一台计算机</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 交互性：用户直接干预操作的每一步</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 独占性：用户感觉不到计算机为他人服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 及时性：系统能对用户提出的额请求即使给予响应</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.影响响应时间的因素</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 机器处理能力</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 请求服务的时间长短</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 系统中连接的终端数目</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务请求的分布</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 调度算法（时间片的选取）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三、实时系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 实时系统是指系统能及时响应外部事件的请求，在规定的时间内，完成对该事件的处理，并控制所有实时任务协调一致地运行。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第一类：实时过程控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 工业控制，军事控制，...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第二类：实时通信（信息）处理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 电讯（自动交换），银行，飞机订票，故事行情</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 实时系统的特征：有多路性、独立性、及时性、交互性和可靠性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 四、嵌入式操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在各种设备、装置或系统中，完成特定功能的软硬件系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它们是一个大设备、装置或系统中的一部分，这个大设备、装置或系统可以不是“计算机”</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通常工作在反应式或对处理时间有较严格要求环境中</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由于它们被嵌入在各种设备、装置或系统中，因此称为嵌入式系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 嵌入式领域广泛使用的操作系统有：嵌入式Linux、Windows Fmbedded、VxWorks等，以及应用在智能手机和平板电脑的Android、iOS等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：系统内核小、专用性强、系统精简、高实用性、多任务的操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 五、个人计算机操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 单用户多任务的操作系统，比如Windows</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：界面友好、使用方便、用户无需具备专门的知识，也能熟练使用。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 六、网络操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 网络操作系统用于管理网络中的各种资源，为用户提供各种资源。其主要功能有网络通信管理、网络资源管理、网络安全管理和网络服务等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 类型：客户/服务器模式（C/S），对等模式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 七、分布式操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分布式处理系统是指由多个分散的处理单元经互联网络的连接而形成的系统。在分布式系统上配置的操作系统成为分布式操作系统。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分布性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 并行性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 透明性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 共享性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 健壮性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 八、智能卡操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它一般是紧紧围绕着它所服务的智能卡的特点而开发的。由于不可避免地收到了智能卡内微处理器芯片的性能及内存容量的影响，因此，在很大程度上不同于我们通常所见到的微机上的操作系统（例如DOS、UNIX等）。</p><p>&nbsp; &nbsp; 网络和分布式操作系统的区别：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.分布具有各个计算机间相互通讯，无主从关系；网络有主从关系、</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.分布式系统资源为所有用户共享；而网络有限制地共享。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.分布式系统中若干个计算机可相互协作共同完成一项任务。</p><p>&nbsp; &nbsp; 操作系统的发展（演化）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.手工操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.监控程序（早期批处理） &nbsp; &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.多道批处理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.分时系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.UNIX通用操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 6.个人计算机操作系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 7.Android操作系统</p><p>&nbsp; &nbsp; 操作系统结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 按照系统的功能和特性要求，选择合适的结构，使用相应的结构设计方法将系统逐步地分解、抽象和综合，使操作系统结构清晰、简单、可靠、易读、易修改，而且使用方便，适应性强。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 整体式结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 层次式结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 微内核（客户机/服务器）结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 一、整体结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 模块接口法、无序模块法、模块组合法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：根据功能划分模块</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：结构紧密，接口简单直接，模块之间转接的灵活性使系统效率高</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：由于模块之间可以任意相互调用，形成网络，各模块相互联系，独立性差，系统结构不清晰</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 结论：可适应性较差，使用与规模较小、使用环境比较稳定却要求效率较高的系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 二、层次结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 三、微内核结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p><br/></p><p><span style="font-size: 18px;"><strong>第二章 操作系统运行机制</strong></span></p><p>&nbsp; &nbsp; 考试内容：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.内核态与用户态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.中断与异常</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.系统调用接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.存储系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.I/O系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 6.时钟（CLock）</p><p>&nbsp; &nbsp; 一、CPU的构成与基本工作方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 处理器由运算器、控制器、一系列的寄存器以及高速缓存构成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 运算器实现指令中的算术和逻辑运算，是计算机计算的核心</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 控制器负责控制程序运行的流程，包括取指令维护CPU状态、CPU与内存的交互等等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 寄存器是指令在CPU内部做处理的过程中暂存数据、地址以及指令信息的存储设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 在计算机的存储系统中它具有最快的访问速度，高速缓存处于CPU和物理内存之间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 利用程序局部性原理使得高速指令处理和低速内存访问得以匹配，从而提高CPU的效率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.处理器中的寄存器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 寄存器提供了一定的存储能力</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 速度比驻村快得多</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 造价高，容量一般都很小</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 两类寄存器：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户可见寄存器，高级语言编译器通过算法分析并使用之，以减少程序访问主存次数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 控制和状态寄存器，用于控制处理器的操作由OS的特权代码使用，以控制其它程序的执行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户可见寄存器：机器语言直接引用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 包括数据寄存器、地址寄存器以及条件码寄存器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数据寄存器（data register）又称通用寄存器，主要用于各种算术逻辑指令和访存指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 地址寄存器（address register）用于存储数据及指令的物理地址、线性地址或者有效地址，用于某种特定方式的寻址。如index register、segment pointer、stack pointer</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 条件码寄存器保存CPU操作结果的各种标记位，如算术运算产生的溢出、符号等等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 控制和状态寄存器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用于控制处理器的操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 大部分对于用户是不可见的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一部分可以在某种特权模式（由OS使用）下访问</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 常见的控制和状态寄存器：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序计数器（PC：Program Counter），记录将要取出的指令的地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 指令寄存器（IR：Instruction Register），包含最近取出的指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序状态字（PSW：Program Status Word），记录处理剂的运行模式信息等等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.指令执行的基本过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 两个步骤：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 先从储存器中每次读取一条指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 然后执行这条指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一个单条指令处理过程称为一个指令周期</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序的执行是由不断取和执行的指令周期组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 仅当关机、出错或有停机相关指令时，程序才停止</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.特权指令和非特权指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特权指令：只能由操作系统使用的指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 使用多道程序设计技术的计算机指令系统必须要区分为特权指令和非特权指令，特权指令一般引起处理器状态的切换。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理器通过特殊的机制将处理器状态切换到操作系统运行的特权状态（管态）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.处理器的状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 根据运行程序对资源和机器指令的使用权限将处理器设置为不同状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 管态：操作系统管理程序运行的状态，较高特权级别，又成为特权态（特态）、系统态、核心态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目态：用户程序运行时的状态，较低的特权级别，又称为（普态）、用户态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有些系统将处理器状态分为核心状态，管理状态和用户程序状态（目标状态）三种。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 管态和目态的差别：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 全部指令（包括特权指令）可以执行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可使用所有资源</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 具有改变处理器状态的能力</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目态-&gt;管态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其转换的唯一途径是通过中断</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 管态-&gt;目态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可用设置PSW（修改程序状态字）可实现</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.程序状态字PSW</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在PSW中专门设置一位，根据运行程序使用指令的权限而设置，PSW（Program Status Word）：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CPU的工作状态码——指明管态还是目态，用来说明当前在CPU上执行的是操作系统还是一般用户，从而决定其是否可以使用特权指令或拥有其它的特殊权利</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 条件码——反映指令执行后的结果特征</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断屏蔽吗——指出是否允许中断</p><p>&nbsp; &nbsp; 二、存储体系</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 支持OS运行硬件环境的一个重要方面：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 作业必须把它的程序和数据存放在内存中才能运行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多道程系统中，若干程序和相关的数据要放入主存储器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 操作系统要管理、保护程序和数据，使它们不至于受到破坏</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 操作系统本身也要存放主存储器中并运行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.存储器的层次结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储系统设计三个问题：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 容量、速度和成本</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 容量：需求无止境</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 速度：能匹配处理器的速度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 成本问题：成本和其它部件相比应在合适范围之内</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.存储保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对主存中的信息加以严格的保护，是操作系统及其它程序不被破坏，是其正确运行的基本条件之一</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多用户、多任务操作系统：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OS给每个运行进程分配一个存储区域</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了保证软件程序只影响程序的内部</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 硬件可提供如下功能：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 界地址寄存器（界限寄存器）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 实现方法：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在CPU中设置一对下限寄存器和上限寄存器存放用户作业在主存中的下限和上限地址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 也可将一个寄存器作为基址寄存器，另一寄存器作为限长寄存器（指示存储区长度）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每当CPU要访问主存，硬件自动将被访问的主存地址与界限寄存器的内容进行比较，以判断是否越界</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果未越界，则按此地址访问主存，否则将产生程序中断——越界中断（存储保护中断）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储键</p><p>&nbsp; &nbsp; 三、中断与异常机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 中断对于操作系统的重要性就像机器中的驱动齿轮一样，所以有人把操作系统成为是由“中断驱动”或者“（中断）事件驱动”，它使得OS可以捕获用户程序发出的系统功能调用及时处理设备的中断请求，定时启动指定程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 中断的概念：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CPU对系统发生的某个事件作出的一种反应</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CPU暂停正在执行的程序，保留现场后自动转去执行相应事件的处理程序，处理完成后返回断电，继续执行被打断的程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.中断是随机的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.中断是可恢复的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.中断是自动处理的 &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 中断/异常概念：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断/异常：balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断的引入：balabala... &nbsp; &nbsp; &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 异常的引入：balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 早期的中断和异常并没有区分，都把它们叫做中断。随着它们的发生原因和处理方式的差别愈发明显，才有了以后的中断和异常</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 中断的分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 广义中断：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断（外中断）：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I/O中断</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 时钟中断</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 硬件故障中断</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 异常（内中断）例外：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 系统调用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺页异常</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 断点指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其他程序性异常（如算术溢出等）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 中断（狭义）与异常的区别：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断：与正执行指令无关，可以屏蔽</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 异常：与正执行指令有关，不可屏蔽</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 中断系统是现代计算机系统的核心机制之一。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 中断系统的两大组成部分：硬件中断装置和软件中断处理程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 中断寄存器：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有的计算机中，由于可能有很多中断源请求同时发生，为了区分和不丢失中断信号，对应每个中断源分别用一固定触发器寄存中断信号。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 规定值为1时，表示有中断信号，为0时表示无</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这些触发器的全体称为中断寄存器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每个触发器称为一个中断位</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 所以中断寄存器是由若干个中断位组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 处理器如何发现中断信号？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理器的控制部件中设一个能检测中断的机构成为中断扫描机构。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在每条指令执行周期的最后时刻扫描中断寄存器，询问是否有中断信号。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 若无中断信号，继续执行下一条指令。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 若有中断，中断硬件将该中断触发器内容按规定编码送入PSW的相应位，称为中断码。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 典型的中断处理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I/O中断</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由I/O设备的控制器或者通道发出</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 两类I/O中断：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I/O操作正常结束</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果要继续I/O操作，需要在准备好以后重新启动I/O</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 若请求I/O程序正处于等待I/O状态，则应将其唤醒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I/O异常</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设备故障或特殊情况</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设备故障时需要重新执行失败的I/O操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 重试次数有上限，次数过大，系统将判定硬件故障</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 时钟中断</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 系统多道能力的重要推动力量，时钟中断处理程序通常做与系统运转、管理和维护相关的工作，包括：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 维护软件时钟：系统有若干个软件时钟，控制定时任务以及进程的处理器时间配额，时钟中断需要维护、定时更新这些软件时钟</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理器时间调度：维护当前进程时间片软件时钟，并在当前进程时间片到时以后运行调度程序选择下一个被调度的进程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 控制系统定时任务：通过软件时钟和调度程序定时激活一些系统任务，如检测死锁、系统记账、系统审计等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 硬件故障中断</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 硬件故障中断处理程序一般需要做的工作：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 保存现场，使用一定警告手段，提供些辅助诊断信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在高可靠系统中，中断处理程序还要评估系统可用性，尽可能恢复系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序性中断</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序指令出错、指令越权或者指令寻址越界而引发</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 两类处理方法：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.只能由操作系统的相关扩展功能模块完成，多为程序试图做不能做的操作引起得系统保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.可由系统自己完成，如一些算术运算错误</p><p>&nbsp; &nbsp; 四、系统调用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.系统调用与一般过程调用的特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）运行在不同的系统状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）状态的转换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）返回问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）嵌套调用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 系统调用的处理步骤</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; 五、I/O技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 主要的I/O控制方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通道</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DMA技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缓冲技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通道</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 独立于中央处理器，专门负责数据I/O传输的处理机，它对外设实现统一管理，代替CPU对I/O操作进行控制，使CPU和外设可以并行工作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通道又称为I/O处理机</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 引入通道的目的：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了使CPU从I/O事务中解脱出来</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 同时为了提高CPU与设备、设备与设备之间的并行度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DMA技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断的引入大大地提高了处理器处理I/O的效率，当处理器和I/O间传送数据时，效率任旧不高</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 解决方法：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 直接存储器访问（DMA：Direct Memory Access）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通过系统总线中一独立控制单元——DMA控制器自动控制成块数据在内存和I/O单元间的传送，大大提高处理I/O的效能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缓冲技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缓冲区是硬件设备之间进行数据传输时，用来暂存数据的一个存储区域</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缓冲技术的三种用途：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理器与主存储器之间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 处理器和其它外部设备之间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设备和设备之间的通信</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目的：解决硬件之间速度不匹配的问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 单缓冲区：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设备向缓冲区输入数据直到装满后，必须等待CPU将其取完，才能继续向其中输入数据。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了提高设备利用率，单缓冲区不够</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多缓冲区（Cache）技术：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Cache：离CPU最近，使CPU快速访问常使用的数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果没有，CPU到二级Cache中找</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果没有，CPU到系统内存中找</p><p>&nbsp; &nbsp; 六、时钟</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 操作系统时钟是微机上所有软件获取时间的主要来源，其位置至关重要。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 操作系统时钟的时间是硬件提供的，如果危机硬件时钟有错，就会影响到操作系统。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 时钟一般分为硬件时钟和软件时钟</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 时钟的用途可分为绝对时钟和相对时钟</p><p><br/></p><p><strong><span style="font-size: 18px;">第三章 进程线程模型</span></strong></p><p>&nbsp; &nbsp; 考试内容：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.并发环境与多道程序设计</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.进程的基本概念，进程控制块（PCB）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.进程状态及状态转换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.进程控制：创建、撤销、阻塞、唤醒、fork()的使用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.线程基本概念，线程的实现机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 6.处理机调度</p><p>&nbsp; &nbsp; 一、并发环境与多道程序设计</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.程序的顺序执行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序：指令或语句序列，体现了某种算法，所有程序是顺序的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 顺序环境：在计算机系统中只有一个程序在运行，这个程序独占系统中所有资源，其执行不收外界影响。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 顺序执行的特征：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 顺序性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 封闭性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序执行结果的确定性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序结果的可再现性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.多道程序系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计算机能够同时处理多个具有独立功能的程序，以增强系统的处理能力和提高机器的利用率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多道程序的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 独立性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 随机性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 资源共享性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.程序的并发执行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 并发环境：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在一定时间内物理机器上有两个或两个以上的程序同处于开始运行但尚未结束的状态，并且次序不是事前确定的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 并发的特征：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）并发程序在执行期间具有相互制约关系</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）程序与计算不在一一对应</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）并发程序执行结果不可再现</p><p>&nbsp; &nbsp; 二、进程模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.进程的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程是正在执行的程序，从操作系统角度可分为系统进程和用户进程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程和程序既有联系又有区别。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.进程的特性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 并发性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 动态性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 独立性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 交往性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 异步性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.进程的基本状态及其转换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程的基本状态：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不同系统设置的进程状态数目不同</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 三状态进程模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 五状态进程模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 七状态进程模型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程的三种基本状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）就绪状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）运行状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）等待状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）创建状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）结束状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6）挂起状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7）激活状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程状态间的转换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）新状态-&gt;就绪状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）就绪状态-&gt;执行状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）执行状态-&gt;阻塞状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）执行状态-&gt;就绪状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）阻塞状态-&gt;就绪状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6）执行状态-&gt;终止状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.进程控制块（PCB）的内容：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分为调度信息和现场信息两大部分。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 调度信息供进程调度时使用，描述进程当前所处的状况。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 现场信息刻画了进程的运行情况。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程的组成：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序、数据和进程控制块（PCB）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.PCB表的组织方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）线性方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）索引方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）链接方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 6.进程控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 创建、撤销进程以及完成进程各状态之间的转换，由具有特定功能的原语完成。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 创建原语</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 撤销原语</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 阻塞原语</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 唤醒原语</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Unix的fork()函数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 父进程通过fork()创建子进程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：只被执行一次，返回两次结果，一次是在调用进程中，一次是在创建的子进程中，父进程中返回的是子进程的PID，子进程中fork()返回0。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;main(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pid_t&nbsp;pid;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;x&nbsp;=&nbsp;1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pid&nbsp;=&nbsp;fork();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pid==0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;child:x=%d\n&quot;,++x);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;parent:x=%d\n&quot;,--x);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有两种可能的运行结果：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; child:x=2;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parent:x=0</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序1</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;main(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fork();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;hello!\n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输出两个hello!</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序2</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;main(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fork();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fork();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;hello!\n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输出四个hello!</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程的创建</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 创建一个PCB</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 赋予一个统一进程标识符</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为进程映像分配空间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 初始化进程控制块</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设置相应的链接</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程的撤销</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）引起进程撤销的事件有三类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程正常结束</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在进程运行期间，由于出现某些错误和故障而使进程被迫中止</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程应外界的请求而终止运行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）进程撤销的过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程阻塞和进程唤醒</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）引起进程阻塞的事件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 请求系统服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 启动某种操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 新数据尚未到达</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 无新工作可做</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）引起进程唤醒的事件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 请求系统服务得到满足</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 启动某种操作完成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 新数据已经到达</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有新工作可做</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 7.线程的控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程作为系统中的一个基本单位，具有两个属性：一是资源分配和拥有的基本单位。二是一个可以地理调度和执行的基本单位。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 而在进程操作过程中，因为进程是一个资源的拥有者。所以，系统要不断地进行资源的分配与回收、现场的保存、恢复等工作。系统要为此付出较大的时间与空间的开销。此外，在系统中所设置的进程数目不能过多，进程切换的频度不能过高，这就限制了系统并发程度的进一步提高。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如何能使进程更好地并发执行，同时又能尽量减少系统开销呢？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将进程的两个属性分开，由操作系统分别处理，即只作为资源分配与拥有的单位，不再是调度和执行的基本单位，使之轻装前进，而对资源分配与拥有的基本单位，不进行频繁的切换处理，以减少系统开销。正是因为这种思想，产生了一个新的概念——线程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 8.线程的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 线程是进程中的一个实体，是被系统独立调度和执行的基本单位。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 线程自己基本上不拥有系统资源，只拥有一点在运行中必不可少的资源（如程序计数器、一组寄存器和栈），但是它可以与同属于一个进程的其他线程共享进程所拥有的全部资源。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一个线程可以创建和撤销另一个进程，同一进程中的多个线程之间可以并发执行。线程之间也会相互制约，使其在运行中呈现异步性。因此，线程同样具有就绪、执行、阻塞三种基本状态。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 9.线程与进程的比较</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）调度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 传统操作系统中，进程是作为资源分配和独立调度的基本单位。在引入线程的操作系统中，则把线程作为调度和分派的基本单位，把进程作为资源拥有的基本单位。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）并发性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 引入线程的操作系统中，不仅进程之间可以并发执行，而且在一个进程中的多个线程之间也可以并发执行。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）拥有资源</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 无论哪种操作系统，进程都是拥有资源的一个独立单位，一般情况，线程自己不拥有系统资源，但线程可以访问属于进程的资源。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）系统开销</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 由于进程的创建和撤销都需要分配拟或回收资源，因此操作系统所付出的开销显著大于创建和撤销进程时的开销。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 同样，进程切换的开销也远大于线程切换的开销。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 简而言之，一个程序至少有一个进程，一个进程至少有一个线程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 10.线程的实现机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）用户级线程。用户级线程是由用户控制的，对于用户级线程的创建、撤销与切换，都与系统控制无关，完全由用户自己管理。简单来说就是系统并不知道有用户级线程的存在，在系统中各种控制仍然是基于进程的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）内核级线程。内核级线程是依赖于内核，即无论是用户进程中的线程，还是系统进程中的线程，它们的创建、撤销与切换都是由内核实现的。在系统中保留了一张线程控制块，系统根据该线程控制块来赶回线程的存在，并对线程进行控制。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）混合实现方式。同时实现用户级和内核级线程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 11.Pthread进程包</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Pthread是一套用户级线程库，定义了线程标准，大部分的UNIX系统都支持该标准。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 12.进程调度的概述</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 调度分层次的，可分为高级调度、中级调度、低级调度。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 高级调度：它用于确定把后备队列上的哪些作业调入内存。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中级调度：核心按一定的调度算法，将内存中处于等待状态的某些进程调至外存对换区，来腾空这部分内存。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 低级调度（进程调度）：指在多道程序环境下，内核按一定的调度算法，从就绪队列中选出一进程，把处理机分配给它。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程调度的时机：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）正在执行的进程运行完毕</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）正在执行的进程调用阻塞原语将自己阻塞，进入等待状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）调用激活原语激活等待资源的进程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）时间片用完</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）就绪队列中的某个进程的优先级高于当前运行进程的优先级</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 13.调度算法设计原则</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）面向用户的原则。这是为满足用户的需求而遵循的一些准则。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）面向系统的原则。这是为了满足系统要求而遵循的一些准则。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 14.进程（线程调度算法）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）先来先服务调度算法（FCFS）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 先来先服务调度算法的裁决模式是非抢占式的，优先权函数=花费在系统中的实际时间，仲裁规则是随机的。这种调度算法有利于长进程，而不利于短进程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）最短作业优先调度算法（SPF）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 短进程优先调度算法的裁决模式是非抢占式的，优先权函数=-运行时间，仲裁规则是按照时间先后顺序或随机方式。这种调度算法照顾到了系统中的短进程，有目的地降低了进程的平均等待时间，提高了系统的吞吐量。但是，这种算法对长进程不利。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）最短剩余时间优先调度算法（SRT）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 最短剩余时间优先调度算法的裁决模式是抢占式的，优先权函数是动态的，随着进程运行和完成时间的减少而增加，仲裁规则是按照时间先后顺序或随机方式。这种调度算法充分照顾到了剩余运行时间短的进程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）最短剩余时间优先调度算法（SRT）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 时间片轮转调度算法的裁决模式是面向时间片的，所有就绪进程的优先权函数值相同，仲裁规则是轮转规则。这种调度算法适用于交互进程的调度。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）最高优先级调度算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优先权调度算法的裁决模式是抢占式的或非抢占式的，优先权函数是用户或系统赋予给它的优先权，仲裁规则是随机的或先进先出的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6）多级反馈队列调度算法（MLF）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 多级反馈队列调度算法的裁决模式是抢占式的或非抢占式的，优先权函数是从最大值开始每执行一次递减1，仲裁规则是轮转的或按照时间先后次序。</p><p><br/></p><p>第四章 并发与同步</p><p>&nbsp; &nbsp; 考试内容</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.进程的同步与互斥</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.信号量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.管程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.进程的通信</p><p>&nbsp; &nbsp; 1.进程的相互作用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.1相关进程和无关进程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）进程互斥</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）进程同步</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.2与时间有关的错误</p><p>&nbsp; &nbsp; 2.进程互斥</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 解决办法两种：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）由竞争双方平等协商</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）引入进程管理者</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 资源共享的程度分为三个层次：互斥、死锁、饥饿</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.1临界资源的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 临界资源的访问过程：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进入区、临界区、退出区、剩余区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.2进程同步机制应遵循的原则</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）空闲让进</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）忙则等待</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）有限等待</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）让权等待</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 进程互斥的软件方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）单标志算法</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(turn!=i);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;临界区
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;turn=j;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;剩余区</pre><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）双标志、先检查算法</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(flag[j])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag[i]=true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;临界区
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag[i]=flase;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;剩余区</pre><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）双标志、后检查算法</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag[i]=true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(flag[j]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag[i]=false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;剩余区</pre><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）先修改、后检查、后修改者等待算法</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag[i]=true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;turn=j;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(flag[j]&amp;&amp;turn==j);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;临界区
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag[i]=false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;剩余区</pre><p>&nbsp; &nbsp; &nbsp; &nbsp; 进程互斥的硬件方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）TS指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每个临界区设置一个公共变量lock:true表示正被占用，false表示空闲进入区利用TS进行检查和修改表示lock。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）Swap指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）信号量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1965年，荷兰学者Dijksrea提出的信号量机制是一种很有效的进程同步工具，得到了广泛的使用。这里讲介绍最简单的经常使用的信号量——整型信号量。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 信号量是一种特殊变量，它用来表示系统中资源的使用情况。而整型信号量就是一个整型变量。当其值大于“0”时，表示系统中对应可用资源的数目；当其值小于“0”时，其绝对值表示因该资源被阻塞的进程的数目；当其值等于“0”时，表示系统中对应资源已经用完，并且没有因该资源而被阻塞的进程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对信号量的操作：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对于整型信号量，仅能通过两个标准的原语操作来访问，这两个操作被称为P操作、V操作，也合称为PV操作。其中P操作在进入临界区前执行，V操作在退出临界区后执行。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P操作，用wait(s)来描述：</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wait(s)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--s.count;&nbsp;&nbsp;//&nbsp;表示申请一个资源
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(s.count&lt;0)&nbsp;&nbsp;&nbsp;//&nbsp;表示没有空闲资源
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;调用进程进入等待队列s.queue;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;阻塞调用进程;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; V操作，用signal(s)来描述：</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;signal(s)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++s.count;&nbsp;&nbsp;//&nbsp;表示申请一个资源
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(s.count&lt;0)&nbsp;&nbsp;&nbsp;//&nbsp;表示没有空闲资源
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从等待队列s.queue中取出头一个进程；
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;进程P进入就绪队列；
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>&nbsp; &nbsp; 3.经典的进程同步问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 简单生产者-消费者问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 生产者进程P：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(true){</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P(empty)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 生产一个产品;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 送到缓冲区;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; V(full);</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 消费者进程Q：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(true){</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P(full)</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从缓冲器取产品;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; V(full);</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 消费产品;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 利用PV操作实现进程同步的方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）使用PV操作的规则</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&gt;分清哪些是互斥问题，哪些是同步问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;对于互斥问题要设置互斥信号量，互斥信号量的个数只与临界资源的种类有关。通常，有几类临界资源就设置几个互斥信号量，且初值为1，代表临界资源可用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;对于同步问题要设置同步信号量，通常同步信号量个数与可参与同步的进程种类有关。同步信号量表示该资源是否可以开始或者进程是否已经结束。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4&gt;在每个进程中用于实现互斥的PV操作必须成对出现；用于实现同步的PV操作也必须成对出现，但是，它们分别出现在不同的进程中；在某个进程中如果同时存在互斥与同步的P操作，则其顺序不能颠倒。必须先执行对同步信号量的P操作，再执行对互斥信号的P操作。但是，V操作的顺序没有严格要求。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）同步互斥问题的解题步骤：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&gt;确定进程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;确定同步互斥关系</p><p>&nbsp; &nbsp; 4.管程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.1引入管程的原因</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每个访问临界资源的进程都必须使用PV操作，是的大量的同步操作分散在各个进程中。这不仅给系统的管理带来了麻烦，还可能因同步操作使用不当而导致系统故障，如顺序不当、读写、漏写等。为此，又产生了一种新的进程同步管理工具——管程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.2管程的组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 管程由四部分组成：管程名称、共享数据的说明、对该数据进行操作的一组过程、对共享数据设置初始值的语句。此外，每个管程都有唯一的名字来标示。管程类似于面向对象程序设计中的类。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.3利用管程实现经典的同步问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程或者线程的阻塞和唤醒，可以通过管程的wait和signal操作来巧妙地实现，所有管程中的过程是互斥的。balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）wait原语</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）signal原语</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了区别阻塞的原因，需要设置一个条件变量。条件变量是一个整型变量，用condition说明，balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 管程具有的三个特征：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）模块化</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）抽象数据类型</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）信息隐蔽</p><p>&nbsp; &nbsp; 5.进程通信</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 进程的同步与互斥成为低级通信。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 用户直接利用操作系统提供的一组通信命令，高效地传送大量数据，成为高级通信，又称管道通信。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 进程之间的通信方式：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）共享内存</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）消息机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）通过共享文件</p><p>&nbsp; &nbsp; 6.共享内存</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 在相互通信的进程之间设置一个公共的内存区，一组进程向该公共内存中写，另一组进程从内存中读，通过这种方式实现两个进程之间的信息交换。</p><p>&nbsp; &nbsp; 7.消息机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 在消息机制中，进程间的数据交换是以消息为单位进行的。用户直接利用系统中提供的一组通信命令（原语）进行通信。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）消息缓冲通信</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 发送原语：Send(Receiver,message);</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 接收原语：Receive(Send,message);</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）信箱通信方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&gt;信箱通信的操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;信箱的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3&gt;进程间的关系</p><p>&nbsp; &nbsp; 8.管道通信系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p><br/></p><p>第五章 存储管理方案</p><p>&nbsp; &nbsp; 考试内容</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.存储管理基本概念，存储管理基本任务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.分区存储管理方案</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.覆盖技术与交换技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.虚存概念与虚拟存储技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.虚拟页式存储管理方案</p><p>&nbsp; &nbsp; 1.存储体系</p><p>&nbsp; &nbsp; 2.存储器管理的主要任务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 存储器由外存和内存组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 内存空间分为两部分：系统区、用户区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）内存的分配和回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）存储共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3）存储保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4）权限保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.1内存的分配和回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）记住每个存储区域的状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）实施分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 实现方法：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 位示图表示法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 空闲页面表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 空闲块表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 内存分配的方式：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）静态分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）动态分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.2存储共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 指两个或多个进程公用内存中的相同区域，使多道程序动态地共享，提高内存利用率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 共享内容：代码共享、数据共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.3存储共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储保护内容</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）地址越界保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）权限保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）存储键保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.4扩充内存</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户在编程的时候，不应该受内存容量限制，要采用一定的技术“扩充”内存的容量。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 采用虚拟存储技术或其他交互技术。</p><p>&nbsp; &nbsp; 3.地址转换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 将用户程序的逻辑地址转换为运行时的物理地址的过程称为地址转换，也称为地址映射（即重定位）。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 静态重定位：在程序装入时，把程序中的指令地址和数据地址全部转换成绝对地址。由于地址转换工作是在程序开始执行前集中完成的，所以在程序执行过程中就无需在进行地址转换工作。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 动态重定位：在程序装入时，不进行地址转换，而是直接把程序装入到分配的内存区域中。在程序执行过程中，每当执行一条指令时由硬件的地址转换机构将指令中的逻辑地址转换成物理地址。</p><p>&nbsp; &nbsp; 4.固定分区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 基本定理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 固定分区存储管理方式是最早使用的一种可以运行多道程序的存储管理方式。它要求把作业全部装入主存，且装入一个连续的存储空间。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 基本特点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）一个作业只能装入一个分区，不能装入两个或多个相邻分区。一个分区只能装入一个作业，当分区大小不能满足作业的要求时，该作业暂时不能装入。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）通过对“分区分配表”的改写，来实现对主存空间的分配与回收。作业在执行时，不会改变存储区域，所以采用静态地址重定位方式易于实现，且系统开销小。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）当分区较大作业较小时，仍然浪费许多主存空间，并且分区总数固定，限制了并发执行的作业数目。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 主存空间的分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在作业分配之前，根据主存分区的划分情况，在分区分配表中填入每个分区的起始地址（简称始址）、大小，在状态栏中一律跳入“0”，表示该分区可用，当作业装入时填入作业名。</p><p>&nbsp; &nbsp; 5.可变分区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 可变分区存储管理方式又称为动态分区存储管理方式。它是根据用户作业的大小，在作业要求装入主存时，动态地划分分区，使分区的大小正好适应作业的要求。采用这种存储管理方式，分区的大小是不定的，分区的数目也是不定的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 可变分区存储管理方式必须解决三个问题：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一是分区分配中所用的数据结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 二是分区的分配算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 三是分区的分配和回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 移动技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 可变分区中，内存经过一段时间的分配和回收后，会存在很小的空闲快，这些小块不足以满足程序进一步分配内存的要求，但其总和却可以满足程序的分配要求，解决的办法就是“碎片整理”，这一技术成为“移动技术”。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 移动技术注意的问题：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）移动会增加系统的开销</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）移动是有条件的 &nbsp; &nbsp; &nbsp;&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.1采用的数据结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了实现可变分区分配，系统必须配置相应的数据结构，用来记录主存的使用情况，包括空闲分区的情况和已分分区的情况，为作业分配主存空间提供依据。为此，设置了两张表，即已分分区表和空闲分区表。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.2主存空间的分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分配主存时，先分配小地址，再分配大地址。空闲分区表中记录的排列也是从小地址向大地址排列的。首次分配时，只有一个空闲区。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 常用的主存分配算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）最先适应分配算法（FF）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它要求空闲分区表中的记录按地址递增的顺序排列。在每次分配主存时，总是从第1条开始顺序查找空闲分区表，找到第一个能满足作业长度要求的空闲区，分割这个空闲区。一部分分配作业，另一部分仍作为空闲区。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它的特点是分配算法简单，容易差生过多的主存碎片。主存碎片是指小的不能使用的主存空间；这种算法把大的空闲区分成了小的空闲区，当有大作业要求分配时，不能满足要求，降低了系统的效率。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）最优适应分配算法（BF）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它是从所有的空闲分区中挑选一个能满足作业要求的最小的空闲区进行分配。这样可以保证不去分割一个更大的空闲区，使装入大作业时比较容易得到满足。为了实现这种算法，把空闲区按长度递增次序登记在空闲分区表中，分配时，顺序查找。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它的优点是解决了大作业的分配问题，不足是容易产生主存碎片，降低了主存空间的利用率。另外收回主存时，要按长度递增顺序插入到空闲分区表中，增加了系统开销（操作系统所占有的系统资源和所需要的处理器的时间成为“系统开销”）。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）最坏适应分配算法（WF）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它每次分配主存时总是挑选一个最大的空闲区，分割一部分给作业使用，使剩下的部分不至于太小而成为主存碎片。为了实现这种算法，把空闲区按长度递减的次序登记在空闲分区表中，分配时，顺序查找。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 它的优点是不会产生过多的碎片，不足是影响大作业的分配。另外收回主存时，要按长度递减的顺序插入到空闲分区表中，增加了系统的开销。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）下次分配算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当接到内存申请时，查找分区说明，从上一次分配的位置开始扫描内存，选择下一个大小足够的可用块。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.3主存空间的回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）回收的分区前后没有相邻的空闲分区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）回收分区的前后有相邻的空闲区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）回收分区的后面有相邻的空闲分区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）回收分区的前后都有相邻的空闲分区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分区管理的优缺点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）分区的长度不是预先固定的，而是按作业的实际需求来划分的。分区的个数也不是预先确定的，而是由装入的作业个数决定的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）分区的大小由作业的大小决定，提高了主存的使用频率。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）在主存分配过程中，会产生许多主存碎片，造成主存空间的浪费。</p><p>&nbsp; &nbsp; 6.覆盖技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 覆盖技术是指一个程序的若干程序段或几个程序段的某个部分共享一个存储空间。覆盖技术的实现是把程序划分为若干个功能上相对独立的程序段，按照其自身的逻辑结构是那些不会同时执行的程序共享一块内存区域。未执行的程序段先保存在磁盘上，当有关程序段的前一部分执行结束后，把后续程序段写入内存，覆盖前面的程序段。</p><p>&nbsp; &nbsp; 7.交换技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 交换技术是指把主存中暂时不能运行的进程，或暂时不用的程序和数据，换出到外存上，把已具备运行条件的进程，或进程所需要的程序或数据换入到主存的技术。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）换出进程的选择</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）交换时机的确定</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3）交换空间的分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4）换入进程换回内存时位置的确定</p><p>&nbsp; &nbsp; 8.页式存储管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 在页式存储管理方式中，将用户作业的地址空间分成若干大小相同的区域，称为页面或页，并为每个页从“0”开始编号。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 相应地，主存空间也分为与页大小相同的若干存储块，成为物理块或页框，并且采用同样的方式为它们进行编号，从0开始：0块，1块，...，n-1块。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 程序的逻辑地址页号和页内地址组成，页号的长度决定了分页的多少，页内地址的长度决定了页面的大小。在为作业分配主存时，以块为单位将作业中的若干页分别装入到多个不相邻的块中。作业执行时根据逻辑地址中的页号找到它所在的块号，再确定当前指令要访问的物理地址。它的地址转换属于动态重定位，由于进程的最后一页经常装不满一块，而形成不可利用的碎片，称为“页内碎片”。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 8.1主存空间的分配与回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1)采用的数据结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了实现页式存储管理方式，系统设置了主存分配表、位示图和页表，记录主存空间的使用情况和每个作业的分配情况。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）主存空间的回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当一个作业执行结束，则应收回该作业所占用的主存块。根据主存分配表中的记录，取出该作业的页表。从该作业的页表中取出每一个归还的块号，计算出该块在位示图中的位置，将占用标志位置“0”。最后，把归还的块数加入到空闲块数中，删除该作业的页表，并把分区分配表中该作业的记录删除。</p><p>&nbsp; &nbsp; 9.地址转换和快表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 9.1地址转换。两个与地址计算有关的方法。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一是，由逻辑地址计算出页号和页内地址的计算方法如下：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 页号=逻辑地址/页长（商）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 页内地址=逻辑地址 % 页长（余数）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 二是，由块号计算物理地址的计算方法为：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 物理地址=块号*块长+块内地址+用户区基址</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 页表：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）多级页表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）散列页表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）反置页表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 页式管理特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）有效地解决了“碎片”多的问题。可以使程序和数据存放在不连续的主存空间，而不必像可变分区管理那样通过增加系统开销来解决主存碎片的问题。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）通过位示图和页表来记录主存的使用情况和每个作业的分配情况，当主存很大，并且作业也很大时，位示图和页表都有可能占用较大的存储空间。另外，它要求有相应的硬件支持，从而增加了系统成本，也增加了系统开销。例如需要地址变换机构、快表等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）要求页的大小固定。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 9.2快表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 因页表在主存中，CPU在存取数据时，要访问主存两次。第一次是访问主存中的页表，从中找出该页的物理块号，将此块号与页内地址拼接形成物理地址，第二次是根据上一步得到的物理地址，到主存中获取数据。这样就降低了计算机的处理速度。为了提高处理速度，可以使用快表和两级页表的方法对页式存储管理进行改进。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 具有快表的地址变换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 具有两级页表的地址转换</p><p>&nbsp; &nbsp; 10.虚拟存储管理方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 虚拟存储器的定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 虚拟存储器是指仅把作业的一部分装入主存便可以运行的存储器系统。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 虚拟存储器的逻辑容量也称为最大容量，是由地址寄存器的位数决定的。如果计算机的地址寄存器是24位，地址按单字节编址，则虚拟存储器的最大（逻辑）熔炼容量是224B。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 虚拟存储器的物理容量也称为实际容量。当最大容量大于等于主存与硬盘容量之和时，虚拟存储器实际容量为主存与硬盘容量之和；当最大值小于主存与硬盘容量之和时，虚拟存储器实际容量就是最大容量。虚拟存储器的运行速度接近于主存速度，而其成本却又接近于外存。可见，虚拟存储技术是一种性能非常优越的存储器管理技术，故被广泛的应用于各类计算机中。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 10.1页式虚拟存储管理基本原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 页式虚拟存储管理是建立在纯分页基础上的，增加了请求调页功能和页面置换功能所形成的页式虚拟存储管理系统。他把作业分成大小相等的若干页，把主存分成与页大小相等的若干块；对每个作业限定分给它的主存块数，先把作业的部分页装入主存的这些块中，在作业运行时再装入所需要的页。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 10.2采用的数据结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 虚拟存储器在实现上是有一定难度的，既需要一定的硬件支持，又需要较多的软件支持，但是，请求分页式存储管理方式相对容易，因为它换进、换出的基本单位是固定长度的页面。采用的数据结构如下：位示图、页表和主存分配表。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 10.3页面调度策略：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 调入策略</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）请求调页</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）预调页</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 置页策略</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 置换策略</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）固定分配局部置换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）可变分配全局置换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）可变分配全局置换</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 10.4页面置换算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）先进先出置换算法（FIFO）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该算法淘汰最早进入主存的页面。因为，最早进入的页面，不再使用的可能性比最近调入的页面要大。先进先出置换算法实现简单，只要把各调入主存的页按其进入主存的先后顺序连成一个队列即可，总是淘汰队首的那一页。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）最近最久未使用算法（LRU）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该算法选择在最近一段时间内最久没有使用过的页淘汰掉。它依据的是程序局部性原理。最近最久未使用算法是利用一个特殊的栈来保存当前使用的各个页的页号。每当访问某页时，考察栈内是否有于此相同的页号，若有则将该页的页号从栈中抽出，再将它压入栈顶。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）最近最不经常使用算法（LFU）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该算法选择到当前时间为止被访问次数最少的页置换。其实现方法是为每页设置一个访问计数器，每当页面被访问时，该页面的访问计数器就加“1”；发生缺页时，淘汰计数器淘汰值最小的页，同时将所有计数器清“0”。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）理想页面置换算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从主存中溢出永远不需要的页。若无这样的页，则移出最长时间不需要访问的页。该算法只有理论意义。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）最近未使用页面置换算法（NRU）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第0类：没有被访问，没有被修改</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第1类：没有被访问，已被修改</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第2类：已被访问，没有被修改</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第3类：已被访问，已被修改</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6）第二次机会页面置换算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7）时钟页面置换算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺页中断率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺页中断率=中断次数/页面访问总次数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 影响缺页中断的因素：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&gt;分配给程序的内存块数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;页面的大小</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3&gt;程序编制方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4&gt;页面置换算法</p><p>&nbsp; &nbsp; 11.段式存储管理方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 基本原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在段式存储管理方式中，作业的地址空间被划分为若干段，每段定义了一组逻辑信息。例如，有主程序段MAIN、子程序段X、数据段D及栈段S等。每个段都有自己的名字。为了实现简单，通常可用一个段号来代替段名，每个段都从0开始编址，并采用一段连续的地址空间。段的长度由相应的逻辑信息组的长度决定，因而各段长度不等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 整个作业的逻辑地址空间，由于分成多个段，因而是二维的，即其逻辑地址由段号和段内地址所组成。</p><p>&nbsp; &nbsp; 12.段页式存储管理方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 基本原理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 段页式存储管理方式的基本原理是段式和页式系统工作原理的组合，即先把用户程序分成若干段，并为每个段划分成大小相等的若干页，把主存分成与页大小相同的块。每段分配与其页数相同的主存块，主存块可以连续，也可以不连续。</p><p><br/></p><p><strong><span style="font-size: 18px;">第六章 文件管理</span></strong></p><p>&nbsp; &nbsp; 考试内容</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.文件的基本概念、文件逻辑结构、文件的物理结构和存取方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.文件目录的基本概念，文件目录的实现</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.文件的操作，目的操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.磁盘空间的管理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.文件系统的可靠性和安全性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 6.文件系统的性能问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 7.Windows的文件系统FAT，UNIX的文件系统</p><p>&nbsp; &nbsp; 1.什么是文件？</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件是指存放在外存上的已命名的一组相关信息的集合，通常将程序和数据组织成文件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件中的基本访问单位是位、字节或记录。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件的属性包括文件类型、文件长度、文件的物理位置、文件的存取控制、文件的建立时间。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件是一种抽象机制，它提供了一种把信息保存在存储介质上而且便于以后存取的方法，用户不用关心文件的实现细节。</p><p>&nbsp; &nbsp; 2.文件系统的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 操作系统中与文件和目录相关的子系统统称为文件系统能够，是操作系统中统一管理信息资源的一种软件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 信息的存储要求：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）能够存储大量的信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）长期保存信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）可以共享信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 操作系统为系统管理者提供了对文件的透明存取。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 研究文件系统的两种角度：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）用户的角度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要关心文件由上面组成，如何命名，如何保护，如何操作等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）操作系统的角度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主要关心文件目录怎样实现，怎样管理存储空间，文件存储位置，磁盘实际运作方式等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）按文件的用途分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 系统文件：操作系统和各种应用程序和数据所组成的文件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 库函数文件：标准子程序及常用应用程序组成文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户文件：用户委托文件系统保存的文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）按文件的阻值形式分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 普通文件：文件的组织格式为文件系统中所规定的最一般格式的文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目录文件：由文件的目录构成的特殊文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特殊文件：形式上与普通文件相同，也可以进行查找目录操作，但有其特殊的性质，比如，UNIX系统中，输入输出设备被看作是特殊文件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）按文件中的保护方式分类：只读文件、读写文件、可执行文件、无保护文件等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）按信息的流向分类：输入文件、输出文件和输入输出文件等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）按文件的存放时限分类：临时文件、永久文件和档案文件等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6）按文件使用的介质类型分类：磁盘文件、磁带文件、卡片文件和打印文件等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7）按照文件的组织结构分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 逻辑文件：流式文件和记录文件等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 物理结构：顺序文件、链接文件和索引文件等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX操作系统中的文件分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.普通文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.目录文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.特殊文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目的：对不同的文件进行管理，提高系统效率，同时提高文件系统的用户界面友好性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件系统的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）统一管理文件的存储空间，实施存储空间的分配和回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）实现文件的按名存取</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）实现文件信息的共享，并提供文件的保护和保密措施</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）向用户提供一个方便使用的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）系统维护及向用户提供有关信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6）保持文件系统的执行效率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 7）提供与I/O的统一接口</p><p>&nbsp; &nbsp; 3.文件的结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）文件逻辑结构的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件的逻辑结构是用户组织文件时可见的结构，即用户所观察到的文件组织形式。文件的逻辑结构是用户的文件组织形式。文件的逻辑结构是用户可以直接处理的数据及其结构，它独立于物理特性，又称为文件组织。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 选择文件的逻辑结构主要有一下原则：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&gt;查找快捷。根据给定的逻辑结构，应使文件系统在尽可能短的时间内找到所需要的记录或基本信息单位。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;修改方便。便于在文件中增加、删除和修改一条或多条记录。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3&gt;空间紧凑。应使文件的信息占据尽可能小的存储空间。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4&gt;易于操作。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）文件逻辑结构的形式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件的逻辑结构从形式上分为两类：有结构的记录式文件和无结构的流式文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 流式文件：文件中的数据是一串字符，没有结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 记录文件：由若干逻辑记录组成，每条逻辑记录又由相同的数据项组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 记录式文件可分为定长记录文件和不定长记录文件。</p><p>&nbsp; &nbsp; 4.文件物理结构的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）文件物理结构的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件的物理结构，又称为文件的存储结构，它是指文件在外存上存储时的组织结构。文件的物理结构与存储介质的物理特性及用户对文件的访问方式有关。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件的物理结构通常划分为大小相等的物理块。这些物理块也称为物理记录，它是文件分配及传输信息的基本单位。物理记录的大小与物理设备有关，与逻辑记录的大小无关。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）文件物理结构的形式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 根据文件存储设备的特征以及用户对文件的访问方式，可以在文件存储器中使用以下三种：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&gt;顺序结构。顺序结构是很简单的一种物理结构。顺序结构将一个在逻辑上连续的文件信息一次存放在外存连续的物理块中，即所谓的逻辑上的连续，物理上也连续。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 顺序结构的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一旦知道文件在存储设备上的其实块号和文件长度，能快速进行存取</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 顺序结构支持顺序存取和随机存取</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 顺序结构的缺点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件不能动态增长</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件分配内存空间比较慢</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 容易产生存储碎片 &nbsp; &nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;链接结构。克服顺序文件缺点的办法之一是采用链接结构。链接结构将文件存放在外存的若干个物理块中，这些物理块不必连续，并且在每一个物理块中设一个指针，指向下一个物理块的位置，从而使得存放在同一个文件的物理块链接起来。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; windows的FAT文件系统采用的就是链接结构。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 链接结构的优点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储碎片问题解决</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 有利于文件动态扩充，有利于文件插入、删除</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 提高磁盘利用率</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 链接结构缺点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存取速度慢</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不适合随机存取文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁盘磁头移动多，效率比较低</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存放文件的可靠性较差</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 链接指针需要额外的空间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3&gt;索引结构。索引文件克服了顺序文件和链接文件的缺点。索引结构将文件存放在外存的若干个物理块中，并将</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 索引文件的优点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 保持了链接结构的优点，又解决了其缺点。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 索引文件既适合于顺序存储，也适合于随机存储。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 索引文件缺点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 会引起较多的寻道次数和寻道时间，索引表增加存储空间的开销。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 索引文件结构对空间占用比较严重，索引表是定长还是不定长，解决问题如下：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）索引表的链接模式。这种模式存取文件需要读所有的索引表，对于大文件需要读很多块。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）多级索引</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4&gt;索引结构的实例——I节点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I节点是一种多级索引结构，最早出现在UNIX系统中。I节点在一般多级索引结构文件基础上，进行了结构的变化。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I节点的思想，是给每个文件赋予一张成为I节点的小表，这张小表列出了文件属性和文件中个这块在磁盘上的地址。</p><p>&nbsp; &nbsp; 5.文件的存储介质，主要是文件的外存储设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.1顺序存储设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 顺序存储设备是按信息的物理位置进行定位和读/写操作的存储设备。在顺序存储设备中，只有前面的物理块被存取之后，才能存取其后的物理块。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁带的存储特性如下：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）磁带是一种顺序存取的存储设备，总是从磁头的当前位置开始读写</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）磁带上的块不由地址来标识，而由其在次带上的位置来识别</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）块与块之间有间隙，磁带上的物理块就是通过间隙来区分的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）磁带的存取速度与信息密度、磁带带速和块间间隙有关。如果带速高，信息密度大，且所需块间隙小，则磁带存取速度高。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）磁带的容量大，采用顺序存取方式时存取速度高，采用随机存取方式效率较低</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.2随机存储设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 允许文件系统直接存取对应存储介质上的任意物理块的存储设备。如磁盘就是典型的随机存储设备。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 与磁盘有关的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）磁道。磁盘盘片上的一系列同心圆成为磁道；为了描述磁道，对磁道由外向内进行编号，成为磁道号（编号均从0开始）。即系统通过磁道号完成对磁道的操作。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）柱面。与盘片中心有相同距离的所有磁道组成一个柱面；当磁臂移动到某一位置时，所有的读写磁头 都在同一个柱面上，盘面上的磁道号即为柱面号；对于软盘，一个柱面仅包含两个磁道。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）扇区。磁道沿径向又分成大小相等的若干区域，每个区域成为一个扇区，每个扇区可以存放相等字节数（一般为512字节）的信息，按照与磁盘旋转相反的方向依次给扇区编号，成为扇区号。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）磁头号。所有的读写磁头由上至下进行编号成为磁头号。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁盘空间的位置由三个因素决定：柱面号、磁头号、扇区号。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 访问磁盘的时间由三部分组成，即寻道时间、延迟时间和传输时间。其中寻道时间是指将磁头从当前位置移动到指定磁道所经历的时间，也称为移臂时间；延迟时间是通过磁盘的旋转将所指定扇区移动到磁头下面的时间，也称为旋转时间；传输时间是指将扇区上的数据从磁盘读出或向磁盘写入数据所经历的时间。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁盘每个物理块的位置可用柱面号、磁头号和扇区号表示：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）已知物理块号，则磁盘地址：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 柱面号=[物理块号/(磁头数*扇区数)]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁头号=[(物理块号%(磁头数*扇区数))/扇区数]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 扇区号=[(物理块号%(磁头数*扇区数))%扇区数]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）已知磁盘地址：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 物理块号=柱面号*(磁头数*扇区数)+磁头数*扇区数+扇区号</p><p>&nbsp; &nbsp; 6.文件的存取方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 随机存取方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 随机（直接）存取方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件目录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 是指存放文件有关信息的一种数据结构。它包含多条记录，每条记录为一个文件的文件控制块（FCB）的有关信息。最简单的记录包含文件名和文件的其实地址，用以建立文件名和存储地址的对应关系。较复杂的记录包含文件控制块的全部内容，此时，文件目录就是文件控制块的集合。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件目录是文件实现按名存取的重要手段，是文件符号到文件物理地址之间的一种映射机制。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目录项：构成文件目录的项目（目录项即使FCB）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 目录文件：用户新建一个文件时，与文件有关的信息在该文件的文件控制块内，多个文件的文件控制块一起组成了文件的目录。为了实现对文件目录的管理通常将文件目录以文件的形式保存在外存。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件目录的管理形式可以分为一级目录、二级目录、多级目录三种。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一级目录，也称为单级目录，是一种最简单、最原始的目录结构。它采用的方法是为外存的全部文件建立一张目录表。表中包括全部文件的文件名、索引表的始址以及文件的其他属性，如文件长度、文件类型等。每个文件占据表中的一条记录。该目录表存放在外存的某个固定区域，需要时系统将其全部或部分导入主存。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一级目录的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）目录结构易于实现，管理简单，只需要建立一个文件目录，对文件的所有操作，都是通过该文件目录实现的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）易发生重名问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）当文件较多时，查找时间较长</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）不便于实现文件共享，适用于PC机的单用户系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了克服单级目录结构所存在的缺点，可以把单级目录扩充为二级目录。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在二级目录中，有主文件目录和用户文件目录。在主文件目录中，每个用户文件目录都占有一个目录项，其中包括用户名和指向该用户目录文件的指针。用户文件的文件说明组成的目录文件成为用户文件目录，不同的用户拥有不同的用户文件目录，这些文件目录具有相似的结构，由用户所有文件的文件控制块组成。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 二级目录的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）提高了检索目录的速度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）可以解决用户文件重名问题</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）可以使不同用户共享同一个文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）可以实现对文件的保护和保密</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）二级文件目录虽然解决了不同用户之间文件同名的问题，但是，同一用户的文件不能同名。当一个用户的文件很多时，这个矛盾就比较突出了。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为了解决用户文件同名的问题，可以把二级目录的层次关系加以推广，就形成了树型目录。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在二级目录结构中，如果进一步允许用户创建自己的子目录并相应地组织自己的文件，即可以形成三级目录结构，依次类推，还可以进一步形成多级目录。通常把三级或三级以上的目录结构成为树型目录结构。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在树型目录结构中，除了最低一级外，其他每一级存放的都是下一级目录或文件的说明信息，最高层为根目录，最底层为文件。UNIX和DOS系统中都采用了树型目录结构。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 树型目录的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）层次清楚：不同性、不同用户的文件可以构成不同的子树，便于管理；不同用户的文件可以被赋予不同的权限，有利于文件的保护。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）解决了用户文件重名问题：只要在同一目录下的文件名不发生重复，就不会由文件重名引起混乱。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）搜索速度快：可为每类文件建立一个子目录，对于多级目录，每次只查找子目录，因此速度比一级和二级目录时快。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 用户在访问文件时，需要进行目录检索，用户给出文件名，系统按名寻找目录项。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 有两种根据路径检索的方法：全路径名和相对路径。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 全路径名：需要从根目录开始，列出由根到用户的所有子目录，又称为“绝对路径名”。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：每次都从根目录开始检索，很不方便，因为通常目录放在外存故影响访问速度，尤其当目录层次较多时，检索需要耗费很长时间。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 相对路径：用于检索的路径只是从当前目录开始到所要访问文件的一段路径，即以当前目录作为路径的相对参照点。这样检索速度比较快。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件寻址：根据FCB中文件物理地址等信息，求出文件的任意记录或字符在存取介质上的地址，称为文件寻址。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件目录改进</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 为加快目录检索可采用目录项分解法：把FCB分成两部分：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 符号目录项（次部）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件名，文件号</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 基本目录项（主部）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 除文件名外的所有项目</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 分解之后的查找过程：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 查找一个目录项就分成两步：首先访问符号目录文件，根据文件名查找相应的文件内部号；然后访问基本目录文件，根据文件内部号，可直接计算出相应基本目录项所在基本目录文件中的相对位置和物理位置，并将它直接读入内存。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 目录操作：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 以UNIX为例：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.Creat</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.Delete</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.Opendir</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.Closedir</p><p>&nbsp; &nbsp; 7.存储空间的分配和回收</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）位图法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用一串二进制位反应磁盘空间中分配使用情况，每个物理块对应一位，分配物理块为1，否则为9</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 申请物理块时，可以在位示图中查找为0的位，返回对应物理块号</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 归还时，将对应位转置0</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 描述能力强，适合各种物理结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 计算公式：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 已知字号i，位号j</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 块号=i*字长+j</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 已知块号：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 字号=[块号/字长]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 位号=块号%字长</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）空闲块表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 将所有空闲块记录在一个表中，即空闲块表特别适合文件物理结构为顺序结构的文件系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3）空闲块链表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 把所有空闲块链成一个链</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4）成组链接法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件系统的实现</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 内存中多需的表目</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）系统打开文件表（整个系统一张）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 放在内存。用于保存已打开文件的FCB</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 此外，文件号，共享计数，修改标志</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）用户打开文件表（每个进程一个）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件描述符，打开方式，读写指针，系统打开文件进程的PCB中，记录了用户打开文件表的位置</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）用户打开文件表与系统打开文件表之间的关系</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户打开文件表指向系统打开文件表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果多个进程共享同一个文件，则多个用户打开文件表目对用系统打开文件表的同一入口</p><p>&nbsp; &nbsp; 8.记录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 记录是一组相关数据项的集合，用于描述数据对象某方面的属性。它是文件中数据处理的基本单位，是组成文件的基本元素。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 在一个由大量记录组成的文件中，为了能惟一地标识一条记录，可以在记录的各个数据项中，确定出一个或几个数据项，把它（或它们）成为关键字（key）。如在描述学生的数据项中，学号可以作为关键字。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 记录的成组和分解</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 每个用户的文件是由用户按照自己的需要组织的，逻辑记录的大小是由文件的性质决定的。而存储介质上的分块是根据存储介质的特性划分的。所以，逻辑记录的大小往往与存储块的大小不一致。为了节省存储空间，提高主存的利用率，系统引入了记录的成组和分解。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 记录成组</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 记录成组是指把若干条逻辑记录合并成一组存入一个物理块的过程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 记录分解是指从一条物理记录中把逻辑记录分离出来的过程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 记录成组存放后，当用户需要某一条记录时，必须把含有该条记录的整块信息独处，再从这一组逻辑记录中找出用户所需要的记录进行处理。记录分解也需要使用主存缓冲区。</p><p>&nbsp; &nbsp; 9.文件的操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 提供设置和修改对用户文件存取权限</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 提供建立、修改、改变、删除目录的服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 提供文件共享，设置访问路径的服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 提供创建、打开、读、写、关闭、撤销文件等服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件系统维护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件系统的转储和恢复</p><p>&nbsp; &nbsp; 10.文件的保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件的共享</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）定义</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一个文件被多个用户或程序使用</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 共享形式：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 被多个用户使用，由存取权限控制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 被多个程序使用，但各用自己的读写指针</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 被多个程序使用，但共享读写指针</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）目的</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 节省时间和存储空间，减少了用户工作量；</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进程间通过文件交换信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件安全是指避免合法用户有意或无意的错误操作破坏文件，或非法用户访问文件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 影响文件安全性的主要因素有：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）认为因素</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）系统因素</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）自然因素</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 为了确保文件系统的安全性，可以采取以下措施：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）建立副本，通过“后备系统”来防止由自然因素所造成的不安全性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）定时转储，通过系统容错技术来防止系统部分的故障所造成的文件不安全性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）规定文件的存取权限，通过存取控制机制来防止由人为因素引起的文件不安全性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：建立副本的方法简单，但是系统开销大，且文件更新时，所有副本都必须更新。这种方法使用容量较小且极为重要的文件。定时转储的方法简单，但是较为费时，在转储过程中一般要停止文件系统的使用。这种方法适用于容量较大的文件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件的使用权限可以设为：只能读、可读可写、只能执行、不能删除等。对多用户共享的文件采用属性、目录结构，反得到某级目录权限的用户就可以得到该目录所属的全部目录和文件。</p><p>&nbsp; &nbsp; 11.文件的存取权限</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）存取控制矩阵：系统以一个二维矩阵来实施文件的存取控制。其方法在概念上比较简单。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）二级存取控制：两个存取级别。第一级，把用户按照某种关系分为若干组，进行对访问者的识别，第二级，进行对操作权限的识别。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; UNIX中的文件存取权限：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第一级：对访问者的识别</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对用户分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件主（owner）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件主的同组用户（group）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 其它用户（other）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 第二级：对操作权限的识别</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 对操作分类：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 读操作（r）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 写操作（w）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 执行操作（x）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 不能执行任何操作（-）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 文件属性rwxr--xr--x用二进制表示是111101101，在UNIX中使用八进制，因此权限是755</p><p>&nbsp; &nbsp; 12.文件保密</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件保密是指文件本身不得不被未授权的用户访问，防止他人窃取文件。实现文件保密采用的方法有：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）隐藏文件目录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）设置口令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）使用密码</p><p>&nbsp; &nbsp; 13.文件系统的优化</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 文件系统的物理基础是磁盘设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 常见的技术措施：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）块高速缓存</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）合理分配磁盘空间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）磁盘的驱动调度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）信息的优化分布</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5）RAID技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1&gt;块高速缓存</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 系统在内存中保存一些块。逻辑上它们属于磁盘</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2&gt;合理分配磁盘空间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3&gt;磁盘的驱动调度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 公平：一个I/O请求在有限时间内满足</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 高效：减少设备机械运动所带来的时间浪费</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁盘调度考虑的问题：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一次访盘时间=寻道时间+旋转延迟时间+传输时间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁盘驱动调度由“移臂调度”和“旋转调度”组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 移臂调度目的是尽可能减少寻找磁道时间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 旋转调度目的是尽可能减少寻找扇区时间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁盘调度算法：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）先来先服务（FCFS）：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 按访问请求到达的先后次序服务</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优点：简单，公平</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缺点：效率不高，相邻两次请求可能会造成最内到最外的柱面寻道，使磁头反复移动，增加了服务时间，对机械也不利</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）最短寻道时间优先（SSTF）：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 优先选择距当前磁头最近的访问请求进行服务，主要考虑寻道优先</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：该调度算法，虽然减少了磁臂的移动距离，但是，会经常改变磁臂的移动方向，花费时间多又影响机械部件，还会导致“饥饿”现象，即较远距离的鼓励的访问者可能很长时间不能获得访问磁盘的机会。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）扫描算法（SCAN电梯算法）：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 克服了最短寻道有限的缺点，考虑了距离和方向</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）循环扫描（C-SCAN）调度算法：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在扫描算法的基础上改进的。balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4&gt;旋转调度算法</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 旋转调度：根据延迟时间来决定执行次序的调度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5&gt;信息的优化分布</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 记录在磁道上的排列方式也会影响磁盘的输入输出时间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6&gt;RAID技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 磁盘时机械设备，一方面速度慢，一方面也容易出现故障。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RAID是一种把多块独立的硬盘（物理硬盘）按不同的方式组合起来形成一个硬盘组（逻辑硬盘），从而提供比单个硬盘更高的存储性能和提供数据备份技术。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Windows的FAT文件系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FAT文件系统是各种Windows操作系统都支持的一个简单的文件系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FAT文件系统一簇为单位进行分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FAT有三个版本：FAT-12，FAT-16，FAT-32</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FAT卷的结构包括：引导扇区、文件分配表、根目录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; UNIX文件系统</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX目录中为每个文件保留了一项，每个目录项包含了两个域，文件名和节点号。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UNIX普通文件的物理结构是三级索引结构</p><p><br/></p><p><strong><span style="font-size: 18px;">第七章 I/O设备管理</span></strong></p><p>&nbsp; &nbsp; 考试内容</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1.设备与设备分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.I/O硬件组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3.I/O软件的特点及结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.典型技术：通道技术，缓冲技术，SPOOLing</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 5.I/O性能问题及解决方案</p><p>&nbsp; &nbsp; 1.设备与设备的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 按设备的使用特性分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）存储设备。存储设备是指用来存放信息的设备，如磁盘、磁带等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）I/O（输入输出）设备</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 按设备共享属性分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）独占设备。独占设备是指在一段时间内只允许一个进程访问的设备。系统一旦把这种设备分配给一个进程后，便由该进程独占，直到用完释放，其他进程才能使用。多数低速设备都属于此类设备，如打印机。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）共享设备。共享设备是指在一段时间内允许多个进程访问的设备，如磁盘。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）虚拟设备。虚拟设备是指通过虚拟技术将一台独占设备变换为若干台逻辑设备，供若干个进程同时使用的设备，如虚拟打印机。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 按设备的信息组织方式来分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）块设备。块设备是指处理信息的基本单位是字符块。一般块的大小为512B~4KB，如磁盘、磁带等。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）字符设备。字符设备是指处理信息的基本单位是字符，如键盘、显示器、打印机等。</p><p>&nbsp; &nbsp; 2.I/O硬件组成</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.1计算机的I/O系统结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 从硬件的角度来看，一个典型的计算机结构，中央部分是CPU和主存，通过总线与第二层的接口部分连接，第三层各种外围设备控制器，最外层是外围设备。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.2I/O设备数据传输控制方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序直接控制方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序直接控制方式也称为“忙——等待”方式，即在一个设备的操作没有完成时，控制程序一直检测设备的状态，直到该操作完成，才能进行下一个操作。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 步骤为：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）当用户需要输入数据时，由处理器向设备控制器发出一条输入输出指令，启动设备进行输入。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）当用户进程需要像设备输出数据时，也必须发出启动命令启动设备输出，并等待输出操作完成。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：工作过程简单，CPU的利用率低。直接控制方式适用于早期的无中断的计算机系统。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序中断控制方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断控制是指计算机在执行期间，系统内发生任何给寻常的或非预期的急需处理事件，使得CPU暂时中止当前执行的程序而转去执行相应的时间处理程序，待处理完毕后又返回原来被中止处继续执行或调度新的进程。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：中断控制方式比程序直接控制方式提高了CPU的利用率。每输入一个数据都会发生中断，传输一组数据需要多次中断，浪费了CPU的时间。中断控制方式应用与现代计算机系统中。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 直接存储器存取控制方式（DMA）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 直接存储器存取方式是指对输入输出设备的控制由DMA控制器完成，在DMA控制器的作用下，设备和主存之间可以成批地进行数交换，而不用CPU的干涉。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：数据的传送方向、存放数据的主存始址及传送数据的长度等都由CPU控制，具体的数据传送由DMA控制器负责，每台设备需要配一个DMA控制器，这样输入输出传输速度快，CPU负担少。直接存储器存取控制方式适用于块设备的数据传输。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通信控制方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I/O通信是一种特殊的处理机</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 具有执行I/O指令的能力</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 具有执行通道（I/O）程序控制I/O操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 指令类型单一，主要限于I/O操作有关的指令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 没有自己的内存，通道程序放在主机内存中</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 特点：通道所需要的CPU干预更少，并可以实现CPU、通道和输入输出设备三者之间的并行操作，从而更有效地提高整个系统资源的利用率。通道控制方式适用于现代计算机系统中的大量数据交换。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2.3输入输出通道的分类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 输入输出通道是用于控制外围设备的。根据信息交换方式的不同，把通道分成三种类型：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）选择通道。可以连接多台高速设备，由于它只含有一个分配型子通道，在一段时间内只能执行一个通道程序，控制一台设备进行数据传送，致使当某台设备占用了该通道后，便一直由它独占，直至该设备传送完毕后释放该通道。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 数据选择通道虽然有很高的传输速率，但它每次只允许一个设备传输设备，这种通道利用率很低。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）字节多路通道。通常都含有许多非分配型子通道，其数量可以从几十到数百个，每一个子通道连接一台输入输出设备，这些子通道按时间片轮转方式共享主通道。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 字节多路通道连接低速或中速设备时，不会丢失信息。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）数组多路通道。将数据选择通道传输速率高和字节多路通道能使各子通道（设备）分时并行操作的优点相结合，而形成的一种新通道。它含有多个非分配子通道，因而这种通道既具有很高的数据传输速率，又能获得令人满意的通道利用率。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 该通道被广泛地用于连接多台高、中速的外围设备，其数据传送是按数组方式进行的。</p><p>&nbsp; &nbsp; 3.I/O软件的特点及结构</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 设计I/O最关键的目标是设备独立性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; I/O设备管理软件的结构，基本思想是分层构造，使底层与硬件相关，把硬件与较高层次的软件隔离。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; I/O软件分为四层：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断处理程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设备驱动程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 与设备无关的系统软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户空间的I/O软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 设备驱动程序的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; balabala...</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 设计I/O最关键的目标是设备独立性。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; I/O设备管理软件的结构，基本思想是分层构造，使底层与硬件相关，把硬件与较高层次的软件隔离。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; I/O软件分为四层：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 中断处理程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设备驱动程序</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 与设备无关的系统软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 用户空间的I/O软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 设备驱动程序的特点：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）驱动程序主要是在请求输入输出的进程与设备控制器之间的一个通信程序。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）驱动程序与输入输出设备的特性密切相关</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）驱动程序与输入输出控制方式紧密相关</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）驱动程序与硬件紧密相关，其部分被固化在ROM中</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 与设备无关的系统软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 除了一些I/O软件与设备相关外，大部分软件是与设备无关的。一般情况，所有设备都需要的I/O功能可以在于设备独立的软件中实现。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 设备无关软件层实现的一些功能：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 统一命名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 设备保护</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 提供与设备无关的逻辑块</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 缓冲</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 存储设备的块分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 独占设备的分配与释放</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 出错处理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 用户空间的I/O软件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 大部分I/O软件都包含在操作系统中，但是用户程序可以和库函数连接在一起</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 标准的I/O库包含了许多设计I/O的过程，他们都是作为用户程序的一部分运行的</p><p>&nbsp; &nbsp; 4.缓冲技术</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 为了提高输入输出设备的速度和利用率，在输入输出设备与处理器交换数据时引入了缓冲技术。缓冲技术是输入输出设备在与主存交换数据时使用缓冲区的技术。缓冲管理的主要功能是组织好缓冲区，并提供获得和释放缓冲区的手段。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.1缓冲的引入</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）缓和CPU与输入输出设备间速度不匹配的矛盾</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）减少对CPU的中断频率，放款对中断响应时间的限制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）提高CPU与输入输出设备间的并行性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.2单缓冲</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 单缓冲是指在设备和处理器之间设置一个缓冲区，用于数据的传输</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.3双缓冲</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 双缓冲是指在设备和处理器之间设置两个缓冲区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.4多缓冲</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在设备和处理器之间设置多个缓冲区</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4.5缓冲池</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当系统较大时，可以利用多个进程共享的缓冲池来提高缓冲区的利用率</p><p>&nbsp; &nbsp; 5.I/O性能问题及解决方案小结</p><p>&nbsp; &nbsp; &nbsp; &nbsp; I/O性能常常成为系统性能的瓶颈，因此提高I/O性能十分重要</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）通过缓冲技术，减少或缓解不同设备之间传输速度的差距</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）通过异步I/O技术，使CPU计算不必等待I/O操作结果</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3）通过应用DMA和通信部件，使CPU摆脱I/O操作，与这些部件并行执行</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4）通过虚拟设备技术，提高独占设备的利用率</p><p><br/></p><p><strong><span style="font-size: 18px;">第八章 死锁</span></strong></p><p>&nbsp; &nbsp; 活锁概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 数据资源释放时间不确定，导致某些事务长时间等待，得不到封锁的机会</p><p>&nbsp; &nbsp; 饥饿的概念</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 系统没有发生死锁，但某些进程可能会长时间等待，当等待时间给进程推进和响应带来明显影响时，称进程饥饿</p><p>&nbsp; &nbsp; 死锁的原因</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）竞争资源</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）进程推进顺序不合理</p><p>&nbsp; &nbsp; 产生死锁的必要条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 死锁并不一定都会出现，如果一旦产生死锁，一定会满足下述4个必要条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）互斥条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）不剥夺条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3）请求和保护条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4）循环等待条件</p><p>&nbsp; &nbsp; 解决死锁的方法分为四种</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 1）预防死锁。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 预防死锁是在进行资源分配之前，通过设置某些资源分配的限制条件，来破坏产生死锁的四个必要条件的一个或几个。预防死锁是一种较简单的方法，容易使用，但是，由于施加了限制条件，会导致系统资源利用率和吞吐量的下降。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 2）避免死锁。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 避免死锁是在资源分配前不设置限制条件，在进行资源分配的过程中，用某种方法对每次资源分配进行管理，以避免某次分配使系统进入不安全状态，以致产生死锁。这种方法限制较小，可以获得较好的系统资源利用率和吞吐量。目前比较完善的系统中，通常采用此种方法。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 3）检测死锁</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 允许系统产生死锁，但在系统中设置检测机构，一旦发生死锁，采取措施解除死锁</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 4）解除死锁</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 通过撤销或挂起一些死锁中的进程，回收相应的资源，进行资源的再次分配，从而将进程死锁状态解除。这种方法没有限制，可以获得较好的系统资源利用率</p><p>&nbsp; &nbsp; 死锁的预防</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 通过对资源分配的原则进行限制，而使产生死锁的四个必要条件中的1个或多个条件不能成立，来预防产生死锁。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 破坏“互斥条件”条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 进制进程独占资源，如果资源不被一个进程独占，你们死锁肯定不会发生</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 此条件实现比较困难，限制比较多</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 破坏“不剥夺”条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一个已经占有某些资源的进程，当它再提出新的资源需求而不能立即得到满足时，必须释放它已经占有的所有资源，待以后需要时再重新申请。这意味着进程已经拥有的资源，在运行过程中可能会暂时被迫释放，即被系统剥夺，从而摒弃了“不剥夺条件”</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这种预防死锁的方法，实现起来比较复杂，并付出较大的代价，会使前段时间的工作实效等。此外这种方法还会因为反复地申请和释放资源，延长进程的周转时间，增加系统开销，降低系统吞吐量。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 破坏“请求和保持”条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 系统要求进程必须一次性地申请其在整个运行期间所需要的全部资源。若系统有足够的资源，便一次性将其所需要的所有资源分配给该进程，这样一来，该进程在整个运行过程中，便不会再提出资源请求，从而摒弃了“请求”条件。而在分配时，只要有一个资源要求不能满足，系统将不分配给该进程任何资源，此时进程没有占有任何资源，因而也摒弃了“保持”条件，所以，可以预防死锁的产生。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这种预防死锁的方法，简答方便、易于实现，但是，因为进程将一次性获得所有资源，并且独占使用，其中可能有些资源在该进程运行期间很少使用，造成资源严重浪费；同时有些进程因不能一次性获得所需要的资源，导致长时间不能投入运行。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 破坏“循环等待”条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在这种方法中规定，系统将所有的资源按照类型进行线性排序，赋予不同的资源序号。并且所有进程对资源的请求和分配必须严格的按照资源序号有小到大地进行，即只有先申请和分配到序号小的资源，才能申请和分配序号大的资源。这样在最后形成的资源分配图中，将不可能再出现环路，从而摒弃了“环路等待”条件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 这种预防死锁的方法与前两种相比，其资源利用率和系统吞吐量，都有明显的改善。但是，这种方法涉及对各类资源的排序编号，考虑到实际的使用，其排序的合理性将受到很大的挑战。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 破坏“循环等待”条件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在这种方法中规定，系统将所有的资源按照类型进行线性排序，赋予不同的资源序号。并且所有进程对资源的请求和分配必须严格的按照资源序号有小到大地进行，即只有先申请和分配到序号小的资源，才能再申请和分配序号大的资源。这样在最后形成的资源分配图中，将不可能再出现环路，从而摒弃了“环路等待”条件。</p><p>&nbsp; &nbsp; 死锁的避免</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 在死锁的避免中，所施加的限制较弱，可以获得较好的系统性能。该方法的系统状态分为安全状态和不安全状态，只要能使系统时钟处于安全状态，便可以避免死锁发生。</p><p>&nbsp; &nbsp; 安全状态和不安全状态</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 安全状态是指系统能够按照某种顺序为每个进程分配搜需要资源，直到最大需求，使每一个进程都可以顺利完成。反之，如果系统不存在这样的一个安全序列，则称系统处于不安全状态。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 当系统进入不安全状态后，很有可能进入死锁状态；反之，只要系统处于安全状态，便可避免进入死锁状态。因此，避免死锁的实质就是如何是系统不进入不安全状态。</p><p>&nbsp; &nbsp; 利用银行家算法避免死锁</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 最具代表性的避免死锁的算法是Dijkstra和Habermann的银行家算法。这是由于该算法能用于银行系统现金贷款的发放而得名。</p><p>&nbsp; &nbsp; 死锁的检测与接触</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 当系统为进程分配资源时，如果没有采取任何限制措施，系统必须提供死锁的检测与解除机制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 死锁的检测</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 在进行死锁的检测时，系统必须能保存有关资源的请求和分配的信息，并提供一种算法，以便利用这些信息来检测系统是否进入死锁状态。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 死锁的解除</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 当检测到系统发生死锁时，就必须立即把死锁状态解除，常用的方法是：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）剥夺资源法。从其他进程剥夺足够数量的资源给死锁进程，使其得到足够的资源，然后继续执行，以解除死锁状态。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）撤销进程法。系统采用强制手段将死锁进程撤销。最简单的方法是将全部死锁进程一次性撤销，但是，代价较大；另一种方法是按照一定的算法，从死锁进程中一个一个地选择进行撤销，并同时剥夺这些进程的资源，直到死锁状态解除为止。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 死锁定理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1）如果资源分配图中没有环路，则系统没有死锁</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2）如果资源分配图中出现了环路，则系统可能出现死锁</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果环路中每个资源的数目只有一个，则意味着死锁的存在，此时，环路是死锁的中分必要条件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果处于环路的每个资源数目不为1，则是死锁产生的必要而不是充分条件</p><p><br/></p>]]></content>
  </entry>
  <entry>
    <title>黑幕！黑色的明天等待着我们</title>
    <link href="https://old-blog.smallyu.net/index48db.html?id=58"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=58</id>
    <published>2017-07-24T16:00:00.000Z</published>
    <updated>2017-07-24T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>考试前一天晚上，所有人都知道了考试题目…… 大学，期末考试，某门课，考试前一天晚上，很多（几乎所有）人，都知道了第二天考试要考的，80%（以上）的试题， 一字不差的那种。 试题的流传过程是这样的。 背景，学生A和学生B都是宿舍A的。 背景，学生A和学生B对试题的传播几乎没有过交流。 老师同时把题给了学生A和学生B，然后人情社会，利益相关， 学生A把题告诉了宿...</p>]]></summary>
    <content type="html"><![CDATA[<p style="text-align: left;">考试前一天晚上，所有人都知道了考试题目……</p><p>大学，期末考试，某门课，考试前一天晚上，很多（几乎所有）人，都知道了第二天考试要考的，80%（以上）的试题，</p><p>一字不差的那种。</p><p><br/></p><p>试题的流传过程是这样的。</p><p>背景，学生A和学生B都是宿舍A的。</p><p>背景，学生A和学生B对试题的传播几乎没有过交流。</p><p>老师同时把题给了学生A和学生B，然后人情社会，利益相关，</p><p>学生A把题告诉了宿舍A（也就是自己宿舍）和宿舍C（平时玩的比较好），</p><p>学生B把题告诉了宿舍B（可能玩的比较好）和宿舍D（其实这里稍有误）。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/07/201707251500981564881973.png" title="搜狗截图20170725174343.png" alt="搜狗截图20170725174343.png" width="434" height="324" style="width: 434px; height: 324px;"/></p><p>图中虚线表示学生A和学生B都是宿舍A的，实线表示试题的流传过程。</p><p><br/></p><p>泄题本身很难判断对错。</p><p>学生A的成绩差，老师一片好心。</p><p>学生B是班长，（脑补原因）。</p><p>噢对，学生A是老师的助理。（所以老师才会关心他的成绩差，而不是别人。成绩差也是能当助理的）</p><p>对于成绩差的学生A，我们丝毫不介意甚至迫切希望老师泄题给他，因为我们也不希望他挂科。（好吧一个宿舍的）</p><p>然后从结果上看，老师泄题，我们几乎所有人（起码我）得知了第二天要考的题目。</p><p>我们平时还盼着老师给划个重点，现在真题都有了，难不成还站在道德的制高点说泄题的行为是错误的？</p><p>当然不可以，但直接出来那么多真题确实有点怀疑人生。</p><p>原来人情，连这种违反规定的事情，都可以解决。</p><p>但是同样从人情的角度看，老师背着违反规定的风险泄题给你，想让你不挂科，给你个机会，这是老师在做好。</p><p>对我们有利，所以我们不能（也不会）说它是错的。</p><p>不过如果我们（我）不是受益者，可能我就会改变说法。</p><p><br/></p><p>泄题的过程才让人感慨。（泄不泄题和我没太大关系，对成绩影响不大）</p><p>全班几十个学生，老师只告诉了两个人，其中没有你，你伤不伤？</p><p>学生A只告诉了宿舍A和宿舍C，那么宿舍B和宿舍D的，你伤不伤？</p><p>同理，学生B只告诉了宿舍B和宿舍D的，尤其，连它自己的宿舍A都没告诉，你伤不伤？</p><p>问题是，资源在人家手里，想给谁给谁。</p><p>尴尬的是，最后，几乎所有人都知道了。</p><p>宿舍B的人跑到宿舍A，咦，你这题哪儿来的？</p><p>宿舍A黑人问号脸，咦，怎么，你知道？</p><p><br/></p><p>哈哈哈哈哈哈哈哈</p><p><br/></p><p>谁都能理解，谁都不想理解。</p><p>面对资源，部分人性可以显露。</p><p>所以石油才会引发大国之间的战争？《文明6》里面加成资源算是很值钱的东西，像牛羊马，鹿，鱼，或者战略资源，石油，铀，硝石。</p><p><br/></p><p>问：好人是从什么时候开始变坏的？</p><p>答：觉得不公平的时候。</p><p><br/></p><p>可是 (公平!=公正)==true</p><p><br/></p><p>社会我社会</p><p><br/></p><p>我等身与名俱灭，不废长江万古流啊</p>]]></content>
  </entry>
  <entry>
    <title>2017年上半年年度总结，2017年下半年年度展望</title>
    <link href="https://old-blog.smallyu.net/index850a.html?id=57"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=57</id>
    <published>2017-07-12T16:00:00.000Z</published>
    <updated>2017-07-12T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>没啥好总结的，没啥好展望的。 （不忍心总结过去的半年，没有勇气开始新的半年）</p>]]></summary>
    <content type="html"><![CDATA[<p>没啥好总结的，没啥好展望的。</p><p><br/></p><p>（不忍心总结过去的半年，没有勇气开始新的半年）</p>]]></content>
  </entry>
  <entry>
    <title>SPL中的常用迭代器和函数</title>
    <link href="https://old-blog.smallyu.net/indexadbc.html?id=56"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=56</id>
    <published>2017-06-15T16:00:00.000Z</published>
    <updated>2017-06-15T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>有一天，我去世了，恨我的人，翩翩起舞，爱我的人，眼泪如露。 第二天，我的尸体头朝西埋在地下深处，恨我的人，看着我的坟墓，一脸笑意，爱我的人，不敢回头看那么一眼。 一年后，我的尸骨已经腐烂，我的坟堆雨打风吹，恨我的人，偶尔在茶余饭后提到我时，仍然一脸恼怒，爱我的人，夜深人静时，无声的眼泪向谁哭诉。 十年后，我没有了尸体，只剩一些残骨。恨我的人，只隐约记得我的名...</p>]]></summary>
    <content type="html"><![CDATA[<blockquote><p>有一天，我去世了，恨我的人，翩翩起舞，爱我的人，眼泪如露。</p><p>第二天，我的尸体头朝西埋在地下深处，恨我的人，看着我的坟墓，一脸笑意，爱我的人，不敢回头看那么一眼。</p><p>一年后，我的尸骨已经腐烂，我的坟堆雨打风吹，恨我的人，偶尔在茶余饭后提到我时，仍然一脸恼怒，爱我的人，夜深人静时，无声的眼泪向谁哭诉。</p><p>十年后，我没有了尸体，只剩一些残骨。恨我的人，只隐约记得我的名字，已经忘了我的面目，爱我至深的人啊，想起我时，有短暂的沉默，生活把一切都渐渐模糊。</p><p>几十年后，我的坟堆雨打风吹去，唯有一片荒芜，恨我的人，把我遗忘，爱我至深的人，也跟着进入了坟墓。对这个世界来说，我彻底变成了虚无。我奋斗一生，带不走一草一木。我一生执着，带不走一分虚荣爱慕。</p><p>今生，无论贵贱贫富，总有一天都要走到这最后一步。</p><p>到了后世，霍然回首，我的这一生，形同虚度！我想痛哭，却发不出一点声音，我想忏悔，却已迟暮！用心去生活，别以他人的眼光为尺度。爱恨情仇其实都只是对自身活着的，每一天幸福就好。</p><p>珍惜内心最想要珍惜的，三千繁华，弹指刹那，百年之后，不过一捧黄沙。</p></blockquote><p><strong><br/></strong></p><p><strong>SPL的常用迭代器</strong>,通过某种统一的方式遍历链表或者数组中的元素的过程叫做迭代遍历，而这种统一的遍历工具我们叫做迭代器。</p><blockquote><p>ArrayIterator</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$fruits&nbsp;=&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;&quot;apple&quot;&nbsp;=&gt;&nbsp;&#39;apple&nbsp;value&#39;,&nbsp;//&nbsp;position&nbsp;=&nbsp;0
&nbsp;&nbsp;&nbsp;&nbsp;&quot;orange&quot;&nbsp;=&gt;&nbsp;&#39;orange&nbsp;value&#39;,&nbsp;//&nbsp;position&nbsp;=&nbsp;1
&nbsp;&nbsp;&nbsp;&nbsp;&quot;grape&quot;&nbsp;=&gt;&nbsp;&#39;grape&nbsp;value&#39;,
&nbsp;&nbsp;&nbsp;&nbsp;&quot;plum&quot;&nbsp;=&gt;&nbsp;&#39;plum&nbsp;value&#39;
];
//&nbsp;一般方式
print_r($fruits);
foreach($fruits&nbsp;as&nbsp;$key&nbsp;=&gt;&nbsp;$value){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$key.$value;
}

//&nbsp;使用ArrayIterator遍历数组
$obj&nbsp;=&nbsp;new&nbsp;ArrayObject($fruits);
$it&nbsp;=&nbsp;$obj-&gt;getIterator();
//&nbsp;foreach方式
foreach($it&nbsp;as&nbsp;$key&nbsp;=&gt;&nbsp;$value){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$key.$value;
}
/*&nbsp;foreach方式和普通的foreach方式没有区别，因为我们在使用foreach的过程中程序默认使用了迭代器，也就是底层实现的方式，先实例化数组为一个对象，然后调用迭代器的方法，进行遍历。&nbsp;*/
//&nbsp;while方式
$it-&gt;rewind();&nbsp;//&nbsp;调用current之前一定要rewind
while($it-&gt;valid()){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$it-&gt;key().$it-&gt;current();
&nbsp;&nbsp;&nbsp;&nbsp;$it-&gt;next();
}
/*&nbsp;while遍历的时候一定要记得rewin重置指针的位置。和普通foreach实现遍历相比，迭代器方式可以实现跳过某些元素再进行遍历，比如从位置1开始，而不是位置0.&nbsp;*/
//&nbsp;跳过某些元素进行打印
$it-&gt;rewind();
if($it-&gt;valid()){
&nbsp;&nbsp;&nbsp;&nbsp;$it-&gt;seek(1);&nbsp;//&nbsp;从position&nbsp;=&nbsp;1开始
&nbsp;&nbsp;&nbsp;&nbsp;while($it-&gt;valid()){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$it-&gt;key().$it-&gt;current();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$it-&gt;next();
&nbsp;&nbsp;&nbsp;&nbsp;}
}
/*&nbsp;ksort方式使得遍历结果按照key的字典序排序，如果想要value按照字典序排序，则使用asort。&nbsp;*/
$it-&gt;ksort();
foreach($it&nbsp;as&nbsp;$key&nbsp;=&gt;&nbsp;$value){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$key.$value;
}</pre><blockquote><p>AppendIterator</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$array_a&nbsp;=&nbsp;new&nbsp;ArrayIterator([&#39;a&#39;,&nbsp;&#39;b&#39;,&nbsp;&#39;c&#39;]);
$array_b&nbsp;=&nbsp;new&nbsp;ArrayIterator([&#39;d&#39;,&nbsp;&#39;e&#39;,&nbsp;&#39;f&#39;]);
$it-&gt;append($array_a);
$it-&gt;append($array_b);
//&nbsp;通过append方法把迭代器对象添加到AppendIterator对象中
foreach($it&nbsp;as&nbsp;$key&nbsp;=&gt;&nbsp;$value){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$value;
}
//&nbsp;只用一个foreach就可以实现多次遍历</pre><blockquote><p>MultipleIterator用于把多个Iterator里面的数据组合成为一个整体来访问</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$idIter&nbsp;=&nbsp;new&nbsp;ArrayIterator([&#39;01&#39;,&nbsp;&#39;02&#39;,&nbsp;&#39;03&#39;]);
$nameIter&nbsp;=&nbsp;new&nbsp;ArrayIterator([&#39;张三&#39;,&nbsp;&#39;李四&#39;,&nbsp;&#39;王五&#39;]);
$ageIter&nbsp;=&nbsp;new&nbsp;ArrayIterator([&#39;22&#39;,&nbsp;&#39;23&#39;,&nbsp;&#39;25&#39;]);
$mit&nbsp;=&nbsp;new&nbsp;MultipleIterator(MultipleIterator::MIT_KETS_ASSOC);
$mit-&gt;attachIterator($idIter,&nbsp;&quot;ID&quot;);
$mit-&gt;attachIterator($nameIter,&nbsp;&quot;NAME&quot;);
$mit-&gt;attachIterator($ageIter,&nbsp;&quot;AGE&quot;);
foreach&nbsp;($mit&nbsp;as&nbsp;$value)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;print_r($value);
}</pre><blockquote><p>FilesystemIterator能遍历文件系统</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$it&nbsp;=&nbsp;new&nbsp;FileSystemIterator(&#39;.&#39;);
foreach&nbsp;($it&nbsp;as&nbsp;$finfo)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;%s\t%s\t%8s\t%s\n&quot;,date(&quot;Y-m-d&nbsp;H:i:s&quot;,&nbsp;$finfo-&gt;getMTime()),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$finfo-&gt;isDIr()&nbsp;?&nbsp;&quot;&lt;DIR&gt;&quot;&nbsp;:&nbsp;&quot;&quot;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;number_format($finfo-&gt;getSize()),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$finfo-&gt;getFileName()
&nbsp;&nbsp;&nbsp;&nbsp;);
}</pre><p><strong>SPL基础接口</strong></p><blockquote><p>SPL的基础接口里面定义了最常用的接口</p><p>-Countable</p><p>--继承了接口的类可以直接调用count()得到元素个数</p><p>OuterIterator</p><p>--如果想对迭代器进行一定的处理之后再返回，可以用这个接口</p><p>RecursiveIterator</p><p>可以对多层结构的迭代器进行迭代，比如遍历一棵树</p><p>SeekableIteraor</p><p>可以通过seek方法定位到集合里面的某个特定元素</p></blockquote><p>Countable，在代码里面经常可以直接用count($obj)方法获得对象里面的元素的个数，对于自定义的类可以implements</p><pre class="prism-highlight prism-language-php">&lt;?php
$array&nbsp;=&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;[1,&nbsp;2],
&nbsp;&nbsp;&nbsp;&nbsp;[3,&nbsp;4],
&nbsp;&nbsp;&nbsp;&nbsp;[5,&nbsp;6]
];
echo&nbsp;count($array);
echo&nbsp;count($array[1]);

&lt;?php
class&nbsp;CountMe&nbsp;implements&nbsp;Countable&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$_myCount&nbsp;=&nbsp;3;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;count(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this-&gt;_myCount;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
$obj&nbsp;=&nbsp;new&nbsp;CountMe();
echo&nbsp;count($obj);</pre><blockquote><p>OuterIterator</p></blockquote><p>&nbsp; &nbsp; &nbsp; &nbsp;如果想对迭代器进行一定的处理之后再返回，可以用这个接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; IteratorIterator类是OuterIterator的实现，扩展的时候可以直接继承IteratorIterator</p><pre class="prism-highlight prism-language-php">&lt;?php
$array&nbsp;=&nbsp;[&#39;1&#39;,&nbsp;&#39;2&#39;,&nbsp;&#39;3&#39;,&nbsp;&#39;4&#39;];
$outerObj&nbsp;=&nbsp;new&nbsp;OuterImpl(new&nbsp;ArrayIterator($array));
foreach&nbsp;($outerObj&nbsp;as&nbsp;$key&nbsp;=&gt;&nbsp;$value)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$key.$value;
}

class&nbsp;OuterImpl&nbsp;extends&nbsp;Iterator&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;current()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;parent::current().&quot;_tail&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;key()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&quot;Pre_&quot;.parent::key();
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote><p>RecursiveIterator</p></blockquote><p>-可以对多层结构的迭代器进行迭代，比如遍历一棵树</p><p>-所有具有层次结构特点的数据都可以用这个接口遍历，如文件夹</p><p>关键方法</p><p>-hasChildren方法用于判断当前节点是否存在子节点</p><p>-getChildren方法用于得到当前节点子节点的迭代器</p><p>SPL实现该接口的类</p><p>-RecursiveArrayIterator，RecursiveCachingIterator等以Recursive开头的类都能够进行多层次结构化的遍历</p><blockquote><p>SeekableIterator</p></blockquote><p>-可以通过seek方法定位到集合里面的某个元素</p><p>-seek方法的参数是元素的位置，以0开始计算</p><p><strong>SPL函数的使用</strong></p><pre class="prism-highlight prism-language-php">&lt;?php
spl_autoload_extensions(&#39;.class.php&#39;,&nbsp;&#39;.php&#39;);
//&nbsp;设置autoload寻找php定义的类文件的扩展名，多个扩展名用逗号分隔，前面的扩展名优先被匹配
set_include_path(get_include_path().PATH_SEPARATOR.&quot;libs/&quot;);
//&nbsp;设置sutoload寻找php定义的类文件的目录，多个目录用PATH_SEPARATOR进行分隔
spl_sutoload_register();
//&nbsp;提示php使用Autoload机制查找类定义
new&nbsp;ClassName();</pre><p>改进</p><pre class="prism-highlight prism-language-php">&lt;?php
function&nbsp;__autoload($class_name){&nbsp;//&nbsp;定义__autoload函数，可以不调用spl_autoload_register函数的情况下完成类的装载
&nbsp;&nbsp;&nbsp;&nbsp;require_once(&quot;libs/&quot;.$class_name.&quot;.php&quot;);&nbsp;//&nbsp;装载类
}
new&nbsp;ClassName();</pre><p>自定义装载</p><pre class="prism-highlight prism-language-php">&lt;?php
function&nbsp;classLoader($class_name){&nbsp;//&nbsp;定义一个替换__autoload函数的类文件装载函数
&nbsp;&nbsp;&nbsp;&nbsp;require_once(&quot;libs/&quot;.$class_name.&quot;.php&quot;);&nbsp;//&nbsp;装载类
}
spl_autoload_register(&#39;classLoader&#39;);&nbsp;//传入定义好的装载类的函数的名称替换__autoload函数
new&nbsp;ClassName();</pre><p><br/></p><p>The End.</p>]]></content>
  </entry>
  <entry>
    <title>今天二十岁</title>
    <link href="https://old-blog.smallyu.net/indexa9e4.html?id=55"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=55</id>
    <published>2017-06-12T16:00:00.000Z</published>
    <updated>2017-06-12T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>莫名想哭，偶尔想笑</p>]]></summary>
    <content type="html"><![CDATA[<p>莫名想哭，偶尔想笑</p>]]></content>
  </entry>
  <entry>
    <title>比起努力，我实在太喜欢睡觉了</title>
    <link href="https://old-blog.smallyu.net/index1e85.html?id=54"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=54</id>
    <published>2017-06-03T16:00:00.000Z</published>
    <updated>2017-06-03T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>尤其是面对电脑不知所措的时候。 B站排行榜的视频刷完了。老友记越看越没劲了。知乎怎么看都看不完了。头条推送的内容没什么新鲜的了。优酷的UI越来越反人类了。虎绿林和zz是早该放弃的社区了。 慕课网上的学习时长增长进度远远低于期望值，去年的日志 （一万小时定律实践计划）Duang~任务进度到1%啦！ post时间到现在将近一年减两个月，也就是十个月，学习时长的统...</p>]]></summary>
    <content type="html"><![CDATA[<p>尤其是面对电脑不知所措的时候。<br/></p><p>B站排行榜的视频刷完了。老友记越看越没劲了。知乎怎么看都看不完了。头条推送的内容没什么新鲜的了。优酷的UI越来越反人类了。虎绿林和zz是早该放弃的社区了。<br/></p><p>慕课网上的学习时长增长进度远远低于期望值，去年的日志<a href="https://old-blog.smallyu.net/index6e03.html?id=13" target="_blank" se_prerender_url="complete">（一万小时定律实践计划）Duang~任务进度到1%啦！</a>post时间到现在将近一年减两个月，也就是十个月，学习时长的统计时间还不到1W小时的5%。然后PHP分类下的视频几乎全是对号。</p><p>IM工具，QQ空间，朋友圈，好友动态的更新频率可能比这个博客还要慢。<br/></p><p>所以总的来说，就是无聊。无聊的时候，就睡一会儿。睡不着的时候，就再无聊一会儿。</p><p><br/></p><p>听说无聊是对欲望的欲望。没有欲望，才对欲望有欲望。人怎么会没有欲望呢，也就是另一种情况，对欲望无能为力的时候，对欲望的欲望。</p><p>这个意思感觉就像，要理解递归，首先要理解递归。</p><p><br/></p><p>最近没什么事情，但又想post点内容，最后可选的标题（和内容）有三个：</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>利用WebView开发一个简单的安卓APP</p></li><li><p>五月乱象：总有几个莫名奇妙的总结</p></li><li><p>超星泛雅《创业管理实战》、《大学语文》答案分享</p></li></ol><p>然后都放弃了。<br/></p><p><br/></p><p>第一个先留着，可能有心情再折腾一下安卓开发的时候再总结。之前没怎么接触过APP开发，有一个比赛的时候试着封装了一个用WebView加载指定页面的很简单的应用。也是踩了一点可能不少新手都会踩的坑。<br/></p><p>第二个是一些看视频的笔记。单个拿出来太少，一起放出来有点乱。有这么几部分：<br/></p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>Java IO流 -&gt; 字节流（概念）</p></li><li><p>Java工厂模式（简单案例）</p></li><li><p>PHP SPL常用迭代器（部分）</p></li><li><p>测试用例（概念）</p></li></ol><p>设计模式和SPL在之前的日志中提到过，只是很不全。Java IO流的概念和测试用例的概念也就是一些文字。就贴在后面。（刚发现SPL的内容比较多，也先留着）</p><p>第三个是最近刷视频课用到的答案。网上重复内容太多，搜索引擎应该不会收录。即使收录了权重也应该低的吓人。而且不能复制粘贴，内容太多了，影响页面加载，只能附件doc。不过那样更没戏，搜索引擎认都不认。</p><p><br/></p><p><strong>Java IO 流</strong>（输入流、输出流）</p><blockquote><p>1.字节流</p><p>&nbsp; &nbsp; 1) InputStream、OutputStream</p><p>&nbsp; &nbsp; &nbsp; &nbsp;InputStream抽象了应用程序读取数据的方式</p><p>&nbsp; &nbsp; &nbsp; &nbsp;OutputStream抽象了应用程序写出数据的方式</p><p>&nbsp; &nbsp; 2) EOF = End 读到-1就读到结尾</p><p>&nbsp; &nbsp; 3) 输入流基本方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp;int b = in.read(); 读取一个字节无符号填充到int低八位，-1是EOF</p><p>&nbsp; &nbsp; &nbsp; &nbsp;in.read(byte[] buf) 速去数据填充到字节数组buf</p><p>&nbsp; &nbsp; &nbsp; &nbsp;in.read(byte[] buf, int start, int size) 读取数据到字节数组buf，从buf的start位置开始存放size长度的数据</p><p>&nbsp; &nbsp; 4) 输出流基本方法</p><p>&nbsp; &nbsp; &nbsp; &nbsp;out.write(int b) 写出一个byte到流，b的低8位</p><p>&nbsp; &nbsp; &nbsp; &nbsp;out.write(byte[] buf) 将buf字节数组都写入到流</p><p>&nbsp; &nbsp; &nbsp; &nbsp;out.write(byte[] buf, int start, int size)</p><p>&nbsp; &nbsp; 5) FileInputStream ---&gt; 具体实现了在文件上读取数据</p></blockquote><p>其实有字节流和字符流两部分，只看了字节流。内容很少，一些流操作用到的方法。</p><p><strong><br/></strong></p><p><strong>Java工厂模式</strong><br/></p><p>使用工厂模式简单实现一下理发店的逻辑。</p><blockquote><p>HairInterface.java</p></blockquote><pre class="prism-highlight prism-language-java">/**
&nbsp;*&nbsp;发型接口
&nbsp;*/
public&nbsp;interface&nbsp;HairInterface&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;实现了发型
&nbsp;&nbsp;&nbsp;&nbsp;pubic&nbsp;void&nbsp;draw();
}</pre><blockquote><p>LeftHair.java</p></blockquote><pre class="prism-highlight prism-language-java">/**
&nbsp;*&nbsp;左偏分发型
&nbsp;*/
public&nbsp;class&nbsp;LeftHair&nbsp;implements&nbsp;HairInterface&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;画了一个左偏分发型
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;draw()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;左偏分发型&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote><p>RightHair.java</p></blockquote><pre class="prism-highlight prism-language-java">/**
&nbsp;*&nbsp;右偏分发型
&nbsp;*/
public&nbsp;class&nbsp;RightHair&nbsp;implements&nbsp;HairInterface&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;画了一个左偏分发型
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;draw()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;右偏分发型&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>发型工厂是实现工厂模式的核心类。<br/></p><blockquote><p>HairFactory.java</p></blockquote><pre class="prism-highlight prism-language-java">/**
&nbsp;*&nbsp;发型工厂
&nbsp;*/
public&nbsp;class&nbsp;hairFactory&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;根据类型来创建对象
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;HairInterface&nbsp;getHair(Strign&nbsp;key)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&quot;left&quot;.equals(key))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;LeftHair();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;if(&quot;right&quot;.equals)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;RightHair();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;null;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;根据类的名称生成对象
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;HairInterface&nbsp;getHairByClass(String&nbsp;className)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HairInterface&nbsp;hair&nbsp;=&nbsp;Class.forName(className).newInstance();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;hair;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>最后模拟客户端实现。<br/></p><blockquote><p>SunntTest.java</p></blockquote><pre class="prism-highlight prism-language-java">/**
&nbsp;*&nbsp;模拟客户端实现
&nbsp;*/
public&nbsp;class&nbsp;SunnyTest&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;原生方法
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HairInterface&nbsp;left&nbsp;=&nbsp;new&nbsp;LeftHair();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;left.draw();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;工厂方法
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HairFactory&nbsp;factory&nbsp;=&nbsp;new&nbsp;HairFactory();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HairInterface&nbsp;left&nbsp;=&nbsp;factory.getHair(&quot;left&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;left.draw();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;优化后的工厂方法，根据类名获取对象
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HairInterface&nbsp;left&nbsp;=&nbsp;factory.getHairByClass(&quot;com.package.LeftHair&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;left.draw();
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>模拟客户端的类在运行时会调用工厂方法，工厂类根据传入的参数返回对应的对象。</p><p><strong><br/></strong></p><p><strong>测试用例</strong></p><blockquote><p>测试用例是什么</p><p>&nbsp; &nbsp; 测试工作的核心</p><p>&nbsp; &nbsp; 一组在测试时输入输出的标准</p><p>&nbsp; &nbsp; 软件需求的具体对照</p><p><br/></p><p>测试用例有什么作用</p><p>&nbsp; &nbsp; 检验软件是否满足客户需求</p><p>&nbsp; &nbsp; 体现一个测试人员的工作量</p><p>&nbsp; &nbsp; 展现测试用例的设计思路</p><p><br/></p><p>测试用例包含哪些内容</p><p>&nbsp; &nbsp; 用例编号</p><p>&nbsp; &nbsp; 用例名臣</p><p>&nbsp; &nbsp; 测试背景</p><p>&nbsp; &nbsp; 前置条件</p><p>&nbsp; &nbsp; 优先级</p><p>&nbsp; &nbsp; 重要级</p><p>&nbsp; &nbsp; 测试数据</p><p>&nbsp; &nbsp; 测试步骤</p><p>&nbsp; &nbsp; 预期结果</p><p>&nbsp; &nbsp; 实际结果</p><p>&nbsp; &nbsp; 备注</p><p><br/></p><p>测试用例编写流程</p><p>&nbsp; &nbsp; 需求分析</p><p>&nbsp; &nbsp; 提取测试点</p><p>&nbsp; &nbsp; 测试用例编写</p><p>&nbsp; &nbsp; 测试用例评审</p><p><br/></p><p>需求分析</p><p>&nbsp; &nbsp; 业务需求，关注系统是否满足业务</p><p>&nbsp; &nbsp; 用户需求，关注系统是否满足用户习惯</p><p>&nbsp; &nbsp; 功能需求，关注系统是否满足功能要求</p></blockquote><p><br/></p><p><strong>超星泛雅《创业管理实战》、《大学语文》答案分享</strong></p><p style="line-height: 16px;"><a style="font-size:12px; color:#0066cc;" href="https://old-blog.smallyu.net/zb_users/upload/2017/06/201706041496570504105531.zip" title="大学语文.zip">大学语文.zip</a></p><p style="line-height: 16px;"><a style="font-size:12px; color:#0066cc;" href="https://old-blog.smallyu.net/zb_users/upload/2017/06/201706041496570507726577.zip" title="创业管理实战.zip">创业管理实战.zip</a></p><p><br/></p><p>一入侯门深似海，从此萧郎是路人。</p>]]></content>
  </entry>
  <entry>
    <title>大误：被人嫌弃的感觉是这样的</title>
    <link href="https://old-blog.smallyu.net/index3ca5.html?id=53"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=53</id>
    <published>2017-05-19T16:00:00.000Z</published>
    <updated>2017-05-19T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>遇到过自己讨厌的人，也遇到过讨厌自己的人。如果一个人不怎么搭理你，应该不再自找没趣。即使自找没趣了，接下来，不应该在内心里潜意识地抵触它才对么？原本以为我会那样。 事件1：我发“作业借我抄一下”，没回。（IM） 事件2：我说“Hi”，立回“你走吧”。（现实） 事件3：我说“Hi”，没回。（IM） 事件1和事件3是在IM工具上，事件2是现实世界中。这三件事情，...</p>]]></summary>
    <content type="html"><![CDATA[<p>遇到过自己讨厌的人，也遇到过讨厌自己的人。如果一个人不怎么搭理你，应该不再自找没趣。即使自找没趣了，接下来，不应该在内心里潜意识地抵触它才对么？原本以为我会那样。</p><blockquote><p>事件1：我发“作业借我抄一下”，没回。（IM）</p><p>事件2：我说“Hi”，立回“你走吧”。（现实）</p><p>事件3：我说“Hi”，没回。（IM）</p></blockquote><p>事件1和事件3是在IM工具上，事件2是现实世界中。这三件事情，让我好多种感觉交集。不但没有想要远远躲开它，保持距离，反倒感觉事情有点意思。人也是。毕竟没遇到过。</p><p><br/></p><p>这些都基于事件之间以及直到目前为止还没有过任何其他联系的基础上。</p><p><span style="text-decoration: none; font-size: 14px;"><strong>时间顺序</strong></span></p><p>事件1分析。</p><p>是故意还是无意？那个时候完全不清楚什么情况。</p><p>如果是故意的，问题就可怕了。此前完全没有意识到它对我的排斥，所以有可能是一直对我心存不满，瞬间爆发了？（其实这个也挺有意思的，什么事情效果这么明显。坏笑脸。后补）</p><p>如果是瞬间爆发，那我到底做了什么事情，或者身上有哪些让它讨厌的地方，才会造成这样的情况？</p><p>如果不是瞬间爆发，说明它一直都有表现出对我的不满。为什么我没有发觉？是我愚钝了？</p><p>如果是我愚钝了，那我就好好想想愚钝在何处。</p><p>如果不是我愚钝，那就是它对我的不满表现的不够充分和合理。它为什么没能将不满表现好？</p><p>如果不是故意的，又为什么不回？是因为当时没看到，觉得过去一点时间了，没必要再回了？</p><pre class="prism-highlight prism-language-c">事件1分析函数&nbsp;()&nbsp;
{
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(故意的)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(瞬间爆发)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对我不满在什么地方？
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(不是瞬间爆发)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(是我愚钝了)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;愚钝在何处？
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(不是我愚钝)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它为什么没能很好表现出不满？
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(不是故意的)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(觉的不需要回了)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不需要回心态分析函数();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;事件1超越了我的智商。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>事件2分析。</p><p>事件2是在现实生活中。我在说出“Hi”的0.5s后，它不假思索的立即说出了“你走吧”。</p><p>？？？</p><p>即使没遇到它，我停在那里也不是没有理由啊。</p><p>从礼貌的角度讲，不管是否、多么不待见我，都不应该这么说话。不然以后还怎么混社会，走向人生巅峰？</p><p>同时，对我不满在什么地方？</p><p>或者其实本来想要表达的是其他意思。</p><pre class="prism-highlight prism-language-c">事件2分析函数&nbsp;()
{
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(故意的)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我要教它做人。
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(不是故意的)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不需要回心态分析函数();
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>事件3分析。</p><p>事件1的分析忽略了事件1的不回是因为抄作业本身的原因。因为事件3没说是抄作业。虽然事件3本来确实就是想抄作业。</p><p>内容和事件1类似。事件3的存在，就是为了从侧面证实事件1，是故意的，还是无意的？</p><p>事件1和事件3相隔时间10天左右。事件3之后，感觉终于放心了。不需要再有疑问，是故意的还是无意的？不回是事实，是故意的。但也有可能进入事件1分析不是故意的流程里的觉得不需要回函数。</p><p>如果是故意的，就是真的厌恶我到打招呼都不想回的程度。那么问题，我到底做了什么我自己没有意识到但却别人看起来惊世骇俗的厌恶至极的事情？</p><p>如果不是故意的，嗯。</p><pre class="prism-highlight prism-language-c">事件3分析函数&nbsp;()
{
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(故意的)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对我不满在什么地方？
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(不是故意的)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(觉的不需要回了)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不需要回心态分析函数();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;事件3超越了我的智商。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>不需要回心态分析。</p><p>我以前有过不回别人消息的经历，但没有过第一句话就不回的，也没有过连续两次不回的。</p><p>以前没有过被别人不回的经历，可能也就是对这点事情和对那个人感兴趣的原因。</p><p>因为并不熟悉它的性格和行事态度，先从我自己的角度分析一下。</p><p>我不回别人的情况。</p><p>按人，比较熟的人，和相当不熟的人。</p><p>我和它，不生不熟。</p><p>如果是因为觉得熟，没话说。</p><p>如果是因为觉得不熟，好伤。</p><p>如果是因为半生不熟，接前，怎么也应该回的才对，从礼貌的角度，从做人的角度。</p><p>按事，不想做的。</p><p>它不想给我抄作业。</p><p>这是一个很扯的分支。</p><pre class="prism-highlight prism-language-c">不需要回心态分析函数&nbsp;()
{
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(针对人)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(熟)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不理解。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(半生不熟)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我要教它做人。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(不熟)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不理解。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(针对事)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不需要回心态超越了我的智商。
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p><strong>逻辑顺序</strong><br/></p><p>逻辑顺序本是按照针对人、针对事的角度。突然不想写了。该写的都写了。</p><p><br/></p><p>综上，感觉是否有趣并没有取决于它的态度。也许其他感觉也是。</p><p>当然，上面的所有内容全都忽略了最后一种可能：想多了。</p><p><br/></p><p>切莫交浅言深。 ——共勉</p>]]></content>
  </entry>
  <entry>
    <title>HTML5 音乐可视化</title>
    <link href="https://smallyu.net/2017/05/17/html5%E9%9F%B3%E4%B9%90%E5%8F%AF%E8%A7%86%E5%8C%96/"/>
    <id>blog:https://smallyu.net/2017/05/17/html5%E9%9F%B3%E4%B9%90%E5%8F%AF%E8%A7%86%E5%8C%96/</id>
    <published>2017-05-16T16:00:00.000Z</published>
    <updated>2025-11-18T12:30:47.852Z</updated>
    <category term="博客"/>
    <summary type="html"><![CDATA[<img src="201705141494765899218386.png"]]></summary>
    <content type="html"><![CDATA[<img src="201705141494765899218386.png" /><p>下面梳理一下HTML5实现音乐可视化的流程。</p><p><strong>搭建静态页面</strong></p><p>静态页面的结构分三部分，header，left，right。header为语义化标签，left和right都用div来实现。</p><img src="201705141494770946657494.png" /><p>类似这样，然后把背景颜色改为黑色，字体改成白色，加上或不加边框线，给一定padding或margin，静态页面就搭建好啦。</p><p>不过重点不是页面布局。可以在左侧栏有一个曲目列表，点击切歌。这里就不那么麻烦，直接后台加载指定的歌曲。歌曲是许嵩的烟花笑，左侧栏显示部分歌词。</p><p><strong>创建音频文件对象</strong></p><p>AudioContext对象用于获取音频文件源。</p><blockquote><p>（节点）AudioContext：包含各个AudioNode对象以及它们的联系的对象，可以理解为上下文对象。绝大多数情况下，一个document中只有一个AudioContext。</p><p>（方法）createBufferSource()：创建audioBufferSourceNode对象。</p></blockquote><p>可以这样写：</p><pre><code>var ac = new window.AudioContext();    // 实例化ac为一个音频对象var bs = ac.createBufferSource();      // 用bs来保存音频文件资源</code></pre><p>有了音频资源，是否就可以播放音频了呢？当然不可以，因为还没有指定文件，告诉对象播放哪一个音频文件。</p><p><strong>获取音频数据</strong></p><p>创建bufferSource后，到了AudioBufferSourceNode这个节点。这个节点有一个属性值buffer，用来指定文件资源。这个属性值需要一个buffer类型的数据。</p><blockquote><p>（节点）AudioBufferSourceNode：表示内存中的一段音频资源，其音频数据存在于AudioBuffer中（其buffer属性）。</p><p>（属性）buffer：AudioBuffer对象，表示要播放的音频资源数据。</p></blockquote><p>获取buffer有两种方式，一种是ajax设置返回值类型为arraybuffer，然后解码，一种是用FileReader读取文件，获得blob值。后一种方式多用input上传文件后获得文件，再进行解析。前面一种好用一点。（留坑）  </p><p>ajax的原生写法：</p><pre><code>var url=&quot;...&quot;;var xhr = new XMLHttpRequest();xhr.abort();xhr.open(&quot;GET&quot;, url);xhr.responseType = &quot;arraybuffer&quot;;xhr.onload = function()&#123;    return xhr.response;&#125;xhr.send();</code></pre><p>onload触发的函数中xhr.response就是我们想要的值。</p><blockquote><p>（方法）decodeAudioData(arrayBuffer, succ(buffer), err) ：异步解码包含在arrayBuffer中的音频数据。</p></blockquote><p>将arraybuffer解码：</p><pre><code>ac.decodeAudioData(arraybuffer, function(buffer)&#123; ... &#125;,function(err)&#123; ... &#125;);bs.buffer = buffer;    // 回调函数中的buffer就是想要的buffer</code></pre><p><strong>播放音乐</strong>  </p><blockquote><p>（方法）start：开始播放音频</p></blockquote><p>这个时候调用start方法：</p><pre><code>bs.start(0);</code></pre><p>打开页面，音乐开始播放。</p><p><strong>音量控制</strong></p><blockquote><p>（节点）GainNode：改变音频音量的对象，会改变通过它的音频数据所有的sample frame的信号强度。</p><p>（方法）createGain()：创建GainNode对象。</p><p>（属性）value：可以改变音频信号的强弱，默认为1，最小值为0。</p></blockquote><p>音乐播放还不行，要添加一个音量控制控件，音量控制用GainNode节点：</p><pre><code>var gainNode = accreateGain();    // 创建GainNode对象gainNode.connect(ac.destination);    // 将gainNode连接到AudioDestinationNode节点</code></pre><p>这样就有了一个音量控制的对象。</p><pre><code>gainNode.gain.value= ... ;</code></pre><p>gain.value用于控制输入信号的强弱，也就是音量的大小。HTML中用type为range的input，把值传递给对象，就可以实时控制音量了。  </p><p><strong>得到音频解析数据</strong></p><blockquote><p>（节点）AnalyserNode：音频分析对象，他能实时的分析音频资源的频域和时域信息，但不会对音频流做任何处理。</p><p>（方法）createAnalyser()：创建AnalyserNode对象。</p></blockquote><blockquote><p>（属性）fftsize：设置FFT（是离散傅里叶变换的快速算法，用于将一个信号变换到频域）值的大小，用于分析得到频域，为32 ~ 2048之间2的整数次倍，默认为2048，实时得到的音频频域的数据个数为fftSize的一半。</p><p>（属性）frequencyBinCount，FFT值的一半，即实时得到的音频频域的数据个数</p></blockquote><blockquote><p>（方法）getByteFrequencyData(Uint8Array)，复制音频当前的频域数据（数量是frequencyBinCount）到Uint8Array（8位无符号整型类型化数组）中。</p></blockquote><p>先创建AnalyserNode对象，然后设置fftsize的值。FFT用于数字信号的处理，会把音频文件流输入的信号变换到频域，用getByteFrequencyData()方法得到经系统处理之后的频域数据。</p><pre><code>var analyser = ac.createAnalyser();    // 实例化对象analyser.fftSize = 32;                 // 设置fftsizevar arr = new Uint8Array(analyser.frequencyBinCount);    // getByteFrequencyData()方法要求参数为8位无符号整型类型化数组analyser.getByteFrequencyData(arr);    //    arr为所需频域数据</code></pre><p>这样得到的数组arr就是用于可视化效果绘制的数据。</p><blockquote><p>（方法）window.requestAnimationFrame()：告诉浏览器您希望执行动画，并请求浏览器调用指定的函数在下一次重绘之前更新动画。该方法将在重绘之前调用的回调作为参数。</p></blockquote><p>一次解析只能得到一组数据，所以需要requestAnimationFrame不断解析，不断得到arr。</p><p><strong>前端界面绘制</strong></p><p>前端界面使用canvas绘制，实现音乐可视化的效果。</p><pre><code>var box = document.getElementById(&quot;right&quot;);    // 获取right区域的dombox.appendChild(canvas);                       // 创建canvas节点var ctx = canvas.getContext(&quot;2d&quot;);             // 实例化canvas画笔</code></pre><p>接下来就是使用for循环和ctx画矩形、圆圈，填充渐变的操作了。（留坑吧，估计不填了）  </p><p>案例用到web Audio API的关系：</p><img src="201705141494773947635812.png" /><p>虚线是可以跳过的节点，直接播放音频文件。好吧有错。</p>]]></content>
  </entry>
  <entry>
    <title>HTML5音乐可视化</title>
    <link href="https://old-blog.smallyu.net/indexfddb.html?id=52"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=52</id>
    <published>2017-05-16T16:00:00.000Z</published>
    <updated>2017-05-16T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>在线demo： https://old-blog.smallyu.net/web/passionate/（历史 Demo 已失效） 下面梳理一下HTML5实现音乐可视化的流程。 搭建静态页面 静态页面的结构分三部分，header，left，right。header为语义化标签，left和right都用div来实现。 类似这样，然后把背景颜色改为黑色，字体改成...</p>]]></summary>
    <content type="html"><![CDATA[<p>在线demo：<span>https://old-blog.smallyu.net/web/passionate/（历史 Demo 已失效）</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/05/201705141494765899218386.png" title="搜狗截图20170514204448.png" alt="搜狗截图20170514204448.png" width="547" height="277" style="width: 592px; height: 312px;"/></p><p><strong><br/></strong></p><p>下面梳理一下HTML5实现音乐可视化的流程。</p><p><strong>搭建静态页面</strong></p><p>静态页面的结构分三部分，header，left，right。header为语义化标签，left和right都用div来实现。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/05/201705141494770946657494.png" title="搜狗截图20170514220851.png" alt="搜狗截图20170514220851.png" width="361" height="250" style="width: 361px; height: 250px;"/></p><p>类似这样，然后把背景颜色改为黑色，字体改成白色，加上或不加边框线，给一定padding或margin，静态页面就搭建好啦。</p><p>不过重点不是页面布局。可以在左侧栏有一个曲目列表，点击切歌。这里就不那么麻烦，直接后台加载指定的歌曲。歌曲是许嵩的烟花笑，左侧栏显示部分歌词。</p><p><strong>创建音频文件对象</strong></p><p>AudioContext对象用于获取音频文件源。</p><blockquote><p>（节点）AudioContext：包含各个AudioNode对象以及它们的联系的对象，可以理解为上下文对象。绝大多数情况下，一个document中只有一个AudioContext。</p><p>（方法）createBufferSource()：创建audioBufferSourceNode对象。</p></blockquote><p>可以这样写：</p><pre class="prism-highlight prism-language-javascript">var&nbsp;ac&nbsp;=&nbsp;new&nbsp;window.AudioContext();&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;实例化ac为一个音频对象
var&nbsp;bs&nbsp;=&nbsp;ac.createBufferSource();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;用bs来保存音频文件资源</pre><p>有了音频资源，是否就可以播放音频了呢？当然不可以，因为还没有指定文件，告诉对象播放哪一个音频文件。</p><p><strong>获取音频数据</strong></p><p>创建bufferSource后，到了AudioBufferSourceNode这个节点。这个节点有一个属性值buffer，用来指定文件资源。这个属性值需要一个buffer类型的数据。</p><blockquote><p>（节点）<span style="text-decoration: underline;">AudioBufferSourceNode</span>：表示内存中的一段音频资源，其音频数据存在于AudioBuffer中（其buffer属性）。</p><p>（属性）<span style="text-decoration: underline;">buffer</span>：AudioBuffer对象，表示要播放的音频资源数据。</p></blockquote><p>获取buffer有两种方式，一种是ajax设置返回值类型为arraybuffer，然后解码，一种是用FileReader读取文件，获得blob值。后一种方式多用input上传文件后获得文件，再进行解析。前面一种好用一点。（留坑）<br/></p><p>ajax的原生写法：</p><pre class="prism-highlight prism-language-javascript">var&nbsp;url=&quot;...&quot;;
var&nbsp;xhr&nbsp;=&nbsp;new&nbsp;XMLHttpRequest();
xhr.abort();
xhr.open(&quot;GET&quot;,&nbsp;url);
xhr.responseType&nbsp;=&nbsp;&quot;arraybuffer&quot;;
xhr.onload&nbsp;=&nbsp;function(){
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;xhr.response;
}
xhr.send();</pre><p>onload触发的函数中xhr.response就是我们想要的值。</p><blockquote><p>（方法）<span style="text-decoration: underline;">decodeAudioData(arrayBuffer, succ(buffer), err)&nbsp;</span>：异步解码包含在arrayBuffer中的音频数据。</p></blockquote><p>将arraybuffer解码：</p><pre class="prism-highlight prism-language-javascript">ac.decodeAudioData(arraybuffer,&nbsp;function(buffer){&nbsp;...&nbsp;},function(err){&nbsp;...&nbsp;});
bs.buffer&nbsp;=&nbsp;buffer;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;回调函数中的buffer就是想要的buffer</pre><p><strong>播放音乐</strong><br/></p><blockquote><p>（方法）<span style="text-decoration: underline;">start</span>：开始播放音频</p></blockquote><p>这个时候调用start方法：</p><pre class="prism-highlight prism-language-javascript">bs.start(0);</pre><p>打开页面，音乐开始播放。</p><p><strong>音量控制</strong></p><blockquote><p>（节点）<span style="text-decoration: underline;">GainNode</span>：改变音频音量的对象，会改变通过它的音频数据所有的sample frame的信号强度。</p><p>（方法）<span style="text-decoration: underline;">createGain()</span>：创建GainNode对象。</p><p>（属性）<span style="text-decoration: underline;">value</span>：可以改变音频信号的强弱，默认为1，最小值为0。</p></blockquote><p>音乐播放还不行，要添加一个音量控制控件，音量控制用GainNode节点：</p><pre class="prism-highlight prism-language-javascript">var&nbsp;gainNode&nbsp;=&nbsp;accreateGain();&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;创建GainNode对象
gainNode.connect(ac.destination);&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;将gainNode连接到AudioDestinationNode节点</pre><p>这样就有了一个音量控制的对象。</p><pre class="prism-highlight prism-language-javascript">gainNode.gain.value=&nbsp;...&nbsp;;</pre><p>gain.value用于控制输入信号的强弱，也就是音量的大小。HTML中用type为range的input，把值传递给对象，就可以实时控制音量了。<br/></p><p><strong>得到音频解析数据</strong></p><blockquote><p>（节点）<span style="text-decoration: underline;">AnalyserNode</span>：音频分析对象，他能实时的分析音频资源的频域和时域信息，但不会对音频流做任何处理。</p><p>（方法）<span style="text-decoration: underline;">createAnalyser()</span>：创建AnalyserNode对象。</p></blockquote><blockquote><p>（属性）<span style="text-decoration: underline;">fftsize</span>：设置FFT（是离散傅里叶变换的快速算法，用于将一个信号变换到频域）值的大小，用于分析得到频域，为32 ~ 2048之间2的整数次倍，默认为2048，实时得到的音频频域的数据个数为fftSize的一半。</p><p>（属性）<span style="text-decoration: underline;">frequencyBinCount</span>，FFT值的一半，即实时得到的音频频域的数据个数</p></blockquote><blockquote><p>（方法）<span style="text-decoration: underline;">getByteFrequencyData(Uint8Array)</span>，复制音频当前的频域数据（数量是frequencyBinCount）到Uint8Array（8位无符号整型类型化数组）中。</p></blockquote><p>先创建AnalyserNode对象，然后设置fftsize的值。FFT用于数字信号的处理，会把音频文件流输入的信号变换到频域，用getByteFrequencyData()方法得到经系统处理之后的频域数据。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;analyser&nbsp;=&nbsp;ac.createAnalyser();&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;实例化对象
analyser.fftSize&nbsp;=&nbsp;32;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设置fftsize
var&nbsp;arr&nbsp;=&nbsp;new&nbsp;Uint8Array(analyser.frequencyBinCount);&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;getByteFrequencyData()方法要求参数为8位无符号整型类型化数组
analyser.getByteFrequencyData(arr);&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;&nbsp;&nbsp;arr为所需频域数据</pre><p>这样得到的数组arr就是用于可视化效果绘制的数据。</p><blockquote><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">（方法）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline;">window.requestAnimationFrame()</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">：</span>告诉浏览器您希望执行动画，并请求浏览器调用指定的函数在下一次重绘之前更新动画。该方法将在重绘之前调<span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">用的回</span>调作为参数。</p></blockquote><p>一次解析只能得到一组数据，所以需要<span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">requestAnimationFrame不断解析，不断得到arr。</span></p><p><strong>前端界面绘制</strong></p><p>前端界面使用canvas绘制，实现音乐可视化的效果。</p><pre class="prism-highlight prism-language-javascript">var&nbsp;box&nbsp;=&nbsp;document.getElementById(&quot;right&quot;);&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;获取right区域的dom
box.appendChild(canvas);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;创建canvas节点
var&nbsp;ctx&nbsp;=&nbsp;canvas.getContext(&quot;2d&quot;);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;实例化canvas画笔</pre><p>接下来就是使用for循环和ctx画矩形、圆圈，填充渐变的操作了。（留坑吧，估计不填了）<br/></p><p><br/></p><p>案例用到web Audio API的关系：</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/05/201705141494773947635812.png" title="搜狗截图20170514203204.png" alt="搜狗截图20170514203204.png" width="777" height="557" style="width: 777px; height: 557px;"/></p><p>虚线是可以跳过的节点，直接播放音频文件。好吧有错。</p>]]></content>
  </entry>
  <entry>
    <title>活着那么累，和我一起去死吧</title>
    <link href="https://old-blog.smallyu.net/index7d36.html?id=51"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=51</id>
    <published>2017-04-25T16:00:00.000Z</published>
    <updated>2017-04-25T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>明天又要回家了。 这个月最后一次post内容。 真的，这样就好。 ······················内容分割线··················· 参加那什么什么比赛很开心。 没想过会有这么一天。 没想到会有这么一个比赛。 想不到以后会怎样…… 这样就好，就这样就好。 不快不慢。 这样就好。 ······················内容分割线...</p>]]></summary>
    <content type="html"><![CDATA[<p style="text-align: left;">明天又要回家了。</p><p>这个月最后一次post内容。</p><p>真的，这样就好。</p><p><br/></p><p>······················内容分割线···················</p><p><br/></p><p>参加那什么什么比赛很开心。</p><p><br/></p><p>没想过会有这么一天。</p><p>没想到会有这么一个比赛。</p><p>想不到以后会怎样……</p><p><br/></p><p>这样就好，就这样就好。</p><p>不快不慢。</p><p>这样就好。</p><p><br/></p><p>······················内容分割线···················</p><p><br/></p><p>论bootstrap党参赛。</p><p>中国“软件杯”软件设计大赛和互联网+创新创业大赛，在4.8之后开始准备，4.15报名了校内选拔赛。</p><p>原先准备软件设计大赛，有一个题目是无微不至的阅读，做一个基于微信的图书借阅平台。</p><p>后来组队了。</p><p>队伍人数超出规则，就选择了创新创业大赛。</p><p>互联网+餐饮。</p><p>如果要真的实现，项目难度大于软件设计赛的题目。</p><p>比赛要求创意组只需要提交项目说明书和商业策划书就好了。</p><p>嗯。</p><p>首页：<span>https://old-blog.smallyu.net/g2025/index.html（历史页面已失效）</span>&nbsp; &nbsp;（主移动）</p><p>后台：<span>https://old-blog.smallyu.net/g2025/admin.html（历史页面已失效）</span>&nbsp;</p><p>登录：<span>https://old-blog.smallyu.net/g2025/bis_log.html（历史页面已失效）</span>&nbsp;</p><p>安卓APP：<span>https://old-blog.smallyu.net/g2025/g2025.apk（历史页面已失效）</span>&nbsp;</p><p>是不是有点拿不出手？</p><p>嗯。</p><p>反正大赛不要求做。</p><p><br/></p><p>······················内容分割线···················</p><p><br/></p><p>《全职高手》出动画了！</p><p>它承载着，我的童年啊。</p><p><br/></p><p>······················内容分割线···················</p><p><br/></p><p>清明来后，情绪还算消极，想写点东西，这是大纲：</p><p><br/></p><p>```Quote</p><p>大学回家，邻座路人</p><p>高中回家，出租车司机</p><p><br/></p><p>1.想做就去做</p><p>清明节回家</p><p>评论说说</p><p><br/></p><p>2.学会堕落</p><p>玩整天游戏</p><p><br/></p><p>3.偶尔沉默</p><p>终有一天会释然</p><p><br/></p><p>4.为自己而活</p><p>晚上跑步</p><p><br/></p><p>为什么要迷茫</p><p>```</p><p><br/></p><p>过去一段时间，当时想要表达什么内容已经，差不多忘了。</p><p><br/></p><p>························时间分割线（4.9）······················</p><p><br/></p><p>每到放假都不知所措，清明小假也一样。纠结半天，回家了。</p><p>大巴邻座是一位大叔。</p><p>一开始沉默不语，后来突然问了一句，“你回哪儿？”</p><p>接着又问我在什么学校读书，什么专业，就业前景怎么样。</p><p>他的儿子高考复读一年，超过二本线个位数，现在进了一所理所当然的学学校读书，文科，历史。</p><p>地球人都知道，大学生工作不好找，普通二本的工作更不好找，文科专业地理、生物、历史、政治，除了师范，研究生都不好找。</p><p>所以大叔很担心他儿子。</p><p><br/></p><p>想起来高中有一次拼车回家，开出租车的师傅也问过类似的问题。</p><p>他的孩子那年要考高中了，你们学校的分数是多少，你当时多少分考进的。</p><p>我问，害怕考不上吗？</p><p>他说，当然怕，要不然进去得花钱（五位数）。</p><p>然后我当时想，为什么一定要读书？</p>]]></content>
  </entry>
  <entry>
    <title>Friends.S09E17</title>
    <link href="https://old-blog.smallyu.net/index0c98.html?id=50"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=50</id>
    <published>2017-04-14T16:00:00.000Z</published>
    <updated>2017-04-14T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>You ready to go? Let me just finish this. Hey, Ross. Check this out. Yeah, I can&amp;#39;t do that. What are you doing? Have you seen this? It&amp;#39;s our new alumni website for college....</p>]]></summary>
    <content type="html"><![CDATA[<p>You ready to go?</p><p>Let me just finish this.</p><p>Hey, Ross. Check this out. Yeah, I can&#39;t do that.</p><p>What are you doing?</p><p>Have you seen this? It&#39;s our new alumni website for college. You can post messages for people let everyone know what you&#39;re up to.</p><p>Oh, great. A faster way to tell people that I&#39;m unemployed and childless.</p><p>It&#39;s actually interesting to find out what people are doing. Remember Andrea Rich?</p><p>That tall girl that wouldn&#39;t sleep with you?</p><p>Well, her Internet company went under, and she lost an ear in a oating accident.</p><p>Bet she&#39;d sleep with you now.</p><p>No, I already e-mailed her.</p><p>Let me see what you wrote about yourself. Doctor of paleontology,two kids. Wait a second. You split with Carol because you had different interests? I think you split with Carol because you had one very similar interest.</p><p>I&#39;m gonna finish this later, okay? Let me just grab my coat.</p><p>Okay!</p><p>What, did you think you learned how to do it in the two minutes?</p><p>Maybe we finish this for him. Also, I cloned a dinosaur in my lab. She is now my girlfriend. I don&#39;t care what society says, it&#39;s the best sex I&#39;ve ever had. And send.</p><p>No, no-- You can&#39;t do that to him.</p><p>All right, let&#39;s go.</p><p>Dude!</p><p>I think you made it clear you can&#39;t be trusted with the ball inside the house.</p><p>And send.</p><p>Hey. How was basketball?</p><p>It was fun. Right up until Chandler got a finger in the eye.</p><p>Oh, no! Who did that?</p><p>Chandler. Yeah.</p><p>Hey!</p><p>Rach?</p><p>Yeah?</p><p>What&#39;s Huggsy doing in the crib with Emma?</p><p>She was just crawling around and found him, so I just let her sleep with him.</p><p>That&#39;s all right, isn&#39;t it?</p><p>Of course. Yeah.</p><p>It&#39;s a stuffed animal, you know? It&#39;s for kids. Not for adults. I know that.</p><p>Joey, you&#39;re sure? I mean, I knew how much you love him.</p><p>Rachel, let&#39;s be clear on this, okay?</p><p>I do not love Huggsy. I like him a normal amount.</p><p>All right. Well, Emma loves him.</p><p>Yeah. Well, why wouldn&#39;t she? He&#39;s a wonderful person!</p><p>Hi.</p><p>Hey, Phoebe.</p><p>How you doing?</p><p>You felling better?</p><p>Breaking up sucks.</p><p>Oh, I really miss Mike.</p><p>Oh, I&#39;m so sorry.</p><p>I&#39;ve tried everything to feel better. I even tried writing a song about it... but I can&#39;t think of anything that rhymes with:</p><p>Oh, I so know how you feel. Breaking up with Richard was the hardest thing I&#39;ve ever done in my life. All right, fine, I&#39;ll put another dollar in the Richard jar.&nbsp;</p><p>Hey, Monica, I&#39;m gonna need your help getting through this.</p><p>You&#39;re saying you&#39;re not gonna need my help?</p><p>No. When I get to the point where I&#39;m ready... to hear cruel, mocking jokes about Mike, I&#39;m gonna come to you.</p><p>Oh, good, because I&#39;ve already thought of three. Four! I just throught of a fourth!</p><p>Okay. I mean, I know I did the right thing. Mike never wants to get married... and I shouldn&#39;t be a relationship that has no future. But pretty soon, I&#39;m gonna miss him so much... I&#39;m gonna want to see him again, and you have to stop me.</p><p>Okay, you got it.</p><p>Unless... Am I being too crazy about this? All right, so there&#39;s no future. But that doesn&#39;t mean we still can&#39;t have fun. You know what? Forget what I said.</p><p>Really? All right, if that&#39;s what you want.</p><p>That was a test, and you just failed.</p><p>Damn it! Rookie mistake!</p><p>I have sex with dinosaurs?</p><p>I believe I read that somewhere.</p><p>Not only is it not funny, it&#39;s physically impossible! Okay? Depending on the species, I&#39;d have to have a 6-foot-long-- It&#39;s not funny!</p><p>I respectfully disagree.</p><p>I can&#39;t believe you put that on my alumni page.</p><p>Who cares? Nobody reads those.</p><p>You better hope not... because I just read what you put on your page today.</p><p>I don&#39;t have a page.</p><p>Oh, I respectfully disagree!</p><p>Huggsy?</p><p>Huggsy?</p><p>Huggsy.</p><p>I want my penguin.</p><p>Look at you. All sweet and innocent, sleeping like an angel.</p><p>With Emma&#39;s chubby little hands wrapped around you.</p><p>It&#39;s okay, Emma. You stay asleep.</p><p>Step away from the crib! I have a weapon!</p><p>It&#39;s okay! It&#39;s okay, Rach! It&#39;s me! Put down the scrunchie.</p><p>What are you doing?</p><p>Well, I heard Emma strring... so I came in to make sure she could reach Huggsy.</p><p>Oh, thanks. All right, well, now that I&#39;m up, I&#39;m gonna go to the bathroom.</p><p>Okay, there you go, sweetie.</p><p>This isn&#39;t over!</p><p>Wait a second. Why would Ross tell everyone on your class that you are &quot;as gay as the day is long&quot;?</p><p>Because I told everyone he alept with dinosaurs.</p><p>Well, that&#39;s clearly a joke.</p><p>This could easily be true.</p><p>Would you get that, please?</p><p>People have been calling to congratulate me all day.</p><p>Hello?</p><p>No, he&#39;s not here. Yeah, this is his wife.</p><p>Yeah. Well, it came as quite a shock to me too!</p><p>Well, I guess I should&#39;ve known. He just kept making me watch Molin Rouge.</p><p>Hang up! Hang up! And that was a great movie.</p><p>I&#39;m so gonna get back at Ross.</p><p>Oh, yeah, this&#39;ll show him. Here we go.</p><p>What are you doing?</p><p>Oh, you&#39;ll see, my friend!</p><p>I&#39;m dead?</p><p>And so young.</p><p>Posting that I died? That really isn&#39;t funny.</p><p>Well, how you died was funny.</p><p>Oh, please. Hit by a blimp?</p><p>It kills over one Americans every year.</p><p>Unbelievable. My classmates are gonna think I&#39;m dead. My professors. My parents are gonna get phone calls! You&#39;re messing with people&#39;s fellings here.</p><p>You wanna talk about people&#39;s fellings? You should have heard how hurt Prodessor Stern was when I told him I wouldn&#39;t be to go to Key West!</p><p>You&#39;v really crossed a line here. But that&#39;s okay. Because I&#39;m on my way to buy some Photoshop software...and a stack of gay porn. That&#39;s right. Your coming- out is about to get real graphic!</p><p>God, I wish Mike were here.</p><p>Okay, if Mike were here, what should the two of you be doing?</p><p>What are you, animates? It&#39;s 4:00 in the afternoon.</p><p>I gotta call him. Just talk to him. There&#39;s no harm in that.</p><p>That&#39;s how it starts. &quot;I don&#39;t need to eat the cake, I&#39;ll just smell the icing. Why not just a little sliver?&quot; Or, &quot;Okay, just a slice or two.&quot; The next thing you know, you&#39;re 210 pounds... and you get wedged in going down the tunnel slide!</p><p>That&#39;s not true, is it?</p><p>They had to cut me out... With the Jaws of Life.</p><p>Phoebe, honey, I know this is hard. But look, if you talk to him, then you&#39;re gonna want to see him. And if you see him, you&#39;re gonna wanna get back together. And I konw that&#39;s not what you want.</p><p>All right, so give me your phone.</p><p>Here.</p><p>- And now your cell. - Okay.</p><p>There you go.</p><p>- This is your cell phone? - Yes.</p><p>This is your current cell phone?</p><p>Yes. It reminds me of a simpler time.</p><p>Phoebe? Where&#39;s your purse?</p><p>- Hey! No! - No!</p><p>- Give it to me! - You can&#39;t have it!</p><p>- Give it to me! - No！</p><p>- I&#39;ll go in there! - Oh, yeah.</p><p>- Phoebe, come here! - No!</p><p>- Give it to me! - You&#39;re crazy!</p><p>Damn you, Monica Geller hyphen Bing!</p><p>Don&#39;t even think of sneaing out and using a pay phone... bacause I am everywhere, baby!</p><p>Hey, look who&#39;s here.</p><p>It&#39;s Joey. And he brought home a friend.</p><p>Joey! Emma&#39;s right here.</p><p>You promised not to bring girls home in the middle of the day!</p><p>No, no, no, it&#39;s not a girl. It&#39;s... a brand-new Huggsy!</p><p>Oh! Oh, that&#39;s so great! Now Emma has two Huggsies!</p><p>No, no. Oh, no. No, Emma has one Huggsy. The new Huggsy. The other Huggsy, I don&#39;t know, I guess I&#39;ll just take him back.</p><p>You know what? When I was a little girl, I had a little pink pony named Cotton. Oh, I loved her so much. I took her everywhere. I would braid her tail--</p><p>Make the transfer!</p><p>Should I be concerned that a button fell off the old Huggsy and I can&#39;t find it?</p><p>No, don&#39;t worry about it. I swallowed that years ago. Hey!</p><p>Oh, what? I don&#39;t think she likes the new Huggsy.</p><p>But he&#39;s the same.</p><p>I think she wants the old one back.</p><p>Yeah, but he&#39;s the same.</p><p>Joey, come on.</p><p>But he&#39;s the same!</p><p>You&#39;re not the same.</p><p>You know, it&#39;s a lot less surprising to do that after I&#39;ve buzzed you into the building.</p><p>So, Phoebe, why are there men&#39;s shoes by the door?</p><p>Those are my shoes.</p><p>Well, when you get over this breakup, we need to go shopping.</p><p>Look, Monica, I really appricate you checking in on me. But I&#39;m actually felling a lot better.</p><p>You are?</p><p>Yeah, I just kind of want to be alone right now.</p><p>- Who&#39;s that? - I ordered Chinese food.</p><p>What are the chances?! One billion Chinese people, and they send Mike!</p><p>What are you doing here?</p><p>Phoebe called me.</p><p>- Phoebe1 - I&#39;m sorry. I broke down.</p><p>I wanted to see him.</p><p>Well, not on my watch.</p><p>Damn it, Phoebe, how did you even call him?</p><p>Theres&#39;s a speakerphone on the base unit.</p><p>Base unit. Think, Monica, think!</p><p>- Can I come in? - No! No.&nbsp;</p><p>Phoebe, isn&#39;t seeing Mike exactly what you wanted me to stop you from doing?</p><p>Look, if I want to see Phoebe, and she--</p><p>This doesn&#39;t concern you!</p><p>Sorry. I guess I was thrown off by the mention of my name.</p><p>Look, guys, you can&#39;t do this.</p><p>It&#39;s gonna make getting over each other harder.</p><p>Not if nothing happens. Why can&#39;t we just hang out as friends?</p><p>Sure. If you&#39;re just gonna hang out as friends, then maybe I&#39;ll join you. You know, I&#39;m your friend and Mike&#39;s friend.</p><p>Sit down.</p><p>Make room for your friend.</p><p>So how have you been?</p><p>I&#39;ve been pretty good.</p><p>You look really beautiful.</p><p>Thinks. You look good too.</p><p>No, no, no. This is dangerous territory. Keep it clean.</p><p>So how&#39;s the piano playing going?</p><p>Actually, I&#39;ve been playing a lot of love songs lately. I&#39;ve missed you.</p><p>I&#39;ve missed you too.</p><p>You know, on the way over here, I saw this drunk guy throw up. And then a pigeon ate it.</p><p>Hey. Ross.</p><p>Look, I just wanted to apologize. Don&#39;t tell me you actually made those gay pictures of me.</p><p>Check this out.</p><p>So that&#39;s what I&#39;d look like if I worked out. And was being serviced by a policeman.</p><p>You&#39;re not gonna actually send these out, are you?</p><p>Actually, I don&#39;t need to, because your little &quot;Ross is dead&quot; joke didn&#39;t work. Okay? There were no responses. Nobody posted anything on the website, nobody called my parents, so the joke is on you. Nobody called, nobody wrote anything, nobody cares that I&#39;m dead.</p><p>Oh, my God. Nobody cares that I&#39;m dead?</p><p>Oh, come on, you know that&#39;s not true.</p><p>What are you talking about? You get 60 responses... just for coming out of the closet. I didn&#39;t get one response, and I&#39;m dead!</p><p>Well, the gay community is a lot more vocal than the dead community.</p><p>I can&#39;t believe this. Not even my geology lab partner. And I carried that guy!</p><p>Look, let&#39;s think about this, okay?</p><p>You think people are gonna disturb your family as this tragic time? That people are gonna post condolences on a website? This isn&#39;t about people not caring. This is about people not having a decent outlet for their grief.</p><p>You&#39;re right. There isn&#39;t a decent outlet.</p><p>Right. I&#39;m sure if you had a funeral or memorial service, tons of people would come.</p><p>Exactly!</p><p>Ross, what are you doing?</p><p>You&#39;re having a memorial service for yourself?</p><p>No, that would be stupid. You&#39;re having it for me.</p><p>Ross, don&#39;t press send. Dont&#39;t press--</p><p>No, too late. Too late. It&#39;s sent. Sorry, so is that picture of you and the policeman.</p><p>That&#39;s all right. I&#39;m tan, limber... And it looks like I talked my way out of that ticket.</p><p>The surgery was not a success. And then you say: &quot;What are we gonna do, Drake?&quot;</p><p>Come in.</p><p>I&#39;m trying to put Emma down for a nap. Have you seen Huggsy?</p><p>Original or crappy?</p><p>Original.</p><p>No.Sorry. Haven&#39;t seen him.</p><p>Then what&#39;s that big lump under your covers?</p><p>It&#39;s Monica, okay?</p><p>That&#39;s not Monical!</p><p>All right, fine! It&#39;s orignal Huggsy! I know Emma wants him, but he&#39;s mine and I need him. She&#39;s being unreasonable.</p><p>Joey, there is a reason that Emma loves that stuid penguin so much! Oh, don&#39;t cover its ears! It&#39;s because it reminds her of her Uncle Joey.</p><p>- It does? - Yeah.</p><p>And I think she really likes him because he smells like you. And she-- She loves that. Go figure. And she&#39;s comforted by him necause she loves her Uncle Joey so much.</p><p>- Really? She loves me? -Oh, yeah.</p><p>But you know what? If you need Huggsy, don&#39;t worry. Emma will totally understand. I won&#39;t, but whatever/</p><p>Okay, wait a minute, Rach. I mean, if... If Huggsy means that much to Emma, then... Well, she can have him.</p><p>Oh, sweet, I knew Uncle Joey would step up. Look, Emma. Look who&#39;s back.</p><p>No, forget it! Forget it! I can&#39;t do it!</p><p>Are you--? You&#39;re gonna take Huggsy away from a little child?</p><p>How do you think I got him in the first place?</p><p>And then it just gobbled up that puke. I mean... That was one gross pigeon.</p><p>Oh, man. Why didn&#39;t I ask Joey to keep us apart? You throw a meatball in the hallway, we&#39;d be doing it like rabbits right now.</p><p>All right, you two. I&#39;m gonna go to the bathroom. I don&#39;t want anything going on while I&#39;m gone. Here&#39;s a few things you can discuss: Mucus, fungus, and the idea of me and Ross doing it.</p><p>I&#39;ve missed you so much. I won&#39;t ask you to get back together. I know we want different things, but... Just to be with you one more night.</p><p>I want that too. But is that gonna make it too hard?</p><p>It can&#39;t be any harder than this. I mean, if had known the last time I saw you would be the last time, I-- I would have stopped to memorize your face, the way you moved. Everything about you. If I had known the last time I kissed you would be the last time... I never would have stopped.</p><p>Kiss him, you fool!</p><p>What?</p><p>Didn&#39;t you hear that speech? If you don&#39;t kiss him, then I will.</p><p>I missed you so much.</p><p>I knew you&#39;d be here!&nbsp;</p><p>Crap.</p><p>Who is this?</p><p>My friend Manny.</p><p>I asked him to keep me away from you.</p><p>Hey, that&#39;s what I&#39;m doing for Phoebe.</p><p>Well, you&#39;re not doing a very good job.</p><p>Excuse me?</p><p>What&#39;s with the kissing?</p><p>Hey, at least I knew where my guy was.</p><p>Yeah, think God you were here to oversee all the kissing.</p><p>You didn&#39;t hear the speech.</p><p>I&#39;ve heard the speech. If he know it was gonna be the last time--</p><p>Hey, it was vary moving. You&#39;re just heartless!</p><p>You&#39;re weak!&nbsp;</p><p>You&#39;re weird!</p><p>Your pants are undone.</p><p>Where&#39;d they go?</p><p>Damn it.</p><p>Well, we blew it. I blame myself.</p><p>And I blame you too.</p><p>It&#39;s been an hour, and not one of my classmates has shown up? I tell you, when I actually die, some people are gonna get seriously haunted.</p><p>There you go. Someone came.</p><p>Okay. Okay. I&#39;m gonna go hide. This is so exciting. My first mourner!</p><p>Hi. Glad you could come.</p><p>Please come in.</p><p>HI. You&#39;re Chandler Bing, right? I&#39;m Tom Gordon. I was in your class.</p><p>Oh, yes, let me take your coat.</p><p>Thanks. I&#39;m so sorry about Ross, it&#39;s...</p><p>No, at least he died doing what he loved. Watching blimps.</p><p>Who is it?</p><p>You know some guy, Tom Gordon?</p><p>I don&#39;t remember him. But then again, I touched so may lives.</p><p>So did you know Ross well?</p><p>Actually, I barely knew him. I came because I heard Chandler&#39;s news. Do you know if he&#39;s seeing anyone?</p><p>Yes, he is. Me.</p><p>What? You mean--?</p><p>Can I ask you a personal question? How do you shave your beard so close?</p><p>Okay, Tommy! That&#39;s enough mourning for you. Here we go. Bye-bye. All right.</p><p>Hey, listen. Call me.</p><p>Okay.</p><p>I&#39;m dead and no one cares?</p><p>I look like a man?</p><p>Please, one ridiculous problem at a time. This isn&#39;t ridiculous. Look around, no one&#39;s here.</p><p>You gave them one day&#39;s notice. Not everyone checks the website every day. And Monica, it&#39;s probably the way you stand!</p><p>I guess you&#39;re right. Still, somebody must have seen it. I went to that school for four years and I didn&#39;t have an impact on anyone?</p><p>Well, that&#39;s not true. You had an impact on me. I mean, it&#39;s 15 years later and we&#39;re still best friends. Doesn&#39;t that count for something?</p><p>Oh, great, more party bosy for Chandler.</p><p>I&#39;m sure it&#39;s somebody for you. Now go hide.</p><p>Hi. I&#39;m here for Ross Geller&#39;s memorial service.</p><p>Kori? Kori Weston?</p><p>Yeah.</p><p>You look amazing.</p><p>And you are?</p><p>Chandler. Chandler Bing. And I&#39;m not gay. I&#39;m not gay at all.</p><p>You are married, though.</p><p>Don&#39;t listen to him. He&#39;s in a really bad mood.</p><p>I can&#39;t believe that Ross is gone. It is just so sad.</p><p>I didn&#39;t know Ross and you were so close.</p><p>Oh, we weren&#39;t. But we had one class together. He was such a great guy. And he talked so passionately about science. I always remembered him.</p><p>I&#39;m sure that would mean a lot to him. And if heaven has a door... I&#39;m sure he&#39;s pressing his ear up against it and listening intently.</p><p>I thought so many times about calling him and asking him out. I guess I really missed my chance.</p><p>No, you didn&#39;t! I&#39;m still alive!</p><p>Who did we bury?</p><p>Kori, I know this is a big surprise for you. It&#39;s a long story. But the things you just said really made my day. The fact that you&#39;re here means more to me... than if this room were filled with people.</p><p>You sick freak! Who does that? I can&#39;t believe I had a crush on you.</p><p>Did you hear that? Kori Weston had a crush on me!</p><p>No, Mom, I am not dead. I know it&#39;s not something to kid about. It was just a practical joke between Chandler and me, but it&#39;s over, okay? Actually, no. Even if I had died, you would not be left childless. Monica?</p><p><br/></p><p>====2017.6.8补==========</p><p>浑浑噩噩的当时，想要借助这样的方式来让英语不要淡出自己的视野，就把这一集的台词全打了一遍。2个小时+，很用时间。</p>]]></content>
  </entry>
  <entry>
    <title>风决定要走，云怎么挽留</title>
    <link href="https://old-blog.smallyu.net/index2568.html?id=49"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=49</id>
    <published>2017-03-10T16:00:00.000Z</published>
    <updated>2017-03-10T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>昨天晚上，一位大学同学精神错乱（意识紊乱），没有清醒的自主意识，做出种种奇怪的行为。直到今天上午，在N多人熬夜的陪同下，等来了他的家人，短暂了解情况后，带走，休学。 这是一位奇怪又不奇怪的同学，这是一件可怕又不可怕的事情。 有生以来第一次亲眼见到精神错乱的人，可怕的不是他现在什么状态，而是他以前，再正常不过的一个普通人。 “普通人”只是我对他的定位，可能他自...</p>]]></summary>
    <content type="html"><![CDATA[<p>昨天晚上，一位大学同学精神错乱（意识紊乱），没有清醒的自主意识，做出种种奇怪的行为。直到今天上午，在N多人熬夜的陪同下，等来了他的家人，短暂了解情况后，带走，休学。</p><p>&nbsp;</p><p>这是一位奇怪又不奇怪的同学，这是一件可怕又不可怕的事情。</p><p>有生以来第一次亲眼见到精神错乱的人，可怕的不是他现在什么状态，而是他以前，再正常不过的一个普通人。</p><p>“普通人”只是我对他的定位，可能他自己并不这么认为。昨天晚上，事情刚刚发生但还没有完全发生的时候，他很大声地说（吼）了一句话：“宿舍楼里没有睡觉的人都听我指挥，我是宿舍部副部长！”。</p><p>他行为异常早有体现。他舍友说，最近几天，就在补考结束之后，他的动作变得奇怪起来。听歌，只单曲循环同一首歌；上课，只坐最后一排；上课的时候，唱歌；晚上，不睡觉；中午喝水，站在阳台，喝一口，咳一下，喝一口，咳一下，喝完一杯，再来一杯，喝完这杯，还有三杯……最奇怪的就是最近两三天尤其是昨天，不停到各个宿舍串门。</p><p>说奇怪是因为他的这些行为，都超过了该有的“度”。</p><ul class=" list-paddingleft-2" style="list-style-type: disc;"><li><p>听歌单曲循环不算是异常行为，但如果循环到让你发毛。你可以打开网易云设置单曲循环，然后打王者荣耀，写作业，聊天，做事情，或者这首歌真的让你喜欢到欲罢不能。好像他听的是，《没有你陪伴真的好孤单》。</p></li><li><p>上课坐最后一排是很多同学的惯例，他不是。以前积极进取，严谨认真，两次班里选积极分子都有他的份。两次积极分子是因为，第一次积极分子考试的时候，就是那种关于党，爱党信党忠党之类内容的考试，他被认为是作弊。现在进考场不能带通讯设备（手机）是惯例也是常识。也许他担心考试过不了。</p></li><li><p>上课的时候，唱歌。想象如果一个真正的精神病人坐在教室里面，旁若无人的“小”声唱《成都》。已经违反公共场合礼仪规范了，不是对不对，而是合不合适。他是一个大学生。据说其实离开宿舍后在上课期间还是很正常的。</p></li><li><p>晚上，好几天没睡觉了，可能这个和意识紊乱的关系会比较大。而且每天早上6点就会起床并把其他人叫醒。</p></li><li><p>中午喝水，没亲眼见过，被同寝室的人认为不正常。</p></li><li><p>逛宿舍，整个事件的始作俑者。昨天中午宿舍挨着逛一遍，中午睡觉醒来准备去上课的时候发现他就在我们宿舍。当时我们宿舍没有醒着的人，都在睡觉，并没有人和他聊天。然后他就那样坐在我（二级）床下的凳子上。舍友和他打招呼，没感觉到异常。</p></li></ul><p>直到昨天晚上，他待在了我们一个兄弟班的宿舍。11点熄灯，人家要睡觉了，他赖着不走。并且之前，他在人家宿舍随便把别人的东西搬来搬去，之前，在逛我们班的某一个宿舍的时候，不声不响的喝掉了某位同学三瓶牛奶。</p><p>赖在别人宿舍不走，说他要玩个游戏。进去一个人，他就会让那个人陪他玩个游戏，发布“关上门”，“面对着门”，“把凳子搬到这里”，“把桌子收拾一下”，等等之类的“命令”。</p><p>然后只能惊动宿管楼姨、班主任、系辅导员、父母。担心他当时的精神状态会有什么危险，男生四个宿舍30个人几乎一晚上没睡（当然也有例外，我就睡得可好了）轮流值班看着他，不让他到阳台，不让他拿什么太锋利尖锐的东西。</p><p>&nbsp;</p><p>综合来看，他突然间意识紊乱的客观因素大概有：</p><ul class=" list-paddingleft-2" style="list-style-type: disc;"><li><p>挂科</p></li><li><p>人际关系差</p></li></ul><p>主观因素大概有：</p><ul class=" list-paddingleft-2" style="list-style-type: disc;"><li><p>现实与梦想的落差</p></li><li><p>迷茫</p></li></ul><p>&nbsp;</p><p>客观因素第一个是挂科，这是一个很重要的原因。前两个学期他都没有挂科并且成绩还不错。上个学期考试之前，他还来我们宿舍并不炫耀的问我们有什么题不会（毕竟我也是考的了前几名的好不好），充分说明了他当时的自信程度。事与愿违，上个学期的成绩下来后，他挂科了，总成绩排名倒数。</p><p>挂科对应的就是主观因素中现实与梦想的落差。原先他是一个成绩并不差的好学生，是一个被选为入党积极分子，马上就可以成为党员的优秀学生，是班里的常委，是宿舍部副部长。他有多重视在学校中的职位从那一句“宿舍楼里没有睡觉的人都听我指挥，我是宿舍部副部长！”就看得出来。也许他的梦想是当官，做一个有权的人。</p><p>对这种梦想挂科带来的是毁灭性的打击。挂一门课总成绩一落千丈，同时只要挂科就不能入党。学生会那边的事情没人清楚，据我所知我们这种三流学校的学生会，部长和副部长差的就很多，如果他在学生会那边受点打击也很惨。</p><p>第二个客观因素的人际关系差。</p><p>有一次他舍友在商店借他一块钱，他舍友正好没有零钱。他说，我不借一块钱，只借十块钱。然后借给了他舍友十块钱。潜台词就是借一块钱我不好意思找你要！那是舍友啊舍友。像我们宿舍不管关系好不好什么时候计较过几块钱？这不是家庭经济情况好不好的原因好么。</p><p>有一次，我们三个人一组打扫教室。我和另外一个人给忘了，他打电话叫我们，当时已经晚了一会儿。然后我们去了之后，看见了啥？他坐在教室里，的椅子上，坐着，玩手机。当时心里一万头草泥马呼啸奔腾而过。我们没来你特喵就不能自己先开始么。后来查教室卫生打扫情况的人还打着官腔说我们不该迟到怎么怎么地。</p><p>还听说，他和他们宿舍的人打过架。他嫌他的下铺打游戏影响他睡觉，就直接睡在了他的下铺的床上。当时是夏天，他经常在外面打球，没有洗澡，就直接睡在了人家的床上。两个人看着不爽，就打了起来。可能他只是没有合理的办法表达出自己的需求。</p><p>人际关系差不是我的判断，是他的舍友们总结出来的，因为他的舍友们并不是很友好的看待他。</p><p>学业崩溃加上人际关系无望。上课上的很不爽，自己平时的努力毁于一旦，学习都会挂科那还学它干吗？（重要的是同学们会不会小看我？）人际关系不是很好，回到宿舍连个说话的人都没有，在宿舍待着岂不是很郁闷？然而对于我们这种业余生活不丰富的学校和生活风气，整天的行程就两个地方，教室，宿舍。于是导致整个人会迷茫，不知所措，看不到希望，压力大，紧张。（迷茫只是我的判断，毕竟漫无目的的逛宿舍不就是迷茫的体现？）</p><p>&nbsp;</p><p>以上是对那位同学仅有的一些了解和目前已知的一些情况。</p><p>我和他的关系没有多好，也并没有在他情绪最并不稳定的时候和他接触过，只是今天早上起床后到他的宿舍看了几分钟。他喘着粗气，偶尔会有一下不寻常的动静，那种只会在电影里看到的不寻常的动静。离得很远就能感受到屋子里面咄咄逼人和不寒而栗的气氛，尽管同在的还有好几个人。</p><p>问题是<span style="font-size: 16px;"><strong><span style="text-decoration: none;">我能确切的想象到他的感受</span></strong></span>。</p><p>我不会说上个学期放寒假回家我差点没哭。</p><p>我想象不到复习一个月考5名开外是什么体验。</p><p>我不明白做很多题CET4不到400分是什么感受。</p><p>我不知道Hello World能给我带来什么。</p><p>我不知道我还要单身多久。</p><p>难道我离那样也不远了？</p>]]></content>
  </entry>
  <entry>
    <title>站在巨人的肩膀上写代码——Spl中的三种数据结构解析</title>
    <link href="https://old-blog.smallyu.net/index4944.html?id=48"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=48</id>
    <published>2017-03-04T16:00:00.000Z</published>
    <updated>2017-03-04T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>今天身体莫名get trouble，心情莫名bad。想说什么又没有什么要说的。I want to get a new object?（她不喜欢我怎么办？）嗯？%e9%9d%b3%e8%8d%a3 来简单说说Spl中三种数据结构的基本操作，这三种数据结构分别为双向链表（SplDoubleLinkedList）、堆栈（SplStack）和队列（SplQueue）...</p>]]></summary>
    <content type="html"><![CDATA[<p>今天身体莫名get trouble，心情莫名bad。想说什么又没有什么要说的。I want to get a new object?（她不喜欢我怎么办？）嗯？%e9%9d%b3%e8%8d%a3</p><p><br/></p><p>来简单说说Spl中三种数据结构的基本操作，这三种数据结构分别为双向链表（SplDoubleLinkedList）、堆栈（SplStack）和队列（SplQueue）。</p><p><span style="font-size: 16px;"><strong>双向链表（SplDoubleLinkedList）</strong></span></p><p><span style="font-size: 16px;"><span style="font-size: 14px;">首先实例化对象为$obj</span><strong><br/></strong></span></p><pre class="prism-highlight prism-language-php">$obj&nbsp;=&nbsp;new&nbsp;SplDoublyLinkedList();</pre><p><span style="font-size: 16px;"><span style="font-size: 14px;"></span></span>然后我们添加三条数据到双向链表中<br/></p><pre class="prism-highlight prism-language-php">$obj-&gt;push(1);
$obj-&gt;push(2);
$obj-&gt;push(3);</pre><p>再来添加一条这样的数据</p><pre class="prism-highlight prism-language-php">$obj-&gt;unshift(10);</pre><p>这个时候打印一下$obj</p><pre class="prism-highlight prism-language-php">print_r($obj);</pre><p>输出的结果会是这样</p><blockquote><pre>SplDoublyLinkedList&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;0
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;10
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[2]&nbsp;=&gt;&nbsp;2
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[3]&nbsp;=&gt;&nbsp;3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre></blockquote><p>对我们看到，1、2和3分别按照次序被添加进了链表对象的数组中，而底部（Bottom）位置的数据则是10，即使用unshift方法添加的数据，这里得知unshift的作用就是添加数据到链表底部。</p><p>再调用这个方法</p><pre class="prism-highlight prism-language-php">$obj-&gt;rewind();&nbsp;//&nbsp;10</pre><p>输出一下当前指针指向的节点</p><pre class="prism-highlight prism-language-php">echo&nbsp;&#39;current:&nbsp;&#39;&nbsp;.&nbsp;$obj-&gt;current();</pre><p>输出的是这个节点<br/></p><blockquote><p><span style="font-family: Simsun; font-size: medium;">current: 10</span></p></blockquote><p>说明双向链表的rewind会将指针移动到底部。<br/></p><p>我们再试试next方法</p><pre class="prism-highlight prism-language-php">$obj-&gt;next();&nbsp;&nbsp;&nbsp;//&nbsp;1</pre><p>输出当前指针指向的节点</p><pre class="prism-highlight prism-language-php">echo&nbsp;&#39;next&nbsp;node:&nbsp;&#39;&nbsp;.&nbsp;$obj-&gt;current();</pre><p>结果是</p><blockquote><p><span style="font-family: Simsun; font-size: medium;">next node: 1</span></p></blockquote><p>结果明了，会将current向顶部移动一个位置。<br/></p><p>再来几个测试</p><pre class="prism-highlight prism-language-php">$obj-&gt;next();&nbsp;&nbsp;&nbsp;//&nbsp;2
$obj-&gt;next();&nbsp;&nbsp;&nbsp;//&nbsp;3
$obj-&gt;prev();&nbsp;&nbsp;&nbsp;//&nbsp;2
echo&nbsp;&#39;next&nbsp;node:&nbsp;&#39;&nbsp;.&nbsp;$obj-&gt;current();&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2
$obj-&gt;next();&nbsp;&nbsp;&nbsp;//&nbsp;3
$obj-&gt;next();&nbsp;&nbsp;&nbsp;//&nbsp;
echo&nbsp;&#39;next&nbsp;node:&nbsp;&#39;&nbsp;.&nbsp;$obj-&gt;current();&nbsp;&nbsp;&nbsp;&nbsp;//</pre><p>代码中反复使用了next方法和prev方法，每次指针指向的节点在代码中都有注释，并输出了两次来验证正确性，输出结果是正确的</p><blockquote><p><span style="font-family: Simsun; font-size: medium;">next node: 2</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">next node:&nbsp;</span></p></blockquote><p>并且我们知道指针超出链表的范围后会返回空值，因此接下来我们可以判断一下当前节点是否有效</p><pre class="prism-highlight prism-language-php">if($obj-&gt;current()){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;Current&nbsp;node&nbsp;valid&nbsp;&lt;br&nbsp;/&gt;&quot;;
}else{
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;Current&nbsp;node&nbsp;invalid&nbsp;&lt;br&nbsp;/&gt;&quot;;
}</pre><p>返回值为</p><blockquote><p><span style="font-family: Simsun; font-size: medium;">Current node invalid&nbsp;</span></p></blockquote><p>或者可以用这样的方式来验证当前节点是否可用</p><pre class="prism-highlight prism-language-php">if($obj-&gt;valid()){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;valid&nbsp;list&nbsp;&lt;br&nbsp;/&gt;&quot;;
}else{
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;invalid&nbsp;list&nbsp;&lt;br&nbsp;/&gt;&quot;;
}</pre><p>返回内容为<br/></p><blockquote><p><span style="font-family: Simsun; font-size: medium;">valid list&nbsp;</span></p></blockquote><p><span style="font-family: Simsun; font-size: medium;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">接下来是删除节点的操作，pop方法用于删除当前指针指向的节点，并返回该节点的内容</span><br/></span></p><pre class="prism-highlight prism-language-php">$obj-&gt;rewind();

echo&nbsp;&quot;&lt;hr&nbsp;/&gt;&nbsp;Pop&nbsp;value:&nbsp;&quot;&nbsp;.&nbsp;$obj-&gt;pop();

print_r($obj);

echo&nbsp;&#39;current:&nbsp;&#39;&nbsp;.&nbsp;$obj-&gt;current();</pre><p>输出的内容为<br/></p><blockquote><p><span style="font-family: Simsun; font-size: medium;">Pop value: 3</span></p><pre>SplDoublyLinkedList&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;0
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;10
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[2]&nbsp;=&gt;&nbsp;2
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre><p><span style="font-family: Simsun; font-size: medium;">current: 10</span></p></blockquote><p><span style="font-family: Simsun; font-size: medium;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">删除节点之前使用rewind重置了指针的位置到Bottom，同时pop删除了Top位置的节点。那么如果current正好指向Top位置会怎样？<br/></span></span></p><pre class="prism-highlight prism-language-php">$obj-&gt;next();&nbsp;&nbsp;&nbsp;//&nbsp;1
$obj-&gt;next();&nbsp;&nbsp;&nbsp;//&nbsp;2

//&nbsp;把Top位置的节点从链表中删除，并返回
echo&nbsp;&quot;&lt;hr&nbsp;/&gt;&nbsp;Pop&nbsp;value:&nbsp;&quot;&nbsp;.&nbsp;$obj-&gt;pop()&nbsp;.&nbsp;&quot;&lt;br&nbsp;/&gt;&quot;;
echo&nbsp;&#39;current:&nbsp;&#39;&nbsp;.&nbsp;$obj-&gt;current()&nbsp;.&nbsp;&#39;&lt;br&nbsp;/&gt;&#39;;&nbsp;&nbsp;//&nbsp;10

print_r($obj);</pre><p>输出</p><blockquote><p><span style="font-family: Simsun; font-size: medium;">Pop value: 2</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">current:&nbsp;</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/></p><pre>SplDoublyLinkedList&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;0
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;10
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre></blockquote><p><span style="font-family: Simsun; font-size: medium;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">如果current正好指向Top位置，那么调用pop之后current会失效。</span></span></p><p><span style="font-family:微软雅黑, Microsoft YaHei">最后一个要试的方法是shift，用于把Bottom位置的节点从链表中删除，并返回，执行</span></p><pre class="prism-highlight prism-language-php">$obj-&gt;shift();
print_r($obj);</pre><p><span style="font-family:微软雅黑, Microsoft YaHei"></span>会只输出</p><blockquote><pre>SplDoublyLinkedList&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;0
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre></blockquote><p><span style="font-family:微软雅黑, Microsoft YaHei">另外两种数据结构的操作类似，啊，好懒，直接贴一下，要不然得很长时间。<br/></span></p><p><span style="font-size: 16px;"><strong><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">堆栈（SplStack）</span></strong></span></p><p><span style="font-family:微软雅黑, Microsoft YaHei">测试代码为</span></p><pre class="prism-highlight prism-language-php">&lt;?php

$stack&nbsp;=&nbsp;new&nbsp;SplStack();

$stack-&gt;push(&#39;a&#39;);&nbsp;&nbsp;//&nbsp;push操作箱堆栈里面放入一个节点到tio位置
$stack-&gt;push(&#39;b&#39;);
$stack-&gt;push(&#39;c&#39;);

echo&nbsp;&#39;&lt;pre&gt;&#39;;
print_r($stack);
echo&nbsp;&#39;&lt;/pre&gt;&#39;;

echo&nbsp;&quot;Bottom:&nbsp;&quot;&nbsp;.&nbsp;$stack-&gt;bottom()&nbsp;.&nbsp;&quot;&lt;br&nbsp;/&gt;&quot;;
echo&nbsp;&quot;Top:&nbsp;&quot;&nbsp;.&nbsp;$stack-&gt;top()&nbsp;.&nbsp;&quot;&lt;br&nbsp;/&gt;&quot;;

$stack-&gt;offsetSet(0,&#39;C&#39;);&nbsp;&nbsp;&nbsp;//&nbsp;堆栈的offset=0是Top所在的位置，offset=1是top位置节点靠近bottom位置的相邻节点，以此类推

echo&nbsp;&#39;&lt;pre&gt;&#39;;
print_r($stack);
echo&nbsp;&#39;&lt;/pre&gt;&#39;;

$stack-&gt;rewind();&nbsp;&nbsp;&nbsp;//&nbsp;双向链表的rewind和堆栈的rewind相反，堆栈的rewind是的当前指针指向Top所在的位置，而双向链表调用之后指向bottom所在位置
echo&nbsp;&#39;current:&nbsp;&#39;&nbsp;.&nbsp;$stack-&gt;current()&nbsp;.&nbsp;&#39;&lt;br&nbsp;/&gt;&#39;;

$stack-&gt;next();&nbsp;//&nbsp;堆栈的next操作使指针靠近Bottom位置的下一个节点，而双向链表是靠近top的下一个节点
echo&nbsp;&#39;current:&nbsp;&#39;&nbsp;.&nbsp;$stack-&gt;current()&nbsp;.&nbsp;&#39;&lt;br&nbsp;/&gt;&#39;;

echo&nbsp;&#39;&lt;hr&nbsp;/&gt;&#39;;

//&nbsp;遍历堆栈
$stack-&gt;rewind();
while($stack-&gt;valid()){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$stack-&gt;key().&quot;=&gt;&quot;.$stack-&gt;current()&nbsp;.&nbsp;&quot;&lt;br&nbsp;/&gt;&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;$stack-&gt;next();&nbsp;//&nbsp;next操作不从链表中删除元素
}

//&nbsp;删除堆栈数据
$popObj&nbsp;=&nbsp;$stack-&gt;pop();&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;pop操作从堆栈里面提取出最后一个元素（top位置），同时在堆栈里面删除该节点
echo&nbsp;&quot;Poped&nbsp;object:&nbsp;&quot;&nbsp;.&nbsp;$popObj&nbsp;.&nbsp;&quot;&lt;br&nbsp;/&gt;&quot;;

echo&nbsp;&#39;&lt;pre&gt;&#39;;
print_r($stack);
echo&nbsp;&#39;&lt;/pre&gt;&#39;;</pre><p><span style="font-family:微软雅黑, Microsoft YaHei"></span>打印内容为</p><blockquote><pre>SplStack&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;6
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;b
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[2]&nbsp;=&gt;&nbsp;c
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre><p><span style="font-family: Simsun; font-size: medium;">Bottom: a</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">Top: c</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/></p><pre>SplStack&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;6
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;b
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[2]&nbsp;=&gt;&nbsp;C
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre><p><span style="font-family: Simsun; font-size: medium;">current: C</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">current: b</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/></p><hr style="font-family: Simsun; font-size: medium; white-space: normal;"/><p><span style="font-family: Simsun; font-size: medium;">2=&gt;C</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">1=&gt;b</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">0=&gt;a</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">Poped object: C</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/></p><pre>SplStack&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;6
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;b
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre></blockquote><p><strong><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 16px;">队列（SplQueue）</span></strong></p><p><span style="font-family:微软雅黑, Microsoft YaHei"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">测试代码为</span></span></p><pre class="prism-highlight prism-language-php">&lt;?php

$obj&nbsp;=&nbsp;new&nbsp;SplQueue();

$obj-&gt;enqueue(&#39;a&#39;);&nbsp;//&nbsp;插入一个节点到队列里面的Top位置
$obj-&gt;enqueue(&#39;b&#39;);
$obj-&gt;enqueue(&#39;c&#39;);

echo&nbsp;&#39;&lt;pre&gt;&#39;;
print_r($obj);
echo&nbsp;&#39;&lt;/pre&gt;&#39;;

echo&nbsp;&quot;Bottom:&nbsp;&quot;&nbsp;.&nbsp;$obj-&gt;bottom()&nbsp;.&nbsp;&quot;&lt;br&nbsp;/&gt;&quot;;
echo&nbsp;&quot;Top:&nbsp;&quot;&nbsp;.&nbsp;$obj-&gt;top()&nbsp;.&nbsp;&quot;&lt;br&nbsp;/&gt;&quot;;

$obj-&gt;offsetSet(0,&#39;A&#39;);&nbsp;//&nbsp;队列里面offset=0Bottom所在位置，offset=1是Top所在位置，以此类推

echo&nbsp;&#39;&lt;pre&gt;&#39;;
print_r($obj);
echo&nbsp;&#39;&lt;/pre&gt;&#39;;

$obj-&gt;rewind();&nbsp;//&nbsp;队列里面rewind操作是的指针指向Bottom所在位置的节点
echo&nbsp;&#39;current:&nbsp;&#39;&nbsp;.&nbsp;$obj-&gt;current()&nbsp;.&nbsp;&#39;&lt;br&nbsp;/&gt;&#39;;

$obj-&gt;rewind();
while($obj-&gt;valid()){
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$obj-&gt;key().&quot;=&gt;&quot;.$obj-&gt;current()&nbsp;.&nbsp;&quot;&lt;br&nbsp;/&gt;&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;$obj-&gt;next();&nbsp;//&nbsp;next操作是的当前指针指向top方向的下一个节点
}

echo&nbsp;&quot;dequeue&nbsp;obj:&nbsp;&quot;.$obj-&gt;dequeue().&quot;\n&quot;;&nbsp;&nbsp;//&nbsp;dequeue操作从队列中提取bottom位置的节点，并返回，同时从队列里面删除该元素

echo&nbsp;&#39;&lt;pre&gt;&#39;;
print_r($obj);
echo&nbsp;&#39;&lt;/pre&gt;&#39;;</pre><p><span style="font-family:微软雅黑, Microsoft YaHei"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;"></span></span>打印内容为</p><blockquote><pre>SplQueue&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;4
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;a
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;b
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[2]&nbsp;=&gt;&nbsp;c
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre><p><span style="font-family: Simsun; font-size: medium;">Bottom: a</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">Top: c</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/></p><pre>SplQueue&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;4
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;A
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;b
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[2]&nbsp;=&gt;&nbsp;c
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre><p><span style="font-family: Simsun; font-size: medium;">current: A</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">0=&gt;A</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">1=&gt;b</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">2=&gt;c</span><br style="font-family: Simsun; font-size: medium; white-space: normal;"/><span style="font-family: Simsun; font-size: medium;">dequeue obj: A</span></p><pre>SplQueue&nbsp;Object
(
&nbsp;&nbsp;&nbsp;&nbsp;[flags:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;4
&nbsp;&nbsp;&nbsp;&nbsp;[dllist:SplDoublyLinkedList:private]&nbsp;=&gt;&nbsp;Array
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[0]&nbsp;=&gt;&nbsp;b
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[1]&nbsp;=&gt;&nbsp;c
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)

)</pre></blockquote><p><span style="font-family:微软雅黑, Microsoft YaHei"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">The End.</span></span></p>]]></content>
  </entry>
  <entry>
    <title>一个简单的对于Mysql的PDO操作类（PHP）</title>
    <link href="https://old-blog.smallyu.net/indexbb33.html?id=47"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=47</id>
    <published>2017-03-02T16:00:00.000Z</published>
    <updated>2017-03-02T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>类结构本身稍微混乱，方法没有规章，这是缺点。 PDOMysql.class.php &amp;lt;?php define(&amp;quot;DB_HOST&amp;quot;, &amp;quot;localhost&amp;quot;); define(&amp;quot;DB_USER&amp;quot;, &amp;#39;root&amp;#39;); define(&amp;quot;DB_PWD&amp;quot;, &amp;#39;...</p>]]></summary>
    <content type="html"><![CDATA[<p>类结构本身稍微混乱，方法没有规章，这是缺点。<br/></p><blockquote><p>PDOMysql.class.php<br/></p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

define(&quot;DB_HOST&quot;,&nbsp;&quot;localhost&quot;);
define(&quot;DB_USER&quot;,&nbsp;&#39;root&#39;);
define(&quot;DB_PWD&quot;,&nbsp;&#39;root&#39;);
define(&quot;DB_NAME&quot;,&nbsp;&#39;minyy&#39;);
define(&quot;DB_PORT&quot;,&nbsp;&#39;3306&#39;);
define(&quot;DB_TYPE&quot;,&nbsp;&#39;mysql&#39;);
define(&quot;DB_CHARSET&quot;,&nbsp;&#39;utf8&#39;);

class&nbsp;PDOMySQL{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$config&nbsp;=&nbsp;array();&nbsp;&nbsp;//&nbsp;设置连接参数&nbsp;配置信息
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$link&nbsp;=&nbsp;null;&nbsp;//&nbsp;保存连接标志符
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$pconnect&nbsp;=&nbsp;false;&nbsp;&nbsp;&nbsp;//&nbsp;是否开启长连接
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$dbVersion&nbsp;=&nbsp;null;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;保存数据库版本
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$connected&nbsp;=&nbsp;false;&nbsp;&nbsp;&nbsp;//&nbsp;是否连接成功
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$PDOStatement&nbsp;=&nbsp;null;&nbsp;//&nbsp;保存PDOStatement对象
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$queryStr&nbsp;=&nbsp;null;&nbsp;//&nbsp;保存最后执行的操作
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$error&nbsp;=&nbsp;null;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;报错错误信息
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$lastInsertId&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;保存上一步插入操作产生AUTO_INSREMENT
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;$numRows&nbsp;=&nbsp;0;&nbsp;//&nbsp;上一步操作产生受影响的记录条数

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;构造函数实现连接数据库
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;array&nbsp;$dbConfig&nbsp;配置项参数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;__construct($dbConfig&nbsp;=&nbsp;&#39;&#39;){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!class_exists(&quot;PDO&quot;)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::throw_exception(&#39;不支持PDO，请先开启&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$dbConfig&nbsp;||&nbsp;!is_array($dbConfig)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbConfig&nbsp;=&nbsp;array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;hostname&#39;&nbsp;=&gt;&nbsp;DB_HOST,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;username&#39;&nbsp;=&gt;&nbsp;DB_USER,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;password&#39;&nbsp;=&gt;&nbsp;DB_PWD,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;database&#39;&nbsp;=&gt;&nbsp;DB_NAME,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;hostport&#39;&nbsp;=&gt;&nbsp;DB_PORT,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;dbms&#39;&nbsp;=&gt;&nbsp;DB_TYPE,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;dsn&#39;&nbsp;=&gt;&nbsp;DB_TYPE.&quot;:host=&quot;.DB_HOST.&quot;;dbname=&quot;.DB_NAME,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty($dbConfig[&#39;hostname&#39;]))&nbsp;self::throw_exception(&#39;没有定义数据库配置&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$config&nbsp;=&nbsp;$dbConfig;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty(self::$config[&#39;params&#39;]))&nbsp;self::$config[&#39;params&#39;]&nbsp;=&nbsp;array();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!isset(self::$link)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$configs&nbsp;=&nbsp;self::$config;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(self::$pconnect){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;开启长连接，添加到配置数组中
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$configs[&#39;params&#39;][constant(&quot;PDO::ATTR_PERSISTENT&quot;)]&nbsp;=&nbsp;true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$link&nbsp;=&nbsp;new&nbsp;PDO($configs[&#39;dsn&#39;],&nbsp;$configs[&#39;username&#39;],&nbsp;$configs[&#39;password&#39;],&nbsp;$configs[&#39;params&#39;]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch(PDOException&nbsp;$e){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::throw_exception($e-&gt;getMessage());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!self::$link){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::throw_exception(&#39;PDO连接错误&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$link-&gt;exec(&#39;SET&nbsp;NAMES&nbsp;&#39;.DB_CHARSET);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$dbVersion&nbsp;=&nbsp;self::$link-&gt;getAttribute(constant(&quot;PDO::ATTR_SERVER_VERSION&quot;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$connected&nbsp;=&nbsp;true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unset($configs);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;得到所有记录
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$sql&nbsp;SQL语句
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;array&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;得到所有数据
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;getAll($sql&nbsp;=&nbsp;null){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($sql){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::query($sql);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$result&nbsp;=&nbsp;self::$PDOStatement-&gt;fetchAll(constant(&quot;PDO::FETCH_ASSOC&quot;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$result;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;得到结果集中的一条记录
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$sql&nbsp;sql语句
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;array&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回一条数据
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;getRow($sql&nbsp;=&nbsp;null){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($sql&nbsp;!=&nbsp;null){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::query($sql);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$result&nbsp;=&nbsp;self::$PDOStatement-&gt;fetch(constant(&quot;PDO::FETCH_ASSOC&quot;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$result;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;根据主键查找记录
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$tabName&nbsp;表名
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$priId&nbsp;&nbsp;&nbsp;主键id
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$field&nbsp;&nbsp;&nbsp;查询项
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;array&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一条记录
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;findById($tabName,&nbsp;$priId,&nbsp;$field=&#39;*&#39;){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sql&nbsp;=&nbsp;&quot;SELECT&nbsp;%s&nbsp;FROM&nbsp;%s&nbsp;WHERE&nbsp;id=%d&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::getRow(sprintf($sql,&nbsp;self::parseField($field),&nbsp;$tabName,&nbsp;$priId));
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;执行普通查询
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$tables&nbsp;查询表名
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$where&nbsp;&nbsp;where
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$fields&nbsp;要查询字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$group&nbsp;&nbsp;group&nbsp;by
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$having&nbsp;having
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$order&nbsp;&nbsp;order
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$limit&nbsp;&nbsp;limit
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;array&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[description]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;find($tables,&nbsp;$where&nbsp;=&nbsp;null,&nbsp;$fields&nbsp;=&nbsp;&#39;*&#39;,&nbsp;$group&nbsp;=&nbsp;null,&nbsp;$having&nbsp;=&nbsp;null,&nbsp;$order&nbsp;=&nbsp;null,&nbsp;$limit&nbsp;=&nbsp;null){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sql&nbsp;=&nbsp;&#39;SELECT&nbsp;&#39;.self::parseField($fields).&#39;&nbsp;FROM&nbsp;&#39;.$tables
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.self::parseWhere($where)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.self::parseGroup($group)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.self::parseHaving($having)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.self::parseOrder($order)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.self::parseLimit($limit);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dataAll&nbsp;=&nbsp;self::getAll($sql);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;count($dataAll)==1&nbsp;?&nbsp;$dataAll[0]&nbsp;:&nbsp;$dataAll;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;添加记录的操作
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;array&nbsp;$data&nbsp;&nbsp;要添加的内容
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;int&nbsp;$table&nbsp;受影响的条数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;add($data,&nbsp;$table){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$keys&nbsp;=&nbsp;array_keys($data);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array_walk($keys,array(&#39;PDOMySQL&#39;,&#39;addSpecilChar&#39;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fieldsStr=join(&#39;,&#39;,$keys);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$values=&quot;&#39;&quot;.join(&quot;&#39;,&#39;&quot;,array_values($data)).&quot;&#39;&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sql&nbsp;=&nbsp;&quot;INSERT&nbsp;{$table}({$fieldsStr})&nbsp;VALUES({$values})&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::execute($sql);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;更新记录
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;array&nbsp;$data&nbsp;&nbsp;要更新内容
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$table&nbsp;表名
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$where&nbsp;条件
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$order&nbsp;排序
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$limit&nbsp;限制
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;受影响条数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;update($data,&nbsp;$table,&nbsp;$where&nbsp;=&nbsp;null,&nbsp;$order&nbsp;=&nbsp;null,&nbsp;$limit&nbsp;=&nbsp;null){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sets&nbsp;=&nbsp;&#39;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;($data&nbsp;as&nbsp;$key&nbsp;=&gt;&nbsp;$val)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sets&nbsp;.=&nbsp;$key.&quot;=&#39;&quot;.$val.&quot;&#39;,&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sets&nbsp;=&nbsp;rtrim($sets,&#39;,&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sql&nbsp;=&nbsp;&quot;UPDATE&nbsp;{$table}&nbsp;SET&nbsp;{$sets}&nbsp;&quot;.self::parseWhere($where).self::parseOrder($order).self::parseLimit($limit);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::execute($sql);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;解析字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$fields&nbsp;字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;解析后的字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;parseField($fields){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(is_array($fields)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array_walk($fields,&nbsp;array(&#39;PDOMySQL&#39;,&nbsp;&#39;addSpecilChar&#39;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fieldsStr&nbsp;=&nbsp;implode(&#39;,&#39;,$fields);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}elseif(is_string($fields)&nbsp;&amp;&amp;&nbsp;!empty($fields)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(strpos($fields,&nbsp;&#39;`&#39;)&nbsp;===&nbsp;false){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fields&nbsp;=&nbsp;explode(&#39;,&#39;,&nbsp;$fields);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array_walk($fields,&nbsp;array(&#39;PDOMySQL&#39;,&nbsp;&#39;addSpecilChar&#39;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fieldsStr&nbsp;=&nbsp;implode(&#39;,&#39;,$fields);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fieldsStr&nbsp;=&nbsp;$fields;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fieldsStr&nbsp;=&nbsp;&#39;*&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$fieldsStr;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;删除操作
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;&nbsp;$table&nbsp;表名
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;&nbsp;$where&nbsp;条件
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;&nbsp;$order&nbsp;排序
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;integer&nbsp;$limit&nbsp;限制
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;integer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;受影响条数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;delete($table,&nbsp;$where=null,&nbsp;$order=null,&nbsp;$limit=0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sql&nbsp;=&nbsp;&quot;DELETE&nbsp;FROM&nbsp;{$table}&nbsp;&quot;.self::parseWhere($where).self::parseOrder($order).self::parseLimit($limit);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::execute($sql);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;得到最后执行的sql语句
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;string&nbsp;sql语句
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;getLastSql(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$link=self::$link;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$link)&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::$queryStr;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;得到插入操作产生的AUTO_INCREMENT
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;int&nbsp;被操作id
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;getLastInsertId(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$link=self::$link;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$link)&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::$lastInsertId;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;得到数据库的版本
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;float&nbsp;数据库版本
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;getDbVersion(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$link=self::$link;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$link)&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::$dbVersion;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;得到数据库中的数据表
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;array&nbsp;所有数据表
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;showTbales(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$tables&nbsp;=&nbsp;[];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(self::query(&quot;SHOW&nbsp;TABLES&quot;)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$result&nbsp;=&nbsp;self::getAll();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;($result&nbsp;as&nbsp;$key&nbsp;=&gt;&nbsp;$value)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$tables[$key]=current($value);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$tables;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;解析where字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$where&nbsp;字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;解析后的字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;parseWhere($where){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$whereStr&nbsp;=&nbsp;&#39;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(is_string($where)&nbsp;&amp;&amp;&nbsp;!empty($where)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$whereStr&nbsp;=&nbsp;$where;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;empty($whereStr)&nbsp;?&nbsp;&#39;&#39;&nbsp;:&nbsp;&#39;&nbsp;WHERE&nbsp;&#39;.$whereStr;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;解析分组字段group&nbsp;by
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$group&nbsp;字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;解析后的字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;parseGroup($group){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$groupStr&nbsp;=&nbsp;&#39;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(is_array($group)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$groupStr&nbsp;.=&nbsp;&#39;&nbsp;GROUP&nbsp;BY&nbsp;&#39;.implode(&#39;,&#39;,&nbsp;$group);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}elseif(is_string($group)&nbsp;&amp;&amp;&nbsp;!empty($group)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$groupStr&nbsp;.=&nbsp;&#39;&nbsp;GROUP&nbsp;BY&nbsp;&#39;.$group;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;empty($groupStr)&nbsp;?&nbsp;&#39;&#39;&nbsp;:&nbsp;$groupStr;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;对分组进行二次筛选
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$having&nbsp;字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;解析后的字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;parseHaving($having){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$havingStr&nbsp;=&nbsp;&#39;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(is_string($having)&nbsp;&amp;&amp;&nbsp;!empty($having)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$havingStr&nbsp;=&nbsp;&#39;&nbsp;HAVING&nbsp;&#39;.$having;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$havingStr;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;解析order&nbsp;by
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$order&nbsp;字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;解析后的字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;parseOrder($order){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$orderStr&nbsp;=&nbsp;&#39;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(is_array($order)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$orderStr&nbsp;.=&nbsp;&#39;&nbsp;ORDER&nbsp;BY&nbsp;&#39;.join(&#39;,&#39;,$order);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}elseif(is_string($order)&nbsp;&amp;&amp;&nbsp;!empty($order)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$orderStr&nbsp;.=&nbsp;&#39;&nbsp;ORDER&nbsp;BY&nbsp;&#39;.$order;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$orderStr;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;解析limit
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;strign&nbsp;$limit&nbsp;字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;strign&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;解析后的字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;parseLimit($limit){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$limitStr&nbsp;=&nbsp;&#39;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(is_array($limit)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(count($limit)&nbsp;&gt;&nbsp;1){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$limitStr&nbsp;=&nbsp;&#39;&nbsp;LIMIT&nbsp;&#39;.$limit[0].&#39;,&#39;.$limit[1];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$limitStr&nbsp;=&nbsp;&#39;&nbsp;LIMIT&nbsp;&#39;.$limit[0];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}elseif(!empty($limit)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$limitStr&nbsp;.=&nbsp;&#39;&nbsp;LIMIT&nbsp;&#39;.$limit;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$limitStr;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;通过反引号引用字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;string&nbsp;&amp;$value&nbsp;不同类型字段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;addSpecilChar(&amp;$value){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($value&nbsp;===&nbsp;&#39;*&#39;&nbsp;||&nbsp;strpos($value,&nbsp;&#39;.&#39;)&nbsp;!=&nbsp;false&nbsp;||&nbsp;strpos($value,&nbsp;&#39;`&#39;)&nbsp;!=&nbsp;false){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;不做处理
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}elseif(strpos($value,&nbsp;&#39;`&#39;)&nbsp;===&nbsp;false){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$value&nbsp;=&nbsp;&#39;`&#39;.trim($value).&#39;`&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$value;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;执行增删改操作，返回受影响的记录条数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$sql&nbsp;sql语句
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;受影响条数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;execute($sql&nbsp;=&nbsp;null){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$link&nbsp;=&nbsp;self::$link;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$link)&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$queryStr&nbsp;=&nbsp;$sql;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!empty(self::$PDOStatement))&nbsp;self::free();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$result&nbsp;=&nbsp;$link-&gt;exec(self::$queryStr);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::haveErrorThrowException();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($result){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$lastInsertId&nbsp;=&nbsp;$link-&gt;lastInsertId();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$numRows&nbsp;=&nbsp;$result;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::$numRows;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;释放结果集
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;null&nbsp;null
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;free(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$PDOStatement&nbsp;=&nbsp;null;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;query($sql&nbsp;=&nbsp;&#39;&#39;){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$link&nbsp;=&nbsp;self::$link;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$link)&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;判断之前是否有结果集，如果有，释放结果集
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!empty(self::$PDOStatement))&nbsp;self::free();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$queryStr&nbsp;=&nbsp;$sql;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$PDOStatement&nbsp;=&nbsp;$link-&gt;prepare(self::$queryStr);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$res&nbsp;=&nbsp;self::$PDOStatement-&gt;execute();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::haveErrorThrowException();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$res;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;haveErrorThrowException(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$obj&nbsp;=&nbsp;empty(self::$PDOStatement)&nbsp;?&nbsp;self::$link&nbsp;:&nbsp;self::$PDOStatement;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$arrError&nbsp;=&nbsp;$obj-&gt;errorInfo();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($arrError[0]&nbsp;!=&nbsp;&#39;00000&#39;){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$error&nbsp;=&nbsp;&#39;SQLStatus:&nbsp;&#39;.$arrError[0].&#39;&lt;br&nbsp;/&gt;SQLError:&nbsp;&#39;.$arrError[2].&#39;&lt;br&nbsp;/&gt;Error&nbsp;SQL:&nbsp;&#39;.self::$queryStr;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::throw_exception(self::$error);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(self::$queryStr&nbsp;==&nbsp;&#39;&#39;){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::throw_exception(&#39;没有执行的SQL语句&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;自定义错误处理
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;string&nbsp;$errMsg&nbsp;错误信息
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;null&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;null
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;throw_exception($errMsg){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$errMsg;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;销毁连接对象，关闭数据库
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;null&nbsp;null
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;close(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$link&nbsp;=&nbsp;null;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>在场景中这样来使用，注释后的内容分别用来测试不同方法：</p><blockquote><p>index.php<br/></p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

$PDOMySQL&nbsp;=&nbsp;new&nbsp;PDOMySQL();

//&nbsp;查询全部记录
$sql&nbsp;=&nbsp;&#39;SELECT&nbsp;*&nbsp;FROM&nbsp;cheat_exam&#39;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;getAll($sql);

//&nbsp;查询一条记录
$sql&nbsp;=&nbsp;&#39;SELECT&nbsp;*&nbsp;FROM&nbsp;cheat_exam&nbsp;WHERE&nbsp;id=1&#39;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;getRow($sql);

//&nbsp;插入一条记录
$sql&nbsp;=&nbsp;&#39;INSERT&nbsp;cheat_exam(name)&nbsp;VALUES&nbsp;(1)&#39;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;execute($sql);
echo&nbsp;$PDOMySQL::$lastInsertId;

//&nbsp;删除一条记录
$sql&nbsp;=&nbsp;&#39;DELETE&nbsp;FROM&nbsp;cheat_exam&nbsp;WHERE&nbsp;id=115&#39;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;execute($sql);

//&nbsp;更新一条记录
$sql&nbsp;=&nbsp;&#39;UPDATE&nbsp;arr&nbsp;SET&nbsp;name=&quot;1&quot;&nbsp;WHERE&nbsp;id=1&#39;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;execute($sql);

//&nbsp;根据主键查询一条记录
$tabName&nbsp;=&nbsp;&#39;cheat_exam&#39;;
$priId&nbsp;=&nbsp;1;
$fields=&#39;subject,name&#39;;
$fields&nbsp;=&nbsp;array(&#39;subject&#39;,&#39;name&#39;);
$res&nbsp;=&nbsp;$PDOMySQL-&gt;findById($tabName,&nbsp;$priId,&nbsp;$fields);

//&nbsp;执行普通查询
$tables&nbsp;=&nbsp;&#39;cheat_exam&#39;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;find($tables);
$res&nbsp;=&nbsp;$PDOMySQL-&gt;find($tables,&nbsp;&#39;id&gt;=30&#39;);
$res&nbsp;=&nbsp;$PDOMySQL-&gt;find($tables,&nbsp;&#39;id&gt;=30&#39;,&nbsp;&#39;subject,name&#39;);
$res&nbsp;=&nbsp;$PDOMySQL-&gt;find($tables,&nbsp;&#39;id&gt;=30&#39;,&nbsp;&#39;*&#39;,&nbsp;&#39;subject&#39;);
$res&nbsp;=&nbsp;$PDOMySQL-&gt;find($tables,&nbsp;&#39;id&gt;=30&#39;,&nbsp;&#39;*&#39;,&nbsp;&#39;subject&#39;,&nbsp;&#39;count(*)&gt;=8&#39;);
$res&nbsp;=&nbsp;$PDOMySQL-&gt;find($tables,&nbsp;&#39;id&gt;=30&#39;,&nbsp;&#39;*&#39;,&nbsp;&#39;&#39;,&nbsp;&#39;&#39;,&nbsp;&#39;id&nbsp;desc&#39;);
$res&nbsp;=&nbsp;$PDOMySQL-&gt;find($tables,&nbsp;&#39;id&gt;=30&#39;,&nbsp;&#39;*&#39;,&nbsp;&#39;&#39;,&nbsp;&#39;&#39;,&nbsp;&#39;id&nbsp;desc&#39;,&nbsp;5);

//&nbsp;更新一条记录
$data&nbsp;=&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;&#39;subject&#39;&nbsp;=&gt;&nbsp;&#39;imooc&#39;,
&nbsp;&nbsp;&nbsp;&nbsp;&#39;name&#39;&nbsp;=&gt;&nbsp;&#39;name&#39;
&nbsp;&nbsp;&nbsp;&nbsp;];
$table&nbsp;=&nbsp;&quot;cheat_exam&quot;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;add($data,&nbsp;$table);
//&nbsp;也是更新操作
$data&nbsp;=&nbsp;[
&nbsp;&nbsp;&nbsp;&nbsp;&#39;subject&#39;&nbsp;=&gt;&nbsp;&#39;imooc&#39;,
&nbsp;&nbsp;&nbsp;&nbsp;&#39;name&#39;&nbsp;=&gt;&nbsp;&#39;name&#39;
&nbsp;&nbsp;&nbsp;&nbsp;];
$table&nbsp;=&nbsp;&quot;cheat_exam&quot;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;update($data,&nbsp;$table,&nbsp;&#39;id&lt;=3&#39;,&nbsp;&#39;id&nbsp;desc&#39;,&nbsp;5);

//&nbsp;删除操作
$table&nbsp;=&nbsp;&quot;cheat_exam&quot;;
$res&nbsp;=&nbsp;$PDOMySQL-&gt;delete($table,&nbsp;&#39;id&lt;3&#39;);

//&nbsp;得到数据表
$res&nbsp;=&nbsp;$PDOMySQL-&gt;showTbales();

print_r($res);</pre><p>会打印出不同结果。<br/></p><p>The End.</p>]]></content>
  </entry>
  <entry>
    <title>PHP-GTK初体验：用最简单的方式运行环境，并实现Hello World</title>
    <link href="https://old-blog.smallyu.net/index084d.html?id=46"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=46</id>
    <published>2017-02-21T16:00:00.000Z</published>
    <updated>2017-02-21T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>首先用最简单的方式把php-gtk运行起来，在gtk扩展官网（ http://gtk.php.net/ ）下载Binaries版本： 点击链接直接下载： http://gtk.php.net/distributions/PHP55-GTK2.zip （PHP-GTK-2.0.1 PHP 5.5） 官方文档提供了三种安装扩展的方式， 使用Gnope 手动安装...</p>]]></summary>
    <content type="html"><![CDATA[<p>首先用最简单的方式把php-gtk运行起来，在gtk扩展官网（<a href="http://gtk.php.net/" _src="http://gtk.php.net/">http://gtk.php.net/</a>&nbsp;）下载Binaries版本：</p><p>点击链接直接下载：<a href="http://gtk.php.net/distributions/PHP55-GTK2.zip" _src="http://gtk.php.net/distributions/PHP55-GTK2.zip">http://gtk.php.net/distributions/PHP55-GTK2.zip</a>&nbsp;（PHP-GTK-2.0.1 PHP 5.5）</p><p>官方文档提供了三种安装扩展的方式，<br/></p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>使用Gnope</p></li><li><p>手动安装</p></li><li><p>使用CVS编译</p></li></ol><p>事实上我们在下载.zip压缩包后解压到任意文件夹下，不需要任何配置或者编译行为。（如果只是先体验一下GTK实现的GUI窗口）</p><p><span style="font-size: 14px;"><strong>一段简单的Hello World脚本</strong></span></p><p>在任意目录下新建一个文件，后缀名为.phpw，比如hello.phpw，编辑文件，写入以下代码：</p><pre class="prism-highlight prism-language-php">&lt;?php
if&nbsp;(!class_exists(&#39;gtk&#39;))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;die(&quot;Please&nbsp;load&nbsp;the&nbsp;php-gtk2&nbsp;module&nbsp;in&nbsp;your&nbsp;php.ini\r\n&quot;);
}

$wnd&nbsp;=&nbsp;new&nbsp;GtkWindow();
$wnd-&gt;set_title(&#39;Hello&nbsp;world&#39;);
$wnd-&gt;connect_simple(&#39;destroy&#39;,&nbsp;array(&#39;gtk&#39;,&nbsp;&#39;main_quit&#39;));

$lblHello&nbsp;=&nbsp;new&nbsp;GtkLabel(&quot;Just&nbsp;wanted&nbsp;to&nbsp;say\r\n&#39;Hello&nbsp;world!&#39;&quot;);
$wnd-&gt;add($lblHello);

$wnd-&gt;show_all();
Gtk::main();
?&gt;</pre><p>保存后，<span style="text-decoration: underline;">右击文件&gt;选择打开方式&gt;其它应用&gt;在这台电脑上浏览应用</span><span style="text-decoration: none;">，选择我们下载并解压好的文件夹下的php-win.exe来执行文件</span>，</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702221487764340907853.png" title="14.png" alt="14.png"/></p><p>就可以得到这样的运行结果：<br/></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702221487764357819986.png" title="2.png" alt="2.png"/></p><p><span style="font-size: 14px;"><strong>检查PHP-GTK是否可用</strong></span></p><pre class="prism-highlight prism-language-php">if&nbsp;(!class_exists(&#39;gtk&#39;))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;die(&quot;Please&nbsp;load&nbsp;the&nbsp;php-gtk2&nbsp;module&nbsp;in&nbsp;your&nbsp;php.ini\r\n&quot;);
}</pre><p><span style="font-size: 14px;">这里我们通过检查gtk类是否存在来确定PHP-GTK是否可用。不像PHP 4和PHP-GTK 1，你不应该通过d1()尝试加载PHP-GTK模块，因为这在PHP 5中是过时的，不应该用于新代码的编写。所以我们打印一个信息，如果模块不可用，就由用户来启用它。</span></p><p><span style="font-size: 14px;"><strong>创建一个窗口</strong></span></p><pre class="prism-highlight prism-language-php">$wnd&nbsp;=&nbsp;new&nbsp;GtkWindow();</pre><p>创建一个窗口就像实例化一个新的对象一样简单：变量$wnd得到了新对象的引用。如果你已经使用PHP 4和PHP-GTK 1，你可以在关键词new之前不使用&amp;符号，因为在PHP 5中它会被自动创建。</p><p><span style="font-size: 14px;"><strong>设置窗口标题</strong></span></p><pre class="prism-highlight prism-language-php">$wnd-&gt;set_title(&#39;Hello&nbsp;world&#39;);</pre><p>为了使窗口在任务栏中更容易被认出，我们设置了标题，仅仅调用了对象的一个方法。</p><p><span style="font-size: 14px;"><strong>使关闭（操作）变得干净</strong></span></p><pre class="prism-highlight prism-language-php">$wnd-&gt;connect_simple(&#39;destroy&#39;,&nbsp;array(&#39;gtk&#39;,&nbsp;&#39;main_quit&#39;));</pre><p>这是代码中第一段稍有意思的部分：参数&#39;destory&#39;传递到了静态方法Gtk::main_quit中。它告诉GTK当窗口被关闭或者销毁的时候退出主循环。（后面会提到关于主循环的内容）</p><p><strong>创建一个展示文本的标签</strong><br/></p><pre class="prism-highlight prism-language-php">$lblHello&nbsp;=&nbsp;new&nbsp;GtkLabel(&quot;Just&nbsp;wanted&nbsp;to&nbsp;say\r\n&#39;Hello&nbsp;world!&#39;&quot;);</pre><p>和上面一样，我们创建了一个新的部件。这次我们想要展示一小段文本，GtkLabel类可以完美的实现这个任务。</p><p><strong>添加标签到窗口</strong></p><pre class="prism-highlight prism-language-php">$wnd-&gt;add($lblHello);</pre><p>我们直接把标签添加到了窗口。<br/></p><p><strong>设置窗口为可见的</strong></p><pre class="prism-highlight prism-language-php">$wnd-&gt;show_all();</pre><p>到现在，我们在屏幕上看不见任何内容。为了使窗口可见，必须调用show()方法，它将会使窗口可见，但不是标签——我们在标签之上（也就是窗口对象上）调用show()。如果你有多个控件比如按钮、复选框或者其它窗口部件不方便一一调用，可以使用show_all()方法来显示所有可见的部件。</p><p><strong>开启主循环</strong></p><pre class="prism-highlight prism-language-php">Gtk::main();</pre><p>在设置完所有配置项之后，我们需要确定窗口停留在打开状态并且会对用户的行为进行反馈。一段普通的PHP脚本在文件执行结束后会停止，因此需要启动GTK主循环。它会保持应用处于运行状态并且会回应用户事件。如果事件发生，它会执行相应的回调。</p><p>（原内容：<a href="http://gtk.php.net/manual/en/html/tutorials/tutorials.helloworld.html" _src="http://gtk.php.net/manual/en/html/tutorials/tutorials.helloworld.html">http://gtk.php.net/manual/en/html/tutorials/tutorials.helloworld.html</a>&nbsp;）<br/></p><p><br/></p><p><strong>更加先进的Hello World脚本</strong></p><p>下面的参考内容会比上面的hello world脚本实现更多的功能。这里我们创建了一个登陆框，可以由用户来输入用户名和密码。当用户点击登陆，如果用户名或者密码为空，文本域可以检查错误并显示。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702221487764374675166.png" title="helloadvanced.png" alt="helloadvanced.png"/></p><p>首先我们先创建一个窗口，设置标题并设置当窗口销毁停止主循环（上面已经实现过）：<br/></p><pre class="prism-highlight prism-language-php">$wnd&nbsp;=&nbsp;new&nbsp;GtkWindow();
$wnd-&gt;set_title(&#39;Login&#39;);
$wnd-&gt;connect_simple(&#39;destroy&#39;,&nbsp;array(&#39;gtk&#39;,&nbsp;&#39;main_quit&#39;));</pre><p>接下来我们的任务是创建所有要显示的部件，先是两个文本域用户名和密码：</p><pre class="prism-highlight prism-language-php">$txtUsername&nbsp;=&nbsp;new&nbsp;GtkEntry();
$txtPassword&nbsp;=&nbsp;new&nbsp;GtkEntry();</pre><p>我们要分别给两个文本域一个描述的标签：</p><pre class="prism-highlight prism-language-php">//&nbsp;第二个参数意思是把下划线解析为下划线
$lblUsername&nbsp;=&nbsp;new&nbsp;GtkLabel(&#39;_Username&#39;,&nbsp;true);
$lblPassword&nbsp;=&nbsp;new&nbsp;GtkLabel(&#39;_Password&#39;,&nbsp;true);</pre><p>最后我们需要两个按钮，登录和取消：<br/></p><pre class="prism-highlight prism-language-php">$btnLogin&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;new&nbsp;GtkButton(&#39;_Login&#39;);
$btnCancel&nbsp;&nbsp;&nbsp;=&nbsp;new&nbsp;GtkButton(&#39;_Cancel&#39;);</pre><p>你可能注意到GtkLable类的构造函数中通过第二个参数设置解析下划线_为一个字符，但是GtkButton类中并没有，因为它会自动设置，这一点是需要记忆的。<br/></p><p>现在标签需要知道哪个行为被激活时使用哪个相应的内容，这样来做：</p><pre class="prism-highlight prism-language-php">$lblUsername-&gt;set_mnemonic_widget($txtUsername);
$lblPassword-&gt;set_mnemonic_widget($txtPassword);</pre><p>然后我们要决定哪个按钮被点击对应哪个事件。取消按钮会关闭窗口，结束程序，登录按钮会检查文本域是否为空等一系列操作：</p><pre class="prism-highlight prism-language-php">$btnCancel-&gt;connect_simple(&#39;clicked&#39;,&nbsp;array($wnd,&nbsp;&#39;destroy&#39;));
$btnLogin&nbsp;-&gt;connect_simple(&#39;clicked&#39;,&nbsp;&#39;login&#39;,&nbsp;$wnd,&nbsp;$txtUsername,&nbsp;$txtPassword);</pre><p>我们把三个参数$wnd、$txtUsername和$txtPassword传递给了登录函数，接下来的操作会用它们从文本域获取值，并且在所有工作结束后关闭窗口。</p><p>现在我们创建了我们需要的所有按钮，它们被添加到了窗口。GtkWindow库是功能容器，它可以捆绑为一个单独的部件，所以我们需要这个容器来更好的展示我们的其它元素。这里决定使用GtkTabel，它可以保持标签在一列，紧随其后的是确定域：<br/></p><pre class="prism-highlight prism-language-php">$tbl&nbsp;=&nbsp;new&nbsp;GtkTable(3,&nbsp;2);
$tbl-&gt;attach($lblCredit,&nbsp;0,&nbsp;2,&nbsp;0,&nbsp;1);
$tbl-&gt;attach($lblUsername,&nbsp;0,&nbsp;1,&nbsp;1,&nbsp;2);
$tbl-&gt;attach($txtUsername,&nbsp;1,&nbsp;2,&nbsp;1,&nbsp;2);
$tbl-&gt;attach($lblPassword,&nbsp;0,&nbsp;1,&nbsp;2,&nbsp;3);
$tbl-&gt;attach($txtPassword,&nbsp;1,&nbsp;2,&nbsp;2,&nbsp;3);</pre><p>（$lblCredit仅仅是一个消息标签），按钮有它们自己的GtkHButtonBox类，因为这个允许它们更美观的布局多个按钮：</p><pre class="prism-highlight prism-language-php">$bbox&nbsp;=&nbsp;new&nbsp;GtkHButtonBox();
$bbox-&gt;set_layout(Gtk::BUTTONBOX_EDGE);
$bbox-&gt;add($btnCancel);
$bbox-&gt;add($btnLogin);</pre><p>对于布局最后要做的事情是把表格和按钮添加到窗口。没有直接的方法，因为GtkWindow是一个GtkBin（类库？），只能包含一个部件。所以我们需要另外的容器，这次用GtkVBox：<br/></p><pre class="prism-highlight prism-language-php">$vbox&nbsp;=&nbsp;new&nbsp;GtkVBox();
$vbox-&gt;pack_start($tbl);
$vbox-&gt;pack_start($bbox);</pre><p>它们所有都需要显示：</p><pre class="prism-highlight prism-language-php">$wnd-&gt;add($vbox);
$wnd-&gt;show_all();
Gtk::main();</pre><p>最后要做的事情，是当用户点击登陆按钮时候的回调事件。它需要检查用户名和密码是否为空，如果它们长度为0，则显示错误信息。如果一切ok，窗口将会关闭并且程序会继续运行来加载主窗口。<br/></p><p>从部件获取文本很简单，我们用GtkEntry的get_text()方法就能实现：</p><pre class="prism-highlight prism-language-php">$strUsername&nbsp;=&nbsp;$txtUsername-&gt;get_text();
$strPassword&nbsp;=&nbsp;$txtPassword-&gt;get_text();</pre><p>检查工作可以用平常的php函数。如果发生错误就显示一个带有错误消息的信息。GtkMessageDialog来完成这些工作是理想的，它可以自动创建图标和按钮（确认，是或否）：<br/></p><pre class="prism-highlight prism-language-php">$dialog&nbsp;=&nbsp;new&nbsp;GtkMessageDialog($wnd,&nbsp;Gtk::DIALOG_MODAL,&nbsp;Gtk::MESSAGE_ERROR,&nbsp;Gtk::BUTTONS_OK,&nbsp;$errors);
$dialog-&gt;set_markup(&quot;The&nbsp;following&nbsp;errors&nbsp;occured:\r\n&lt;span&nbsp;foreground=&#39;red&#39;&gt;&quot;&nbsp;.&nbsp;$errors&nbsp;.&nbsp;&quot;&lt;/span&gt;&quot;);
$dialog-&gt;run();
$dialog-&gt;destroy();</pre><p>现在可以确定你把登录功能函数放到了主循环中并使其运行。<br/></p><p><strong>完整代码</strong><br/></p><pre class="prism-highlight prism-language-php">&lt;?php
/**
*&nbsp;&nbsp;&nbsp;Here&nbsp;we&nbsp;create&nbsp;a&nbsp;login&nbsp;window.
*&nbsp;&nbsp;&nbsp;It&nbsp;has&nbsp;a&nbsp;username&nbsp;and&nbsp;a&nbsp;password&nbsp;field,&nbsp;and&nbsp;a
*&nbsp;&nbsp;&nbsp;Cancel&nbsp;and&nbsp;Login&nbsp;button.&nbsp;Some&nbsp;error&nbsp;checking
*&nbsp;&nbsp;&nbsp;is&nbsp;being&nbsp;done&nbsp;when&nbsp;the&nbsp;user&nbsp;clicks&nbsp;&quot;Login&quot;.
*/

if&nbsp;(!class_exists(&#39;gtk&#39;))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;die(&quot;Please&nbsp;load&nbsp;the&nbsp;php-gtk2&nbsp;module&nbsp;in&nbsp;your&nbsp;php.ini\r\n&quot;);
}

/**
*&nbsp;&nbsp;&nbsp;This&nbsp;function&nbsp;gets&nbsp;called&nbsp;as&nbsp;soon&nbsp;as&nbsp;the&nbsp;user&nbsp;
*&nbsp;&nbsp;&nbsp;clicks&nbsp;on&nbsp;the&nbsp;Login&nbsp;button.
*
*&nbsp;&nbsp;&nbsp;@param&nbsp;GtkWindow&nbsp;$wnd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The&nbsp;login&nbsp;window,&nbsp;needed&nbsp;to&nbsp;close&nbsp;it
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when&nbsp;all&nbsp;is&nbsp;ok
*&nbsp;&nbsp;&nbsp;@param&nbsp;GtkEntry&nbsp;$txtUsername&nbsp;&nbsp;&nbsp;&nbsp;The&nbsp;username&nbsp;text&nbsp;field,&nbsp;used&nbsp;to&nbsp;get
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;username
*&nbsp;&nbsp;&nbsp;@param&nbsp;GtkEntry&nbsp;$txtPassword&nbsp;&nbsp;&nbsp;&nbsp;The&nbsp;password&nbsp;widget&nbsp;to&nbsp;retrieve&nbsp;the
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password
*/
function&nbsp;login(GtkWindow&nbsp;$wnd,&nbsp;GtkEntry&nbsp;$txtUsername,&nbsp;GtkEntry&nbsp;$txtPassword)
{
&nbsp;&nbsp;&nbsp;&nbsp;//fetch&nbsp;the&nbsp;values&nbsp;from&nbsp;the&nbsp;widgets&nbsp;into&nbsp;variables
&nbsp;&nbsp;&nbsp;&nbsp;$strUsername&nbsp;=&nbsp;$txtUsername-&gt;get_text();
&nbsp;&nbsp;&nbsp;&nbsp;$strPassword&nbsp;=&nbsp;$txtPassword-&gt;get_text();

&nbsp;&nbsp;&nbsp;&nbsp;//Do&nbsp;some&nbsp;error&nbsp;checking
&nbsp;&nbsp;&nbsp;&nbsp;$errors&nbsp;=&nbsp;null;
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(strlen($strUsername)&nbsp;==&nbsp;0)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$errors&nbsp;.=&nbsp;&quot;Username&nbsp;is&nbsp;missing.\r\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(strlen($strPassword)&nbsp;==&nbsp;0)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$errors&nbsp;.=&nbsp;&quot;No&nbsp;password&nbsp;given.\r\n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;($errors&nbsp;!==&nbsp;null)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//There&nbsp;was&nbsp;at&nbsp;least&nbsp;one&nbsp;error.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//We&nbsp;show&nbsp;a&nbsp;message&nbsp;box&nbsp;with&nbsp;the&nbsp;errors
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dialog&nbsp;=&nbsp;new&nbsp;GtkMessageDialog($wnd,&nbsp;Gtk::DIALOG_MODAL,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gtk::MESSAGE_ERROR,&nbsp;Gtk::BUTTONS_OK,&nbsp;$errors);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dialog-&gt;set_markup(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;following&nbsp;errors&nbsp;occured:\r\n&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.&nbsp;&quot;&lt;span&nbsp;foreground=&#39;red&#39;&gt;&quot;&nbsp;.&nbsp;$errors&nbsp;.&nbsp;&quot;&lt;/span&gt;&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dialog-&gt;run();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dialog-&gt;destroy();
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//No&nbsp;error.&nbsp;You&nbsp;would&nbsp;need&nbsp;to&nbsp;hide&nbsp;the&nbsp;dialog&nbsp;now
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//instead&nbsp;of&nbsp;destroying&nbsp;it&nbsp;(because&nbsp;when&nbsp;you&nbsp;destroy&nbsp;it,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Gtk::main_quit()&nbsp;gets&nbsp;called)&nbsp;and&nbsp;show&nbsp;the&nbsp;main&nbsp;window
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$wnd-&gt;destroy();
&nbsp;&nbsp;&nbsp;&nbsp;}
}

//Create&nbsp;the&nbsp;login&nbsp;window
$wnd&nbsp;=&nbsp;new&nbsp;GtkWindow();
$wnd-&gt;set_title(&#39;Login&#39;);
//Close&nbsp;the&nbsp;main&nbsp;loop&nbsp;when&nbsp;the&nbsp;window&nbsp;is&nbsp;destroyed
$wnd-&gt;connect_simple(&#39;destroy&#39;,&nbsp;array(&#39;gtk&#39;,&nbsp;&#39;main_quit&#39;));


//Set&nbsp;up&nbsp;all&nbsp;the&nbsp;widgets&nbsp;we&nbsp;need
$lblCredit&nbsp;&nbsp;&nbsp;=&nbsp;new&nbsp;GtkLabel(&#39;Please&nbsp;provide&nbsp;your&nbsp;data&#39;);
//The&nbsp;second&nbsp;parameter&nbsp;says&nbsp;that&nbsp;the&nbsp;underscore&nbsp;should&nbsp;be&nbsp;parsed&nbsp;as&nbsp;underline
$lblUsername&nbsp;=&nbsp;new&nbsp;GtkLabel(&#39;_Username&#39;,&nbsp;true);
$lblPassword&nbsp;=&nbsp;new&nbsp;GtkLabel(&#39;_Password&#39;,&nbsp;true);
$txtUsername&nbsp;=&nbsp;new&nbsp;GtkEntry();
$txtPassword&nbsp;=&nbsp;new&nbsp;GtkEntry();
$btnLogin&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;new&nbsp;GtkButton(&#39;_Login&#39;);
$btnCancel&nbsp;&nbsp;&nbsp;=&nbsp;new&nbsp;GtkButton(&#39;_Cancel&#39;);


//Which&nbsp;widget&nbsp;should&nbsp;be&nbsp;activated&nbsp;when&nbsp;the&nbsp;
//&nbsp;mnemonic&nbsp;(Alt+U&nbsp;or&nbsp;Alt+P)&nbsp;is&nbsp;pressed?
$lblUsername-&gt;set_mnemonic_widget($txtUsername);
$lblPassword-&gt;set_mnemonic_widget($txtPassword);
//Hide&nbsp;the&nbsp;password
//$txtPassword-&gt;set_invisible_char(&#39;*&#39;);

//Destroy&nbsp;the&nbsp;window&nbsp;when&nbsp;the&nbsp;user&nbsp;clicks&nbsp;Cancel
$btnCancel-&gt;connect_simple(&#39;clicked&#39;,&nbsp;array($wnd,&nbsp;&#39;destroy&#39;));
//Call&nbsp;the&nbsp;login&nbsp;function&nbsp;when&nbsp;the&nbsp;user&nbsp;clicks&nbsp;on&nbsp;Login
$btnLogin-&gt;connect_simple(&#39;clicked&#39;,&nbsp;&#39;login&#39;,&nbsp;$wnd,&nbsp;$txtUsername,&nbsp;$txtPassword);


//Lay&nbsp;out&nbsp;all&nbsp;the&nbsp;widgets&nbsp;in&nbsp;the&nbsp;table
$tbl&nbsp;=&nbsp;new&nbsp;GtkTable(3,&nbsp;2);
$tbl-&gt;attach($lblCredit,&nbsp;0,&nbsp;2,&nbsp;0,&nbsp;1);
$tbl-&gt;attach($lblUsername,&nbsp;0,&nbsp;1,&nbsp;1,&nbsp;2);
$tbl-&gt;attach($txtUsername,&nbsp;1,&nbsp;2,&nbsp;1,&nbsp;2);
$tbl-&gt;attach($lblPassword,&nbsp;0,&nbsp;1,&nbsp;2,&nbsp;3);
$tbl-&gt;attach($txtPassword,&nbsp;1,&nbsp;2,&nbsp;2,&nbsp;3);


//Add&nbsp;the&nbsp;buttons&nbsp;to&nbsp;a&nbsp;button&nbsp;box
$bbox&nbsp;=&nbsp;new&nbsp;GtkHButtonBox();
$bbox-&gt;set_layout(Gtk::BUTTONBOX_EDGE);
$bbox-&gt;add($btnCancel);
$bbox-&gt;add($btnLogin);


//Add&nbsp;the&nbsp;table&nbsp;and&nbsp;the&nbsp;button&nbsp;box&nbsp;to&nbsp;a&nbsp;vbox
$vbox&nbsp;=&nbsp;new&nbsp;GtkVBox();
$vbox-&gt;pack_start($tbl);
$vbox-&gt;pack_start($bbox);

//Add&nbsp;the&nbsp;vbox&nbsp;to&nbsp;the&nbsp;window
$wnd-&gt;add($vbox);
//Show&nbsp;all&nbsp;widgets
$wnd-&gt;show_all();
//Start&nbsp;the&nbsp;main&nbsp;loop
Gtk::main();
?&gt;</pre><p>（原内容：<a href="http://gtk.php.net/manual/en/html/tutorials/tutorials.helloadvanced.html" _src="http://gtk.php.net/manual/en/html/tutorials/tutorials.helloadvanced.html">http://gtk.php.net/manual/en/html/tutorials/tutorials.helloadvanced.html</a>）</p><p>The End.<br/></p>]]></content>
  </entry>
  <entry>
    <title>PHP写简单爬虫抓取太工教务处通告中的，考试作弊学生名单</title>
    <link href="https://old-blog.smallyu.net/index98dc.html?id=45"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=45</id>
    <published>2017-02-18T16:00:00.000Z</published>
    <updated>2017-02-18T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>目标是太原工业学院（tit）教务处（ http://jwc.tit.edu.cn ） 通告栏信息中考试作弊学生的名单。 过程中涉及到的内容有： curl获取页面内容 正则表达式匹配目标内容 相关字符串处理函数整理数据 mysql数据库基本操作 首先打开教务处最新一条考试作弊通告，查看页面源代码，内容类似于： 可以获取到两个信息： 通告地址为： http://...</p>]]></summary>
    <content type="html"><![CDATA[<p>目标是太原工业学院（tit）教务处（<a href="https://jwc.tit.edu.cn/">http://jwc.tit.edu.cn</a>）&nbsp;通告栏信息中考试作弊学生的名单。</p><p>过程中涉及到的内容有：</p><ul class=" list-paddingleft-2" style="list-style-type: disc;"><li><p>curl获取页面内容</p></li><li><p>正则表达式匹配目标内容</p></li><li><p>相关字符串处理函数整理数据</p></li><li><p>mysql数据库基本操作</p></li></ul><p>首先打开教务处最新一条考试作弊通告，查看页面源代码，内容类似于：</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702191487511072510789.png" title="1.png" alt="1.png" width="705" height="299" style="width: 705px; height: 299px;"/></p><p>可以获取到两个信息：</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>通告地址为：<a href="http://jwc.tit.edu.cn/info/news/content/3013.htm">http://jwc.tit.edu.cn/info/news/content/3013.htm</a>&nbsp;，有很明显的规律</p></li><li><p>页面内容太乱了。</p></li></ol><p>因为页面链接太有规律，我们可以用简单粗暴的方式来循环爬取各个页面，而不用分析页面中的链接然后执行另外的curl请求。</p><p>第二个信息是页面内容比较乱，主要是太多html标签+样式覆盖了内容。（吐槽一下教务处系统的开发者？）可以在得到页面内容后先过滤掉每个标签。</p><p>接下来开始写代码了。<br/></p><p>一、curl请求一共需要四个步骤：</p><blockquote><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>初始化会话请求</p></li><li><p>设置请求选项，包括具体的url</p></li><li><p>执行一个curl会话并且获得相关回复</p></li><li><p>释放curl句柄，关闭一个curl会话<br/></p></li></ol></blockquote><p>涉及到的四个函数分别为：</p><pre class="prism-highlight prism-language-php">curl_init();
curl_setopt();
curl_exec();
curl_close();</pre><p>略过一些内容后就可以拿到以字符串形式返回的包含页面内容的变量$response。<br/></p><p>二、然后写正则表达式结合一些函数来分离出所需信息，涉及到的函数有：<br/></p><pre class="prism-highlight prism-language-php">preg_replace();</pre><p>好像就这一个，功能很强大。关于正则表达式可以用这个在线工具：<a href="http://regexpal.isbadguy.com/" _src="http://regexpal.isbadguy.com/">http://regexpal.isbadguy.com/</a> </p><p>三、再然后整理数据，也就使用这个函数：</p><pre class="prism-highlight prism-language-php">substr();</pre><p>以数组形式返回整齐的数据。</p><p>四、最后就要把数据储存到mysql，表的结构是：（资源小浪费）</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702201487567639455976.png" title="搜狗截图20170220130805.png" alt="搜狗截图20170220130805.png"/></p><p>基本步骤之后可以拿到包含一个页面所需数据的数组。最终执行需要重复执行这些基本步骤很多（3013）次。</p><p>过程中用ob缓存来实时输出内容反馈到浏览器：<br/></p><pre class="prism-highlight prism-language-php">ob_flush();
flush();</pre><p><strong>完整代码</strong><br/></p><pre class="prism-highlight prism-language-php">&lt;?php

set_time_limit(0);&nbsp;&nbsp;//&nbsp;设置PHP最长执行时间

$times&nbsp;=&nbsp;3013;
while($times&nbsp;&gt;&nbsp;0){
&nbsp;&nbsp;&nbsp;&nbsp;$url&nbsp;=&nbsp;&quot;http://jwc.tit.edu.cn/info/news/content/&quot;.$times.&quot;.htm&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$url.&quot;&lt;br&nbsp;/&gt;&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;$res&nbsp;=&nbsp;curl($url);
&nbsp;&nbsp;&nbsp;&nbsp;if($res){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data&nbsp;=&nbsp;getData($res);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($data){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data&nbsp;=&nbsp;infoArr($data);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;saveData($data);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$times++;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;ob_flush();&nbsp;//&nbsp;从缓存中输出内容
&nbsp;&nbsp;&nbsp;&nbsp;flush();&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;刷出缓存内容到浏览器
&nbsp;&nbsp;&nbsp;&nbsp;sleep(1);&nbsp;&nbsp;&nbsp;//&nbsp;延时1s执行
&nbsp;&nbsp;&nbsp;&nbsp;$times--;
}

function&nbsp;curl($url&nbsp;=&nbsp;&quot;http://www.baidu.com&quot;){
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1.初始化会话请求
&nbsp;&nbsp;&nbsp;&nbsp;$ch&nbsp;=&nbsp;curl_init();
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2.设置请求选项，包括具体的url
&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch,&nbsp;CURLOPT_URL,&nbsp;$url);&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;需要获取的&nbsp;URL&nbsp;地址，也可以在curl_init()初始化会话的时候
&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch,&nbsp;CURLOPT_RETURNTRANSFER,&nbsp;1);&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TRUE&nbsp;将curl_exec()获取的信息以字符串返回，而不是直接输出
&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch,&nbsp;CURLOPT_HEADER,&nbsp;0);&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;启用时会将头文件的信息作为数据流输出（到页面）
&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch,&nbsp;CURLOPT_CONNECTTIMEOUT,&nbsp;30);&nbsp;&nbsp;&nbsp;//&nbsp;连接超时时长
&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch,&nbsp;CURLOPT_TIMEOUT,&nbsp;30);&nbsp;&nbsp;//&nbsp;执行超时时长
&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch,&nbsp;CURLOPT_HTTP_VERSION,&nbsp;CURL_HTTP_VERSION_1_0);&nbsp;//强制协议为1.0
&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch,&nbsp;CURLOPT_HTTPHEADER,&nbsp;array(&quot;Expect:&nbsp;&quot;));&nbsp;//头部要送出&#39;Expect:&nbsp;&#39;
&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($ch,&nbsp;CURLOPT_IPRESOLVE,&nbsp;CURL_IPRESOLVE_V4&nbsp;);&nbsp;//强制使用IPV4协议解析域名
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;3.执行一个curl会话并且获得相关回复
&nbsp;&nbsp;&nbsp;&nbsp;$response&nbsp;=&nbsp;curl_exec($ch);
&nbsp;&nbsp;&nbsp;&nbsp;if($response&nbsp;===&nbsp;false){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;4.释放curl句柄，关闭一个curl会话
&nbsp;&nbsp;&nbsp;&nbsp;curl_close($ch);

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$response;
}

function&nbsp;getData($response&nbsp;=&nbsp;&#39;&#39;){

&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;过滤html标签
&nbsp;&nbsp;&nbsp;&nbsp;$replace_pattern&nbsp;=&nbsp;&#39;/&lt;[^&gt;]*&gt;/x&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;$str_replace&nbsp;=&nbsp;preg_replace($replace_pattern,&nbsp;&#39;&#39;,&nbsp;$response);

&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;获取日期
&nbsp;&nbsp;&nbsp;&nbsp;$dates&nbsp;=&nbsp;[];
&nbsp;&nbsp;&nbsp;&nbsp;$date_pattern&nbsp;=&nbsp;&#39;/\d{1,4}年\d{1,2}月\d{1,2}日/u&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;preg_match_all($date_pattern,&nbsp;$str_replace,&nbsp;$dates);

&nbsp;&nbsp;&nbsp;&nbsp;if(empty($dates[0])){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;($dates&nbsp;as&nbsp;$value)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;($value&nbsp;as&nbsp;$v)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$v&nbsp;=&nbsp;str_replace(array(&#39;年&#39;,&#39;月&#39;,&#39;日&#39;),&nbsp;array(&#39;-&#39;,&nbsp;&#39;-&#39;,&nbsp;&#39;&#39;),&nbsp;$v);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$date[]&nbsp;=&nbsp;$v;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;获取科目
&nbsp;&nbsp;&nbsp;&nbsp;$subjects&nbsp;=&nbsp;[];
&nbsp;&nbsp;&nbsp;&nbsp;$subject_pattern&nbsp;=&nbsp;&#39;/《[^(》|太)]*》/u&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;preg_match_all($subject_pattern,&nbsp;$str_replace,&nbsp;$subjects);

&nbsp;&nbsp;&nbsp;&nbsp;if(empty($subjects[0])){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;($subjects&nbsp;as&nbsp;$value)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;($value&nbsp;as&nbsp;$v)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$subject[]&nbsp;=&nbsp;$v;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;获取学号姓名
&nbsp;&nbsp;&nbsp;&nbsp;$students&nbsp;=&nbsp;[];
&nbsp;&nbsp;&nbsp;&nbsp;$students_pattern&nbsp;=&nbsp;&#39;/\d{7,9}(班)?\d{0,2}(号)?[^(\d\w\s,)]{6,9}/x&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;preg_match_all($students_pattern,&nbsp;$str_replace,&nbsp;$students);

&nbsp;&nbsp;&nbsp;&nbsp;if(empty($students[0])){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;$students=$students[0];

&nbsp;&nbsp;&nbsp;&nbsp;foreach($students&nbsp;as&nbsp;$info){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$info&nbsp;=&nbsp;str_replace(array(&#39;班&#39;,&#39;号&#39;,&#39;在&#39;,&#39;、&#39;),&nbsp;&#39;&#39;,&nbsp;$info);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$stuId[]&nbsp;=&nbsp;substr($info,&nbsp;0,&nbsp;9);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$name[]&nbsp;=&nbsp;substr($info,&nbsp;9,&nbsp;11);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;date&#39;]&nbsp;=&nbsp;$date;
&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;subject&#39;]&nbsp;=&nbsp;$subject;
&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;stuId&#39;]&nbsp;=&nbsp;$stuId;
&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;name&#39;]&nbsp;=&nbsp;$name;

&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$data;
}

function&nbsp;infoArr($data&nbsp;=&nbsp;[]){
&nbsp;&nbsp;&nbsp;&nbsp;$dateNum&nbsp;=&nbsp;count($data[&#39;date&#39;]);
&nbsp;&nbsp;&nbsp;&nbsp;$subNum&nbsp;=&nbsp;count($data[&#39;subject&#39;]);
&nbsp;&nbsp;&nbsp;&nbsp;$idNum&nbsp;=&nbsp;count($data[&#39;stuId&#39;]);
&nbsp;&nbsp;&nbsp;&nbsp;$nameNum&nbsp;=&nbsp;count($data[&#39;name&#39;]);
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果日期数目为1，其它不为1
&nbsp;&nbsp;&nbsp;&nbsp;if($dateNum&nbsp;==&nbsp;1){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($i&nbsp;=&nbsp;0;&nbsp;$i&nbsp;&lt;&nbsp;$idNum&nbsp;-&nbsp;1;&nbsp;$i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;date&#39;][$i+1]&nbsp;=&nbsp;$data[&#39;date&#39;][$i];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果课程数为1，人数不为1
&nbsp;&nbsp;&nbsp;&nbsp;if($subNum&nbsp;==&nbsp;1&nbsp;&amp;&amp;&nbsp;$idNum&nbsp;!=&nbsp;1){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($i&nbsp;=&nbsp;0;&nbsp;$i&nbsp;&lt;&nbsp;$idNum&nbsp;-&nbsp;1;&nbsp;$i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;date&#39;][$i+1]&nbsp;=&nbsp;$data[&#39;date&#39;][$i];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;subject&#39;][$i+1]&nbsp;=&nbsp;$data[&#39;subject&#39;][$i];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;如果课程数大于1，人数大于课程数
&nbsp;&nbsp;&nbsp;&nbsp;if($subNum&nbsp;&gt;&nbsp;1&nbsp;&amp;&amp;&nbsp;$idNum&nbsp;&gt;&nbsp;$subNum){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($i&nbsp;=&nbsp;0;&nbsp;$i&nbsp;&lt;&nbsp;$idNum-1;&nbsp;$i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(substr($data[&#39;stuId&#39;][$i],&nbsp;0,&nbsp;5)&nbsp;==&nbsp;substr($data[&#39;stuId&#39;][$i+1],&nbsp;0,&nbsp;5)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($j&nbsp;=&nbsp;$idNum-1;&nbsp;$j&nbsp;&gt;&nbsp;$i;&nbsp;$j--){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;subject&#39;][$j]&nbsp;=&nbsp;$data[&#39;subject&#39;][$j-1];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#39;date&#39;][$j]&nbsp;=&nbsp;$data[&#39;date&#39;][$j-1];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;暂时忽略其它情况
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$data;
}

function&nbsp;saveData($data&nbsp;=&nbsp;[]){

&nbsp;&nbsp;&nbsp;&nbsp;$mysql_host&nbsp;=&nbsp;&#39;localhost&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;$mysql_username&nbsp;=&nbsp;&#39;root&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;$mysql_password&nbsp;=&nbsp;&#39;root&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;$mysql_db&nbsp;=&nbsp;&#39;minyy&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;$mysql_table&nbsp;=&nbsp;&#39;cheat_exam&#39;;

&nbsp;&nbsp;&nbsp;&nbsp;$link&nbsp;=&nbsp;mysql_connect($mysql_host,&nbsp;$mysql_username,&nbsp;$mysql_password);
&nbsp;&nbsp;&nbsp;&nbsp;mysql_select_db($mysql_db,&nbsp;$link);
&nbsp;&nbsp;&nbsp;&nbsp;mysql_query(&quot;set&nbsp;names&nbsp;utf8&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;$sql&nbsp;=&nbsp;&quot;CREATE&nbsp;TABLE&nbsp;IF&nbsp;NOT&nbsp;EXISTS&nbsp;$mysql_table(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;int(6)&nbsp;unsigned&nbsp;NOT&nbsp;NULL&nbsp;AUTO_INCREMENT,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PRIMARY&nbsp;KEY(id),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stuId&nbsp;int(11),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;date&nbsp;date,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;subject&nbsp;tinytext,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;tinytext
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;ENGINE=MyISAM&nbsp;&nbsp;DEFAULT&nbsp;CHARSET=utf8&nbsp;AUTO_INCREMENT=1&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;mysql_query($sql);
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;$times&nbsp;=&nbsp;count($data[&#39;stuId&#39;]);

&nbsp;&nbsp;&nbsp;&nbsp;for($i&nbsp;=&nbsp;0;&nbsp;$i&nbsp;&lt;&nbsp;1;&nbsp;$i++){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$stuId&nbsp;=&nbsp;$data[&#39;stuId&#39;][$i];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$date&nbsp;=&nbsp;&#39;&quot;&#39;.$data[&#39;date&#39;][$i].&#39;&quot;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$subject&nbsp;=&nbsp;&#39;&quot;&#39;.$data[&#39;subject&#39;][$i].&#39;&quot;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$name&nbsp;=&nbsp;&#39;&quot;&#39;.$data[&#39;name&#39;][$i].&#39;&quot;&#39;;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sql&nbsp;=&nbsp;&quot;SELECT&nbsp;*&nbsp;FROM&nbsp;$mysql_table&nbsp;WHERE&nbsp;stuId={$data[&#39;stuId&#39;][$i]}&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$res&nbsp;=&nbsp;mysql_fetch_array(mysql_query($sql));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$res){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sql&nbsp;=&nbsp;&quot;INSERT&nbsp;INTO&nbsp;$mysql_table&nbsp;(stuId,&nbsp;date,&nbsp;subject,&nbsp;name)&nbsp;VALUES&nbsp;($stuId,&nbsp;$date,&nbsp;$subject,&nbsp;$name)&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql_query($sql);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;1;
}</pre><p>事实上是比较简单的一段小程序。</p><p>执行后的页面会不断显示出一个一个网址。（忘了截图）</p><p>（由于网速慢）程序跑了很多（10？）个小时。</p><p>一共抓到106条数据，手工删掉几条非法数据后还剩98条。数据样本有点小啊。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702191487511119176721.png" title="2.png" alt="2.png" width="693" height="469" style="width: 693px; height: 469px;"/></p><p>唯一（三）能得到的结果图：</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702191487513020390196.png" title="5553.png" alt="5553.png" width="696" height="471" style="width: 696px; height: 471px;"/></p><p>不同系部的人数分布如上。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702191487511152333623.png" title="3.png" alt="3.png" width="691" height="458" style="width: 691px; height: 458px;"/></p><p>不同入学年份的学生人数分布如上。<br/></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/02/201702191487511179190399.png" title="搜狗截图20170219204308.png" alt="搜狗截图20170219204308.png" width="701" height="454" style="width: 701px; height: 454px;"/></p><p>不同年份考试的学生人数如上。（O__O &quot;…）</p><p>程序比较简单懒得详细写了，注释很全。不具有普遍性也就不封装成类了，得加很多判断好麻烦。</p><p>The End.<br/></p>]]></content>
  </entry>
  <entry>
    <title>JAVA中的几种设计模式</title>
    <link href="https://old-blog.smallyu.net/indexa916.html?id=44"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=44</id>
    <published>2017-02-10T16:00:00.000Z</published>
    <updated>2017-02-10T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>单例模式 饿汉模式 Singleton.java package com.imooc public class Singleton { // 1.将构造方法私有化，不允许外部直接创建对象 private Singleton() { } // 2.创建类的唯一示例,使用private static修饰 private static Singleton inst...</p>]]></summary>
    <content type="html"><![CDATA[<p><span style="font-size: 16px;"><strong>单例模式</strong></span></p><p>饿汉模式</p><blockquote><p>Singleton.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc
public&nbsp;class&nbsp;Singleton&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1.将构造方法私有化，不允许外部直接创建对象
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Singleton()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2.创建类的唯一示例,使用private&nbsp;static修饰
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;Singleton&nbsp;instance&nbsp;=&nbsp;new&nbsp;Singleton();
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;3.提供一个用于获取示例的方法
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;Singleton&nbsp;getInstance()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;instance;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>饿汉模式指第二步时，加载类的同时生成了实例化的对象。特点是加载类时比较慢，但运行时获取对象的速度比较快，线程安全。</p><blockquote><p>Test.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc;
public&nbsp;class&nbsp;Test&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Singleton&nbsp;s1&nbsp;=&nbsp;Singleton.getInstance;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Singleton&nbsp;s2&nbsp;=&nbsp;Singleton.getInstance;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>懒汉模式</p><blockquote><p>Singleton2.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc

public&nbsp;class&nbsp;Singleton2&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;1.将构造方法私有化，不允许外部直接创建对象
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Singleton2()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;2.创建类的唯一示例,使用private&nbsp;static修饰
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;static&nbsp;Singleton2&nbsp;instance;

&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;3.提供一个用于获取示例的方法
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;Singleton2&nbsp;getInstance()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(install==null){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;instance&nbsp;=&nbsp;new&nbsp;Singleton2();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;instance;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>懒汉模式指第二步没有实例化对象，而是在第三步，当调用方法，才会判断并进行实例化，特点是加载类时比较快，但运行时获取对象的速度比较慢，线程不安全。</p><p><span style="font-size: 16px;"><strong>模板方法模式</strong></span><br/></p><p>应用场景为模拟制备饮料。制备饮料一共有四个步骤，即为RefreshBeverage.java中注释中写到的四步。泡制饮料和加入调味料在抽象基类中没有提供具体的实现方法，只是定义接口方法，在子类中应用模板方法模式分别实现具体内容。<strong><br/></strong></p><p>第四步加入调味料用到了钩子方法，可以提高代码灵活性，判断子类要泡制的饮料中要不要加入调味料。</p><blockquote><p>RefreshBeverage.java<strong><br/></strong></p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.template;

/**
&nbsp;*&nbsp;抽象基类，为所有子类提供一个算法框架
&nbsp;*&nbsp;
&nbsp;*&nbsp;提神饮料
&nbsp;*/
public&nbsp;abstract&nbsp;class&nbsp;RefreshBeverage&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;制备饮料的模板方法
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;封装了所有子类共同遵循的算法框架
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;final&nbsp;void&nbsp;prepareBeverageTemplate()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;步骤1&nbsp;将水煮沸
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boilWater();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;步骤2&nbsp;泡制饮料
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;brew();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;步骤3&nbsp;将饮料倒入杯中
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pourInCup();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isCustomerWantsCondiments()){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;步骤4&nbsp;加入调味料
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addCondiments();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Hook，钩子函数，提供一个默认或空的实现
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;具体的子类可以自行决定是否挂钩或者如何挂钩
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;询问用户是否加入调料
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;boolean&nbsp;isCustomerWantsCondiments()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;基本方法，将水煮沸
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;void&nbsp;boilWater()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;将水煮沸&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;抽象的基本方法，泡制饮料
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;abstract&nbsp;void&nbsp;brew();

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;基本方法，将饮料倒入杯中
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;void&nbsp;pourInCup()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;将饮料倒入杯中&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;抽象的基本方法，加入调味料
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;abstract&nbsp;void&nbsp;addCondiments();
}</pre><blockquote><p>Coffee.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.template;

/**
&nbsp;*&nbsp;具体子类，提供了咖啡制备的具体实现
&nbsp;*/
public&nbsp;class&nbsp;Coffee&nbsp;extends&nbsp;RefreshBeverage&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;brew()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;用沸水冲泡咖啡&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;addCondiments()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;加入糖和牛奶&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote><p>Tea.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.template;

/**
&nbsp;*&nbsp;具体子类，提供了制备茶的具体实现
&nbsp;*/
public&nbsp;class&nbsp;Tea&nbsp;extends&nbsp;RefreshBeverage&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;brew()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;用80度的热水浸泡茶叶5分钟&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;addCondiments()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;加入柠檬&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;子类通过覆盖的方式选择挂载钩子函数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;boolean&nbsp;isCustomerWantsCondiments(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>RefreshBeverageTest.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.template;

public&nbsp;class&nbsp;RefreshBeverageTest&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;制备咖啡...&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RefreshBeverage&nbsp;b1&nbsp;=&nbsp;new&nbsp;Coffee();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b1.prepareBeverageTemplate();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;咖啡好了！&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;**********************************&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;制备茶...&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RefreshBeverage&nbsp;b2&nbsp;=&nbsp;new&nbsp;Tea();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b2.prepareBeverageTemplate();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;茶好了！&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><p>运行结果：<br/></p><pre class="prism-highlight prism-language-java">制备咖啡...
将水煮沸
用沸水冲泡咖啡
将饮料倒入杯中
加入糖和牛奶
咖啡好了！
**********************************
制备茶...
将水煮沸
用80度的热水浸泡茶叶5分钟
将饮料倒入杯中
茶好了！</pre><p>其中用到的钩子方法会使子类更加灵活。</p><p><span style="font-size: 16px;"><strong>适配器模式</strong></span></p><p>应用场景为模拟二相转三相插座适配器，NoteBook需要三相电流供电，但只有二相电流插座，TwoPlugAdapter.java中适配了二相电流。</p><blockquote><p>ThreePlugIf.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.apttern.adapter;
/**
&nbsp;*&nbsp;三相插座接口
&nbsp;*/
public&nbsp;interface&nbsp;ThreePlugIf&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;使用三相电流供电
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;powerWithThree(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote><p>GBTwoPlug.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.apttern.adapter;

public&nbsp;class&nbsp;GBTwoPlug&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;使用二相电流供电
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;powerWithTwo(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;使用二相电流供电&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote><p>NoteBook.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.apttern.adapter;

public&nbsp;class&nbsp;NoteBook&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;ThreePlugIf&nbsp;plug;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;NoteBook(ThreePlugIf&nbsp;plug){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.plug&nbsp;=&nbsp;plug;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;使用插座充电
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;change(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;plug.powerWithThree();
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GBTwoPlug&nbsp;two&nbsp;=&nbsp;new&nbsp;GBTwoPlug();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreePlugIf&nbsp;three&nbsp;=&nbsp;new&nbsp;TwoPlugAdapter(two);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NoteBook&nbsp;nb&nbsp;=&nbsp;new&nbsp;NoteBook(three);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nb.change();
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote><p>TwoPlugAdapter.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.apttern.adapter;

/**
&nbsp;*&nbsp;二相转三相的插座适配器
&nbsp;*/
public&nbsp;class&nbsp;TwoPlugAdapter&nbsp;implements&nbsp;ThreePlugIf&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;GBTwoPlug&nbsp;plug;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;TwoPlugAdapter(GBTwoPlug&nbsp;plug){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.plug&nbsp;=&nbsp;plug;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;powerWithThree()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;通过转化&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;plug.powerWithTwo();
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><p>运行结果：<br/></p><pre class="prism-highlight prism-language-java">通过转化
使用二相电流供电</pre><p><span style="font-size: 16px;"><strong>策略模式</strong></span></p><p>策略模式将可变部分从程序中抽象分离成算法接口，在该接口下分别封装一系列算法实现</p><p>What is composition ?</p><p>在类中增加一个私有域，引用另一个已有的类的实例，通过调用引用实例的方法从而获得新的功能，这种设计被称作组合（复合）。</p><p>策略模式的优点：</p><blockquote><p>1.使用了组合，是架构更加灵活</p><p>2.富有弹性，可以较好的应对变化（开——闭原则）</p><p>3.更好的代码复用性（相对于继承）</p><p>4.消除大量的条件语句</p></blockquote><p>策略模式的缺点：</p><blockquote><p>1.客户代码需要了解每个策略的细节</p><p>2.增加了对象的数目</p></blockquote><p>策略模式的应用场景：</p><blockquote><p>1.许多相关的类仅仅是行为差异</p><p>2.运行时选取不同的算法变体</p><p>3.通过条件语句在多个分支中选取一</p></blockquote><p>代码的应用场景模拟了鸭子的生产过程，鸭子一共有三个行为：展示、鸣叫、飞行。不同的鸭子有不同的飞行行为，使用到了策略模式。<br/></p><blockquote><p>Duck.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.strategy;

/**
&nbsp;*&nbsp;超类，所有的鸭子都要继承此类
&nbsp;*抽象了鸭子的行为：显示和鸣叫
&nbsp;*/
public&nbsp;abstract&nbsp;class&nbsp;Duck&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;鸭子发出叫声
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;通用行为，由超类实现
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;quack(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;嘎嘎嘎&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;显示鸭子的外观
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;鸭子的外观不相同，声明为abstract，由子类实现
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;abstract&nbsp;void&nbsp;display();
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;FlyingStrategy&nbsp;flyingStrategy;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;setFlyingStrategy(FlyingStrategy&nbsp;flyingStrategy){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.flyingStrategy&nbsp;=&nbsp;flyingStrategy;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;fly(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flyingStrategy.performFly();
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote><p>FlyingStrategy.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.strategy;

/**
&nbsp;*&nbsp;策略接口，实现鸭子的飞行行为
&nbsp;*/
public&nbsp;interface&nbsp;FlyingStrategy&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;performFly();
}</pre><blockquote><p>MallardDuck.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.strategy;

import&nbsp;com.imooc.pattern.strategy.impl.FlyWithWin;

//&nbsp;绿脖鸭
public&nbsp;class&nbsp;MallardDuck&nbsp;extends&nbsp;Duck&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;MallardDuck(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.setFlyingStrategy(new&nbsp;FlyWithWin());
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;display()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;我的脖子是绿色的&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>RedheadDuck.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.strategy;

import&nbsp;com.imooc.pattern.strategy.impl.FlyWithWin;

//&nbsp;红头鸭
public&nbsp;class&nbsp;RedheadDuck&nbsp;extends&nbsp;Duck&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;RedheadDuck(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.setFlyingStrategy(new&nbsp;FlyWithWin());
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;display()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;我的头是红色的&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>RubberDuck.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.strategy;

import&nbsp;com.imooc.pattern.strategy.impl.FlyNoWay;

//&nbsp;橡胶鸭
public&nbsp;class&nbsp;RubberDuck&nbsp;extends&nbsp;Duck&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;RubberDuck(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.setFlyingStrategy(new&nbsp;FlyNoWay());
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;display()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;我全身发黄，嘴巴很红&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;quack(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;叫声稍有不同，复写了父类方法
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;嘎~嘎~嘎~&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>不同的飞行策略类：</p><blockquote><p>FlyWithWin.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.strategy.impl;

import&nbsp;com.imooc.pattern.strategy.FlyingStrategy;

public&nbsp;class&nbsp;FlyWithWin&nbsp;implements&nbsp;FlyingStrategy&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;performFly()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;振翅高飞&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>FlyNoWay.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.strategy.impl;

import&nbsp;com.imooc.pattern.strategy.FlyingStrategy;

public&nbsp;class&nbsp;FlyNoWay&nbsp;implements&nbsp;FlyingStrategy&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;performFly()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;我不会飞行！&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><p>最后测试生产出的鸭子：<br/></p><blockquote><p>DuckTest.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.pattern.strategy;

public&nbsp;class&nbsp;DuckTest&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;测试鸭子程序&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Duck&nbsp;duck&nbsp;=&nbsp;null;
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duck&nbsp;=&nbsp;new&nbsp;MallardDuck();
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duck&nbsp;=&nbsp;new&nbsp;RedheadDuck();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duck&nbsp;=&nbsp;new&nbsp;RubberDuck();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duck.display();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duck.quack();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;duck.fly();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;测试完毕&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>运行结果:</p><pre class="prism-highlight prism-language-java">测试鸭子程序
我全身发黄，嘴巴很红
嘎~嘎~嘎~
我不会飞行！
测试完毕</pre><p>这样就用JAVA实现了策略模式。</p><p><span style="font-size: 16px;"><strong>代理模式</strong></span></p><blockquote><p>远程代理：为不同地理的对象提供局域网代表对象</p><p>虚拟代理：根据需要将资源消耗很大的对象进行延迟，真正需要的时候进行创建</p><p>保护代理：控制用户的访问权限</p><p>智能引用代理：提供对目标对象额外服务</p></blockquote><p><span style="font-size: 14px;">应用场景模拟了汽车行驶时间的显示和日志记录两个功能。</span><br/></p><blockquote><p><span style="font-size: 14px;">Moveable.java</span></p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.proxy;

//&nbsp;接口文件
public&nbsp;interface&nbsp;Moveable&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;move();
}</pre><blockquote><p><span style="font-size: 14px;"></span>Car.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.proxy;

import&nbsp;java.util.Random;

public&nbsp;class&nbsp;Car&nbsp;implements&nbsp;Moveable&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;move()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;实现开车
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(new&nbsp;Random().nextInt(1000));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;汽车行驶中……&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}catch(InterruptedException&nbsp;e){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
}</pre><blockquote><p>Car2.java<span style="font-size: 14px;"></span><br/></p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.proxy;

//&nbsp;实现汽车行驶时间
public&nbsp;class&nbsp;Car2&nbsp;extends&nbsp;Car&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;move(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;strattime&nbsp;=&nbsp;System.currentTimeMillis();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;汽车开始行驶……&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.move();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;endtime&nbsp;=&nbsp;System.currentTimeMillis();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;汽车结束行驶中……&nbsp;汽车行驶时间：&quot;+(endtime-strattime)+&quot;毫秒！&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote><p><span style="font-size: 14px;"></span></p><p>Car3.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.proxy;

//&nbsp;时间代理实现汽车行驶时间
public&nbsp;class&nbsp;Car3&nbsp;implements&nbsp;Moveable&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Car3(Car&nbsp;car)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.car&nbsp;=&nbsp;car;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Car&nbsp;car;

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;move(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;strattime&nbsp;=&nbsp;System.currentTimeMillis();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;汽车开始行驶……&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;car.move();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;endtime&nbsp;=&nbsp;System.currentTimeMillis();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;汽车结束行驶中……&nbsp;汽车行驶时间：&quot;+(endtime-strattime)+&quot;毫秒！&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>Car4.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.proxy;

//&nbsp;增加log记录代理
public&nbsp;class&nbsp;Car4&nbsp;implements&nbsp;Moveable&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Car4(Moveable&nbsp;m)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.m&nbsp;=&nbsp;m;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Moveable&nbsp;m;

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;move(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;日志开始……&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.move();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;日志结束……&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>Client.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.proxy;

/**
&nbsp;*&nbsp;测试类
&nbsp;*/
public&nbsp;class&nbsp;Client&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;直接
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Car&nbsp;car&nbsp;=&nbsp;new&nbsp;Car();
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;car.move();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;使用集成方法
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Moveable&nbsp;m&nbsp;=&nbsp;new&nbsp;Car2();
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.move();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;使用聚合方法
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Car&nbsp;car&nbsp;=&nbsp;new&nbsp;Car();
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Moveable&nbsp;m&nbsp;=&nbsp;new&nbsp;Car3(car);
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.move();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;增加日志记录
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Car&nbsp;car&nbsp;=&nbsp;new&nbsp;Car();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Car3&nbsp;ctp&nbsp;=&nbsp;new&nbsp;Car3(car);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Car4&nbsp;clp&nbsp;=&nbsp;new&nbsp;Car4(ctp);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clp.move();
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>运行结果像这样：<br/></p><pre class="prism-highlight prism-language-java">日志开始……
汽车开始行驶……
汽车行驶中……
汽车结束行驶中……&nbsp;汽车行驶时间：497毫秒！
日志结束……</pre><p>下面使用动态代理来是代码更灵活（<strong>有错误</strong>）。</p><blockquote><p>TimeHandler.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.jdkproxy;

import&nbsp;java.lang.reflect.InvocationHandler;
import&nbsp;java.lang.reflect.Method;

import&nbsp;com.imooc.proxy.Car;

/**
&nbsp;*&nbsp;JDK动态代理
&nbsp;*&nbsp;只能代理实现了接口的类
&nbsp;*&nbsp;没有实现接口的类不能实现JDK的动态代理
&nbsp;*/
public&nbsp;class&nbsp;TimeHandler&nbsp;implements&nbsp;InvocationHandler&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;TimeHandler(Object&nbsp;target){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.target&nbsp;=&nbsp;target;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Object&nbsp;target;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;参数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;proxy&nbsp;被代理对象
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;method&nbsp;被代理的方法
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;args&nbsp;方法的参数
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;返回值
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Object&nbsp;方法的返回值
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Object&nbsp;invoke(Object&nbsp;arg0,&nbsp;Method&nbsp;arg1,&nbsp;Object[]&nbsp;arg2)&nbsp;throws&nbsp;Throwable&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO&nbsp;Auto-generated&nbsp;method&nbsp;stub
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;strattime&nbsp;=&nbsp;System.currentTimeMillis();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;汽车开始行驶……&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;method.invoke(target);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;endtime&nbsp;=&nbsp;System.currentTimeMillis();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;汽车结束行驶中……&nbsp;汽车行驶时间：&quot;+(endtime-strattime)+&quot;毫秒！&quot;);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;null;
&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>Test.java</p></blockquote><pre class="prism-highlight prism-language-java">package&nbsp;com.imooc.jdkproxy;

import&nbsp;java.lang.reflect.InvocationHandler;
import&nbsp;java.lang.reflect.Proxy;

import&nbsp;com.imooc.proxy.Car;
import&nbsp;com.imooc.proxy.Moveable;

/**
&nbsp;*&nbsp;JDK动态代理测试类
&nbsp;*/
public&nbsp;class&nbsp;Test&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Car&nbsp;car&nbsp;=&nbsp;new&nbsp;Car();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InvocationHandler&nbsp;h&nbsp;=&nbsp;new&nbsp;TimeHandler(car);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&lt;?&gt;&nbsp;cls&nbsp;=&nbsp;car.getClass();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;loader&nbsp;类加载器
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;interface&nbsp;实现节后
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;h&nbsp;InvocationHander
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Moveable&nbsp;m&nbsp;=&nbsp;(Moveable)Proxy.newProxyInstance(cls.getClassLoader(),&nbsp;cls.getInterfaces(),&nbsp;h);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.move();
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p><span style="font-size: 14px;">etc.<br/></span></p>]]></content>
  </entry>
  <entry>
    <title>PHP中多种常用的设计模式举例</title>
    <link href="https://old-blog.smallyu.net/index2580.html?id=43"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=43</id>
    <published>2017-01-24T16:00:00.000Z</published>
    <updated>2017-01-24T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>适配器模式 策略模式 数据对象映射模式 观察者模式 原型模式 装饰器模式 迭代器模式 代理模式 适配器模式 1.适配器模式，可以将截然不同的函数接口封装成统一的API 2.实际应用举例，PHP的数据库操作有mysql,musqli,pdo三种，可以用适配器模式统一成一致。类似的场景还有cache适配器，将memcache，redis，file，apc等不同的...</p>]]></summary>
    <content type="html"><![CDATA[<div style="border: 1px solid #968A8A;padding: 5px;z-index: 2;background: rgba(245, 242, 240, 0.50);position:fixed;right:0;bottom:0;"><a href="#1">适配器模式</a><br/><a href="#2">策略模式</a><br/><a href="#3">数据对象映射模式</a><br/><a href="#4">观察者模式</a><br/><a href="#5">原型模式</a><br/><a href="#6">装饰器模式</a><br/><a href="#7">迭代器模式</a><br/><a href="#8">代理模式</a></div><p><strong><a name="1"></a>适配器模式</strong><br/></p><blockquote style="white-space: normal;"><p>1.适配器模式，可以将截然不同的函数接口封装成统一的API</p><p>2.实际应用举例，PHP的数据库操作有mysql,musqli,pdo三种，可以用适配器模式统一成一致。类似的场景还有cache适配器，将memcache，redis，file，apc等不同的缓存函数，统一成一致</p></blockquote><blockquote style="white-space: normal;"><p>Database.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
interdace&nbsp;IDatabase{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname);
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;query($sql);
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;close();
}</pre><p style="white-space: normal;">在Database.php中定义了数据库操作的接口，接下来将MySQL、MySQLi、PDO三种数据库操作适配为接口中定义的方法。</p><blockquote style="white-space: normal;"><p>MySQL.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
namespace&nbsp;Database;
class&nbsp;MySQL&nbsp;implements&nbsp;IDatabase{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$conn&nbsp;=&nbsp;mysql_connect($host,&nbsp;$user,&nbsp;$passwd);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql_select_db($dbname,&nbsp;$conn);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this-&gt;conn&nbsp;=&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;query($sql){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$res&nbsp;=&nbsp;mysql_query($sql,&nbsp;$this-&gt;conn);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$res;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;close(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql_close($this-&gt;conn);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote style="white-space: normal;"><p>MySQLi.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
namespace&nbsp;Database;
class&nbsp;MySQLi&nbsp;implements&nbsp;IDatabase{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$conn&nbsp;=&nbsp;mysqli_connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this-&gt;conn&nbsp;=&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;query($sql){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$res&nbsp;=&nbsp;mysqli_query($this-&gt;conn,&nbsp;$sql);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$res;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;close(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysqli_close($this-&gt;conn);
&nbsp;&nbsp;&nbsp;&nbsp;}</pre><blockquote style="white-space: normal;"><p>PDO.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
namespace&nbsp;Database;
class&nbsp;PDO&nbsp;implements&nbsp;IDatabase{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;\PDO(&quot;mysql:host=$host;dbname=$dbname&quot;,&nbsp;$user,&nbsp;$passwd);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;conn&nbsp;=&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;query($sql){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this-&gt;conn-&gt;query($sql);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;close(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unset($this-&gt;conn);
&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p style="white-space: normal;">然后在应用中可以这样使用：</p><blockquote style="white-space: normal;"><p>index.php<br/></p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$db&nbsp;=&nbsp;new&nbsp;Database\MySQL();
$db-&gt;connect(&#39;localhost&#39;,&nbsp;&#39;root&#39;,&nbsp;&#39;root&#39;,&nbsp;&#39;test&#39;);
$db-&gt;query(&#39;show&nbsp;database&#39;);
$db-&gt;close();</pre><p style="white-space: normal;">或者实例化其他类型的数据库，只需要使用同一种标准。</p><p style="white-space: normal;"><strong><a name="2"></a>策略模式</strong></p><blockquote style="white-space: normal;"><p>1.策略模式，将一组特定行为和算法封装成类，以适应某些特定的上下文环境，这种模式就是策略模式</p><p>2.实际应用举例，假如一个电商网站系统，针对男性女性用户要各自跳转到不同的商品类目，并且所有广告位展示不同的广告</p><p>3.使用策略模式可以实现Ioc，依赖倒置、控制反转</p></blockquote><blockquote style="white-space: normal;"><p>UserStrategy.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
interface&nbsp;UserStrategy&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;showAd();
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;showCategory();
}</pre><p style="white-space: normal;">UserStrategy.php文件定义了用户策略的接口，面对不同的用户将分别实现相应的内容。</p><blockquote style="white-space: normal;"><p>FemaleUserStrategy.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;FemaleUserStrategy&nbsp;implements&nbsp;UserStrategy&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;showAd()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;2017新款女装&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;showCategory()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;女装&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote style="white-space: normal;"><p>MaleUserStrategy.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;MaleUserStrategy&nbsp;implements&nbsp;UserStrategy&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;showAd()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;IPhone7&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;showCategory()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;电子产品&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p style="white-space: normal;">在index.php中这样做就可以实现从硬编码到实现解耦，即不需要修改Page类的内容，只需要传递不同的参数。</p><blockquote style="white-space: normal;"><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Page&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;index()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;AD:&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;strategy-&gt;showAd();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;Category:&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;strategy-&gt;showCategory();
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;setStrategy(UserStrategy&nbsp;$strategy)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;strategy&nbsp;=&nbsp;$strategy;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
$page&nbsp;=&nbsp;new&nbsp;Page();
if&nbsp;(isset($_GET[&#39;female&#39;]))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;$strategy&nbsp;=&nbsp;new&nbsp;FemaleUserStrategy();
}&nbsp;else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;$strategy&nbsp;=&nbsp;new&nbsp;MaleUserStrategy();
}
$page-&gt;setStrategy($strategy);
$page-&gt;index();</pre><p><strong><a name="3"></a>数据对象映射模式</strong><br/></p><p style="white-space: normal;">数据对象映射模式，是将对象和数据存储映射起来，对一个对象的操作会映射为对数据存储的操作。</p><p style="white-space: normal;">在下面的代码中实现数据对象映射模式，我们将实现一个ORM类，将复杂的SQL语句映射成对象属性的操作。</p><blockquote style="white-space: normal;"><p>User.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;User&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;$id;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;$mobile;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;$regtime;

&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$db;

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;__construct($id)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;数据库查询操作
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;db&nbsp;=&nbsp;new&nbsp;MySQLi();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;db-&gt;connect(&#39;localhost&#39;,&nbsp;&#39;root&#39;,&nbsp;&#39;root&#39;,&nbsp;&#39;test1&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$res&nbsp;=&nbsp;$this-&gt;db-&gt;query(&quot;select&nbsp;*&nbsp;from&nbsp;user&nbsp;where&nbsp;id={$this-&gt;id}&nbsp;limit&nbsp;1&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data&nbsp;=&nbsp;$res-&gt;fetch_assoc();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;id&nbsp;=&nbsp;$data[&#39;id&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;name&nbsp;=&nbsp;$data[&#39;name&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;mobile&nbsp;=&nbsp;$data[&#39;imobile];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;regtime&nbsp;=&nbsp;$data[regtimed&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;__destruct()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;数据库写入操作
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;db-&gt;query(&quot;update&nbsp;user&nbsp;set&nbsp;name&nbsp;=&nbsp;&#39;{$this-&gt;name}&#39;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mobile=&#39;{$this-&gt;mobile}&#39;,&nbsp;regtime=&#39;{$this-&gt;regtime}&#39;&nbsp;where&nbsp;id&nbsp;=&nbsp;{$this-&gt;id}&nbsp;limit&nbsp;1&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p style="white-space: normal;">这样来使用：</p><blockquote style="white-space: normal;"><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$user&nbsp;=&nbsp;new&nbsp;User(1);
$user-&gt;mobile&nbsp;=&nbsp;&#39;18812345678&#39;;
$user-&gt;name&nbsp;=&nbsp;&#39;test&#39;;
$user-&gt;regtime&nbsp;=&nbsp;date(&#39;Y-m-d&nbsp;H:i:s&#39;);</pre><p style="white-space: normal;">下面结合使用数据对象映射模式，工厂模式，注册器模式：</p><blockquote style="white-space: normal;"><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Page&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;index()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user&nbsp;=&nbsp;Factory::getUser(1);&nbsp;//&nbsp;工厂模式的实现
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user-&gt;name&nbsp;=&nbsp;&#39;rango&#39;;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;test();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;test()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user&nbsp;=&nbsp;Factory::getUser(1);&nbsp;//&nbsp;工厂模式的实现
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user-&gt;mobile&nbsp;=&nbsp;&#39;18844448888&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
$page&nbsp;=&nbsp;new&nbsp;Page();</pre><blockquote style="white-space: normal;"><p>Factory.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Factory&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;function&nbsp;getUser($id)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;注册器模式的实现
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$key&nbsp;=&nbsp;&#39;user_&#39;.$id;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user&nbsp;=&nbsp;Register::get($key);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!user)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$user&nbsp;=&nbsp;new&nbsp;User($id);&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Register::set($key,$user);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$user;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p style="white-space: normal;"><strong><a name="4"></a>观察者模式</strong></p><blockquote><p>1.观察者模式（Observer），当一个对象状态发生改变时，依赖它的对象全部会收到通知，并自动更新</p><p>2.场景：一个事件发生后，要执行一连串更新操作，传统的编程方式，就是在事件的代码之后直接加入处理逻辑。当更新的逻辑增多之后，代码会变得难以维护。这种方式是耦合的，侵入式的，增加新的逻辑需要修改事件主体的代码</p><p>3.观察者模式实现了低耦合，非侵入式的通知与更新机制</p></blockquote><blockquote style="white-space: normal;"><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Event&nbsp;extends&nbsp;EventGenerator&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;trigger()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;Event&lt;br&nbsp;/&gt;&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;notify();
&nbsp;&nbsp;&nbsp;&nbsp;}
}

class&nbsp;Observer1&nbsp;implements&nbsp;Obsrver&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;update($event_info&nbsp;=&nbsp;null)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;逻辑1&lt;br&nbsp;/&gt;&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
}

class&nbsp;Observer2&nbsp;implements&nbsp;Obsrver&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;update($event_info&nbsp;=&nbsp;null)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;逻辑2&lt;br&nbsp;/&gt;&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;}
}

$event&nbsp;=&nbsp;new&nbsp;Event;
$event-&gt;addObserver(new&nbsp;Observer1);&nbsp;//&nbsp;观察者模式的实现
$event-&gt;addObserver(new&nbsp;Observer2);&nbsp;//&nbsp;观察者模式的实现
$event-&gt;trigger();</pre><blockquote style="white-space: normal;"><p>EventGenerator.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
abstract&nbsp;class&nbsp;EventGenerator&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$observers&nbsp;=&nbsp;array();

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;addObserver(Observer&nbsp;$observer)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;observers[]&nbsp;=&nbsp;$observer;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;notify()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach($this-&gt;observers&nbsp;as&nbsp;$ovserver)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$observer-&gt;update();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote style="white-space: normal;"><p>Observer.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
interface&nbsp;Observer&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;update($event_info&nbsp;=&nbsp;null);
}</pre><p style="white-space: normal;"><strong><a name="5"></a>原型模式</strong></p><blockquote><p>1.与工厂模式作用类似，都是用来创建对象</p><p>2.与工厂模式的实现不同，原型模式是先创建好一个原型对象，然后通过clone原型对象来创建新的对象。这样就免去了类创建时重复的初始化操作</p><p>3.原型模式适用于大对象的创建。创建一个大对象需要很大的开销，如果每次new就会消耗很大，原型模式内存拷贝即可</p></blockquote><blockquote style="white-space: normal;"><p>Canvas.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Canvas&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;...
}</pre><p style="white-space: normal;">index.php将实例化Canvas类以实现图像绘制，并使用关键字clone实现原型模式：<br/></p><blockquote style="white-space: normal;"><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$prototype&nbsp;=&nbsp;new&nbsp;Canvas();
$prototype-&gt;init();

//&nbsp;原型模式的实现
$canvas1&nbsp;=&nbsp;clone&nbsp;$prototype;
$canvas2&nbsp;=&nbsp;clone&nbsp;$prototype;

$canvas1-&gt;rect(1,2,3,4);
$canvas1-&gt;draw();
$canvas2-&gt;rect(5,6,7,8);
$canvas2-&gt;draw();</pre><p style="white-space: normal;"><strong><a name="6"></a>装饰器模式</strong></p><blockquote><p>1.装饰器模式（Decorator），可以动态地添加修改类的功能</p><p>2.一个类提供了一项功能，如果要在修改并添加额外的功能，传统的编程模式，需要写一个子类继承它，并重新实现类的方法</p><p>3.使用装饰器模式，仅需要在运行时添加一个装饰器对象即可实现，可以实现最大的灵活性</p></blockquote><blockquote><p>DrawDecorator.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
interface&nbsp;DrawDecorator&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;beforeDraw();
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;afterDraw();
}</pre><p style="white-space: normal;">DrawDecorator.php定义了装饰器的接口，将会在装饰器类中用到。</p><blockquote style="white-space: normal;"><p>Canvas.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Canvas&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$decorator&nbsp;=&nbsp;array();

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;draw()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;装饰器模式实现点
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;beforeDraw();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;afterDraw();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;addDecorator(DrawDecorator&nbsp;$decorator)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;decorators[]&nbsp;=&nbsp;$decorator;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;beforeDraw()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach($this-&gt;decorators&nbsp;as&nbsp;$decorator)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$decorator-&gt;beforeDraw();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;fucntion&nbsp;afterDraw()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$decorators&nbsp;=&nbsp;array_reverse($this-&gt;decorators);&nbsp;//&nbsp;反转，后进先出
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach($decorators&nbsp;as&nbsp;$decorator)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$decorator-&gt;afterDraw();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote style="white-space: normal;"><p>ColorDrawDecorator.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
//&nbsp;第一个装饰器：颜色装饰器
class&nbsp;ColorDrawDecortor&nbsp;implements&nbsp;DrawDecorator&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;beforeDraw()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;afterDraw()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p style="white-space: normal;"><strong><a name="7"></a>迭代器模式</strong></p><blockquote><p>1.迭代器模式，在不需要了解内部实现的前提下，遍历一个聚合对象的内部元素</p><p>2.相比于传统的编程模式，迭代器模式可以隐藏遍历元素所需的操作</p></blockquote><blockquote style="white-space: normal;"><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$users&nbsp;=&nbsp;new&nbsp;AllUser();
foreach($users&nbsp;as&nbsp;$user)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;var_dump($user);
}</pre><p style="white-space: normal;">迭代器的实现：</p><blockquote style="white-space: normal;"><p>AllUser.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$canvas1&nbsp;=&nbsp;new&nbsp;Canvas();
$canvas1-&gt;init();
$canvas1-&gt;addDecorator(new&nbsp;ColorDrawDecortor());&nbsp;//&nbsp;添加装饰器
$canvas1-&gt;draw();</pre><p style="white-space: normal;">这样来使用：</p><blockquote style="white-space: normal;"><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;AllUser&nbsp;implements&nbsp;\Iterator&nbsp;{

&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$ids;
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$data&nbsp;=&nbsp;array();
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$index;

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;__construct()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db&nbsp;=&nbsp;Factory::getDatabase();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$result&nbsp;=&nbsp;$db-&gt;query(&#39;select&nbsp;id&nbsp;from&nbsp;user&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;ids&nbsp;=&nbsp;$result-&gt;fetch_all(MUSQLI_ASSOC);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;current()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$id&nbsp;=&nbsp;$this-&gt;ids[$this-&gt;index][&#39;id&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Factory::getUser($id);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;next()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;index&nbsp;++;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;valid()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this-&gt;id&nbsp;&lt;&nbsp;count($this-&gt;ids);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;rewind()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;index&nbsp;=&nbsp;0;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;key()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this-&gt;index;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;
}</pre><p style="white-space: normal;"><strong><a name="8"></a>代理模式</strong></p><blockquote><p style="white-space: normal;">1.在客户端与实体之间建立一个代理对象（proxy），客户端对实体进行操作全部委派给代理对象，隐藏实体的具体实现细节</p><p>2.Proxy还可以与业务代码分离，部署到另外的服务器，业务代码中通过RPC来委派任务</p></blockquote><blockquote style="white-space: normal;"><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">$proxy&nbsp;=&nbsp;new&nbsp;Proxy();
$proxy-&gt;getUserName();
$proxy-&gt;setUserName($id,&nbsp;$proxy);</pre><blockquote style="white-space: normal;"><p>Proxy.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Procy&nbsp;implemets&nbsp;IUserProxy&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;getUserName($id)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db&nbsp;=&nbsp;Factory::getDatabase(&#39;slave&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db-&gt;query(&#39;select&nbsp;name&nbsp;from&nbsp;user&nbsp;where&nbsp;id&nbsp;=&nbsp;1&nbsp;limit&nbsp;1&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;setUserName($id,&nbsp;$name)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db1&nbsp;=&nbsp;Factory::getDatabase(&#39;master&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db-&gt;query(&#39;update&nbsp;user&nbsp;name&nbsp;=&nbsp;$name&nbsp;from&nbsp;user&nbsp;where&nbsp;id&nbsp;=&nbsp;1&nbsp;limit&nbsp;1&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote style="white-space: normal;"><p>IUserProxy.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
interface&nbsp;IUserName&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;getUserName($id);
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;setUserName($id,&nbsp;$name);
}</pre>]]></content>
  </entry>
  <entry>
    <title>PHP面向对象编程的基本原则，以及三种基本设计模式</title>
    <link href="https://old-blog.smallyu.net/index7df0.html?id=41"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=41</id>
    <published>2017-01-23T16:00:00.000Z</published>
    <updated>2017-01-23T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>面向对象编程的基本原则 1.单一职责：一个类，只需要做好一件事情 2.开放封闭：一个类，应该是可扩展的，而不可修改的 3.依赖倒置：一个类，不应该强依赖另一个类。每个类对于另外一个类都是可替换的 4.配置化：尽可能地使用配置，而不是硬编码 5.面向接口编程：只需要关心接口，不需要关心实现 PSR-0命名规范 1. 命名空间必须与绝对路径一致 2. 类名首字母...</p>]]></summary>
    <content type="html"><![CDATA[<p><strong>面向对象编程的基本原则</strong><br/></p><blockquote style="white-space: normal;"><p>1.单一职责：一个类，只需要做好一件事情</p><p>2.开放封闭：一个类，应该是可扩展的，而不可修改的</p><p>3.依赖倒置：一个类，不应该强依赖另一个类。每个类对于另外一个类都是可替换的</p><p>4.配置化：尽可能地使用配置，而不是硬编码</p><p>5.面向接口编程：只需要关心接口，不需要关心实现</p></blockquote><p style="white-space: normal;"><strong>PSR-0命名规范</strong></p><blockquote><p style="white-space: normal;">1. 命名空间必须与绝对路径一致</p><p style="white-space: normal;">2. 类名首字母必须大写<br/>3. 除入口文件外，其他“.php”必须只有一个类</p></blockquote><p style="white-space: normal;"><strong>开发符合PSR-0规范的基础框架</strong></p><blockquote><p style="white-space: normal;">1. 全部使用明明空间<br/>2. 所有PHP文件必须自动载入，不能有include/require<br/>3. 单一入口</p></blockquote><p><strong>类的自动载入</strong></p><blockquote><p>Test1.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

class&nbsp;Test1{

&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;function&nbsp;test(){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;__METHOD__;

&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>Test2.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

class&nbsp;Test2{

&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;function&nbsp;test(){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;__METHOD__;

&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><blockquote><p>test.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

spl_autoload_register(&#39;autoload1&#39;);

spl_autoload_register(&#39;autoload2&#39;);

function&nbsp;autoload1($class){

&nbsp;&nbsp;&nbsp;&nbsp;require&nbsp;__DIR__.&#39;/&#39;.$class.&#39;.php&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;
}

function&nbsp;autoload2($class){

&nbsp;&nbsp;&nbsp;&nbsp;require&nbsp;__DIR__.&#39;/&#39;.$class.&#39;.php&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;
}

Test1::test();

Test2::test();</pre><p>&nbsp;运行test.php会得到这样的结果：</p><pre class="prism-highlight prism-language-php">Test1::testTest2::test</pre><p>__autoload()函数只可以存在一个，如果重复定义会报致命错误，所以目前一般使用spl_autoload_regisiter()来实现类的自动加载。</p><p><strong>PHP链式调用的实现</strong></p><blockquote><p>Database.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

class&nbsp;Database{

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;where($where){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;order($order){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;limit($limit){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...

&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><p>如果Database.php是这样，那么在index.php中就需要这样来写以实现sql查询：</p><blockquote><p>index.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

$db=new&nbsp;Database();

$db-&gt;where(&quot;id=2&quot;);

$db-&gt;where(&quot;name=2&quot;);

$db-&gt;order(&quot;id&nbsp;desc&quot;);

$db-&gt;limit(10);</pre><p>&nbsp;要实现链式调用只需要这样做：</p><blockquote><p>Database.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

class&nbsp;Database{

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;where($where){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this;

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;order($order){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this;

&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;limit($limit){

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this;

&nbsp;&nbsp;&nbsp;&nbsp;}

}</pre><p>在每个方法的末尾加上&#39;return $this;&#39;，然后就可以：</p><blockquote><p>Data</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php

$db-&gt;where(&quot;id=1&quot;)-&gt;where(&quot;name=2&quot;)-&gt;order(&quot;id&nbsp;desc&quot;)-&gt;limit(10);</pre><p>三种基础的设计模式包括工厂模式、单例模式和注册器模式。</p><p style="white-space: normal;"><strong>工厂模式</strong></p><blockquote style="white-space: normal;"><p>Factory.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Factory{
&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;function&nbsp;createDatabase(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$db&nbsp;=&nbsp;new&nbsp;Database();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$db;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
$db&nbsp;=&nbsp;Factory::createDatabase();</pre><p style="white-space: normal;">工厂模式的作用在于不在类外实例化对象。</p><p style="white-space: normal;"><strong>单例模式</strong></p><blockquote style="white-space: normal;"><p>Database.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Database{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$db;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;第一步
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;__construct(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;private可以屏蔽外部new这个类
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;第二步
&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;function&nbsp;getInstance(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(self::$db){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::$db;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::$db&nbsp;=&nbsp;new&nbsp;self();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::$db;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
}
$db&nbsp;=&nbsp;Database::getInstance();</pre><p style="white-space: normal;">单例模式用于数据库连接等只需要一个对象的场景，避免资源的浪费。</p><p style="white-space: normal;"><strong>注册器模式</strong></p><blockquote style="white-space: normal;"><p>Register.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
class&nbsp;Register{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;static&nbsp;$objects;
&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;function&nbsp;set($name,&nbsp;$object){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self::objects[$name]&nbsp;=&nbsp;$object;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;function&nbsp;get($name){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;self::objects[$name];
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;function&nbsp;_unset($name){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unset(self::objects[$name]);
&nbsp;&nbsp;&nbsp;&nbsp;}
}
Register::set(&#39;db1&#39;,$db);
$db&nbsp;=&nbsp;Register::get(&#39;$db1&#39;);</pre><p style="white-space: normal;"><strong>适配器模式</strong></p><blockquote><p style="white-space: normal;">1.适配器模式，可以将截然不同的函数接口封装成统一的API</p><p style="white-space: normal;">2.实际应用举例，PHP的数据库操作有mysql,musqli,pdo三种，可以用适配器模式统一成一致。类似的场景还有cache适配器，将memcache，redis，file，apc等不同的缓存函数，统一成一致</p></blockquote><blockquote style="white-space: normal;"><p>Database.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
interdace&nbsp;IDatabase{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname);
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;query($sql);
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;close();
}</pre><p style="white-space: normal;">在Database.php中定义了数据库操作的接口，接下来将MySQL、MySQLi、PDO三种数据库操作适配为接口中定义的方法。</p><blockquote style="white-space: normal;"><p>MySQL.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
namespace&nbsp;Database;
class&nbsp;MySQL&nbsp;implements&nbsp;IDatabase{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$conn&nbsp;=&nbsp;mysql_connect($host,&nbsp;$user,&nbsp;$passwd);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql_select_db($dbname,&nbsp;$conn);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this-&gt;conn&nbsp;=&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;query($sql){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$res&nbsp;=&nbsp;mysql_query($sql,&nbsp;$this-&gt;conn);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$res;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;close(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql_close($this-&gt;conn);
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><blockquote style="white-space: normal;"><p>MySQLi.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
namespace&nbsp;Database;
class&nbsp;MySQLi&nbsp;implements&nbsp;IDatabase{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$conn&nbsp;=&nbsp;mysqli_connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this-&gt;conn&nbsp;=&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;query($sql){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$res&nbsp;=&nbsp;mysqli_query($this-&gt;conn,&nbsp;$sql);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$res;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;close(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysqli_close($this-&gt;conn);
&nbsp;&nbsp;&nbsp;&nbsp;}</pre><blockquote style="white-space: normal;"><p>PDO.php</p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
namespace&nbsp;Database;
class&nbsp;PDO&nbsp;implements&nbsp;IDatabase{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;connect($host,&nbsp;$user,&nbsp;$passwd,&nbsp;$dbname){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;\PDO(&quot;mysql:host=$host;dbname=$dbname&quot;,&nbsp;$user,&nbsp;$passwd);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;conn&nbsp;=&nbsp;$conn;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;query($sql){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this-&gt;conn-&gt;query($sql);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;close(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unset($this-&gt;conn);
&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p style="white-space: normal;">然后在应用中可以这样使用：</p><blockquote style="white-space: normal;"><p>index.php<br/></p></blockquote><pre class="prism-highlight prism-language-php">&lt;?php
$db&nbsp;=&nbsp;new&nbsp;Database\MySQL();
$db-&gt;connect(&#39;localhost&#39;,&nbsp;&#39;root&#39;,&nbsp;&#39;root&#39;,&nbsp;&#39;test&#39;);
$db-&gt;query(&#39;show&nbsp;database&#39;);
$db-&gt;close();</pre><p style="white-space: normal;">或者实例化其他类型的数据库，只需要使用同一种标准。</p>]]></content>
  </entry>
  <entry>
    <title>一个简单的验证码生成类（PHP）</title>
    <link href="https://old-blog.smallyu.net/indexab5e.html?id=40"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=40</id>
    <published>2017-01-16T16:00:00.000Z</published>
    <updated>2017-01-16T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>可配置项： /** * $_fontfile=&amp;#39;&amp;#39;; // 字体文件 * $_size=20; // 字体大小 * $_width=120; // 画布宽度 * $_height=40; // 画布高度 * $_length=4; // 验证码长度 * $_image=null; // 画布资源 * // 干扰元素 * $_snow=0; /...</p>]]></summary>
    <content type="html"><![CDATA[<p>可配置项：<br/></p><pre class="prism-highlight prism-language-php">/**
&nbsp;*&nbsp;$_fontfile=&#39;&#39;;&nbsp;//&nbsp;字体文件
&nbsp;*&nbsp;$_size=20;&nbsp;//&nbsp;字体大小
&nbsp;*&nbsp;$_width=120;&nbsp;//&nbsp;画布宽度
&nbsp;*&nbsp;$_height=40;&nbsp;//&nbsp;画布高度
&nbsp;*&nbsp;$_length=4;&nbsp;//&nbsp;验证码长度
&nbsp;*&nbsp;$_image=null;&nbsp;//&nbsp;画布资源
&nbsp;*&nbsp;//&nbsp;干扰元素&nbsp;
&nbsp;*&nbsp;$_snow=0;&nbsp;//&nbsp;雪花个数
&nbsp;*&nbsp;$_pixel=0;&nbsp;//&nbsp;像素个数
&nbsp;*&nbsp;$_line=0;&nbsp;//&nbsp;线段个数
&nbsp;*/</pre><p>其中字体文件路径必须配置。</p><blockquote><p><span style="text-decoration: underline;">Captcha.class.php</span><br/></p></blockquote><pre class="prism-highlight prism-language-php">Class&nbsp;Captcha{
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;字体文件
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_fontfile=&#39;&#39;;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;字体大小
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_size=20;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;画布宽度
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_width=120;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;画布高度
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_height=40;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;验证码长度
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_length=4;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;画布资源
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_image=null;
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;干扰元素&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;雪花个数
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_snow=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;像素个数
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_pixel=0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;线段个数
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;$_line=0;
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;初始化数据
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;array&nbsp;$config&nbsp;[description]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;__construct($config=array()){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(is_array($config)&amp;&amp;count($config)&gt;0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;检测字体文件是否存在并且可读
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset($config[&#39;fontfile&#39;])&amp;&amp;is_file($config[&#39;fontfile&#39;])&amp;&amp;is_readable($config[&#39;fontfile&#39;])){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_fontfile=$config[&#39;fontfile&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;检测是否设置字体大小
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset($config[&#39;size&#39;])&amp;&amp;$config[&#39;size&#39;]&gt;0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_size=(int)$config[&#39;size&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;检测是否设置画布宽和高
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset($config[&#39;width&#39;])&amp;&amp;$config[&#39;width&#39;]&gt;0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_width=(int)$config[&#39;width&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset($config[&#39;height&#39;])&amp;&amp;$config[&#39;height&#39;]&gt;0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_height=(int)$config[&#39;height&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;检测是否设置验证码长度
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset($config[&#39;length&#39;])&amp;&amp;$config[&#39;length&#39;]&gt;0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_length=(int)$config[&#39;length&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;配置干扰元素
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset($config[&#39;snow&#39;])&amp;&amp;$config[&#39;snow&#39;]&gt;0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_snow=(int)$config[&#39;snow&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset($config[&#39;pixel&#39;])&amp;&amp;$config[&#39;pixel&#39;]&gt;0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_pixel=(int)$config[&#39;pixel&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset($config[&#39;line&#39;])&amp;&amp;$config[&#39;line&#39;]&gt;0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_line=(int)$config[&#39;line&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_image=imagecreatetruecolor($this-&gt;_width,&nbsp;$this-&gt;_height);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$this-&gt;_image;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;得到验证码
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;[type]&nbsp;[description]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;getCaptcha(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$white=imagecolorallocate($this-&gt;_image,&nbsp;255,&nbsp;255,&nbsp;255);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;填充矩形
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imagefilledrectangle($this-&gt;_image,&nbsp;0,&nbsp;0,&nbsp;$this-&gt;_width,&nbsp;$this-&gt;_height,&nbsp;$white);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;生成验证码
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$str=$this-&gt;_generateStr($this-&gt;_length);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(false==$str){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fontfile=$this-&gt;_fontfile;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;绘制验证码
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($i=0;$i&lt;$this-&gt;_length;$i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$size=$this-&gt;_size;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$angle=mt_rand(-30,30);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$x=ceil($this-&gt;_width/$this-&gt;_length)*$i+mt_rand(5,10);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$y=ceil($this-&gt;_height/1.5);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$color=$this-&gt;_getRandColor();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;$text=mb_substr($str,$i,1,&#39;utf-8&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$text=$str{$i};
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imagettftext($this-&gt;_image,&nbsp;$size,&nbsp;$angle,&nbsp;$x,&nbsp;$y,&nbsp;$color,&nbsp;$fontfile,&nbsp;$text);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($this-&gt;_snow){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;使用雪花当做干扰元素
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_getSnow();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($this-&gt;_pixel){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_getPixel();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($this-&gt;_line){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;_getLine();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;输出图像
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ob_clean();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;header(&#39;content-type:image/png&#39;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imagepng($this-&gt;_image);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imagedestroy($this-&gt;_image);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;strtolower($str);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;产生雪花
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;[type]&nbsp;[description]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;_getSnow(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($i=1;$i&lt;=$this-&gt;_snow;$i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imagestring($this-&gt;_image,&nbsp;mt_rand(1,5),&nbsp;mt_rand(0,$this-&gt;_width),&nbsp;mt_rand(0,$this-&gt;_height),&nbsp;&#39;*&#39;,&nbsp;$this-&gt;_getRandColor());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;绘制像素
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;[type]&nbsp;[description]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;_getPixel(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($i=1;$i&lt;=$this-&gt;_pixel;$i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imagesetpixel($this-&gt;_image,&nbsp;mt_rand(0,$this-&gt;_width),&nbsp;mt_rand(0,$this-&gt;_height),&nbsp;$this-&gt;_getRandColor());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;绘制线段
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;[type]&nbsp;[description]
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;_getLine(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for($i=1;$i&lt;=$this-&gt;_line;$i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imageline($this-&gt;_image,&nbsp;mt_rand(0,$this-&gt;_width),&nbsp;mt_rand(0,$this-&gt;_height),&nbsp;mt_rand(0,$this-&gt;_width),&nbsp;mt_rand(0,$this-&gt;_height),&nbsp;$this-&gt;_getRandColor());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;产生验证码字符
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;&nbsp;integer&nbsp;$length&nbsp;验证码长度
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;随机字符
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;_generateStr($length=4){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if($length&lt;1||$length&gt;30){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$chars=array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;a&#39;,&#39;b&#39;,&#39;c&#39;,&#39;d&#39;,&#39;e&#39;,&#39;f&#39;,&#39;g&#39;,&#39;h&#39;,&#39;k&#39;,&#39;m&#39;,&#39;n&#39;,&#39;p&#39;,&#39;x&#39;,&#39;y&#39;,&#39;z&#39;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;A&#39;,&#39;B&#39;,&#39;C&#39;,&#39;D&#39;,&#39;E&#39;,&#39;F&#39;,&#39;G&#39;,&#39;H&#39;,&#39;K&#39;,&#39;M&#39;,&#39;N&#39;,&#39;P&#39;,&#39;X&#39;,&#39;Y&#39;,&#39;Z&#39;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;2&#39;,&#39;3&#39;,&#39;4&#39;,&#39;5&#39;,&#39;6&#39;,&#39;7&#39;,&#39;8&#39;,&#39;9&#39;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$str=join(&#39;&#39;,array_rand(array_flip($chars),$length));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;$str;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;_getRandColor(){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;imagecolorallocate($this-&gt;_image,&nbsp;mt_rand(0,255),&nbsp;mt_rand(0,255),&nbsp;mt_rand(0,255));
&nbsp;&nbsp;&nbsp;&nbsp;}
}</pre><p>然后在应用中使用这个类：</p><blockquote><p>captcha.php</p></blockquote><pre class="prism-highlight prism-language-php">require&nbsp;&#39;Captcha.class.php&#39;;
ob_clean();
$config=array(
&nbsp;&nbsp;&nbsp;&nbsp;&#39;fontfile&#39;=&gt;&#39;INFROMAN.TTF&#39;,
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&#39;snow&#39;=&gt;10,
&nbsp;&nbsp;&nbsp;&nbsp;&#39;pixel&#39;=&gt;100,
&nbsp;&nbsp;&nbsp;&nbsp;&#39;line&#39;=&gt;5
&nbsp;&nbsp;&nbsp;&nbsp;);
$captcha=new&nbsp;Captcha($config);
$captcha-&gt;getCaptcha();</pre><p>就可以生成类似这样的验证码：<br/></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/01/201701171484646995847698.png" style="" title="2.png"/></p><p>或者：</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2017/01/201701171484646997834282.png" style="" title="1.png"/></p><p>getCaptcha()会以字符串的形式返回验证码的值。</p><p>比较简单的一种验证码，用了PHP的扩展GD库。</p>]]></content>
  </entry>
  <entry>
    <title>2016下半年年度总结，2017上半年年度展望</title>
    <link href="https://old-blog.smallyu.net/index1e35.html?id=39"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=39</id>
    <published>2017-01-07T16:00:00.000Z</published>
    <updated>2017-01-07T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>为什么面朝大海，就站成了大海？因为有人在心里面浮沉啊。 2016下半年年度总结： （某个人的名字） （某个人的名字） （某个人的名字） …… 好吧总结可以结束了。 2017上半年年度展望： 注定平凡。 …… 好吧展望可以结束了。 &amp;lt;&amp;lt;&amp;lt;(2017.1.17) 水了好久都有点开始怀疑人生了。 2016年确实过得一塌糊涂。上半年过去都不知道过去...</p>]]></summary>
    <content type="html"><![CDATA[<p>为什么面朝大海，就站成了大海？因为有人在心里面浮沉啊。<br/></p><p><br/></p><p>2016下半年年度总结：</p><p>&nbsp;&nbsp;&nbsp;&nbsp;（某个人的名字）<br/></p><p>&nbsp;&nbsp;&nbsp;&nbsp;（某个人的名字）<br/></p><p>&nbsp; &nbsp; （某个人的名字）</p><p>&nbsp;&nbsp;&nbsp;&nbsp;……<br/></p><p>好吧总结可以结束了。</p><p><br/></p><p>2017上半年年度展望：</p><p>&nbsp;&nbsp;&nbsp;&nbsp;注定平凡。<br/></p><p>&nbsp;&nbsp;&nbsp;&nbsp;……<br/></p><p>好吧展望可以结束了。</p><p><br/></p><p><em>&lt;&lt;&lt;(2017.1.17)</em></p><p>水了好久都有点开始怀疑人生了。</p><p>2016年确实过得一塌糊涂。上半年过去都不知道过去了。下半年，四级四级考不过，期末期末没考好。我都干了些什么？</p><p><em>(2017.1.17);</em></p><p><em><br/></em></p><p><em><em style="white-space: normal;">&lt;&lt;&lt;(2017.2.10)</em></em></p><p>明天是正月十五了，什么节日来着？</p><p>啊，最近在写singcms。</p><p><em><em style="white-space: normal;"><em style="white-space: normal;">(2017.1.20);</em></em></em></p><p><br/></p><p><em style="white-space: normal;">&lt;&lt;&lt;(2017.3.3)</em></p><p>时过境迁。</p><p><em style="white-space: normal;"><em style="white-space: normal;">(2017.1.3.3);</em></em></p>]]></content>
  </entry>
  <entry>
    <title>春宵苦短日高起，不来</title>
    <link href="https://old-blog.smallyu.net/indexcdef.html?id=38"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=38</id>
    <published>2016-12-16T16:00:00.000Z</published>
    <updated>2016-12-16T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>标题来自知乎。 这个东西，折磨了我几个月。 刷完，大概粗略算了一下正确率： 拍照环境不好，也没必要对图片做什么高大上的处理。这种黑乎乎的照片，放在洁白的网页上真的真的会影响美观，但真的真的就不处理了，也可能我不会。图片就是事实，而已。 图片不清楚，并不影响看到图片上写着的大大的最终结果： 39.52% 图片本身不小，有1M。确实像素低可能看不清。上面的所有数...</p>]]></summary>
    <content type="html"><![CDATA[<p>标题来自知乎。</p><p>这个东西，折磨了我几个月。</p><p style="text-align:center"><img src="https://old-blog.smallyu.net/zb_users/upload/2016/12/201612171481983159491799.png" title="搜狗截图20161217215720.png" alt="搜狗截图20161217215720.png" width="219" height="311" style="width: 219px; height: 311px;"/></p><p>刷完，大概粗略算了一下正确率：</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/12/201612171481982785428410.jpg" title="IMG_20161214_102021.jpg" width="536" height="315" border="0" vspace="0" alt="IMG_20161214_102021.jpg" style="width: 536px; height: 315px;"/><br/></p><p>拍照环境不好，也没必要对图片做什么高大上的处理。这种黑乎乎的照片，放在洁白的网页上真的真的会影响美观，但真的真的就不处理了，也可能我不会。图片就是事实，而已。</p><p>图片不清楚，并不影响看到图片上写着的大大的最终结果：<strong>39.52%</strong></p><p>图片本身不小，有1M。确实像素低可能看不清。上面的所有数字都表示选择题的个数，除了旧型听力最后一题的十个听力填空。分母表示总数，分子表示正确的数量。总之，按照平均数的算法，正确率就是，残酷的39.52%。<br/></p><p>其实用平均数来表示正确率是有问题的，万一一不小心就有了那么一点点的进步呢？事实证明我想多了。</p><p>数据分析的话，拍照来的总归感觉不是很好，于是，就真的无聊地统计了一下，一共有三部分，第一部分是十套真题，除掉写作和翻译的，第二部分是长篇阅读专项，第三部分是新型听力专项。</p><p>这个是十套真题的统计：</p><table height="228"><colgroup><col width="72"/><col width="111"/><col width="109"/><col width="126"/><col width="125"/><col width="72"/></colgroup><tbody><tr height="19" class="firstRow"><td class="et2" colspan="6" x:str="" height="22" width="461" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">四级套题/10</span></td></tr><tr height="19"><td class="et2" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><br/></td><td class="et2" x:str="" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">听力/35</span></td><td class="et2" x:str="" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">选词填空/10</span></td><td class="et2" x:str="" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">长篇阅读/10</span></td><td class="et2" x:str="" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">仔细阅读/10</span></td><td class="et2" x:str="" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">总数</span></td></tr><tr height="19"><td class="et2" x:num="1" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">1</span></td><td class="et2" x:num="8" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">8</span></td><td class="et2" x:num="1" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">1</span></td><td class="et2" x:num="5" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">5</span></td><td class="et2" x:num="3" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">3</span></td><td class="et2" x:num="17" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">17</span></td></tr><tr height="19"><td class="et2" x:num="2" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">2</span></td><td class="et2" x:num="9" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">9</span></td><td class="et2" x:num="6" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">6</span></td><td class="et2" x:num="5" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">5</span></td><td class="et2" x:num="3" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">3</span></td><td class="et2" x:num="23" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">23</span></td></tr><tr height="19"><td class="et2" x:num="3" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">3</span></td><td class="et2" x:num="10" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">10</span></td><td class="et2" x:num="5" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">5</span></td><td class="et2" x:num="6" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">6</span></td><td class="et2" x:num="7" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">7</span></td><td class="et2" x:num="28" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">28</span></td></tr><tr height="19"><td class="et2" x:num="4" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">4</span></td><td class="et2" x:num="15" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">15</span></td><td class="et2" x:num="4" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">4</span></td><td class="et2" x:num="7" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">7</span></td><td class="et2" x:num="5" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">5</span></td><td class="et2" x:num="31" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">31</span></td></tr><tr height="19"><td class="et2" x:num="5" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">5</span></td><td class="et2" x:num="10" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">10</span></td><td class="et2" x:num="7" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">7</span></td><td class="et2" x:num="5" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">5</span></td><td class="et2" x:num="5" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">5</span></td><td class="et2" x:num="27" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">27</span></td></tr><tr height="19"><td class="et2" x:num="6" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">6</span></td><td class="et2" x:num="10" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">10</span></td><td class="et2" x:num="1" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">1</span></td><td class="et2" x:num="1" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">1</span></td><td class="et2" x:num="8" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">8</span></td><td class="et2" x:num="20" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">20</span></td></tr><tr height="19"><td class="et2" x:num="7" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">7</span></td><td class="et2" x:num="9" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">9</span></td><td class="et2" x:num="4" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">4</span></td><td class="et2" x:num="6" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">6</span></td><td class="et2" x:num="7" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">7</span></td><td class="et2" x:num="26" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">26</span></td></tr><tr height="19"><td class="et2" x:num="8" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">8</span></td><td class="et2" x:num="10" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">10</span></td><td class="et2" x:num="6" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">6</span></td><td class="et2" x:num="4" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">4</span></td><td class="et2" x:num="6" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">6</span></td><td class="et2" x:num="26" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">26</span></td></tr><tr height="19"><td class="et2" x:num="9" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">9</span></td><td class="et2" x:num="10" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">10</span></td><td class="et2" x:num="4" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">4</span></td><td class="et2" x:num="3" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">3</span></td><td class="et2" x:num="4" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">4</span></td><td class="et2" x:num="21" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle; word-break: break-all;"><span style="font-size: 14px;">21</span></td></tr><tr height="19"><td class="et2" x:num="10" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">10</span></td><td class="et2" x:num="12" height="14" width="83" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">12</span></td><td class="et2" x:num="1" height="14" width="81" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">1</span></td><td class="et2" x:num="4" height="14" width="69" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">4</span></td><td class="et2" x:num="6" height="14" width="120" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">6</span></td><td class="et2" x:num="23" height="14" width="63" style="font-size: 11pt; text-align: center; vertical-align: middle;"><span style="font-size: 14px;">23</span></td></tr></tbody></table><p>这个是长篇阅读专项的统计：</p><table height="57"><colgroup><col width="72"/><col width="72"/><col width="72"/><col width="72"/><col width="72"/><col width="72"/></colgroup><tbody><tr height="19" class="firstRow"><td class="et2" colspan="6" x:str="" height="14" width="324" style="font-size: 11pt; text-align: center; vertical-align: middle;">长篇阅读专项</td></tr><tr height="19"><td class="et2" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;"><br/></td><td class="et2" x:num="1" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">1</td><td class="et2" x:num="2" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">2</td><td class="et2" x:num="3" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">3</td><td class="et2" x:num="4" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">4</td><td class="et2" x:num="5" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">5</td></tr><tr height="19"><td class="et2" x:str="" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">数值/10</td><td class="et2" x:num="7" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">7</td><td class="et2" x:num="8" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">8</td><td class="et2" x:num="7" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">7</td><td class="et2" x:num="7" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">7</td><td class="et2" x:num="6" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">6</td></tr></tbody></table><p>这个是新型听力的专项：</p><table height="57"><colgroup><col width="72"/><col width="72"/><col width="72"/><col width="72"/><col width="72"/><col width="72"/></colgroup><tbody><tr height="19" class="firstRow"><td class="et2" colspan="6" x:str="" height="14" width="324" style="font-size: 11pt; text-align: center; vertical-align: middle;">新型听力专项</td></tr><tr height="19"><td class="et2" height="14" width="59" style="font-size: 11pt; text-align: center; vertical-align: middle;"><br/></td><td class="et2" x:num="1" height="14" width="49" style="font-size: 11pt; text-align: center; vertical-align: middle;">1</td><td class="et2" x:num="2" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">2</td><td class="et2" x:num="3" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">3</td><td class="et2" x:num="4" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">4</td><td class="et2" x:num="5" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">5</td></tr><tr height="19"><td class="et2" x:str="" height="14" width="59" style="font-size: 11pt; text-align: center; vertical-align: middle;">数值/25</td><td class="et2" x:num="10" height="14" width="49" style="font-size: 11pt; text-align: center; vertical-align: middle;">10</td><td class="et2" x:num="9" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">9</td><td class="et2" x:num="9" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">9</td><td class="et2" x:num="12" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">12</td><td class="et2" x:num="8" height="14" width="54" style="font-size: 11pt; text-align: center; vertical-align: middle;">8</td></tr></tbody></table><p>只看表格好像没什么感觉，那就把它变成折线图。两个专项是在四级考前的后半段时间做的，时间上和套题的后半段比较接近。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/12/201612171481985096527211.png" title="图片10.png" style="white-space: normal;"/></p><p>先是听力。默认没有图表标题，因为有两条线，就懒得手动改了。新型听力比旧型听力少十道题，所以可以看到，有没有那十道题正确的总量是差不多的，说明那十道题本来就几乎对不了几个啊。</p><p><br/></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/12/201612171481984076134040.png" style="" title="图片2.png"/></p><p>然后是选词填空，就是十五选十，波动比较大，应该是看懂了就对得多，看不懂就对的少。所以这个图表没有任何价值。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/12/201612171481985096850007.png" style="" title="图片9.png"/></p><p>这个也没有图表标题，这个是长篇阅读。可以看到，专项的正确率远超套题的，然而做它们的时间差不多，说明，我没认真做啊。专项用的时间比较多一点。还有可能专项的题简单一点，毕竟不是真题。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/12/201612171481984076688729.png" style="" title="图片4.png"/></p><p>仔细阅读，精读，总体来说还是稍微有那么一点点进步的看样子。</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/12/201612171481984076488149.png" style="" title="图片5.png"/></p><p>最后这个是正确量的总数。整体来看，最后一次做的和第一次做的没什么差别。没有有体现出上升或者下降。也就是说，这两个半月来，我只是简单地做到了没有退步……</p><p>至于四级考试。</p><p>对啊，今天刚考的，上午9点。考前心情异常沉重。估计有生以来还没有哪次考试是明知道自己不会过但还必须得认真复习认真考试的。</p><p>然后就炸了。<br/></p><p>按39.52%的正确率来算，710 * 0.3952 = 280.592.</p><p>严肃地说，根据我多年考试的经验以及对我自己的了解，按照最好的情况来算，710的总分，我会考差不多400分。详情如下：</p><blockquote><p>短文写作 &nbsp; &nbsp;106.5 * 0.5 = 53.25</p><p>听力 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 248.5 * 0.5 = 124.25</p><p>选词填空 &nbsp; &nbsp;35.5 * 0.8 &nbsp; = 28.4</p><p>长篇阅读 &nbsp; &nbsp;71 * 0.6 &nbsp; &nbsp; &nbsp;= 42.6</p><p>仔细阅读 &nbsp; &nbsp;142 * 0.7 &nbsp; &nbsp;= 99.4</p><p>翻译 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 106.5 * 0.5 = 53.25</p><p>53.25 + 124.25 + 28.4 + 42.6 + 99.4 + 53.25 = 401.15</p></blockquote><p>401.15，差不多400。但是，这估计已经是最最好的情况下的数字。当然，425才会pass，差一大截。</p><p>计算的时候的比例都要超过平时练习时候真确率的比例，一方面因为考试会比较认真，另一方面。</p><p>实在不能接受不到300分的英语四级成绩啊。</p><p>嗯，过的希望是很渺茫的。</p><p>嗯。</p><p>一个月以后，看我估计的对不对。</p><p>然后对四级想说的也真的不只是这些啊。</p><p><br/></p><p><em>&lt;&lt;&lt;(2016.2.21)</em></p><p>cet4成绩明天出，等待一个会令人失望但仍然抱有一丝丝点侥幸希望的心情，还是不要不要的~</p><p><em><span style="text-decoration: none;">(2016.2.21);</span></em></p><p><em><span style="text-decoration: none;"><br/></span></em></p><p><em><span style="text-decoration: none;">&lt;&lt;&lt;(<em style="white-space: normal;">2016.2.22</em>)</span></em></p><p><span style="text-decoration: none;">估的，高了……</span><em><span style="text-decoration: none;"><br/></span></em></p><p><em><span style="text-decoration: none;">(<em style="white-space: normal;">2016.2.22</em>);</span></em></p>]]></content>
  </entry>
  <entry>
    <title>生命不息，折腾不止——hexo并不好玩</title>
    <link href="https://old-blog.smallyu.net/index4411.html?id=37"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=37</id>
    <published>2016-11-17T16:00:00.000Z</published>
    <updated>2016-11-17T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>双十一妥妥地过去了。 对于一只无聊的野生单身汪来说，这样的节日确实，无聊。于是尝试了一下看起来13格很高的github+hexo博客。 可能时间隔得稍微有点长，双十一不是早就过去了么。。。 阮一峰在博客里这么写： 喜欢写Blog的人，会经历三个阶段。 第一阶段，刚接触Blog，觉得很新鲜，试着选择一个免费空间来写。 第二阶段，发现免费空间限制太多，就自己购买...</p>]]></summary>
    <content type="html"><![CDATA[<p>双十一妥妥地过去了。</p><p>对于一只无聊的野生单身汪来说，这样的节日确实，无聊。于是尝试了一下看起来13格很高的github+hexo博客。</p><p>可能时间隔得稍微有点长，双十一不是早就过去了么。。。<br/></p><p>阮一峰在博客里这么写：<br/></p><blockquote><p>喜欢写Blog的人，会经历三个阶段。</p><p>　　第一阶段，刚接触Blog，觉得很新鲜，试着选择一个免费空间来写。</p><p>　　第二阶段，发现免费空间限制太多，就自己购买域名和空间，搭建独立博客。</p><p>　　第三阶段，觉得独立博客的管理太麻烦，最好在保留控制权的前提下，让别人来管，自己只负责写文章。</p></blockquote><p>我就高高兴兴地奔着第三个阶段去了。</p><p>后面留坑，如果可能的话就分享一下在用github搭建博客过程中遇到的问题以及解决方法。</p><p><em>&lt;&lt;&lt;(2016.11.19)-1</em></p><p>hexo是用node.js写的，github要用到git，所以首先要在电脑上安装这两样东西。</p><p>node.js: <a href="https://nodejs.org/" _src="https://nodejs.org/">https://nodejs.org/</a> </p><p>git:&nbsp;<a href="https://git-scm.com/" _src="https://git-scm.com/">https://git-scm.com/</a> </p><p>装好之后，多半需要配置环境变量</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/11/201611191479570009725656.png" title="搜狗截图20161119233943.png" alt="搜狗截图20161119233943.png"/></p><p>差不多这样，要配置git的和hexo的。<br/></p><p>应用的安装顺序是：</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>安装node.js</p></li><li><p>安装git</p></li><li><p>在git命令行中安装hexo</p></li></ol><p>环境变量的配置顺序是：</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>git的bin和git-core</p></li><li><p>（安装hexo）<br/></p></li><li><p>hexo<br/></p></li></ol><p>hexo是全局安装的，git命令行要用到的npm工具其实是node.js的，所以可以在node.js或者git的CMD中执行hexo的安装命令，都行（建议在node.js中，因为能成功）</p><pre class="prism-highlight prism-language-actionscript">npm&nbsp;install&nbsp;-g&nbsp;hexo-cli</pre><p>这里的意思是，node.js安装成功后就有CMD了，在这个CMD中始终可以使用npm。如果环境变量配置有问题，会发生git的CMD里npm出错的情况。<br/></p><p>安装hexo后要配置hexo的环境变量，所以说上面环境变量的配置不是一步完成的。</p><p>然后，，，</p><p>坑还是留着吧。</p><p>hexo: <a href="https://hexo.io/" _src="https://hexo.io/">https://hexo.io/</a>&nbsp;有完整的文档，英文的</p><p><em>(2016.11.19)-1;</em></p><p>后来发现对于在github上部署的博客，git的使用难于站点的搭建。<br/></p><p>因为hexo要配置域名才能正常使用，图方便前几天就把blog.how.gs这个域名解析过去了。不过最终，现在还是回来了。</p><p>同样原因，留坑……</p><p><em>&lt;&lt;&lt;(2016.11.19)-2</em></p><p>gthub搭建博客的缺点：</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>每次发布文章都需要重新部署站点</p></li><li><p>本地文件备份难</p></li><li><p>百度不收录</p></li><li><p>MarkDown真的好用？</p></li><li><p>附件管理</p></li></ol><p>第一个，我们常用的博客，每次发布文章只需要添加一条新的记录到数据库就好了。就像web开发中的Ajax。hexo是静态的博客框架。每一次新建文章，都需要执行clean命令清空数据库、缓存，然后执行g命令重新编译文件，生成博客内容，最后将public目录中的内容推到gtithub上。</p><p>这个过程稍微繁琐。如果拿ajax作类比，有异步数据交互的方法不用，非要每次都完全刷（部）新（署）网（网）页（站）吗？</p><p>如果博客内容非常多。百兆以下还将就，如果以上，每发布一篇文章都需要推那么数据上去呢。</p><p style="text-align:center"><em><img src="https://old-blog.smallyu.net/zb_users/upload/2016/11/201611191479556719301099.png" title="10无语wy.png" alt="10无语wy.png" width="133" height="144" style="width: 133px; height: 144px;"/></em></p><p>所以每次发布文章都需要部署站点是缺点。</p><p>第二个是是本地文件备份难。</p><p>比如多云转晴hower用的zblog，需要备份的数据有两部分，mysql中的配置数据和文件中的附件。</p><p>hexo的话需要备份的是当时选定的本地目录。这里的问题是原作者本意希望将hexo目录下的文件也都推送到git上面。可以前几天在尝试的时候，（由于能力不足）遇到一些不好解决的问题。在hexo推送文件的过程中会在本地生成隐藏的.git目录，包含一些git信息。然后在github提交hexo模板目录时，会因为git已经被管理提交失败。</p><p>每次都手动删掉？（麻烦。。）</p><p>或许可以尝试用onedrive把目录挂载到网盘上。</p><p>第三个，百度不收录。知乎上可以找到很好的解决办法，于是，我还是觉得独立博客好用。<br/></p><p>第四个，MarkDown会将内容解析成HTML，目的是提高可读性。这本身没什么问题，可猿们很多用sublime，换行不是像段落一样换行，是折行。当然这不是什么大问题。</p><p>第五个有点和第一个重了，好吧其实本来就三个。hexo的附件管理需要像管理网页资源一样放到sources文件夹。怎么用都感觉不如zblog。</p><p>gthub搭建博客的优点：</p><ol class=" list-paddingleft-2" style="list-style-type: decimal;"><li><p>速度理想，流量无限，空间很大</p></li><li><p>13格高</p></li></ol><p>hexo自然是有优点的，很多人都是冲着github的可靠性去的。</p><p>不过我相信大多数人更倾向于第二点。</p><p><em>(2016.11.19)-2;</em></p>]]></content>
  </entry>
  <entry>
    <title>CET4 · 不屈的Writing路（2016.12.8）</title>
    <link href="https://old-blog.smallyu.net/indexf62c.html?id=36"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=36</id>
    <published>2016-11-01T16:00:00.000Z</published>
    <updated>2016-11-01T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>(2016.12.8) 英语老师并不给口语不好的人机会。 原本有 Unit 1 ~ Unit 6 一共六个单元的内容需要背。是的这里列出了两篇，默写的。 时间隔了好久，从1.9的最后一篇四级作文到12.7的第一篇课文翻译。英语确实很难啊！ 四级作文记了两篇坚持不下去，就搁置了。当时两篇作文用了两个星期的时间。然后就到最近，老师要求被课文翻译，一共六个单元。反...</p>]]></summary>
    <content type="html"><![CDATA[<p style="white-space: normal;">(2016.12.8)</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;英语老师并不给口语不好的人机会。<img src="https://old-blog.smallyu.net/zb_users/emotion/default/unhappy.png"/></p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;原本有 Unit 1 ~ Unit 6 一共六个单元的内容需要背。是的这里列出了两篇，默写的。</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;时间隔了好久，从1.9的最后一篇四级作文到12.7的第一篇课文翻译。英语确实很难啊！</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;四级作文记了两篇坚持不下去，就搁置了。当时两篇作文用了两个星期的时间。然后就到最近，老师要求被课文翻译，一共六个单元。反正快考四级了，英语怎么学都是学，就决定背一下，期末还会考课文，背了也不亏。两天时间背了两篇。课文翻译比四级作文要简单很多，句子大多是简单句，虽然也有生词，不过还不算是问题。</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;问题是老师说只能背，不能背写。平时成绩的问题。</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;这种要求真的可以完全把我难住。如果可以背写的话还能试一下，但是背，嗯，挂科无憾。</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;所以就决定可以放心地旷课了，几乎没有故意旷课过，感谢英语课给了我旷课的勇气。<img src="https://old-blog.smallyu.net/zb_users/emotion/default/neutral.png"/></p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;有的人英语本来就好，不用做任何准备裸考就能过。然而有的人T_T。</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;以我三个月断断续续的复习、做了很多篇模拟题以及很多份真题的经验来看，我敢很肯定的说，今年的四级考试，肯定过不了。。。</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;难不成为了听好听力，就从小学的字母发音开始恶补基础吗，应该为了写好作文，就从小学的遣词造句开始学习语法吗。你努力，拼命在追赶的，是别人的起点。为什么非要走这条路？如果可以在其它路上超越别人，可以凭借其它技能找到工作，挣到钱，还有必要依靠这个吗？</p><p style="white-space: normal;">&nbsp;&nbsp;&nbsp;&nbsp;可是连这个都搞不定，不甘心啊。</p><p style="white-space: normal;">(Unit 2) Realizing the great national rejuvenation, which we define as the Chinese Dream, has been the greatest Chinese expectation since modern times. It basically means achieving prosperity for the country, renewal of the nation and happiness for the people, thus ensuring that every enterprising Chinese carries, generation after generation, the firm conviction that a better life is accomplished through persistent effort. People should achieve their prosperity through diligence, courage, creativity and determination instead of aid from society or other people. Each individual is a participant and a designer in the casue of realizing the Chinese Dream, it is a dream not only for the entire nation, but also for every Chinese.</p><p style="white-space: normal;"><br/></p><p style="white-space: normal;">(2016.12.7)</p><p>(Unit 1) Nowedays, many young people no longer choose “stable”&nbsp;jobs. Instead, they prefer to start their own businesses and realize their self-value through their own wisdom and efforts. Young entrepreneurship is the source of national economic vitality in the future. The success of entrepreneurs not only creates fortune, increases job opportunities, improves people’s life, but it is also good for the country in long term. Entrepreneurs are a driving force in upgrading China’s economy. Especially for the time being, our country is encouraging people to start their own businesses and make innovations and giving pocily support for medium and small businesses. This further arouses young people’s enthusiasm to start their own businesses.</p><p><br/></p><p style="white-space: normal;">(2016.11.9)</p><p style="white-space: normal;">Many cultural and sporting events are held on our campus each year, and I often participate actively in them. I find it beneficial to be involved in various campus activities. The speech contest held last month has benefited me most.</p><p style="white-space: normal;">The speech contest was held by the Students Union. The moment I was informed I would compete with more than 100 competitors, I became exceedingly nervous. But my roommates encouraged me and cheered me on. They are all willing to be my audience whenever I wanted to practice speaking, giving me much courage. They also offered me constructive advice to help me imporve my presentaion skills. Thanks to their support, I ranked third in this speech contest. The speech contest not only gave me a opportunity to practice eloquence and strengthen my confidence, but also deepened the friendship between my roommates and me.</p><p style="white-space: normal;">I will take part in such campus activities as a speech contest. I would contend they should be organized regularly to make our college life more colorful and meaningful.</p><p><br/></p><p>(2016.11.2)</p><p>If a foreign friend is coming to visit our campus, the most intersting place I&#39;d like to take him/her to see is the school art gallery. There are many exhibitions held here periodically, including calligraphy, painting, photograpy and sculpture, etc. Most of exhibits are created by our university students, but somtimes, there are some authentic works of well-known artists, like the famous painting Shrimp by Qi Baishi.</p><p>The reason why I take him/her to the school art gallery is that I hope he/she can known more about the campus life of Chinese university students. I&#39;d like him/her to known that our campus life is not defined to study; on the contrary, our campus life is rich and colorful. In addition, compared with other places, the school art gallery is more representative, because it collects excellent works of our university students and it shows our intelligence and wisdom intensively.</p><p>I&#39;m glad that our school has this art galley and I believe that everyone comes to see it will like it.</p>]]></content>
  </entry>
  <entry>
    <title>课程手记 · Hello，移动web</title>
    <link href="https://old-blog.smallyu.net/index40ac.html?id=35"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=35</id>
    <published>2016-10-17T16:00:00.000Z</published>
    <updated>2016-10-17T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>内容来自慕课网WebApp开发课程的内容，看完之后回想起来，确实有必要记录一下，便于温故 课程地址： http://www.imooc.com/learn/494 Pixel移动开发像素基础 px : CSS pixels 逻辑像素，浏览器使用的抽象单位 dp,pt : device independent pixels 设备无关像素 dpr : devic...</p>]]></summary>
    <content type="html"><![CDATA[<p>内容来自慕课网WebApp开发课程的内容，看完之后回想起来，确实有必要记录一下，便于温故</p><p>课程地址：<a href="http://www.imooc.com/learn/494" _src="http://www.imooc.com/learn/494">http://www.imooc.com/learn/494</a></p><p><strong><span style="font-size: 16px;">Pixel移动开发像素基础</span></strong><br/></p><p><span style="text-decoration: underline;">px</span>: CSS pixels 逻辑像素，浏览器使用的抽象单位</p><p><span style="text-decoration: underline;">dp,pt</span>: device independent pixels 设备无关像素</p><p><span style="text-decoration: underline;">dpr</span>: devicePixelRatio 设备像素缩放比</p><p>计算公式：<span style="text-decoration: underline;">1px = (dpr)^2 * dp</span></p><p><span style="text-decoration: underline;">DPI</span>: 打印机每英寸可以喷的墨汁点（印刷行业）</p><p><span style="text-decoration: underline;">PPI</span>: 屏幕每英寸的像素数量，即单位英寸内的像素密度</p><p>目前，在计算机显示设备参数描述上，二者意思表达的是一样的（单位为硬件像素，非px）</p><p>PPI越高，像素数越高，图像越清晰，但可视度越低（小），系统默认设置缩放比越大</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610181476787434192242.png" style="white-space: normal; width: 535px; height: 104px;" width="535" height="104"/></p><p>Retina屏（高清屏）dpr都是大于等于2</p><p><strong><span style="font-size: 16px;">Viewport视图</span></strong><br/></p><p>思考下面一个问题：</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610181476787435437480.png" style="white-space: normal; width: 535px; height: 211px;" width="535" height="211"/></p><p><span style="text-decoration: underline;">手机浏览器默认为我们做了两件事情</span>：</p><p>一：页面渲染在移动设备分辨率大小的viewport</p><p>二：缩放</p><p><span style="text-decoration: underline;">为什么渲染时，要有Viewport</span><span style="text-decoration: none;">？</span></p><p>为了排版正确。</p><p>viewport有两个，visual viewport和layout viewport</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610181476787434971290.png" style="width: 533px; height: 204px;" width="533" height="204"/><br/></p><p><span style="text-decoration: underline;">Viewport Meta标签</span></p><p>&lt;meta name=&quot;viewport&quot; content=&quot;name1=value1,name2=value2&quot;&gt;</p><p>width: 设置布局viewport的特定值（&quot;device-width&quot;）</p><p>initial-scale: 设置页面的初始缩放</p><p>minimum-scale: 最少缩放</p><p>maximum-scale: 最大缩放</p><p>user-scalable: 用户能否缩放</p><p><span style="text-decoration: underline;">常用写法</span>：</p><p>&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width,inital-scale=1,user-scalable=no&quot;&gt;</p><p><strong><span style="font-size: 16px;">Flex弹性盒子布局</span></strong><br/></p><p>.nav{display:-webkit-flex;}/*父元素*/</p><p>.item{flex:1}/*子元素*/</p><p>display:-webkit-flex 标示使用弹性布局</p><p>flex:num 占容器的比例</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610181476787435453961.png" style="width: 190px; height: 184px;" width="190" height="184"/></p><p><span style="text-decoration: underline;">Flex不定宽高的水平垂直居中</span></p><p>.parent{</p><p>&nbsp; &nbsp; justify-content:center;/*子元素水平居中*/</p><p>&nbsp; &nbsp; align-items:center;/*子元素垂直居中*/</p><p>&nbsp; &nbsp; display:-webkit-flex;</p><p>}</p><p><strong><span style="font-size: 16px;">Web的Flex弹性盒模型</span></strong><br/></p><p><span>https://old-blog.smallyu.net/web/web_flex.html（历史 Demo 已失效）</span></p><p>访问这个链接查看flex的所有属性案例</p><p><strong><span style="font-size: 16px;">响应式设计</span></strong><br/></p><p><span style="text-decoration: underline;">兼容性</span></p><p>·iOS可以使用最新的flex布局</p><p>·android4.4以下，只能兼容旧版的flexbox布局</p><p>·android4.4及以上，可以使用最新的flex布局</p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610181476787435416462.png" style="width: 711px; height: 151px;" width="711" height="151"/></p><p><span style="text-decoration: underline;">媒体类型</span></p><p>screen（屏幕）</p><p>print（打印机）</p><p>handheld（手持设备）</p><p>all（通用）</p><p><span style="text-decoration: underline;">常用该媒体查询参数</span>：</p><p>width—视口宽高</p><p>height——视口宽高</p><p>device-width——设备的宽度</p><p>device-height——设备的高度</p><p>orientation：检查设备处于横向（landscape）还是竖屏（portrait）</p><p><strong><span style="text-decoration: underline;">设计点一：百分比布局</span></strong></p><p>仅仅使用媒体查询来适应不同的固定宽高设计，只会从一组css到另一组css的切换。两种之间没有任何平滑渐变。当没有命中媒体查询时，表现就会变得不可控制（滚动，换行）。</p><p><strong><span style="text-decoration: underline;">设计点二：弹性图片</span></strong></p><p>很简单，如同多一点布局使用百分比，图片也使用百分比。其背后的思路是：无论何时，都全包在图片的元素宽度范围内，以最大的宽度同比完整的显示图片。</p><p><strong><span style="text-decoration: underline;">设计点三：重新布局，显示与隐藏</span></strong></p><p>当页面达到屏幕手机宽度的时候，很多时候就要放弃一些传统的页面设计思想。力求页面简单，简介。所以我们必须要做出以下处理：</p><p>1.同比例缩减元素尺寸</p><p>2.调整页面结构布局</p><p>3.隐藏冗余的元素</p><p><strong style="font-size: 16px;">移动web特别样式处理</strong><br/></p><p><span style="text-decoration: underline;">高清图片</span></p><p>在移动web也页面上渲染图片，为了避免图片产生模糊，图片的宽高应该用物理像素单位渲染，即是100*100的图片，应该使用100dp*100dp</p><p>width:(w_value/dpr)px;</p><p>height:(h_value/dpr)px;</p><p><span style="text-decoration: underline;">一像素边框</span></p><p>同样是retina屏幕下的问题，根本原因：1px使用2dp渲染</p><p>border:0.5px (FALSE) 仅仅ios8可以用</p><p>sacleY(.5)</p><p><span style="text-decoration: underline;">相对单位rem</span></p><p>为了是一个各大屏幕的手机，px略显固定，不能根据尺寸的大小而改变，使用相对单位更能体验页面兼容性</p><p>em：根据父节点的font-size为相对单位</p><p>rem：是根据html的font-size为相对单位</p><p>em在多层嵌套下，变得非常难以为何</p><p>rem更加能作为全局统一设置的度量</p><p>rem的基值设置为多少好？</p><p>为了使用各大手机屏幕，rem=screen.width/20</p><p>不使用rem的情况：font-size</p><p><span style="text-decoration: underline;">多行文本溢出</span></p><p>单行文本溢出，对title类的使用非常多，而多行文本溢出，在详情介绍则使用的比较多</p><p><span style="text-decoration: underline;">终端交互优化</span></p><p><span style="font-size: 16px;"><strong>Tap基础事件</strong></span><br/></p><p><span style="text-decoration: underline;">300毫秒的故事</span></p><p>移动web页面上的click时间响应都要慢上300毫秒。移动设备访问的web页面都是pc上的页面。在默认的viewport（980px）的页面往往都是需要“双击”或“捏开”放大页面，来看高清页面。而正是为了确认用户是“双击”还是“单击”，safari需要300ms的延迟来判断。</p><p><span style="text-decoration: underline;">300ms延迟怎么破？</span></p><p>使用Tap时间来代替click事件</p><p><span style="text-decoration: underline;">自定义Tap事件原理</span>：</p><p>在touchstart、touchend时记录时间、手指位置，在touchend时进行比较，如果手指位置为同一位置（或允许移动一个非常小的位移值）且时间间隔比较短（一般认为是200ms），且过程中未曾触发过touchmove，即可认为触发了手持设备上的“click”，一般称它为“tap”。(移动框架库Zepto.js)</p><p><span style="text-decoration: underline;">Tap“点透”的bug</span></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610181476787436121082.png" style="white-space: normal; width: 708px; height: 182px;" width="708" height="182"/></p><p>看过这个过程应该可以秒懂“点透”</p><p><span style="text-decoration: underline;">Tap透传的解决方案</span></p><p>1.使用缓动动画，过度300ms的延迟</p><p>2.中间层dom元素的假如，让中间层接受这个“穿透”</p><p>3.“上下”都使用tap时间，原理上解决tap透传事件（但不可避免原生标签click事件）</p><p>4.改用Fastclick的库（听过最新的zepto已经fixed掉这个bug）</p><p><strong style="font-size: 16px;">触摸Touch</strong><br/></p><p><span style="text-decoration: underline;">Touch基础事件</span></p><p>触摸才是移动设备的交互的核心事件</p><p>touchstart：手指触摸屏幕触发（已经有手指放屏幕上不会触发）</p><p>touchmove：手指在屏幕滑动，连续触发</p><p>touchend：手指离开屏幕时触发</p><p>touchcancel：系统取消touch时候触发（不常用）</p><p>除常见的事件属性外，触摸事件包含专有的触摸属性</p><p>touches：跟踪触摸操作的touch对象数组</p><p>targetTouches：特定时间目标的touch对象数组</p><p>changeTouches：上次触摸改变的touch对象数组</p><p><span style="text-decoration: underline;">每个touch对象包含属性</span>：</p><p>clientX：触摸目标在视口中的x坐标</p><p>clientY：触摸目标在视口中的y坐标</p><p>identifier：表示触摸的唯一ID。</p><p>pageX：触摸目标在页面中的x坐标（包含滚动）。</p><p>pageY：触摸目标在页面中的y坐标（包含滚动）。</p><p>screenX：触摸目标在屏幕中的x坐标。</p><p>screenY：触摸目标在屏幕中的y坐标。</p><p>target：触摸的DOM节点目标。</p><p>根据touch对象跟踪触摸具体位置，从而判断触摸交互或手势事件。</p><p><span style="text-decoration: underline;">BUG</span></p><p>Android只会触发一次touchstart，一次touchmove，touchend不触发</p><p><span style="text-decoration: underline;">解决方案</span></p><p>在touchmove中加入：enevt.preventDefault()。</p><p><span style="text-decoration: underline;">但注意</span></p><p>enevt.preventDefault()会导致默认行为不发生，如scroll，导致页面不滚动。</p><p><span style="text-decoration: underline;">弹性滚动</span></p><p>当客户端的页面滚动到顶部或底部的时候，滚动条会收缩并让我们多滑动一定距离。通过缓冲反弹的效果，带给用户良好的体验。</p><p><span style="text-decoration: underline;">移动web页面也是拥有这样能力的，但滚动有几种情况需要考虑</span>：</p><p>body层滚动：（系统特殊化处理）</p><p>再带弹性滚动，overflow：hidden失效，GIF和定时器暂停</p><p><span style="text-decoration: underline;">局部滚动开启弹性滚动</span>：</p><p>body{</p><p>&nbsp; &nbsp; overflow:scroll;</p><p>&nbsp; &nbsp; -webkit-over-scrolling:touch;</p><p>}</p><p>注意Android不支持原生的弹性滚动！但可以借助三方库iScroll来实现</p><p><span style="text-decoration: underline;">下拉刷新</span></p><p>顶端下拉一小点距离，页面弹性滚动向下</p><p><span style="text-decoration: underline;">上拉加载</span></p><p>使用scroll事件而不是touch时间（android有bug）</p><p><strong><span style="font-size: 16px;">总结</span></strong></p><p><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610181476787436203666.png" style="width: 709px; height: 361px;" width="709" height="361"/></p>]]></content>
  </entry>
  <entry>
    <title>实习报告 · 软件实验：Protel99（Altium designer 6.9）</title>
    <link href="https://old-blog.smallyu.net/indexd5e8.html?id=34"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=34</id>
    <published>2016-10-15T16:00:00.000Z</published>
    <updated>2016-10-15T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>一、实验目的 1.掌握电路原理图的设计步骤 2.掌握原理图报表文件的生成方法与作用 3.熟悉元器件库编辑器及其原理 4.学会使用印制电路板编辑器，达到自动布线画电路板比较熟悉的程度 二、实验内容 1.电路原理图的绘制 实验在仿真软件Altium designer 6.9上进行。绘制电路原理图大体分为四个步骤，新建原理图文件、放置元件、设置元件参数、画线。 1...</p>]]></summary>
    <content type="html"><![CDATA[<p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 16px;"><strong>一、实验目的</strong></span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">1.掌握电路原理图的设计步骤</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">2.掌握原理图报表文件的生成方法与作用</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">3.熟悉元器件库编辑器及其原理</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">4.学会使用印制电路板编辑器，达到自动布线画电路板比较熟悉的程度</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 16px;"><strong>二、实验内容</strong></span></p><p><span style="font-size: 14px;"><strong><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none;">1.电路原理图的绘制</span></strong></span><span style="font-size: 16px;"><strong><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none; font-size: 16px;"></span></strong><strong><span style="font-size: 16px; font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none;"></span></strong></span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">实验在仿真软件Altium designer 6.9上进行。绘制电路原理图大体分为四个步骤，新建原理图文件、放置元件、设置元件参数、画线。</span></p><p style="text-indent:28px"><span style="font-size: 14px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none; font-size: 14px;">1）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline; font-size: 14px;">新建原理图文件</span></span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">进入AD主界面，点击菜单栏File选项，在出现的菜单选项中选择New&gt;Schematic，软件自动生成的Free Documents工程以及Source Document文件夹和Sheet1.SchDoc原理图文件均会出现在左侧File View操作面板中。</span></p><p style="text-indent:28px"><span style="font-size: 14px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none; font-size: 14px;">2）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline; font-size: 14px;">放置元件</span></span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">明确并在元件库中寻找电路中需要放置的元件。寻找元件有两条思路。</span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">1&gt;点击菜单栏Design选项，在出现的菜单选项中选择Browes Library...，主界面右侧会弹出Libraries面板。点击Libraries...按钮，出现Available Libraries窗口，点击Insatll...按钮加载常用的两个杂项集成库Miscellaneous Connectors.IntLib和Miscellaneous Devices.IntLib，然后点击close按钮关闭窗口。</span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">加载元件库后就可以在元件库操作面板的下拉选项中选择相应的库，并用上下键选择、预览元件，逐个寻找所需元件。</span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">2&gt;点击search...按钮，出现Libraries Search窗口，在输入框中输入想要搜索的元件名，选择Libraries on path选项并设置Path的值就可以在遍历本地目录下的所有元件库搜索所需元件。</span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">如果出现元件库中没有所需元件，可以点击File，选择New&gt;Library&gt;Schemtic Library，左侧File View面板中会出现Schlib1.SchLib文件，单击选定，菜单栏中选择Tool的New Component，就可以自定义元件，之后保存，直接作为库加载就可以用了。</span></p><p style="text-indent:28px"><span style="font-size: 14px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none; font-size: 14px;">3）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline; font-size: 14px;">设置元件参数</span></span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">元件需要设置的参数一般有三个，Designator（元件名）、Comment（元件注释）、Footprint（元件封装）。按照需要分别设置就可以了。</span></p><p style="text-indent:28px"><span style="font-size: 14px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none; font-size: 14px;">4）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline; font-size: 14px;">画线</span></span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">原理图操作界面中，点击菜单栏中Place，选择Wire，鼠标光标会变成十字形，然后就可以根据需求按照网格放置线条了。</span></p><p style="text-indent: 28px; text-align: center;"><span style="font-size: 16px; font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;"><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610161476601683976607.png" alt="搜狗截图20161016110703.png" width="645" height="301" style="width: 645px; height: 301px;"/>&nbsp;</span></p><p><span style="font-size: 14px;"><strong><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">2.网络表的生成与作用</span></strong></span></p><p style="text-indent:28px"><span style="font-size: 14px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none;">1）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline;">网络表的生成</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">：画好原理图后，点击菜单栏中的Design，选择Netlist for document&gt;Protel，在原理图同目录就会生成Sheet1.NET文件。</span></span></p><p style="text-indent:28px"><span style="font-size: 14px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: none; font-size: 14px;">2）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline; font-size: 14px;">网络表的作用</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">：网络表包含了原理图中的所有元件以及元件参数，包括值的大小和封装信息等，用于在PCB电路的设计中导入元件以及校验元件信息。</span></span></p><p><span style="font-size: 14px;"><strong><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">3.PCB（印制电路板）的绘制</span></strong></span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">绘制PCB可以分为两个步骤，导入元件和布线。</span></p><p style="text-indent:28px"><span style="font-size: 14px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">1）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline; font-size: 14px;">导入元件</span></span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">点击菜单栏中的Project，选择Show Differences...，会弹出Choose Docuents To Compare窗口，在下角勾选Advanced Mode选项，窗口会变成两栏。左边一栏选中已经保存过的PCB文件，右边一栏选择刚才生成的网络表文件，点击OK，就会出现工程差异的一个比对窗口，右击任一列表中的文件，选择Update All &gt;&gt; PCB Document [PCB1.PcbDoc]选项，然后点击窗口左下角Create Engineering Change Order...按钮，就出现了Engineering Charge Order窗口。</span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">在出现的窗口中点击左下角的Execte Charges执行更改，之后就会出现一个执行情况统计的窗口。如果窗口中有错误项，就需要关闭窗口，根据错误提示更改、调整出现问题的元件。如果没有错误项，那么所有元件就成功地导入PCB文件中了。</span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">自定义放置元件的位置，然后点击Place，选择Line，画置印刷版的边界，限制电路板的大小，不然在自动布线的时候软件会卡死。</span></p><p style="text-indent:28px"><span style="font-size: 14px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">2）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; text-decoration: underline; font-size: 14px;">布线</span></span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">点击菜单栏的Auto Route，选择All，弹出窗口中保持默认选项选择OK，软件就可以在5秒之内自动为PCB印制板布线。</span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">AD在自动布线的时候不需要切换到Keep-Out Layer画布也可以实现双面板的布线，因为在弹出窗口中会选择布线格式。</span></p><p style="text-indent:28px"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">最后检查PCB是否有错误。</span></p><p style="text-indent: 28px; text-align: center;"><span style="font-size: 16px; font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;"><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610161476581086624422.png" alt="搜狗截图20161016010218.png" width="536" height="299" style="width: 536px; height: 299px;"/></span></p><p style="text-indent: 28px;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">应付作业的内容，先在电脑上写的，就顺手发上来。对软件的学习没有借鉴意义</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; font-size: 14px;">。&nbsp;</span></p>]]></content>
  </entry>
  <entry>
    <title>博观而约取，厚积而薄发</title>
    <link href="https://old-blog.smallyu.net/indexef73.html?id=33"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=33</id>
    <published>2016-10-05T16:00:00.000Z</published>
    <updated>2016-10-05T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>博观而约取，厚积而薄发。 可能在说这句话的时候，我也不知道自己想要表达什么。（真的想写个技术类的，分享一下自己的知识，顺便提升一下自己的格调。想想而已。）听着陈旧的许嵩的歌，在图书馆信息阅览室里，用着极不舒服的键盘，在XP系统的word上，写这篇日志（的时候心情是沉重的）。 许嵩的歌不新，却异常喜欢。可能仅仅是耳朵适应了他的歌的节奏和频率，不想再猎新奇。虽然...</p>]]></summary>
    <content type="html"><![CDATA[<p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">博观而约取，厚积而薄发。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">可能在说这句话的时候，我也不知道自己想要表达什么。（真的想写个技术类的，分享一下自己的知识，顺便提升一下自己的格调。想想而已。）听着陈旧的许嵩的歌，在图书馆信息阅览室里，用着极不舒服的键盘，在XP系统的word上，写这篇日志（的时候心情是沉重的）。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">许嵩的歌不新，却异常喜欢。可能仅仅是耳朵适应了他的歌的节奏和频率，不想再猎新奇。虽然我还年轻。天下雨了，打开窗户就可以感受到雨水带来的降温，和寒意。博观而约取，厚积而薄发，是刚才在意林杂志上看到的一句话。我们不止一次看到过类似这样的话，“我们总是对博学能够侃侃而谈的人感到敬佩，可谁又看到他们十年寒窗门前苦读的光景。”不鸣则已，一鸣惊人？我不屑一笑。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">总是希望自己以后可以变成厉害的人，希望现在没有做的一些事情，不会给自己留下遗憾，希望自己不要一无是处，然而。国庆节的假期，回家的回家，旅游的旅游。我不想回家，也没人和我一起旅游，所以，只剩下宅。但是又不甘愿浪费时间。所以，就有一段时间呆在图书馆了。短短几天时间，根本不足够我学习到多少东西。正是有这样的想法，让我对未来倍感迷茫。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">我知道自己可以不在乎游玩，没兴趣聚会。可以像暑假一样一下子呆在电脑前两个月。可是每当看到朋友圈的各种动态，就稍微有点按耐不住了。是羡慕吗？是羡慕吧？或者是攀比心理？或者是担心被别人“小看”的心理？（看，我们的生活丰富多彩，你呢？）</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">看到NCRE三级网络技术的教材，才接触到线程、分页、作业、UPS等概念。看到软考的网络工程师考题，才亲身接触到，有那么多我连名字都看不懂的东西。网上N多人说，NCRE完全没用，软考除了评职称也没什么用。可为什么我却觉得，那些考试的内容都不简单？着实不是突击就可以把证书考下来的程度。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">在这个博客网站，不知道可以写些什么内容。写这句话的同时，发现自己终究还是怕出丑。是的，担心博客文章的质量太低，像其他独立博客一样，发发牢骚，写写XXX的配置，贴点福利内容，科学上网方法等。每当看到那样的文章内容，总会觉得一下子就可以知道站长的水平了。什么样的文章，由什么样水平的作者来写。（所以你也应该知道多云转晴hower是个彻头彻尾的萌新小白了吧？）网络上的大牛很多，牛到难以想象。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">这段时间，一直以学习web开发自居。学到了什么？每当想，“自己写个小东西出来吧”的时候，会有一个始终回答不了的问题，写什么？入门容易学精难也就这么回事吧，高不成低不就的。想到写一个在线文件管理器，那么，写出来的东西给谁用呢？现在已经不是几年前独立网站的概念盛行，文件管理器还会用爱特的年代了。vps越来越流行，也许未来的某一天都装windows系统了，阿里云现在不就有这样的主机在卖吗。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">程序方面，目前就有很多优秀的在线文件管理系统，不管是中文的还是英文的。这些程序有什么功能不完善的地方需要自己改进吗？完全没有。那么，如果自己开始写这样一个程序，除了基本的copy、rename、unzip，都是PHP内置函数的使用，难以扩展它的功能了。界面方面，有好用的jquery插件，配置上就可以用。说的轻描淡写了一点。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">站点功能的话，还是按需开发比较好，有时候我们不需要乱七八糟的功能。</span><span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">https://old-blog.smallyu.net/demo/uplaod</span>（历史页面已失效）</span><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">只有简单的上传功能，不上KB的代码，却够我用用了。（没有安全措施，牛们不要黑我。）其他类型的内容也差不多是这样，在没有实施之前想法就被自己推翻了。</span></p><p style="text-align: center;"><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">&nbsp;<img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610061475749162970932.jpg" alt="u=3109424556,3539797443&amp;fm=11&amp;gp=0.jpg"/></span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">最近迷上一款游戏，王者荣耀。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">和LOL比起来，节奏快，打一场时间短，也算是变相的节省时间了。和英魂之刃比起来，画面好，技能炫。当然，王者荣耀是手游，不过我一般在电脑上用模拟器玩。为什么说是迷上呢？以前是不玩网游的。玩过，一点兴趣都没有。（如果保卫萝卜不算网游）后来和一个朋友一起玩王者荣耀。5V5种类的游戏很多。玩了一段时间后，发现这种竞技游戏确实有不少吸引人的地方。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;"><span style="text-decoration: underline; font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">自由度非常高。</span>单机游戏和RGP网游是没法比的。队友和对方分别有5个英雄，一队间不可重复。假如荣耀有50个可选英雄，那么用排列来算，一队间可能的情况有:</span></p><p style="text-align: center;"><img src="https://old-blog.smallyu.net/zb_users/upload/2016/10/201610081475937735554125.png" alt="搜狗截图20161008224137.png" style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;; width: 200px; height: 36px;" width="200" height="36"/><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;"></span><br/></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">这个数是多少？懒得算了。实际上不会有这么多种情况，不可能每个人都有这么多英雄可选，但有这么多种可能的队伍组合。那么，自己一队，对方一队，对战的组合就要二次方了。玩一款游戏，常常因为“玩腻了”不想再玩，单机游戏会找秘籍输命令尽可能看看这个游戏到底“有什么”。但是这个……</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;"><span style="text-decoration: underline; font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">合作的精神。</span>个人技术可以秀一时，秀不了一场。合作的好能虐杀对方，不懂合作各打各的人家一个一个也能团死你。那么，其实我还是比较喜欢辅助。不用带兵线，不用打野，工作也就是在队友身边放放技能就好了，还可以心安理得的全场乱跑，辅助队友嘛！被人杀了，我是辅助，血薄！杀的人少？我是辅助！只是排位就不敢那么随便了。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;"><span style="text-decoration: underline; font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">竞技的精神。</span>这本身就是竞技游戏。排位。赢了，还想再赢。输了，不服，想赢回来。感觉和赌博差不多。最怕的也就是挂机了。只要有人挂机，那基本就是输了。暂时没输也就垂死挣扎，只要对方不菜。于是，每当因为有人挂机输了的时候，总觉得特别不爽，不行，还得再来！总不会一直有人挂机吧？对了，还真遇到连3场有人挂机的。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">亚瑟是小短手，攻击距离近，除了第三个技能能跳一下，跑路是硬伤，一般带个闪现就挺好。最怕狄仁杰，远距攻击还带减速，见了就跑吧。如果有三技能见了后羿还是能拼一拼的。妲己的减速也厉害，不过战士不应该怕她。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">孙悟空据说最强。定位属于刺客和战士。血薄，靠暴击，死得快，打一下就跑的那种。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">后羿是热门英雄，经常看见他的身影。身为射手主要输出，远远地打就行了，三技能用处不详，什么时候都可以放，但不知道什么时候能够发挥好作用。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">蔡文姬比较讨人喜欢，（我单身久了？）因为可爱。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">孙斌看样子是S4的主角了。（现在是正S4呢吧？）辅助很强，一技能眩晕，二技能是2s的加速，三技能就挺酷的，时光炸弹，到后期冷却也不长，伤害不高，减速能力很强，团的时候丢对位置能把对方*死。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">……</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">另一款也不错的游戏，贪吃蛇大作战。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">这要不是单机游戏，估计它的火爆程度不会低于荣耀。规则很简单，生存。不是长大，是生存。前几天玩slither.io的时候，不断有一个想法冒出来：“蛇蛇大作战杀气太重了，我不敢再玩。”暴走蛇蛇也好，supersnake.io也好，总会有人不断想要杀掉你，你自己在玩的时候也会不断想要杀掉其它的蛇，尤其是大的，因为长得快嘛，积分很容易就上去。如果抢银行变成一种合法的行为，谁不愿意去抢？</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">&nbsp;</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">就这么乱乱地写写吧，没毛病。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">前几天杂志上看到一篇文章，论题是“你相信男女之间有纯洁的友谊吗？”我不信。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">我不只不相信男女之间没有友谊，还有男男之间，女女之间，所以说，我不相信友谊。没有永恒的友谊，只有永恒的利益，不是空穴来风。同时，我还看到一篇文章，论题是，“世界上的感情，都是一种仪式。”大概意思是说，仪式其实很重要。有仪式不一定有感情，但要有感情就应该有仪式，以表达，“我在乎你，我需要你”这类的含义。因为对方需要这样的仪式来相信你。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">看到这样的文章，会引起我一些思考，也会让我想起一些事情，所以有时候需要看看杂志。比如，上面的话题，我不得不想起一个大学同学。</span></p><p><span style="font-family: 微软雅黑, &#39;Microsoft YaHei&#39;;">我很喜欢的一个朋友。</span></p>]]></content>
  </entry>
  <entry>
    <title>叙述一次不愉快的拼车</title>
    <link href="https://old-blog.smallyu.net/index6fb5.html?id=31"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=31</id>
    <published>2016-09-15T16:00:00.000Z</published>
    <updated>2016-09-15T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>过去几天时间了，总是心有不甘。就当一次教训。事情很简单。 家里有事，正好周末，就在周六早上早早地回家了。周日整整一天在处理该处理的事情。周一早上，出发回到了这座城市。 坐大巴来的，停在了汽车站。差不多十点半。汽车站离目的地还有一段不短的距离，挤公交车得两个小时。其实本来两站路就能到，最多也就一个半小时，因为万恶的修路，修了老长时间了，公交车不能过。一般到断路...</p>]]></summary>
    <content type="html"><![CDATA[<p style="text-align: center;"><img src="https://old-blog.smallyu.net/zb_users/upload/2016/09/201609161474014361322020.jpg" alt="u=4177088956,1854946446&amp;fm=21&amp;gp=0.jpg"/></p><p>过去几天时间了，总是心有不甘。就当一次教训。事情很简单。</p><p>家里有事，正好周末，就在周六早上早早地回家了。周日整整一天在处理该处理的事情。周一早上，出发回到了这座城市。</p><p>坐大巴来的，停在了汽车站。差不多十点半。汽车站离目的地还有一段不短的距离，挤公交车得两个小时。其实本来两站路就能到，最多也就一个半小时，因为万恶的修路，修了老长时间了，公交车不能过。一般到断路部分是坐摩的过去的，不太熟悉路。</p><p>于是有点嫌麻烦，天正热，还要奔波两个小时，就想到了拼车。上次拼车正赶上开学，人多，三十块钱不到一个小时就到了。原想快十一点了，最好能尽快去，下午还有事，而且三十块钱就当用来买时间了，不算太亏，还图个省心省事，就搭了一个汽车站出口附近拉人的出租车，说拼车。</p><p>上次是开学季，所以三十就能搞定，这次没什么人，我也知道路不近，司机要五十，随口对付了几句，就答应了。当时车里只有我一个人，在等。先付了钱的。</p><p>等啊等。</p><p>特喵的，想想都来气。等了一个小时。是的，硬是到了十一点半，那个司机没拉到人。</p><p>怎么办？</p><p>等了这么长时间，难不成中途放弃？可是时间都出去了，又快到中午，比刚来更热了。这时候，出租车司机回来了，说要我稍等，让另一一辆车拉我去吧。以前也遇到过这样的情况，反正我给钱了，剩下的应该交给他处理，不管坐哪个车只要我能去就行。我是这么想的。</p><p>另一辆车来了之后，他在找人。</p><p>我又等了二十分钟。同时，接到了朋友的电话，说中午稍微有点事。手机信号不好，正好那天我的手机欠费了，只能接电话，不能打电话，没太听清楚说的是什么。总之能早点就早点吧。心想。</p><p>人找到了，还没完。上车后，还要去接两个人。打车的另外一个人的同伴。让人抓狂的是，没找到，找了半个小时。重点是那个人的同伴第一次来这个城市，不知道他们自己现在身处哪儿。问他们在哪条路？他们看了看路标后就说了。对，指示哪个方向是哪条路的那种，导向路标。</p><p>快十二点半了。</p><p>如果我当时坐公交车，省好多钱不说，现在也就到了。可是现在？难不成弃车？去得更晚。</p><p>于是我耐了一下心。半个小时后，拼车的人到目的地，下车了。他们给了司机七十。本来说好的五十，因为他的同伴耽误了，加了点钱。一点了。</p><p>再然后，司机问我去哪儿？我说了。</p><p>再一次特喵的。原来他本来不知道我去的那是个什么地方，是我原先拼的那个车得司机忽悠了他。他拿出手机导航，一查，十几公里。于是，你猜他会干嘛？</p><p>加钱。</p><p>我说那是你和前一辆车那个司机的事。钱我已经付过了，说好了的。</p><p><span style="text-decoration: underline;">他说，要么加钱，要么你下车，自己坐公交车回去。</span></p><p>当时是在有点偏远的地方，我的目的地本来就是郊区，哪有那么多方便的公交车让你坐。问题是就算有车，我也不清楚该坐哪路车，手机没网想查也查不了，同时万一要是还遇上修路那段，不还得折腾一下么，修路那段好点十块，差点十五。</p><p>我加钱了。</p><p>人在汽车里，不得不低头。</p><p>火大，没办法。</p><p>加了二十。</p><p>二十分钟后，到达目的地。</p><p>他说，小兄弟，真不是想坑你钱，你自己看导航，真挺远的，要是两三公里我肯定就顺你了。看嘛，一共走了三十二公里。</p><p>我也不知道三十二公里是什么概念。</p><p>百度地图提示，单就我的路程，按驾车的最短路程算，38元。</p><p><br/></p><p>其实还好，也没什么，以后注意点，小心点。面对这种事情，暂时想不出什么好的解决办法。毕竟回家也是真的有事。</p><p>我回家干嘛去呢，当孝子。</p><p style="text-align: center;"><img src="https://old-blog.smallyu.net/zb_users/upload/2016/09/201609161474014380133297.jpg" alt="u=2163755914,2001027881&amp;fm=21&amp;gp=0.jpg"/></p><p>祭奠我已故的伯父。</p>]]></content>
  </entry>
  <entry>
    <title>（失败2016.9.16）（程序猿养成计划）PHP参考手册实例遍历计划</title>
    <link href="https://old-blog.smallyu.net/index6258.html?id=21"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=21</id>
    <published>2016-08-28T16:00:00.000Z</published>
    <updated>2016-08-28T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>就是把参考手册里面的实例代码打一遍。 参考手册涵盖了该语言的任何内容（用法不包括理解）。不要笑我做无用的事情，这就是我的学习方法。 决定一个小节就用一篇文章来承载。有的小节内容会很短，但多云转晴hower的文章列表里面不会跳票。虽然这样做有可能会拉低站点文章的质量（本来就不高），但有的很长，如果采用另外的处理方法，比如把短的小节整合，文章名就不好取了，和PH...</p>]]></summary>
    <content type="html"><![CDATA[<p>就是把参考手册里面的实例代码打一遍。<br/></p><p>参考手册涵盖了该语言的任何内容（用法不包括理解）。不要笑我做无用的事情，这就是我的学习方法。</p><p>决定一个小节就用一篇文章来承载。有的小节内容会很短，但多云转晴hower的文章列表里面不会跳票。虽然这样做有可能会拉低站点文章的质量（本来就不高），但有的很长，如果采用另外的处理方法，比如把短的小节整合，文章名就不好取了，和PHP参考手册上面的内容也难以对应。</p><p>同时，会建立Python参考手册和PHP参考手册的分类。</p><p>Just do it!</p><p>PS:参考手册就是目前PHP官方文档最新的版本<br/></p><p>参考手册在线版：<a href="https://php.net/manual/zh/" _src="http://php.net/manual/zh/">http://php.net/manual/zh/</a> </p><p>参考手册下载地址：<a href="http://cn2.php.net/distributions/manual/php_manual_zh.chm" _src="http://cn2.php.net/distributions/manual/php_manual_zh.chm">http://cn2.php.net/distributions/manual/php_manual_zh.chm</a></p><p><br/></p><p>（失败2016.9.16）</p><p>这样做确实没有意义。</p><p>发布文章后的几天我翻出文章再看时，看不懂。</p><p>（同时）</p><p>删除实例文章。</p><p>撤销分类。</p>]]></content>
  </entry>
  <entry>
    <title>（失败2016.9.16）（程序猿养成计划）Python参考手册翻译计划</title>
    <link href="https://old-blog.smallyu.net/index190a.html?id=17"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=17</id>
    <published>2016-08-23T16:00:00.000Z</published>
    <updated>2016-08-23T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>这可能是无稽之谈。 为什么目前流传的高质量的Python中文参考手册少之又少呢？ 1.热度。不论。 2.难度。篇幅比PHP的长很多。 目的？ 学习。 能坚持多久？ 谁知道。 质量？ 比机器翻译差一点。 翻译目标： Python版本：2.7.12 原版手册： Python Manuals.zip 翻译计划？ 应该会是个漫长的过程。篇幅真的很长。 不断修改。 不...</p>]]></summary>
    <content type="html"><![CDATA[<p>这可能是无稽之谈。<br/></p><p><br/></p><p>为什么目前流传的高质量的Python中文参考手册少之又少呢？</p><p>1.热度。不论。</p><p>2.难度。篇幅比PHP的长很多。</p><p><br/></p><p>目的？</p><p>学习。</p><p><br/></p><p>能坚持多久？</p><p>谁知道。</p><p><br/></p><p>质量？</p><p>比机器翻译差一点。</p><p><br/></p><p>翻译目标：</p><p>Python版本：2.7.12</p><p>原版手册：<img style="VERTICAL-ALIGN: middle; MARGIN-RIGHT: 2px" src="https://old-blog.smallyu.net/zb_system/image/filetype/rar.png"/><a style="COLOR: rgb(0,102,204); FONT-SIZE: 12px" title="Python Manuals.zip" href="https://old-blog.smallyu.net/zb_users/upload/2016/08/201608241472050096171713.zip">Python Manuals.zip</a></p><p><br/></p><p>翻译计划？</p><p>应该会是个漫长的过程。篇幅真的很长。</p><p>不断修改。</p><p>不讲废话。</p><p><br/></p><p>还有没有什么要说的？</p><p>不足之处，敬请指点。</p><p><br/></p><p>（失败2016.9.16）</p><p>好难。</p><p>（同时）</p><p>删除文章。</p><p>撤销分类。</p><p><br/></p><hr/><p><br/></p><p>(2016.12.8) 偶然翻出以前的文件，看到了这些。</p><p><span style="text-decoration: underline;">Python2.7.12参考手册.txt</span><br/></p><blockquote><p>Python2.7.12参考手册</p><p><br/></p><p>欢迎你！这是Python2.7.12版本的中文参考手册，（原版本）最后的更新时间是2016年7月27日。</p><p><br/></p><p>参考手册目录：</p><p>&nbsp; &nbsp; Python2.7有什么新内容？ 或者说所有2.0版本以来所有的新内容</p><p>&nbsp; &nbsp; 使用说明 在这儿开始</p><p>&nbsp; &nbsp; 库参考 把这个放到你的枕头下</p><p>&nbsp; &nbsp; 语言参考 描述语法和语言描述</p><p>&nbsp; &nbsp; Python的配置和用法 如何在不同的平台使用Python</p><p>&nbsp; &nbsp; Python用户手册 具体主题的深入描述</p><p>&nbsp; &nbsp; 安装Python模块 从Python的包索引或者其他来源安装</p><p>&nbsp; &nbsp; Python的模块分类 用于安装的其他模块</p><p>&nbsp; &nbsp; 继承和植入 对C/C++程序员的教程</p><p>&nbsp; &nbsp; Python对C语言的API 给C/C++程序员的参考</p><p>&nbsp; &nbsp; 常见问题解答 经常被问到的问题及其答案</p><p><br/></p><p>索引和表：</p><p>&nbsp; &nbsp; 全局模块索引 快速进入所有的模块</p><p>&nbsp; &nbsp; 总索引 所有的函数、类、条款</p><p>&nbsp; &nbsp; 词汇表 最重要的条款解释</p><p>&nbsp; &nbsp; 搜索页面 搜索这个文档</p><p>&nbsp; &nbsp; 完整的内容表 列出所有的章节和小小节</p><p><br/></p><p>元信息：</p><p>&nbsp; &nbsp; 错误报告</p><p>&nbsp; &nbsp; 关于文档</p><p>&nbsp; &nbsp; 历史许可</p><p>&nbsp; &nbsp; 版权</p></blockquote><p><span style="text-decoration: underline;">Python模块索引.txt</span></p><blockquote><p><br/></p><p>Python模块索引</p><p><br/></p><p>_|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z</p><p><br/></p><p>_</p><p>&nbsp; &nbsp; __builtin__ 提供了内置命名空间的模块</p><p>&nbsp; &nbsp; __future__ 本声明的定义</p><p>&nbsp; &nbsp; __main__ 顶层脚本运行的环境</p><p>&nbsp; &nbsp; _winreg (Windows) 操作Windows注册表的程序和对象</p><p><br/></p><p>a</p><p>&nbsp; &nbsp; abc 基于PEP 3119的抽象基类</p><p>&nbsp; &nbsp; aepack (Mac) 不赞同的：Python和苹果事件之间会话的容器</p><p>&nbsp; &nbsp; aetools (Mac) 不赞同的：对发送苹果事件的基础支持</p><p>&nbsp; &nbsp; aetypes (Mac) 不赞同的：Python显示苹果的事件对象模型。读和写AIFF和AIFC格式的音频文件</p><p>&nbsp; &nbsp; aifc 读和写AIFF或AIFC格式的音频</p><p>&nbsp; &nbsp; al (IRIX) 不赞同的：SGI上的音频功能</p><p>&nbsp; &nbsp; AL (IRIX) 不赞同的：与al模块结合使用的常量</p><p>&nbsp; &nbsp; anydbm DBM型数据库模块的通用接口</p><p>&nbsp; &nbsp; applesingle (Mac) AppleSingle格式文件基本的解码器</p><p>&nbsp; &nbsp; argparse 命令行选项和参数解析库</p><p>&nbsp; &nbsp; array 节省空间的类型一致的数字阵列</p><p>&nbsp; &nbsp; ast 抽象语法树的类和操作。</p><p>&nbsp; &nbsp; asynchat 对异步命令/响应协议的支持</p><p>&nbsp; &nbsp; asyncore 一个异步套接字处理服务的基类</p><p>&nbsp; &nbsp; atexit 注册和执行清楚功能</p><p>&nbsp; &nbsp; audioop 操作未经加工的音频数据</p><p>&nbsp; &nbsp; autoGIL (Mac) 不赞同的：在时间循环中的全局解释器锁处理</p><p><br/></p><p>b</p><p>&nbsp; &nbsp; base64 标准6548：Base16,Base32,Base64 Data Encodings</p><p>&nbsp; &nbsp; BaseHTTPServer 基础的HTTP服务（对SimpleHTTPServer and CGIHTTPServer）</p><p>&nbsp; &nbsp; Bastion &nbsp;不赞同的：提供受限制的对象访问</p><p>&nbsp; &nbsp; bdb 调试器框架</p><p>&nbsp; &nbsp; binascii 二进制码和ASCII二进制编码之间转换的工具</p><p>&nbsp; &nbsp; binhex 加解密binhex4格式的文件</p><p>&nbsp; &nbsp; bisect 对二进制搜索的数组分割算法</p><p>&nbsp; &nbsp; bsddb 对Berkrlry DB数据库的接口</p><p>&nbsp; &nbsp; buildtools (Mac) 不赞同的：对BuildApplet,BuildApplication和macfreeze的辅助模块</p><p>&nbsp; &nbsp; bz2 兼容bizp2的压缩和解压缩程序接口</p><p><br/></p><p>c</p><p>&nbsp; &nbsp; calendar 日历工作的功能，包含一些Unix计算的仿真程序</p><p>&nbsp; &nbsp; Carbon</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.AE (Mac) 不赞同的：苹果事件工具盒的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.AH (Mac) 不赞同的：苹果帮助管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.App (Mac) 不赞同的：外观管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Appearance (Mac) 不赞同的：外观管理器定义常量的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.CarbonEvents (Mac) 不赞同的：Carbon事件管理器接口的常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.CarbonEvt (Mac) 不赞同的：Carbon事件管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.CF (Mac) 不赞同的：核心基础的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.CG (Mac) 不赞同的：绘图核心的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Cm (Mac) 不赞同的：组件管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Components (Mac) 不赞同的：组件管理器的界面常数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.ControlAccessor (Mac) 不赞同的：控制器接口的访问函数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Controls (Mac) 不赞同的：控制器界面常数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.CoreGraphics (Mac) 不赞同的：核心绘图界面常数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Ctl (Mac) 不赞同的：控制器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Dialogs (Mac) 不赞同的：对话框管理器界面常数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Dlg (Mac) 不赞同的：对话框管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Drag (Mac) 不赞同的：拖放管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Dragconst (Mac) 不赞同的：拖放管理器的界面常数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Events (Mac) 不赞同的：经典事件管理器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Evt (Mac) 不赞同的：经典事件管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.File (Mac) 不赞同的：文件管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Files (Mac) 不赞同的：文件管理器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Fm (Mac) 不赞同的：字体管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Folder (Mac) 不赞同的：文件夹管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Folders (Mac) 不赞同的：文件夹管理器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Fonts (Mac) 不赞同的：字体管理器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Help (Mac) 不赞同的：Carbon帮助管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.IBCarbon (Mac) 不赞同的：Carbon接口建立支持库的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.IBCarbonRuntime (Mac) 不赞同的：Carbon接口建立支持库的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Icns (Mac) 不赞同的：Carbon图标管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Icons (Mac) 不赞同的：Carbon图标管理器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Launch (Mac) 不赞同的：Carbon运行服务的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.LaunchServices (Mac) 不赞同的：Carbon运行服务的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.List (Mac) 不赞同的：列表管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Lists (Mac) 不赞同的：列表管理器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.MacHelp (Mac) 不赞同的：Carbon帮助管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.MediaDescr (Mac) 不赞同的：QuickTime媒体描述符解析器和发生器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Menu (Mac) 不赞同的：菜单管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Menus (Mac) 不赞同的：菜单管理器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Mlte (Mac) 不赞同的：多语言文本编辑器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.OSA (Mac) 不赞同的：Carbon OSA库的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.OSAconst (Mac) 不赞同的：Carbon OSA库的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Qd (Mac) 不赞同的：QuickDraw工具盒的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Qdoffs (Mac) 不赞同的：QuickTime工具盒的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.QDOffscreen (Mac) 不赞同的：QuickDraw Offscreen APIs的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Qt (Mac) 不赞同的：QuickTime工具盒的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.QuickDraw (Mac) 不赞同的：QuickDraw工具盒的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.QuickTime (Mac) 不赞同的：QuickTime工具盒的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Res (Mac) 不赞同的：资源管理器和句柄的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Resources (Mac) 不赞同的：资源管理器和句柄的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Scrap (Mac) 不赞同的：Scrap管理器提供了剪切、粘贴和剪贴板的操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Snd (Mac) 不赞同的：声音管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Sound (Mac) 不赞同的：声音管理器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.TE (Mac) 不赞同的：文本编辑器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.TextEdit (Mac) 不赞同的：文本编辑器的界面常量</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Win (Mac) 不赞同的：窗口管理器的接口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Carbon.Windows (Mac) 不赞同的：敞口管理器的界面常量</p><p>&nbsp; &nbsp; cd (IRIX) Silicon图形系统上光盘的接口</p><p>&nbsp; &nbsp; cfmfile (Mac) 不赞同的：代码片段资源模块</p><p>&nbsp; &nbsp; cgi 不赞同的：运行Python脚本通过公共网关接口的助手</p><p>&nbsp; &nbsp; CGIHTTPServer 这个模块提供了当运行CGI脚本的时候HTTP服务的处理程序</p><p>&nbsp; &nbsp; cgitb CGI脚本配置的追踪处理</p><p>&nbsp; &nbsp; chunk 读取IFF块的模块</p><p>&nbsp; &nbsp; cmath 对于复杂数学运算的功能</p><p>&nbsp; &nbsp; cmd 构建面向行的命令解释器</p><p>&nbsp; &nbsp; code 实行读-执行循环的工具</p><p>&nbsp; &nbsp; codecs 编码和解码数据和流</p><p>&nbsp; &nbsp; codeop 编译（可能不完全）的Python代码</p><p>&nbsp; &nbsp; collections 高性能的数据类型</p><p>&nbsp; &nbsp; ColorPicker (Mac) 不赞同的：标准颜色编辑对话框的接口</p><p>&nbsp; &nbsp; colorsys RGB和其它颜色系统的绘画功能</p><p>&nbsp; &nbsp; commands (Unix) 不赞同的：运行外部命令的实用功能</p><p>&nbsp; &nbsp; compileall 字节编译目录树中所有的Python源文件的工具</p><p>&nbsp; &nbsp; compiler 不赞同的：写在Python里的Python代码编译</p><p>&nbsp; &nbsp; &nbsp; &nbsp; compiler.ast</p><p>&nbsp; &nbsp; &nbsp; &nbsp; compiler.visitor</p><p>&nbsp; &nbsp; ConfigParser 配置文件分析器</p><p>&nbsp; &nbsp; contextlib 实用的声明上下文</p><p>&nbsp; &nbsp; Cookie HTTP数据(cookie)管理的支持</p><p>&nbsp; &nbsp; cookielib 对于HTTP cookies的自动处理类</p><p>&nbsp; &nbsp; copy 浅层和深部复制操作</p><p>&nbsp; &nbsp; copy_reg 寄存器pickle支持功能</p><p>&nbsp; &nbsp; cPickle 快捷版本的pickle，但不能产生子类</p><p>&nbsp; &nbsp; cProfile</p><p>&nbsp; &nbsp; crypt (Unix) crypt()功能用来检查Unix密码</p><p>&nbsp; &nbsp; csv 从分隔的文件中写入和读取表格数据</p><p>&nbsp; &nbsp; ctypes Python中一个外部的库</p><p>&nbsp; &nbsp; curses (Unix) 一个curses库的接口，支持便携式终端处理</p><p>&nbsp; &nbsp; &nbsp; &nbsp; curses.ascii 对ASCII字符的常量和关系函数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; curses.panel 一个面板堆栈的扩展，对curse窗口增加了深度</p><p>&nbsp; &nbsp; &nbsp; &nbsp; curses.textpad Emacs一样在curse窗口输入和编辑</p><p><br/></p><p>d</p><p>&nbsp; &nbsp; datetime 基本日期和时间类型</p><p>&nbsp; &nbsp; dbhash BSD数据库DBM风格的接口</p><p>&nbsp; &nbsp; dbm (Unix) 基于ndbm的标准的数据库接口</p><p>&nbsp; &nbsp; decimal 通用十进制算术规范的实现</p><p>&nbsp; &nbsp; DEVICE (IRIX) 不赞同的：和gl模块的常量一起使用</p><p>&nbsp; &nbsp; difflib 辅助计算对象之间差异</p><p>&nbsp; &nbsp; dircache 不赞同的：返回目录列表，具有缓存机制</p><p>&nbsp; &nbsp; dis Python字节码反汇编程序</p><p>&nbsp; &nbsp; distutils 对组建和安装Python的支持</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.archive_util 对创建归档文件是有用的功能（如原始码文件或zip文件等等）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.bcppcompiler</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.ccompiler CCompiler类的摘要</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.cmd &nbsp;这个模块提供了基类命令的摘要。这个类是distutils命令包模块的子类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command 这个包包含了一个模块，涵盖每一条标准Distutils命令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.bdist 为程序组建一个二进制安装包</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.bdist_dumb 组建一个“dumb”安装包——一个简单的存档文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.bdist_msi 组建二进制程序为一个Windows MSI文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.bdist_packager 包的基类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.bdist_rpm 组建一个二进制程序为一个Redhat的RPM和SRPM</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.bdist_wininst 组建一个Windows安装包</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.build 组件所有文件为一个包</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.build_clib 组建所有C函数库在一个包里</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.build_ext 组建任何扩展程序在一个包里</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.build_py 组建一个包中的.py和.pyc文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.build_scripts 组建一个包中的脚本文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.check 检查一个包中的测试数据</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.config 执行包的配置</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.insatll 安装一个包</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.install_data 从一个包中安装数据文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.install_headers 从一个包中安装C或C++头文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.install_lib 从一个包中安装数据库文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.instal_scripts 从一个包中安装脚本文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.register 注册一个有Python包索引的模块</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.command.sdist 资源分配</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.core Distutils功能核心</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.cygwinccompiler&nbsp;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.debug 支持distutils错误标记</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.dep_util 有用的功能对于简单的从属检查</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.dir_util 有用的功能对于目录和目录树的操作</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.dist 提供了配置类，可以代替该模块组建、安装、设置</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.emxcconpiler 对OS/2 EMX编译器的支持</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.errors 提供标准的distutils异常</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.extension 提供了扩展类，被用于在脚本中描述C和C++扩展模块</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.fancy_getopt 额外的getopt功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.file_util 对单个文件操作是有用的功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.filelist 这个FileList类被用于解除关于文件系统和组建文件列表</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.log 一个简单的记录机制，282风格</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.msvccompiler 微软软件编译器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.spawn 提供spawn()函数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.sysconfig Python解释器配置信息低等级的入口</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.text_file 一个简单的文件系统接口，提供文本文件类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.unixccomiler Unix系统下的C语言编译器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.util 混杂着其他工具功能</p><p>&nbsp; &nbsp; &nbsp; &nbsp; distutils.version 表示模板版本数字的工具类</p><p>&nbsp; &nbsp; dl (Unix) 不赞同的：在一个共享的对象中调用C语言的函数</p><p>&nbsp; &nbsp; doctest 文档中测试部分的代码</p><p>&nbsp; &nbsp; DocXMLRPCServer 文档自身的XML-RPC服务工具</p><p>&nbsp; &nbsp; dumdbbm DBM接口的一个便携工具</p><p>&nbsp; &nbsp; dummy_thread 进入代替交织的模块</p><p>&nbsp; &nbsp; dummy_threading 进入代替正在交织的模块</p><p><br/></p><p>e</p><p>&nbsp; &nbsp; EasyDialogs (Mac) 不赞同的：基本的Macintosh对话框</p><p>&nbsp; &nbsp; email 一个提供了解析、操作和生成email信息功能的包，包括MIME文档</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.charset 字符设置</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.encoders email信息酬载编码器</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.errors 使用email包的异常类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.generator 从一个email结构中生成单调的email文本消息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.header 描述非正规的ASCII头部</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.iterators 对一个信息对象树的迭代</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.message 描述email信息的基类</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.mime 组建MIME消息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.parser 解析浅显的eamil文本信息去生成一个消息模板</p><p>&nbsp; &nbsp; &nbsp; &nbsp; email.utils 混杂着email包工具</p><p>&nbsp; &nbsp; encodings</p><p>&nbsp; &nbsp; &nbsp; &nbsp; encodings.idna 国际化域名绑定</p><p>&nbsp; &nbsp; &nbsp; &nbsp; ecodings.utf_8_sig UTF-8编码无BOM格式</p><p>&nbsp; &nbsp; ensurepip pip安装助手的引导程序对于已存在的Python的安装或程序环境</p><p>&nbsp; &nbsp; errno 标准的errno系统符号</p><p>&nbsp; &nbsp; exceptions 标准的异常类</p><p><br/></p><p>f</p><p>&nbsp; &nbsp; fcntl (Unix) fcnt()和ioctl()系统响应</p><p>&nbsp; &nbsp; filecmp 有效地比较文件</p><p>&nbsp; &nbsp; fileinput 标准的输入或文件列表循环</p><p>&nbsp; &nbsp; findertools (Mac) 探测苹果事件接口周围的包装</p><p>&nbsp; &nbsp; FL (IRIX) 不赞同的：和fl模块一起使用的常量</p><p>&nbsp; &nbsp; fl (IRIX) 不赞同的：表单函数库，生动的用户接口应用</p><p>&nbsp; &nbsp; flp (IRIX) 不赞同的：加载储存的表单设计功能</p><p>&nbsp; &nbsp; fm (IRIX) 不赞同的：SGI终端智能的字体管理器接口</p><p>&nbsp; &nbsp; fnmatch Unix shell风格文件名样式匹配</p><p>&nbsp; &nbsp; formatter 普通输出格式化程序和配置接口</p><p>&nbsp; &nbsp; fpformat 不赞同的：普通的浮点数格式化功能</p><p>&nbsp; &nbsp; fractions 合理的数字</p><p>&nbsp; &nbsp; FrameWork (Mac) 不赞同的：交互式的应用框架</p><p>&nbsp; &nbsp; ftplib FTP协议客户端（需要sockets）</p><p>&nbsp; &nbsp; functools 更高的处理和操作功能在可响应的对象中</p><p>&nbsp; &nbsp; future_builtins</p><p><br/></p><p>g</p><p>&nbsp; &nbsp; gc 循环检测垃圾回收的接口</p><p>&nbsp; &nbsp; gdbm (Unix) dbm下GNU的重新编译</p><p>&nbsp; &nbsp; gensuitemodule (Mac) 从一个OSA字典中创建一个存根包</p><p>&nbsp; &nbsp; getopt 便携的命令行选择分析工具，提供了长短两种选择</p><p>&nbsp; &nbsp; getpass 便携的用户名和密码检索工具</p><p>&nbsp; &nbsp; gl (IRIX) 不赞同的：绘图功能</p><p>&nbsp; &nbsp; GL (IRIX) 不赞同的：和gl模块一起使用的常量</p><p>&nbsp; &nbsp; glob Unix shall风格的路径名样式扩展</p><p>&nbsp; &nbsp; grp (Unix) 数据库组（getgrnam()和friends）</p><p>&nbsp; &nbsp; gzip 压缩和解压文件对象的接口</p><p><br/></p><p>h</p><p>&nbsp; &nbsp; hashlib 安全散列和消息摘要算法</p><p>&nbsp; &nbsp; heapq 堆排序的算法（即优先级队列）</p><p>&nbsp; &nbsp; hmac 散列消息鉴别码（HMAC）的实现</p><p>&nbsp; &nbsp; hotshot 高性能日志分析器，主要是用C语言编写的</p></blockquote><p><br/></p>]]></content>
  </entry>
  <entry>
    <title>换主题啦！告别Metro，迎来百度efe</title>
    <link href="https://old-blog.smallyu.net/index7429.html?id=15"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=15</id>
    <published>2016-08-23T16:00:00.000Z</published>
    <updated>2016-08-23T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>免不了灌水。刚刚发了牢骚，咋么P大点事也要发一篇文章？ 此话有理。不过转念一想，谁看呐！况且独立个人博客的意义何在？ 博客标题。 一开始是“多云转晴hower”，后来是“Hower&amp;#39;s Blog”，现在又改回了“多云转晴hower”。 Hower只有多云转晴hower一个人是事实。 Hower称呼何来？how.gs这个域名作怪。这确实是一个不错的域名...</p>]]></summary>
    <content type="html"><![CDATA[<p>免不了灌水。刚刚发了牢骚，咋么P大点事也要发一篇文章？</p><p>此话有理。不过转念一想，谁看呐！况且独立个人博客的意义何在？</p><p><br/></p><p><strong>博客标题。</strong></p><p>一开始是“多云转晴hower”，后来是“Hower&#39;s Blog”，现在又改回了“多云转晴hower”。</p><p>Hower只有多云转晴hower一个人是事实。</p><p>Hower称呼何来？how.gs这个域名作怪。这确实是一个不错的域名，但又是一个有风险的域名，因为它是国别域名，谁都无法保证它有多长时间的可用性，以及续费价格是否可以稳定。指不定哪天，就不存在了。聊以情怀。</p><p>索引问题。不精通SEO，但是如果用“Hower&#39; Blog”这么一个全英文的标题，是不会受本土居民以及搜索引擎待见的。</p><p>友情链接。不必要更名。</p><p><br/></p><p><strong>博客主题</strong>。</p><p>由原先系统自带的“新鲜人”的“Metro”主题，换成“老白”的“ydefe”仿百度<a href="http://efe.baidu.com/">http://efe.baidu.com</a>主题。</p><p>Metro确实有很多难以容忍的缺点。固定的像素布局感觉老套落后于潮流，颜色搭配也很难调剂，包括背景图，虽然它也有优点。</p><p>efe既然是仿百度的，从某些审美角度就可以忽略N多问题，并且实现一开始没有实现的响应式。虽然它也有缺点。</p><p><br/></p><p><strong>内容展示。</strong></p><p>由主题更改带来一些展示内容的更改。</p><p>目前没有文章阅读量、评论数目和网站访问量统计，因为模板本身没有。Metro模板文章相关的统计是自带的，站点访问量是后加的。至于现在的efe，没有添加这些功能的打算。没有辣眼睛的数据统计何尝不是一件好事？</p><p>后来：保留了网站页面加载数目统计，在每个页面的最下面一行。因为我喜欢大数据。至于单个文章阅读量，还在考虑。</p><p>后来：稍微折腾了一下下Font awesome，把该有的统计都加上了。虽然辣眼睛，不过把数据明明白白摆出来，总好过什么都不知道，想看看不上。</p><p>efe的列表展示效果不尽人意，没有Metro条理、清晰。暂时忽略。还在考虑以前的文章要不要重新排版？</p><p><br/></p><p>1313这么些，说什么优点缺点？</p><p>并没有褒贬的成份在里面。谁又能说PHP不是世界上最好的语言？</p><p><br/></p><p>那你怎么不自己开发个模板？</p><p>不会。</p><p><br/></p><p><strong>主题版权。</strong></p><p>可能“不道德”地去除了版权。个人观点，影响版面内容。不是版面问题，多这么一句外部内容总感觉不放心。也看的出来作者对于这句版权稍上心，文件里面用了不少缩进。原版权内容：</p><blockquote><p><span style="font: 12px/normal &quot;Avenir Next&quot;, Helvetica, Arial, &quot;Lantinghei SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; color: #AAAAAA; text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; float: none; display: inline !important; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: #FFFFFF; -webkit-text-stroke-width: 0px;">Powered By<span class="Apple-converted-space">&nbsp;</span></span><a style="font: 12px/normal &quot;Avenir Next&quot;, Helvetica, Arial, &quot;Lantinghei SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; color: rgb(170, 170, 170); text-transform: none; text-indent: 0px; letter-spacing: normal; text-decoration: underline; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;" href="http://www.zblogcn.com/" target="_blank" rel="nofollow" se_prerender_url="complete">Z-BlogPHP</a><span style="font: 12px/normal &quot;Avenir Next&quot;, Helvetica, Arial, &quot;Lantinghei SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; color: #AAAAAA; text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; float: none; display: inline !important; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: #FFFFFF; -webkit-text-stroke-width: 0px;">. theme by<span class="Apple-converted-space">&nbsp;</span></span><a style="font: 12px/normal &quot;Avenir Next&quot;, Helvetica, Arial, &quot;Lantinghei SC&quot;, &quot;Microsoft YaHei&quot;, sans-serif; color: rgb(170, 170, 170); text-transform: none; text-indent: 0px; letter-spacing: normal; text-decoration: underline; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;" href="http://www.b5b6.com/" target="_blank">letterpress</a></p></blockquote><p>如果侵权（应该没那么严重），留言，即刻更改。<br/></p><p style="text-align: center;"><img alt="qb.gif" src="https://old-blog.smallyu.net/zb_users/upload/2016/08/201608241472022486856113.gif" width="310" height="342" style="width: 310px; height: 342px;"/></p>]]></content>
  </entry>
  <entry>
    <title>没有尼禄的本事还想泡茱莉亚一样的妞？</title>
    <link href="https://old-blog.smallyu.net/index87f1.html?id=14"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=14</id>
    <published>2016-08-21T16:00:00.000Z</published>
    <updated>2016-08-21T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>知道我写这个东西用的是什么编辑器吗？对，sublime 不善言辞，不喜表达，却又不想无趣。博客应该有什么内容？在这个博客早已落寞的年代。现在互联网上最热门的是什么内容？只知道贴吧人多，天涯、猫扑有人灌水，头条访问量高，慕课的人气也经久不衰。还有呢？互联网辣么庞大，除去所谓的暗网，也有数以万计的站点散布在网络上，我们能够看到的网站入口却寥寥无几。 优酷？爱奇艺...</p>]]></summary>
    <content type="html"><![CDATA[<p>知道我写这个东西用的是什么编辑器吗？对，sublime</p><p>不善言辞，不喜表达，却又不想无趣。博客应该有什么内容？在这个博客早已落寞的年代。现在互联网上最热门的是什么内容？只知道贴吧人多，天涯、猫扑有人灌水，头条访问量高，慕课的人气也经久不衰。还有呢？互联网辣么庞大，除去所谓的暗网，也有数以万计的站点散布在网络上，我们能够看到的网站入口却寥寥无几。<br/>优酷？爱奇艺？还是英雄联盟？人生似乎有点boring。网络世界很繁华，却不止一次感受到它的冷漠。</p><p><span style="font-size: 14px; text-decoration: none;"><strong>敲键盘的手承载不起按吉他和弦的强度。</strong></span><br/>这段时间唯一的长进也就打字速度稍微能看了一点，却在打这段汉字的时候，发现根本毫无暖用。也就一两个月没怎么碰吉他，十分钟就开始手疼了。sublime不折不扣是一个灰常给力的编辑器，小巧轻便，功能丰富，界面上也可以甩notepad几条街，边角圆滑，还有平滑的过度动画。可惜是用Python开发的。<br/>为什么可惜呢？因为不会啊！有人比喻，Java是重剑，PHP是轻剑，Python是匕首。要怎么用，看用来干什么。java除了完全面向对象，语法上和js还是稍微有点像的，都用+作为连接符。也就是说，能看得懂。不熟练，但也不能说生疏。就像在学过C之后看了看C++的基础课程，发现并没有多么变态。可Python的dict和map就有点无解了，想学，就要花时间去弄清楚一些新概念。<br/>对于新生猿来说，花点时间确实没啥？是的。曾经以为echo和include就可以做很多事情，直到后来用了GD库，听到了tpl，还有MVC构架，和smarty模板、tp框架、yii框架，7.0的新特性、mysqli，设计模式，微信开发，等等等等N多内容需要学习甚至精通。Python？我真的还想再活五百年。（H5和CSS3呢？Js呢？提都不提，你多伤它们的心）</p><p style="text-align: center;"><img alt="48865d8f196515f559ffae9f9cdc577f.png" src="https://old-blog.smallyu.net/zb_users/upload/2016/08/201608221471864759129687.png" width="377" height="205" style="width: 377px; height: 205px;"/></p><p><span style="font-size: 14px;"><strong>人生就像保卫萝卜，没钱，你的萝卜就会被怪吃掉。</strong></span>不管是跑得飞快体积娇小的小黄怪，还是身高体宽，虎背熊腰的大黑怪，都能咬你几口。<br/>就萝卜本身而言，3的难度比2高了不止一个难度。高难度的情况下有哪些方法可以通关呢？<br/>1.<span style="text-decoration: underline;">提高自身实力</span>。萝卜的生命也好，技能也好，炮塔也好，肯定越厉害就真的越厉害。如果一个人就是一根萝卜，炮塔就是萝卜的各项技能，炮塔越多，炮塔等级越高，怪就越渺小。多，指知识范围广，等级高，指学术精。只多不行，伤害低人家怪防得住。只有一个炮塔也不行，攻击再高人家躲过那一段就没事。单个炮塔放满屏幕？一招吃遍天下的伎俩，够你一时猖狂，不够你一生保命。<br/>2.<span style="text-decoration: underline;">换装</span><span style="text-decoration: none;">。</span>萝卜也是有等级的，也是有服装的。等级？就是身价咯，得用角色碎片来进阶，不止是金钱就可以买到的。服装？就是装13呗。装的好，就能把小怪给唬住喽。<br/>3.<span style="text-decoration: underline;">好友助阵</span>。可以提高炮塔的攻击力，不同等级的好友增益不同，不言而喻，看你朋友的身价。不过当然，次数多了就要花金币才能让人家帮助你，等级高的还得用钻石。<br/>4.<span style="text-decoration: underline;">没了</span>，就这么没了。真的没有其他方法了吗？你还有颠覆你人生更好的方法吗？</p><p>&lt;&lt;&lt;（2016.9.8）</p><p><span style="color: #666666; font-family: &#39;Avenir Next&#39;, Helvetica, Arial, &#39;Lantinghei SC&#39;, &#39;Microsoft YaHei&#39;, sans-serif; line-height: 20px; background-color: #FFFFFF;">保卫萝卜告诉我们，</span><br style="color: rgb(102, 102, 102); font-family: &#39;Avenir Next&#39;, Helvetica, Arial, &#39;Lantinghei SC&#39;, &#39;Microsoft YaHei&#39;, sans-serif; line-height: 20px; white-space: normal; background-color: rgb(255, 255, 255);"/><span style="color: #666666; font-family: &#39;Avenir Next&#39;, Helvetica, Arial, &#39;Lantinghei SC&#39;, &#39;Microsoft YaHei&#39;, sans-serif; line-height: 20px; background-color: #FFFFFF;">1.不要怕输，输了可以再来，怕输连开始都难。面对不进则退的晋升关卡，勇敢地打。</span><br style="color: rgb(102, 102, 102); font-family: &#39;Avenir Next&#39;, Helvetica, Arial, &#39;Lantinghei SC&#39;, &#39;Microsoft YaHei&#39;, sans-serif; line-height: 20px; white-space: normal; background-color: rgb(255, 255, 255);"/><span style="color: #666666; font-family: &#39;Avenir Next&#39;, Helvetica, Arial, &#39;Lantinghei SC&#39;, &#39;Microsoft YaHei&#39;, sans-serif; line-height: 20px; background-color: #FFFFFF;">2.后期新出的炮塔不一定就越好，集市主题第一关的船锚炸弹也就如此，用起来可能还不如飞机，所以告诉我什么是爱情？</span><br style="color: rgb(102, 102, 102); font-family: &#39;Avenir Next&#39;, Helvetica, Arial, &#39;Lantinghei SC&#39;, &#39;Microsoft YaHei&#39;, sans-serif; line-height: 20px; white-space: normal; background-color: rgb(255, 255, 255);"/><span style="color: #666666; font-family: &#39;Avenir Next&#39;, Helvetica, Arial, &#39;Lantinghei SC&#39;, &#39;Microsoft YaHei&#39;, sans-serif; line-height: 20px; background-color: #FFFFFF;">3.顶级炮塔的攻击速度和攻击力远超降一级的炮塔，性价比更高。学艺要学精？低级炮塔多不见得比少数几个顶级炮塔有气场。不过在糖果赛中炮塔等级高，损失的也就多。学PHP再精通，人家企业就要Python的，奈何？此题无解。</span></p><p>（2016.9.8）;</p><p style="text-align: center;"><img width="400" height="210" style="width: 400px; height: 210px;" alt="7170ae91aa44f193046b0e11e8b27356.jpg" src="https://old-blog.smallyu.net/zb_users/upload/2016/08/201608221471864772427867.jpg"/></p><p>想写博客不容易。毕竟看多了水到发慌的数不胜数的个人博客，或者为盈利而生的商业博客。</p><p>技术博客？啥也不会啊！技术圈有大波大波的大神在写博客，技术到什么程度？到很多人看不懂的程度。甚至出现的名词都没听过。<br/>生活博客？生活比看时间简史还要枯燥。<br/><strong>没有尼禄的本事还想泡茱莉亚一样的妞？</strong>是不是稍微有点跳。对，Devil May Cry 4，就是鬼泣4...<br/>是我老了吗？接受不了新鲜事物了吗？玩的游戏还是08年的鬼泣4，和孢子，听的歌，也是前几年，很多年前的歌，筷子兄弟的你一定会成功算不算？<br/>不会写小说，写不下去，时间成本大。其实我还想再活六百年。</p><p style="text-align: center;"><img width="145" height="144" style="width: 145px; height: 144px;" alt="dacd54dc847817e7edc7e70868cb2d8a.jpg" src="https://old-blog.smallyu.net/zb_users/upload/2016/08/201608221471865266872281.jpg"/></p><p>单纯闲的发发牢骚。你想不想再多活几年？</p>]]></content>
  </entry>
  <entry>
    <title>（一万小时定律实践计划）Duang~任务进度到1%啦！</title>
    <link href="https://old-blog.smallyu.net/index6e03.html?id=13"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=13</id>
    <published>2016-08-01T16:00:00.000Z</published>
    <updated>2016-08-01T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>作家格拉德威尔在《异类》一书中指出： “人们眼中的天才之所以卓越非凡，并非天资超人一等，而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成超凡的必要条件。“ 他将此称为“一万小时定律”。要成为某个领域的专家，需要10000小时，按比例计算就是：如果每天工作八个小时，一周工作五天，那么成为一个领域的专家至少需要五年。这就是一万小时定律。 那么这一万小时...</p>]]></summary>
    <content type="html"><![CDATA[<blockquote><div label-module="para">作家格拉德威尔在《异类》一书中指出：</div><div label-module="para">&nbsp;“人们眼中的天才之所以卓越非凡，并非天资超人一等，而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成超凡的必要条件。“</div><p>他将此称为“一万小时定律”。要成为某个领域的专家，需要10000小时，按比例计算就是：如果每天工作八个小时，一周工作五天，那么成为一个领域的专家至少需要五年。这就是一万小时定律。</p></blockquote><p>那么这一万小时按照什么标准算呢？我也不知道O_O<br/></p><p style="text-align: center;"><img width="517" height="263" style="width: 517px; height: 263px;" alt="搜狗截图20160802195426.png" src="https://old-blog.smallyu.net/zb_users/upload/2016/08/201608021470139349319124.png"/>&nbsp;</p><p>就当做里程碑式的纪念，100个小时，1%！<br/></p>]]></content>
  </entry>
  <entry>
    <title>（程序猿养成计划）Linux手记（I）</title>
    <link href="https://old-blog.smallyu.net/index4ef9.html?id=12"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=12</id>
    <published>2016-08-01T16:00:00.000Z</published>
    <updated>2016-08-01T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>跳了好多内容呢，所以手记内容并不全，真是一段艰辛的历程，然而还没有结束。 课程来源： http://www.imooc.com/learn/175 Linux基本操作 查询目录中内容: ls ls [选项] [文件或目录] 选项： -a 显示所有文件，包括隐藏文件 -l 显示详细信息 -d 查看目录属性 -h 人性化显示文件大小 -i 显示inode 举例：...</p>]]></summary>
    <content type="html"><![CDATA[<p>跳了好多内容呢，所以手记内容并不全，真是一段艰辛的历程，然而还没有结束。<br/></p><p>课程来源：<a href="http://www.imooc.com/learn/175" _src="http://www.imooc.com/learn/175">http://www.imooc.com/learn/175</a></p><blockquote><p>Linux基本操作</p><p><br/></p><p>&nbsp; &nbsp; 查询目录中内容: ls</p><p>&nbsp; &nbsp; ls [选项] [文件或目录]</p><p>&nbsp; &nbsp; 选项：</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -a 显示所有文件，包括隐藏文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -l 显示详细信息</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -d 查看目录属性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -h 人性化显示文件大小</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -i 显示inode</p><p>&nbsp; &nbsp; 举例：ls -lh</p><p><br/></p><p>&nbsp; &nbsp; 建立目录(make directories)：mkdir&nbsp;</p><p>&nbsp; &nbsp; mkdir -p [目录名]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -p 递归创建</p><p><br/></p><p>&nbsp; &nbsp; 切换所在目录(change directory)：cd</p><p>&nbsp; &nbsp; 简化操作</p><p>&nbsp; &nbsp; cd 进入当前用户的家目录</p><p>&nbsp; &nbsp; cd ~ 进入当前用户的家目录</p><p>&nbsp; &nbsp; cd - 进入上次所在目录</p><p>&nbsp; &nbsp; cd .. 进入上一级目录</p><p>&nbsp; &nbsp; cd cd. 进入当前目录</p><p><br/></p><p>&nbsp; &nbsp; 查询所在目录位置(print working directory)：pwd</p><p>&nbsp; &nbsp; pwd</p><p><br/></p><p>&nbsp; &nbsp; 删除空目录(remove empty directors): rmdir</p><p>&nbsp; &nbsp; rmdir[目录名]</p><p><br/></p><p>&nbsp; &nbsp; 复制命令(copy)：cp</p><p>&nbsp; &nbsp; cp [选项] [原文件或目录] [目标目录]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -r 复制目录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -p 连带文件属性复制</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -d 若原文件是链接文件，则复制链接属性</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -a 相当于 -pdr</p><p><br/></p><p>&nbsp; &nbsp; 剪切或改名命令(move): mv</p><p>&nbsp; &nbsp; mv [原文件或目录] [目标目录]</p><p><br/></p><p>&nbsp; &nbsp; 删除目录或文件(remove)：rm</p><p>&nbsp; &nbsp; rm -rf [文件或目录]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -r 删除目录</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -f 强制</p><p><br/></p><p>&nbsp; &nbsp; 链接命令(link): ln</p><p>&nbsp; &nbsp; ln -s [原文件] [目标文件]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -s 创建软链接</p><p><br/></p><p>&nbsp; &nbsp; #文件搜索命令locate</p><p>&nbsp; &nbsp; #命令搜索命令whereis与which</p><p>&nbsp; &nbsp; #文件搜索命令find</p><p>&nbsp; &nbsp; #字符串搜索命令grep</p><p><br/></p><p>&nbsp; &nbsp; locate命令格式</p><p>&nbsp; &nbsp; locate 文件名 #在后台数据库中按文件名搜索，搜索速度更快</p><p>&nbsp; &nbsp; /var/lib/mlocate #locate命令所搜索的后台数据库</p><p>&nbsp; &nbsp; updatedb #更新数据库</p><p><br/></p><p>&nbsp; &nbsp; 搜索命令的命令whereis</p><p>&nbsp; &nbsp; whereis 命令名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -b 只查找可执行文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -m 只查找帮助文件</p><p><br/></p><p>&nbsp; &nbsp; find命令</p><p>&nbsp; &nbsp; find [搜索范围] [搜索命令]</p><p>&nbsp; &nbsp; #find / -name install.log #按文件名查找</p><p>&nbsp; &nbsp; #find /root -iname install.log #不区分大小写</p><p>&nbsp; &nbsp; #find /root -user root #按照所有者搜索</p><p>&nbsp; &nbsp; #find /root -nouser #查找没有所有者的文件</p><p>&nbsp; &nbsp; #find /var/log/ -mtime +10 #查找10天前修改的文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -10 10天内修改的文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 10 10天当天修改的文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; +10 10天前修改的文件</p><p>&nbsp; &nbsp; atime 文件访问时间</p><p>&nbsp; &nbsp; ctime 改变文件属性</p><p>&nbsp; &nbsp; mtime 修改文件内容</p><p>&nbsp; &nbsp; #find /etc -size +20k -a -size -50k #查找/etc/目录下，大于20KB并且小于50KB的文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -a and 逻辑与</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -o or 逻辑或</p><p>&nbsp; &nbsp; #find /etc -size +20k -a -size -50k -exec ls -lh {} \; #查找/etc/目录下，大于20KB并且小于50KB的文件，并且显示详细信息</p><p>&nbsp; &nbsp; #-exec/ok 命令 {} \; 对搜索结果执行操作</p><p><br/></p><p>&nbsp; &nbsp; 搜搜字符串命令grep</p><p>&nbsp; &nbsp; grep [选项] 字符集 文件名</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -i 忽略大小写</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -v 排除指定字符集</p><p><br/></p><p>&nbsp; &nbsp; 帮助命令man</p><p>&nbsp; &nbsp; man 命令 #获取指定命令的帮助</p><p>&nbsp; &nbsp; man ls #查看ls的帮助</p><p>&nbsp; &nbsp; man -f 命令 #相当于 whatis 命令</p><p>&nbsp; &nbsp; 举例：man -5 password</p><p>&nbsp; &nbsp; 按q键退出man命令</p><p><br/></p><p>&nbsp; &nbsp; 选项帮助 --help</p><p>&nbsp; &nbsp; 举例：ls --help</p><p><br/></p><p>&nbsp; &nbsp; shell内部命令帮助</p><p>&nbsp; &nbsp; help shell内部命令</p><p>&nbsp; &nbsp; 举例：whereis cd #确定是否是shell内部命令&nbsp;</p><p>&nbsp; &nbsp; 举例：help cd #获取内部命令帮助</p><p><br/></p><p>&nbsp; &nbsp; 详细命令帮助info</p><p>&nbsp; &nbsp; info 命令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -回车：进入子帮助页面（带有*号标记）</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -u: 进入上层页面</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -n: 进入下一个帮助小节</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -p: 进入上一个帮助小节</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -q: 退出</p><p><br/></p><p>&nbsp; &nbsp; .zip格式压缩</p><p>&nbsp; &nbsp; zip 压缩文件名 原文件 #压缩文件</p><p>&nbsp; &nbsp; zip -r 压缩文件名 源目录 #压缩目录</p><p><br/></p><p>&nbsp; &nbsp; .zip格式解压缩</p><p>&nbsp; &nbsp; unzip 压缩文件 #解压缩文件</p><p><br/></p><p>&nbsp; &nbsp; .gz格式压缩</p><p>&nbsp; &nbsp; gzip 源文件 #压缩为.gz格式的压缩文件，源文件会消失</p><p>&nbsp; &nbsp; gzip -c 源文件 &gt; 压缩文件 #压缩为.gz格式，源文件保留</p><p>&nbsp; &nbsp; 例如：gzip -c cangls &gt; cangls.gz</p><p>&nbsp; &nbsp; gzip -r 目录 #压缩目录下所有的子文件，但是不能压缩目录</p><p><br/></p><p>&nbsp; &nbsp; gzip -d 压缩文件 #解压缩文件</p><p>&nbsp; &nbsp; gunzip 压缩文件 #解压缩文件</p><p><br/></p><p>&nbsp; &nbsp; .bz2格式压缩</p><p>&nbsp; &nbsp; bzip2 源文件 #压缩文件.bz2格式，不保留源文件</p><p>&nbsp; &nbsp; bzip2 -k 源文件 #压缩之后保留源文件</p><p>&nbsp; &nbsp; 注意：bzip2命令不能压缩目录</p><p><br/></p><p>&nbsp; &nbsp; 打包命令tar</p><p>&nbsp; &nbsp; tar -cvf 打包文件名 源文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -c 打包</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -v 显示过程</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -f 指定打包后的文件名</p><p>&nbsp; &nbsp; 例如 tar -cvf longzls.tar longzls</p><p><br/></p><p>&nbsp; &nbsp; .tar.gz压缩格式</p><p>&nbsp; &nbsp; tar -zcvf 压缩包名.tar.gz 源文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -z 压缩为.tar.gz格式</p><p>&nbsp; &nbsp; tar -zxvf 压缩包名.tar.gz</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -x 解压缩.tar.gz格式</p><p><br/></p><p>&nbsp; &nbsp; .tar .bz2压缩格式</p><p>&nbsp; &nbsp; tar -jcvf 压缩包名.tar.bz2 源文件</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -z 压缩为.tar.bz2格式</p><p>&nbsp; &nbsp; tar -jxvf 压缩包名.tar.bz2</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -x 解压缩.tar.bz2格式</p><p><br/></p><p>&nbsp; &nbsp; 关机 shutdown命令</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="d8aab7b7ac98b4b7bbb9b4b0b7abac">[email&#160;protected]</a> ~]# shutdown [选项]时间</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -c 取消前一个关机命令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -h 关机</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -r 重启</p><p><br/></p><p>&nbsp; &nbsp; 其他关机命令</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="691b06061d2905060a080501061a1d">[email&#160;protected]</a> ~]# halt</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="44362b2b3004282b2725282c2b3730">[email&#160;protected]</a> ~]# poweroff</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="cdbfa2a2b98da1a2aeaca1a5a2beb9">[email&#160;protected]</a> ~]# init 0</p><p><br/></p><p>&nbsp; &nbsp; 其他重启命令</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="5b2934342f1b3734383a373334282f">[email&#160;protected]</a> ~]# reboot</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="ddafb2b2a99db1b2bebcb1b5b2aea9">[email&#160;protected]</a> ~]# init 6</p><p><br/></p><p>&nbsp; &nbsp; 系统运行级别</p><p>&nbsp; &nbsp; 0 关机</p><p>&nbsp; &nbsp; 1 单用户</p><p>&nbsp; &nbsp; 2 不完全多用户，不含NFS服务</p><p>&nbsp; &nbsp; 3 完全多用户</p><p>&nbsp; &nbsp; 4 未分配</p><p>&nbsp; &nbsp; 5 图形界面</p><p>&nbsp; &nbsp; 6 重启</p><p><br/></p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="23514c4c57634f4c40424f4b4c5057">[email&#160;protected]</a> ~]# cat/etc/inittab</p><p>&nbsp; &nbsp; #修改系统默认运行级别</p><p>&nbsp; &nbsp; id:3:initdafault:</p><p><br/></p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="f5879a9a81b5999a9694999d9a8681">[email&#160;protected]</a> ~]# runlevel</p><p>&nbsp; &nbsp; #查询系统运行级别</p><p><br/></p><p>&nbsp; &nbsp; 退出登录命令</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="4b3924243f0b2724282a272324383f">[email&#160;protected]</a> ~]# logout</p><p><br/></p><p>&nbsp; &nbsp; 1.查询与自动挂载</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="55273a3a2115393a3634393d3a2621">[email&#160;protected]</a> ~]# mount</p><p>&nbsp; &nbsp; #查询系统中已经挂载的设备</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="582a37372c1834373b393430372b2c">[email&#160;protected]</a> ~]# mount -a</p><p>&nbsp; &nbsp; #依据配置文件/etc/fstab的内容，自动挂载</p><p><br/></p><p>&nbsp; &nbsp; 2.挂载命令格式</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="5d2f3232291d31323e3c3135322e29">[email&#160;protected]</a> ~]# mount [-t 文件系统] [-o 特殊选项] 设备 文件名 挂载点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -t 文件系统：指定挂载类型，可以ext3、ext4、iso9660等</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -o 特殊选项：可以指定挂载的额外选项</p><p><br/></p><p>&nbsp; &nbsp; 3.挂载光盘</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="1765787863577b7874767b7f786463">[email&#160;protected]</a> ~]# mkdir /mnt/cdrom</p><p>&nbsp; &nbsp; #建立挂载点</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="55273a3a2115393a3634393d3a2621">[email&#160;protected]</a> ~]# mount -t iso9660 /dev/cdrom/mnt/cdrom</p><p>&nbsp; &nbsp; #挂载光盘</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="1765787863577b7874767b7f786463">[email&#160;protected]</a> ~]# mont /dev/sr0/mnt/cdrom</p><p><br/></p><p>&nbsp; &nbsp; 4.卸载命令</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="d6a4b9b9a296bab9b5b7babeb9a5a2">[email&#160;protected]</a> ~]# umount 设备文件名或挂载点</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="c3b1acacb783afaca0a2afabacb0b7">[email&#160;protected]</a> ~]# umount /mnt/cdrom</p><p><br/></p><p>&nbsp; &nbsp; 5.挂载U盘</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="0d7f6262794d61626e6c6165627e79">[email&#160;protected]</a> ~]# fdisk -l</p><p>&nbsp; &nbsp; #查看U盘设备文件名</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="73011c1c07331f1c10121f1b1c0007">[email&#160;protected]</a> ~]# mount -t vfat /dev/sdb1/mnt/usb/</p><p>&nbsp; &nbsp; 注意：Linux默认不支持NTFS文件系统</p><p><br/></p><p>&nbsp; &nbsp; 查看登录用户信息</p><p>&nbsp; &nbsp; w 用户名</p><p>&nbsp; &nbsp; 命令输出：登录的用户名</p><p>&nbsp; &nbsp; USER: 登录终端</p><p>&nbsp; &nbsp; TTY: 从哪个IP地址登录</p><p>&nbsp; &nbsp; FROM: 登录时间</p><p>&nbsp; &nbsp; <a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="c985868e808789">[email&#160;protected]</a>: 用户闲置时间</p><p>&nbsp; &nbsp; IDLE: 用户限制时间</p><p>&nbsp; &nbsp; JCPU: 连接所有进程占用时间</p><p>&nbsp; &nbsp; PCPU: 当前进程占用时间</p><p>&nbsp; &nbsp; WHAT: 当前正在运行的命令</p><p><br/></p><p>&nbsp; &nbsp; Linux中的通配符</p><p>&nbsp; &nbsp; * 匹配任意内容</p><p>&nbsp; &nbsp; ? 匹配任意一个字符</p><p>&nbsp; &nbsp; [] 匹配任意一个中括号内的字符</p><p><br/></p><p>&nbsp; &nbsp; 文件类型显示</p><p>&nbsp; &nbsp; 第一位：-文件 d目录 l软链接</p><p>&nbsp; &nbsp; 后三位：u所有者</p><p>&nbsp; &nbsp; 后三位：g所属组</p><p>&nbsp; &nbsp; 后三位：o其他人</p><p>&nbsp; &nbsp; 共十位：r读 w写 x执行</p><p><br/></p><p>&nbsp; &nbsp; 常用目录作用</p><p>&nbsp; &nbsp; / 根目录</p><p>&nbsp; &nbsp; /bin 命令保存目录（普通用户就可以读取的命令）</p><p>&nbsp; &nbsp; /boot 启动目录，启动相关文件</p><p>&nbsp; &nbsp; /dev设备文件保存目录</p><p>&nbsp; &nbsp; /etc 配置文件保存目录</p><p>&nbsp; &nbsp; /home 普通用户的家目录</p><p>&nbsp; &nbsp; /lib 系统库保存目录</p><p>&nbsp; &nbsp; /mnt 系统挂载目录</p><p>&nbsp; &nbsp; /media 挂载目录</p><p><br/></p><p>Shall基础</p><p><br/></p><p>&nbsp; &nbsp; 1.echo输出命令</p><p>&nbsp; &nbsp; echo [选项] [输出命令]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -e 支持反斜杠控制的字符转换</p><p><br/></p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="abd9c4c4dfebc7c4c8cac7c3c4d8df">[email&#160;protected]</a> ~]# echo -e &quot;hell\bo&quot;</p><p>&nbsp; &nbsp; #删除左侧字符</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="abd9c4c4dfebc7c4c8cac7c3c4d8df">[email&#160;protected]</a> ~]# echo -e &quot;h\te\tl\nl\to&quot;</p><p>&nbsp; &nbsp; #制表符与换行符</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="5f2d30302b1f33303c3e3337302c2b">[email&#160;protected]</a> ~]# echo -e \ &quot;x68\t\x65\t\x6c\n\x6c\t\x6f\t&quot;</p><p>&nbsp; &nbsp; #按照十六进制ASCII码也同样可以输出</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="43312c2c37032f2c20222f2b2c3037">[email&#160;protected]</a> ~]# echo -e &quot;\e[1;31m 嫁人就要嫁凤姐 \e[0m&quot;</p><p>&nbsp; &nbsp; #输出颜色</p><p><br/></p><p>&nbsp; &nbsp; 2.第一个脚本</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="01736e6e75416d6e62606d696e7275">[email&#160;protected]</a> sh]# vi hello.sh</p><p>&nbsp; &nbsp; #!/bin/bash</p><p>&nbsp; &nbsp; #The first program</p><p><br/></p><p>&nbsp; &nbsp; echo -e &quot;\e[1;34m 天上掉下个林妹妹！ \e[0m&quot;</p><p><br/></p><p>&nbsp; &nbsp; 3.脚本执行</p><p>&nbsp; &nbsp; 赋予执行权限，直接运行</p><p>&nbsp; &nbsp; chmod 755 hello.sh</p><p>&nbsp; &nbsp; ./hello.sh</p><p>&nbsp; &nbsp; 通过Bash调用执行脚本</p><p>&nbsp; &nbsp; bash hello.sh</p><p>&nbsp; &nbsp;&nbsp;</p><p>&nbsp; &nbsp; 1.查看与设定别名</p><p>&nbsp; &nbsp; alias #查看系统中所有的命令别名</p><p>&nbsp; &nbsp; alias 别名=&#39;原命令&#39; #设定命令别名</p><p><br/></p><p>&nbsp; &nbsp; 别名永久生效与删除别名</p><p>&nbsp; &nbsp; vi ~/.bashrec #写入环境变量配置文件</p><p>&nbsp; &nbsp; unalias 别名 #删除别名</p><p><br/></p><p>&nbsp; &nbsp; 命令生效顺序</p><p>&nbsp; &nbsp; ...</p><p><br/></p><p>&nbsp; &nbsp; 常用快捷键</p><p>&nbsp; &nbsp; ctrl + c &nbsp;强制终止当前命令</p><p>&nbsp; &nbsp; ctrl + l &nbsp;清屏</p><p>&nbsp; &nbsp; ctrl + a &nbsp;光标移动到命令行首</p><p>&nbsp; &nbsp; ctrl + e &nbsp;光标移动到命令行尾</p><p>&nbsp; &nbsp; ctrl + u &nbsp;从光标所在位置删除到行首</p><p>&nbsp; &nbsp; ctrl + z &nbsp;把命令放入后台</p><p>&nbsp; &nbsp; ctrl + r &nbsp;在历史命令中搜索</p><p><br/></p><p>&nbsp; &nbsp; 2.历史命令</p><p>&nbsp; &nbsp; history [历史命令] [历史命令保存文件]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -c: 清空历史命令</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -w: 把缓存中的命令写入历史命令保存文件~/.bash_history</p><p>&nbsp; &nbsp; 历史命令默认保存1000条，可以在环境变量配置文件/etc/profile中进行修改</p><p><br/></p><p>&nbsp; &nbsp; 历史命令的调用</p><p>&nbsp; &nbsp; 使用上下箭头调用以前的历史命令</p><p>&nbsp; &nbsp; 使用&quot;!n&quot;重复执行第n条命令</p><p>&nbsp; &nbsp; 使用&quot;!!&quot;重复执行上一条命令</p><p>&nbsp; &nbsp; 使用&quot;!字串&quot;重复执行最后一条以该字串开头的命令</p><p><br/></p><p>&nbsp; &nbsp; 命令与文件补全</p><p>&nbsp; &nbsp; 在Bash中，Tab自动补全</p><p>&nbsp; &nbsp; ...</p><p>&nbsp; &nbsp; 输入命令后 + 两次Tab &nbsp; 路径补全、命令补全</p><p>&nbsp; &nbsp; ... &nbsp; &nbsp;&nbsp;</p><p>&nbsp; &nbsp; ll == ls -l</p><p><br/></p><p>&nbsp; &nbsp; 1.标准输入输出</p><p>&nbsp; &nbsp; 设备 &nbsp; 设备文件名 &nbsp;文件描述符 类型</p><p>&nbsp; &nbsp; 键盘 &nbsp; /dev/stdin &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;标准输入</p><p>&nbsp; &nbsp; 显示器 /dev/sdtout 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;标准输入</p><p>&nbsp; &nbsp; 显示器 /dev/sdterr 2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;标准错误输出</p><p><br/></p><p>&nbsp; &nbsp; 2.输出重定向</p><p>&nbsp; &nbsp; ...</p><p><br/></p><p>&nbsp; &nbsp; 3.输入重定向</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="acdec3c3d8ecc0c3cfcdc0c4c3dfd8">[email&#160;protected]</a> ~]# wc [选项] [文件名]</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -c 统计字节数</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -w 统计单词书</p><p>&nbsp; &nbsp; &nbsp; &nbsp; -l 统计行数</p><p><br/></p><p>&nbsp; &nbsp; 1.度命令顺序执行</p><p>&nbsp; &nbsp; ...</p><p><br/></p><p>&nbsp; &nbsp; 2.管道符</p><p>&nbsp; &nbsp; [<a href="https://old-blog.smallyu.net/cdn-cgi/l/email-protection.html" class="__cf_email__" data-cfemail="4b3924243f0b2724282a272324383f">[email&#160;protected]</a> ~]# 命令1 | 命令2</p><p>&nbsp; &nbsp; #命令1的正确输出作为命令2的操作对象</p><p><br/></p><p>&nbsp; &nbsp; 1.通配符</p><p>&nbsp; &nbsp; ...</p><p><br/></p><p>&nbsp; &nbsp; 2.bash中其他特殊符号</p></blockquote><p>虽然用了引用格式，但内容并不是真的引用，只是为了排版舒服一点。<br/></p><p>课程的主讲老师是@Tony老师，Tony老师不仅是一位Linux大神，还是一个灵魂画手哦！上图：</p><p style="text-align: center;"><img src="https://old-blog.smallyu.net/zb_users/upload/2016/08/201608021470123813396008.png" alt="搜狗截图20160728143439_副本.png" width="489" height="273" style="width: 489px; height: 273px;"/></p><p>最后由衷感谢这位坏坏的老师！</p><p>PS:<span style="line-height: 16px;">参考手册：</span><a href="https://old-blog.smallyu.net/zb_users/upload/2016/08/201608021470150110146059.chm" title="Linux常用命令大全.chm" se_prerender_url="loading" style="line-height: 16px; font-size: 12px; color: rgb(0, 102, 204);">Linux常用命令大全.chm</a></p><p><br/></p>]]></content>
  </entry>
  <entry>
    <title>写代码过程中几个无足轻重的小习惯</title>
    <link href="https://old-blog.smallyu.net/index0055.html?id=11"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=11</id>
    <published>2016-07-12T16:00:00.000Z</published>
    <updated>2016-07-12T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>想哪写哪。 1、$,&amp;quot;$&amp;quot;和&amp;#39;&amp;#39;？ C语言里&amp;quot;&amp;quot;表示字符串，&amp;#39;&amp;#39;表示字符，规则，乱了就会报错，PHP作为“松散”的语言，都能用来表示字符串。 $str = &amp;quot;aaa&amp;quot;; //定义变量为字符串 echo $str; //输出aaa echo &amp;quot;$str&amp;quo...</p>]]></summary>
    <content type="html"><![CDATA[<p>想哪写哪。<br/><strong>1、$,&quot;$&quot;和&#39;&#39;？</strong><br/>C语言里&quot;&quot;表示字符串，&#39;&#39;表示字符，规则，乱了就会报错，PHP作为“松散”的语言，都能用来表示字符串。<br/></p><pre class="prism-highlight prism-language-php">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$str&nbsp;=&nbsp;&quot;aaa&quot;;&nbsp;&nbsp;&nbsp;//定义变量为字符串
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$str;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//输出aaa
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;$str&quot;;&nbsp;&nbsp;&nbsp;&nbsp;//输出aaa
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&#39;$str&#39;;&nbsp;&nbsp;&nbsp;&nbsp;//输入$str</pre><p><br/>这就能看出&quot;&quot;和&#39;&#39;的区别了，当然，这是基础。那么在使用的时候，是直接使用变量还是&quot;&quot;?<br/>效率：当然是少打个&quot;&quot;了。<br/>不过在Mysql里就有点问题，如果定义column1 varchar(arbitrary value)，然后执行<br/></p><pre class="prism-highlight prism-language-php">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$str&nbsp;=&nbsp;$_POST[&#39;name&#39;];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysql_query(&quot;INSERT&nbsp;INTO&nbsp;table_name&nbsp;(column1)&nbsp;VALUES&nbsp;($str)&quot;);</pre><p><br/>程序会报错（一般人会记住错误内容吗），因为$str是不带&quot;&quot;的字符串，PHP认识，Mysql不认识...<br/>解决办法是，$str = &quot;\&quot;&quot; . $str . &quot;\&quot;&quot;; 是不是有点无聊，哈哈。<br/><strong>2、空格还是Tab？</strong><br/>老生常谈的问题，这种问题的答案我怎么会知道T_T</p><p>习惯用四个空格，常用的文本开发工具会支持Tab转空格的，可以转写好的，也可以直接转Tab键输入的，比如Notepad++，缩进也方便，因为有快捷键，重点是网页显示友善。</p><p>补充：空格可以解决这种样式的排版问题,tab是做不到的：</p><pre class="prism-highlight prism-language-php">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;?php
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$abc&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$abcdef&nbsp;=&nbsp;2;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;3;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&gt;</pre><p><strong>3、{$}</strong><br/></p><pre class="prism-highlight prism-language-php">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;?php
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$link&nbsp;=&nbsp;abc.xyz;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;&quot;&lt;a&nbsp;href=&#39;http://{$link}&#39;&gt;google&lt;/a&gt;&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;?&gt;</pre><p><br/>挺有用的一种用法，可能是个人都知道、、然而我后来才知道，后来，我终于学会了，如何……<br/><strong>4、紧凑、空格还是换行？</strong><br/>比如function abc(){}，大括号怎么安排位置？<br/>CSS里，可以<br/></p><pre class="prism-highlight prism-language-css">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;body&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;......
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p><br/>PHP里，可以<br/></p><pre class="prism-highlight prism-language-php">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;......
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p>毕竟if后面的条件可能会很长，css选择器一般很短，话说function也换行比较醒目，嗯，还是换行好。（补充：不提倡）</p><p>补充：</p><pre class="prism-highlight prism-language-php">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class&nbsp;AClass&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;......
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</pre><p><strong>5、格式化</strong><br/></p><p>在一些代码编辑工具中，比如Visual Studio，会自动在运算符&quot;=&quot;、&quot;&gt;&quot;、&quot;&lt;&quot;等两边加上空格，以及在多参数的&quot;,&quot;后边加上空格，原先是</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;a=3;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a(int,int){}</pre><p>格式化之后</p><pre class="prism-highlight prism-language-c">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;a&nbsp;=&nbsp;3;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;(int,&nbsp;int)&nbsp;{}</pre><p>有的工具其中一个选项就是“格式化代码”，做的就是这样的事情，在写好的代码上进行这些操作。</p><p>习惯在写的时候就加上这些空格。</p><p>无伤大雅，哈，要不然怎么说是“无足轻重”的小习惯呢。</p><p><strong>6、elseif还是else if?</strong></p><p>都差不多，凑合用吧。</p><p><strong>7、没了。</strong></p><p style="text-align: center;"><img width="337" height="335" style="width: 332px; height: 317px;" alt="322a1aa5ccd4acd2ba0c4a4fb8541a27_b.jpg" src="https://old-blog.smallyu.net/zb_users/upload/2016/07/201607121468330477423171.jpg"/></p>]]></content>
  </entry>
  <entry>
    <title>不得不说的科学上网浏览器：Tor Browser（洋葱浏览器）</title>
    <link href="https://old-blog.smallyu.net/indexf41b.html?id=10"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=10</id>
    <published>2016-06-18T16:00:00.000Z</published>
    <updated>2016-06-18T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>可以访问 大 陆屏蔽了的国外网站 Tro本是通过多层代理节点用于实现匿名访问网络的浏览器，被更多用于访问暗网，在实现多节点代理的同时，也就使得大陆网络用户可以访问国外的网站，因为Tro用的代理节点全是国外的： Tro并不好用 Tro和VPN相比天壤之别，Tro网络的链接速度非常非常慢（可能由于使用多层代理节点需要足够的服务器响应时间），并且Tro并不稳定，以...</p>]]></summary>
    <content type="html"><![CDATA[<p style="text-align: center;"><br/></p><p style="text-align: center;"><img width="422" height="246" style="width: 422px; height: 246px;" alt="搜狗截图20160618222051.png" src="https://old-blog.smallyu.net/zb_users/upload/2016/06/201606191466339972946769.png"/></p><p><span style="font-size: 16px; text-decoration: none;"><strong>可以访问</strong><strong>大</strong><strong>陆屏蔽了的国外网站</strong></span></p><p><span style="font-size: 14px;"><span style="text-decoration: none;">Tro本是通过多层代理节点用于实现匿名访问网络的浏览器，被更多用于访问暗网，在实现多节点代理的同时，也就使得大陆网络用户可以访问国外的网站，因为Tro用的代理节点全是国外的：</span></span></p><p style="text-align: center;"><img width="330" height="170" style="width: 330px; height: 170px;" alt="搜狗截图20160619203514.png" src="https://old-blog.smallyu.net/zb_users/upload/2016/06/201606191466340247222347.png"/></p><p><span style="text-decoration: none;"><strong><span style="font-size: 16px; text-decoration: none;">Tro并不好用</span></strong></span></p><p><span style="font-size: 14px;"><span style="text-decoration: none;">Tro和VPN相比天壤之别，Tro网络的链接速度非常非常慢（可能由于使用多层代理节点需要足够的服务器响应时间），并且Tro并不稳定，以前出现过一直无法连接网络的情况（现在好转）。</span></span></p><p><span style="font-size: 14px;"><span style="text-decoration: none;">不过，当ISP封锁了Tro网络连接的时候，用户可以通过建立网桥来连接互联网，&nbsp;还可以在Tro官网获得专属的网桥。</span></span></p><p><span style="font-size: 14px;"><span style="text-decoration: none;">在大陆的网络环境下，可用的免费科学上网方法有限，Tro并不理想，但是喜欢折腾的友友可以试一试来玩，毕竟它是少有的匿名浏览器，黑客难以从用它浏览的站点上追踪到用户的访问信息。</span></span></p><p style="text-align: center;"><span style="font-size: 14px;"><span style="text-decoration: none;"><img width="382" height="264" style="width: 382px; height: 264px;" alt="搜狗截图20160618223615.png" src="https://old-blog.smallyu.net/zb_users/upload/2016/06/201606191466341047746978.png"/></span></span></p><p><span style="font-size: 14px;"><span style="text-decoration: none;">Tro无法直接从官网下载（无法访问），只能从国内的软件下载站下载。</span></span></p><p><span style="font-size: 14px;"><span style="text-decoration: none;">PS1</span></span><strong><span style="font-size: 14px;"><span style="text-decoration: none;">：</span></span></strong>每天免费一小时的vpn赤兔（号称不限免费时长）：<a href="http://www.getchitu.cc/">http://www.getchitu.cc</a></p><p><span style="text-decoration: line-through;"><span style="font-size: 14px; text-decoration: line-through;">PS2</span><strong><span style="font-size: 14px; text-decoration: line-through;">：</span></strong>可用的可选择线路Chrome扩展：</span><a title="Jumbo Proxy Switcher.zip" href="https://old-blog.smallyu.net/zb_users/upload/2016/07/201607131468413496189482.zip" style="color: rgb(0, 102, 204); font-size: 12px; text-decoration: line-through;">Jumbo Proxy Switcher.zip</a></p><p>PS3：二师兄（免费）VPN：<a href="http://2-vpn5.com/home.action" _src="http://2-vpn5.com/home.action">http://2-vpn5.com/home.action</a>（每三天登录激活）</p>]]></content>
  </entry>
  <entry>
    <title>这些常用的Windows10快捷键，你都会用了吗？</title>
    <link href="https://old-blog.smallyu.net/index5255.html?id=9"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=9</id>
    <published>2016-06-08T16:00:00.000Z</published>
    <updated>2016-06-08T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>快捷键这种东西，可以不会，但适度掌握一些还是有必要的，尤其是想要把计算机玩6的小伙伴们。下面引用了一些常用的win10快捷键： Win键+Tab：激活多任务视图 Win键+A：激活操作中心 Win键+C：通过语音激活Cortana Win键+D：显示桌面 Win键+E：打开文件管理器 Win键+G：打开Xbox游戏录制工具栏，供用户录制游戏视频或截屏 Win...</p>]]></summary>
    <content type="html"><![CDATA[<p>快捷键这种东西，可以不会，但适度掌握一些还是有必要的，尤其是想要把计算机玩6的小伙伴们。下面引用了一些常用的win10快捷键：</p><blockquote><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Win键+Tab：激活多任务视图</p><p>　　Win键+A：激活操作中心</p><p>　　Win键+C：通过语音激活Cortana</p><p>　　Win键+D：显示桌面</p><p>　　Win键+E：打开文件管理器</p><p>　　Win键+G：打开Xbox游戏录制工具栏，供用户录制游戏视频或截屏</p><p>　　Win键+H：激活Windows&nbsp;10应用的分享功能</p><p>　　Win键+I：打开Windows&nbsp;10设置</p><p>　　Win键+K：激活无线显示器连接或音频设备连接</p><p>　　Win键+L：锁定屏幕</p><p>　　Win键+P：投影屏幕</p><p>　　Win键+R：运行</p><p>　　Win键+S：激活Cortana</p><p>　　Win键+X：打开高级用户功能</p><p>　　Win键+左/右/上/下：移动应用窗口</p><p>　　Win键+Ctrl+D：创建一个新的虚拟桌面</p><p>　　Win键+Ctrl+F4：关闭最近使用的虚拟桌面</p><p>　　Win键+Ctrl+左/右：切换虚拟桌面</p><p>　　Win键+Shift+左/右：将应用从一个显示屏移至另一个显示屏</p><p>　　Win键+1/2/3：打开任务栏中固定的程序，1代表任务栏中第一个应用图标</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ctrl&nbsp;+&nbsp;V:粘贴文本光标</p><p>　　Ctrl&nbsp;+&nbsp;C:将选中的文本复制到剪贴板</p><p>　　Ctrl&nbsp;+&nbsp;A&nbsp;:选择当前行中的所有文本</p><p>　　Shift&nbsp;+左/右/上/下:移动光标并选中文本</p><p>　　Ctrl&nbsp;+&nbsp;Shift&nbsp;+左/右：移动光标向左或向右</p><p>　　Shift&nbsp;+向上翻页/下一页：移动光标向上或向下一页</p><p>　　Ctrl&nbsp;+&nbsp;Shift&nbsp;+&nbsp;Home&nbsp;/End：移动光标的开始或者结束“屏幕缓冲区，”选择所有文本光标和命令提示符开头或结尾的输出。</p><p>　　Ctrl&nbsp;+上/下：向上或向下移动一行命令提示符的历史</p><p>　　Alt&nbsp;+&nbsp;F4&nbsp;：关闭当前窗口</p></blockquote><p>保存下来，&nbsp;&nbsp;用到的时候可以require一下哦！</p>]]></content>
  </entry>
  <entry>
    <title>（程序猿养成计划）脚本语言实例（暂停更新）</title>
    <link href="https://old-blog.smallyu.net/indexc3c9.html?id=8"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=8</id>
    <published>2016-06-03T16:00:00.000Z</published>
    <updated>2016-06-03T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>用一个页面来记录学习过程中编写的一些实例，包括原创和非原创，代码一定是经过多云转晴hower之手的。 页面地址： https://old-blog.smallyu.net/demo/（历史页面已失效） /**以下引用内容用内联框架显示 历史嵌入页面已失效。 */ 欢迎来和多云转晴hower一起交流学习！ 暂停更新（2016.8.11）：任重而道远。</p>]]></summary>
    <content type="html"><![CDATA[<p>用一个页面来记录学习过程中编写的一些实例，包括原创和非原创，代码一定是经过多云转晴hower之手的。</p><p>页面地址：<span>https://old-blog.smallyu.net/demo/（历史页面已失效）</span></p><p>/**以下引用内容用内联框架显示</p><blockquote><p><span>历史嵌入页面已失效。</span></p></blockquote><p>*/&nbsp;</p><p>欢迎来和多云转晴hower一起交流学习！<br/></p><p>暂停更新（2016.8.11）：任重而道远。</p>]]></content>
  </entry>
  <entry>
    <title>屏幕录制软件：Bandicam面前屏幕录制专家只是浮云（带注册机）</title>
    <link href="https://old-blog.smallyu.net/index8803.html?id=7"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=7</id>
    <published>2016-06-02T16:00:00.000Z</published>
    <updated>2016-06-02T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>当你使用屏幕录制专家录制的游戏视频卡成汪的时候，当屏幕录制专家提示丢失了50%以上帧的时候，不要太过疑虑你的机子是不是out了，也许只是你应该换一个更好用的屏幕录制软件。 Bandicam是国外的一款软件，支持中国简体语言，功能强大，可以访问官网下载未注册版本： 官网地址： http://www.handicam.com 关于Bandicam的介绍官网上已经...</p>]]></summary>
    <content type="html"><![CDATA[<p>当你使用屏幕录制专家录制的游戏视频卡成汪的时候，当屏幕录制专家提示丢失了50%以上帧的时候，不要太过疑虑你的机子是不是out了，也许只是你应该换一个更好用的屏幕录制软件。</p><p>Bandicam是国外的一款软件，支持中国简体语言，功能强大，可以访问官网下载未注册版本：</p><p>官网地址：<a href="http://www.handicam.com/">http://www.handicam.com</a></p><p>关于Bandicam的介绍官网上已经很齐全，就不贴图了，重点在于介绍中有这么一句：<span style="font-size: 14px;">Bandicam是针对</span><span style="font-size: 14px; text-decoration: underline;">应用DirectX/OpenGL图形技术的程序</span><span style="font-size: 14px;">进行视频录制的软件。也就是说在录制游戏方面的性能很优越，值得友友尝试一下。</span></p><p><span style="font-size: 14px;">下面引用官网对Bandicam的部分介绍：</span></p><blockquote><h3 style="font: 700 12pt/23.46px arial, STHeiti, &quot;Microsoft YaHei&quot;, 宋体; margin: 0px 0px 8px; padding: 0px; border: 0px currentColor; border-image: none; text-align: left; color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; vertical-align: baseline; white-space: normal; max-height: 999999px; widows: 1; font-size-adjust: none; font-stretch: inherit; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;">主要特点及优点</h3><ul class=" list-paddingleft-2" style="list-style-type: square;"><li><p>可同时录制电脑屏幕、电脑声音、麦克风声音。</p></li><li><p>被录制的视频容量很小。(现有程序的1/5至1/20水平)</p></li><li><p>如果硬盘容量足够，可24小时长时间录制视频。</p></li><li><p>与其他软件不同，电脑上很少出现网速减慢现象(Lag)。</p></li><li><p>支持图像截图(BMP、PNG、JPG)及连续截图功能。</p></li><li><p>在录像对象屏幕上可添加网络摄像头(Webcam)视频。(可实时合并网络摄像头画面，PIP功能)</p></li><li><p>无需编码，即可将录制的视频上传至Youtube。(可上传720p及1080p)</p></li><li><p>可录制电脑全屏，或选择指定区域录制视频。</p></li><li><p>支持在预约时间开始录制视频，可使用自动结束的计时器功能。</p></li><li><p>可通过硬件加速并快速录制高清视频，也能实现高压缩。</p></li><li><p>支持CFR功能，能与Sony Vegas、Adobe Premiere等视频编辑软件兼容</p></li></ul></blockquote><p><span style="font-size: 14px;"></span></p><p style="white-space: normal;">当然，万能的网友还是提供了注册机的，可以通过下面的链接直接下载注册机以注册Bandicam：下载附件：<img src="https://old-blog.smallyu.net/zb_system/image/filetype/rar.png" style="margin-right: 2px; vertical-align: middle;"/><a title="Bandicam注册机.zip" href="https://old-blog.smallyu.net/zb_users/upload/2016/06/201606031464962742825018.zip" style="color: rgb(0, 102, 204); font-size: 12px;">Bandicam注册机.zip</a></p>]]></content>
  </entry>
  <entry>
    <title>每个人心中都有一个夏洛，尽管只是一场梦</title>
    <link href="https://old-blog.smallyu.net/index3a9f.html?id=6"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=6</id>
    <published>2016-05-29T16:00:00.000Z</published>
    <updated>2016-05-29T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>时隔N久，还是对《夏洛特烦恼》不能忘怀，很少有电影可以像它，让人翻出来一看再看。 文章标题前半句来自豆瓣某一影评，这不重要。我不写影评，也不会写，只是夏洛着实让我笑了，开怀大笑，并且，让我想了，想想人生，想想理想。本质来说，夏洛只是一场梦，他所经历的一切，只是自己的空想而已，电影将梦的内容真实华丽地展现了出来，然而事实上，如果夏洛真实存在于世间，那么，他经历...</p>]]></summary>
    <content type="html"><![CDATA[<p style="text-align: center;"><audio autoplay="autoplay" loop="loop" controls="controls"><source src="https://old-blog.smallyu.net/zb_users/upload/2016/05/201605301464540774343309.mp3" type="audio/mpeg"/></audio></p><p style="text-align: left;"><span style="font-family: Microsoft YaHei; font-size: 14px;">时隔N久，还是对《夏洛特烦恼》不能忘怀，很少有电影可以像它，让人翻出来一看再看。</span></p><p style="text-align: left;"><span style="font-family: &#39;Microsoft YaHei&#39;; text-indent: 28px;">文章标题前半句来自豆瓣某一影评，这不重要。我不写影评，也不会写，只是夏洛着实让我笑了，开怀大笑，并且，让我想了，想想人生，想想理想。本质来说，夏洛只是一场梦，他所经历的一切，只是自己的空想而已，电影将梦的内容真实华丽地展现了出来，然而事实上，如果夏洛真实存在于世间，那么，他经历了许多许多，经历了另一次人生，大彻大悟，改变自己对马冬梅的心意，是好事，可对别人来说，他仅仅只是做了一场梦，就是这样，夏洛还是夏洛，爱马冬梅了，很爱很爱，但还是一事无成、一无是处的夏洛。</span></p><p style="text-align: left;"><span style="font-family: &#39;Microsoft YaHei&#39;; text-indent: 28px;">写到这儿，我突然发现需要改变一下自己的观点了。原本以为夏洛只是改变了对马冬梅的情绪，而已，毕竟电影没有关于夏洛事业相关的内容，他会奋起吗？还是想像先前马冬梅说的，“整天躺在床上，什么都不做，四肢都快躺退化了”？电影没有说明，其实还是留给了我们一些遐想的。我以为夏洛没有事业上的变化，想要稍稍吐槽一下下，刚才却意识到，或许不是，改变了对马冬梅态度的同时，万一一不小心改变了对生活的态度，积极向上地生活，迎着新时代的光芒，走向人生的巅峰？</span></p><p style="text-align: left;"><span style="font-family: &#39;Microsoft YaHei&#39;; text-indent: 28px;">每个人心中都有一个夏洛。</span></p><p style="text-align: left;"><span style="font-family: &#39;Microsoft YaHei&#39;; text-indent: 28px;">一方面，《夏洛》思路“新颖”，给我们很强的代入感。以前，有一句话让我兴奋不已，“如果有一天你从睡梦中醒来，发现自己趴在小学课堂的课桌上，身旁的同桌在认真的发呆，看看窗外，熟悉的操场，原来自己所经历的一切，只是一场梦，一切都才要开始，一切都还充满希望……”夏洛，则将这个场景还原。它满足了我的这个心愿，也可能是很多人的心愿，饱了眼福。在看电影的时候就会想，如果自己是夏洛，遇上这样的情况，会发生些什么？拥有现代的记忆，过着以往的生活。回到中学，我要首先要做的事情和夏洛一样，一定一样，那就是拼命追求自己喜欢的女孩，不会给自己的过去留下遗憾。</span></p><p style="text-align: left;"><span style="font-family: &#39;Microsoft YaHei&#39;; text-indent: 28px;">虽然自己的中学时代并没有这样的人，如果有，那么一定会。即使没有，也可以有嘛（。。。）女神不都是想出来的……好吧，换个话题，夏洛用别人的歌让自己成为了大明星。其实这里也可以省略了，毕竟自己连唱歌都不会。危机感又袭来，现在想想，即使自己回到了过去，也不见得能混得好，是的，真的是的</span><span style="text-indent: 28px; font-family: Calibri;">T_T</span><span style="text-indent: 28px; font-family: 宋体;">。</span></p><p style="text-align: left;"><span style="font-family: &#39;Microsoft YaHei&#39;; text-indent: 28px;">另一方面，情节感人至深。马冬梅对夏洛无拘无束大大咧咧毫不遮掩的爱，多少人的梦，谁不想有一个这样爱自己的人。情感高潮，让夏洛情绪反转，推动电影大情节的，就要是马冬梅跟着坏混混进小树林了。看的时候曾经一度心疼啊，结果并没有发生想象中的事情，只是被电影的这种手法吊起了胃口。不得不说，我认为，马冬梅戴着彩色狗狗帽对着人流广告挥手的那个笑容，是整部片子马冬梅最美的镜头。当然，某人在某年某月某日某个时刻戴着彩色狗狗帽的笑容也是我认为曾经的最美最温暖的笑容，可惜已经成为过去了。</span></p><p style="text-align: center;"><img width="488" height="225" title="201605301464538308693589.png" style="width: 488px; height: 225px;" src="https://old-blog.smallyu.net/zb_users/upload/2016/05/201605301464538308693589.png"/></p><p><span style="font-family: &#39;Microsoft YaHei&#39;; text-indent: 28px;">自从前几天多云转晴</span><span style="text-indent: 28px; font-family: Calibri;">hower</span><span style="text-indent: 28px; font-family: 宋体;">博客建立后，突然觉得自己拥有了一个可以发言的阵地，这也是这篇文章会出现的原因。以前也有过几个博客，去年夏天的神天天雨博客，没几天就没落然后放弃了。想想原因，也许是因为无知，然后和某人有关，也确实没有什么存在的意义。仅仅是给自己一个展现自己的平台，写一些无所谓的话，同时技术也不过关，界面连自己的眼睛都满足不了，放弃在情理之中。对啊，时间也就只过了一年，发生了好多事情呢。</span></p><p><span style="font-family: &#39;Microsoft YaHei&#39;; text-indent: 28px;">回到《夏洛》，片中涉及到的有三首歌非常好，重点是配上夏洛的相关情节，感人。</span></p><p style="text-align: center;"><img width="483" height="201" title="201605301464538301541364.png" style="width: 483px; height: 201px;" src="https://old-blog.smallyu.net/zb_users/upload/2016/05/201605301464538301541364.png"/></p><p style="text-align: center; text-indent: 28px;"><span style="font-family: Microsoft YaHei; font-size: 14px;"><span style="font-family: Microsoft YaHei; font-size: 14px;">《一次就好》</span></span><span style="font-family: Microsoft YaHei; font-size: 14px;"><span style="font-family: Microsoft YaHei; font-size: 14px;"><br/></span></span></p><p style="text-align: center;"><span style="font-family: Microsoft YaHei; font-size: 14px;"><img width="482" height="301" title="201605301464538304216687.png" style="width: 482px; height: 301px;" src="https://old-blog.smallyu.net/zb_users/upload/2016/05/201605301464538304216687.png"/></span></p><p style="text-align: center; text-indent: 28px;"><span style="font-family: Microsoft YaHei; font-size: 14px;"><span style="font-family: Microsoft YaHei; font-size: 14px;">《有个爱你的人不容易》</span></span><span style="font-family: Microsoft YaHei; font-size: 14px;"><span style="font-family: Microsoft YaHei; font-size: 14px;"><br/></span></span></p><p style="text-align: center;"><span style="font-family: Microsoft YaHei; font-size: 14px;"><img width="489" height="284" title="201605301464538301525622.png" style="width: 489px; height: 284px;" src="https://old-blog.smallyu.net/zb_users/upload/2016/05/201605301464538301525622.png"/></span></p><p style="text-align: center;"><span style="font-family: Microsoft YaHei; font-size: 14px;"><span style="font-family: Microsoft YaHei; font-size: 14px;">《夏洛特烦恼》</span></span><span style="font-family: Microsoft YaHei; font-size: 14px;"><span style="font-family: Microsoft YaHei; font-size: 14px;"><br/></span></span></p><p><span style="font-family: Microsoft YaHei; font-size: 14px;"><span style="font-family: Microsoft YaHei; font-size: 14px;">我也想做一场梦。</span></span></p>]]></content>
  </entry>
  <entry>
    <title>XAMPP错误：Apache shutdown unexpectedly解决办法：更改端口</title>
    <link href="https://old-blog.smallyu.net/indexd61c.html?id=5"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=5</id>
    <published>2016-05-26T16:00:00.000Z</published>
    <updated>2016-05-26T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>如果你新安装的XAMPP遇到apache不能启动的情况，提示如下错误信息： [Apache] Error: Apache shutdown unexpectedly. [Apache] This may be due to a blocked port, missing dependencies, [Apache] improper privileges,...</p>]]></summary>
    <content type="html"><![CDATA[<p>如果你新安装的XAMPP遇到apache不能启动的情况，提示如下错误信息：</p><blockquote><p>[Apache] &nbsp;Error: Apache shutdown unexpectedly.<br/>[Apache] &nbsp;This may be due to a blocked port, missing dependencies, <br/>[Apache] &nbsp;improper privileges, a crash, or a shutdown by another method.<br/>[Apache] &nbsp;Press the Logs button to view error logs and check<br/>[Apache] &nbsp;the Windows Event Viewer for more clues<br/>[Apache] &nbsp;If you need more help, copy and post this<br/>[Apache] &nbsp;entire log window on the forums</p></blockquote><p>关键信息在第二句：这可能是一个堵塞的端口，缺少了依赖关系。apache启动需要80端口和443端口，如果被占用将发生错误，可以通过XAMPP控制面板右侧栏的Netstat按钮查看主机的端口使用情况。</p><p style="text-align: center;"><img width="664" height="244" title="201605271464357219394974.png" style="width: 581px; height: 223px;" alt="搜狗截图20160527215318.png" src="https://old-blog.smallyu.net/zb_users/upload/2016/05/201605271464357219394974.png"/></p><p>想要解决这个问题的方法是简单的。只要更改apache的配置文件中所需使用的被占用的端口80或者443为其它端口，80端口的配置文件为httpd.conf，443端口的配置文件为httpd-ssl.conf，找到语句Listen，后面的数字即为对应端口号。（这里省略相应配置文件路径的内容，网络上相关内容很丰富了）</p><p><span style="font-size: 14px; text-decoration: underline;">注</span><span style="font-size: 14px; text-decoration: none;">：</span><span style="font-size: 16px; text-decoration: underline;"></span><span style="font-size: 14px;"></span></p><p><span style="font-size: 14px; text-decoration: none;">1.可能在配置文件中会找到多个80或者443的字样，</span><span style="font-size: 14px; text-decoration: underline;">只需更改Listen后面的数字</span><span style="font-size: 14px; text-decoration: none;">就可以了。</span></p><p><span style="font-size: 14px; text-decoration: none;">2.端口号可以随意定义，但是要注意</span><span style="color: #000000;"><span style="font-size: 14px; text-decoration: underline;">端口号最大值为65000</span><span style="font-size: 14px; text-decoration: none;"></span></span><span style="color: #000000;"><span style="font-size: 14px; text-decoration: none;"></span></span><span style="color: #000000;"></span><span style="font-size: 14px; text-decoration: none;">，不要超过这个数字，比如将80端口改为8080是合法的，但把443改为443443就是非法的，可以使用444等端口数值。</span></p>]]></content>
  </entry>
  <entry>
    <title>浅思考：我为什么想要坚持写博客</title>
    <link href="https://old-blog.smallyu.net/indexd708.html?id=3"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=3</id>
    <published>2016-05-23T16:00:00.000Z</published>
    <updated>2016-05-23T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>一直想要得到一个足够说服自己坚持写博客的理由，未果。但现实征服了我自己，作为一个IT爱好者，网站builder，未来的程序猿，网络已然植根在我的生命中 。 来看一下下面的引用内容： 作者：陈素封 链接：https://zhuanlan.zhihu.com/p/19743861 来源：知乎 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。...</p>]]></summary>
    <content type="html"><![CDATA[<p style="text-align: left;"><span style="font-family: Microsoft YaHei;"></span></p><p style="text-align: left;"><span style="font-family: Microsoft YaHei;"></span></p><p style="text-align: center;"><img title="201605261464238871130612.jpg" alt="850cfa3f7733c8b234deac0057aa4656.jpg" src="https://old-blog.smallyu.net/zb_users/upload/2016/05/201605261464238871130612.jpg" style="font-family: &#39;Microsoft YaHei&#39;;"/><br/></p><p style="text-align: left;"><span style="font-family: Microsoft YaHei;">一直想要得到一个足够说服自己坚持写博客的理由，未果。但现实征服了我自己，作为一个IT爱好者，网站builder，未来的程序猿，网络已然植根在我的生命中<span style="font: 14px/24px arial; color: #333333; text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; float: none; display: inline !important; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: #FFFFFF; -webkit-text-stroke-width: 0px;">。</span></span></p><p style="text-align: left;"><span style="font: 14px/24px Microsoft YaHei; color: #333333; text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; float: none; display: inline !important; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: #FFFFFF; -webkit-text-stroke-width: 0px;">来看一下下面的引用内容：</span></p><hr/><blockquote style="text-align: left;"><p style="text-align: left;">作者：陈素封<br style="text-align: left;"/>链接：https://zhuanlan.zhihu.com/p/19743861<br style="text-align: left;"/>来源：知乎<br style="text-align: left;"/>著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p></blockquote><blockquote style="text-align: left;"><div style="text-align: left;"><p style="text-align: left;"><span style="background-color: #FFFFFF;">为什么你要写博客？</span></p><h2 style="text-align: left;"><span style="color: #000000; background-color: #FFFFFF;">一个选择</span></h2><p style="text-align: left;"><span style="background-color: #FFFFFF;">我知道现在可能说这话有点不合时宜，毕竟博客时代都已经过去了，再号召大家用过就好像时的东西是不是有点逆流而上？</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">我曾经也问过自己这个问题，但是我觉得，博客时代过去跟我们要开博客是没有多大关系的，就好像你的读书时代已经过去你就不再读书一样。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">判断一件事情值不值得去做有一个方法：在一张白纸的左边写不值得做的原因，然后在右边写值得做的原因，写完一比较，一权衡，自然能够得出结果。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">大家都成年人了，你会觉得这样思考分析总结的过程才是正确的思考的方法吧？</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">所以，我在这里列出要写（独立）博客的原因，供大家去选择，然后填在你白纸的右边。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">注意，我不是给你一个建议，而是提供一个选择，这个选择蕴藏着我也不知道的可能。</span></p><h2 style="text-align: left;"><span style="color: #000000; background-color: #FFFFFF;">博客的内容</span></h2><p style="text-align: left;"><span style="background-color: #FFFFFF;">写博客不难，你可以当作是生活的记录，但是这样的记录没有任何的意义。写要对得住写本身，写出来的东西应该是思考的结果。我认为，如果你要开一个博客，博客的内容应该是这样的：</span></p><ul class=" list-paddingleft-2"><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">1. 不是生活杂记、不是流水账、不是牢骚、不是抱怨、不是心情琐记……；</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">2. 有目的地写，要务实，追求质量；</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">3. 承认真实的自己，不要吹嘘，不要装逼，无需讨好读者；</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">4. 记录自己学习、思考、总结的过程；</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">5. 分享你的故事、所得、感想、经验；</span></p></li></ul><h2 style="text-align: left;"><span style="color: #000000; background-color: #FFFFFF;">值得写的原因</span></h2><p style="text-align: left;"><span style="background-color: #FFFFFF;">以下是一个清单，可以根据自己的情况匹配，然后选择。</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">重新认识自己</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">是不是很久没有跟自己对话了？</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">你可以尝试从回答一些问题开始，将你过去要回避的问题写下来，例如就可以从这个九个问题开始：</span></p><ul class=" list-paddingleft-2"><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">1、请你介绍一下你自己，你是个什么样的人？</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">2、你有什么理想吗？这个理想是怎么形成的？</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">3、你理想的伴侣关系是什么样的？你自己在这个伴侣关系中扮演什么样的角色？要承担什么样的责任？</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">4、你理想的事业是什么，你正在做的工作符合你的事业理想吗？这份工作对你的意义是什么？</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">5、你对亲子关系怎么看？对你来说，什么是一个理想的父亲（母亲），你期望自己成为这样一个理想父亲（母亲）吗？</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">6、你对钱怎么看，你认为赚到多少钱是足够的？如果你明天一早醒来，已经有足够的钱，你将会如何继续安排自己的生活？</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">7、对你来说，什么是理想的性生活？什么是理想的性道德，在你的性道德观中，什么样的性生活是禁忌的，需要避免的，什么样的性生活是美好的，需要得到鼓励和发展的？</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">8、你的择友标准是什么？什么样的人你会愿意交往，什么样的人你会拒绝和他交往？</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">9、你对死亡怎么看？你希望自己活到多少岁，你准备怎么度过从现在到死亡的这段时间？如果你要立遗嘱，这份遗嘱会怎么写？</span></p></li></ul><p style="text-align: left;"><span style="background-color: #FFFFFF;">以上的这九个问题摘自《很少人能顺畅回答这9个问题——心理治疗刚开始医生常常会先问你的 》by 李孟潮。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">这些问题的答案你可以选择不发，但是我强烈地建议写下来，只有在写的时候你才可以慎重地思考这些问题，而不会回避跳过或者留下空白，这是接受自己的第一步。</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">提供持续学习的动力</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">例如，我为自己设限每天写一千字，信息的不断输出给我带来恐惧，我害怕有一天我写无可写，于是我不停地阅读，通过个人的知识管理促使自己不断学习，提高核心竞争力。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">详细的知识管理可以看我的这篇文章：《个人知识管理的方法》，回复「知识」可见</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">积累更多的知识</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">写并不是单纯的写。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">例如你写着写着，你突然忘记了一个概念，于是上网找，找回来这个概念的时候，你重温这个概念，可能还会顺便看了一下这个概念的其他东西。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">例如你需要获取第一手的资料，寻找信息来源本身就是一个知识积累的过程，同时，你慢慢就学会了鉴别知识：什么是没有用的心灵鸡汤，什么是不值得关注的吐槽名人，还有，在这个过程中，你还养成你的心智。</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">提高将事情讲清楚的能力</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">很多东西你以为懂了，但当你在写下来的时候，你就觉得无从下手了。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">如果一件事情你不能讲清楚，十有八九你还没有完全理解。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">将事情写下来，慢慢就可以提高你的逻辑思维能力，分析能力，写会迫使你在你脑中搭建一个有条理的框架。例如我写这篇文章一样，我就将值得写博客的原因一点一点地罗列出来，事情就更加清晰，你也可以更好的思考问题。</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">分享带来的连锁反应</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">“通过分享，你获得了直接而快速的回报，你最终或许会发现你已将版权和“保留所有权利”抛诸脑后。新的经济学准则是：参与你作品的人越多，回报越高。在分享主义里，如果你愿意你可以保留所有权，但是我乐于分享。” by 毛向辉 《分享主义：一场思维革命》</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">互联网精神其中最重要的就是分享主义，基于分享主义，你可以享受到社会化及互联网给你带来的种种便利和好处，你分享了一个知识，你就成为了互联网中的一个点，这个点的大小由你自己来决定，互联网的大潮会将你的这个点推送到它所能触及的每个角落，让需要的人得到，同时，你的这个点也会继续扩大，连接到整个网络，这个点有可能连接成一张网，而你就是这张网的中心。</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">帮你找到志同道合的人</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">在微博，在朋友圈，你可能找不到跟你志同道合的人，而在博客，你可以通过看他的几篇文章就迅速地理解认同这个人，即使你没有见过这个人，但你也可以通过这种关联来相互学习。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">如果你在一个领域有相当的了解，你将这些内容发在网络上，网络上跟你志趣相投的人也会被你吸引过来，根据吸引力法则，你是怎样的人你就被怎么样的人吸引，这就是博客所能赋予你的魅力。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">即使博客没有被他人关注，我们依然可以找到同好，你可以自己将博文转载到其他站点，人们会通过搜索引擎找到你，有邮件、微博等工具，我们不乏与他人交流的途径。by Gabriel Weinberg《Why I blog》</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">记录成长</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">隔一段时间，你再回头看你写的博客，你会发现自己正在通过这样的方式在不断的成长，这种成长在自己眼里是一种财富，在别人眼里是一张地图，你得到了收获，不断修正自己的错误，别人得到了指引，避免走弯路。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">更多的情况是当你回望自己的时候你会发现自己是一个傻逼，so what，that is what I am！</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">培养持续做一件事情的能力</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">开始是坚持，后来是习惯，接着喜欢。以后当有人对你说，「你写那么多有用的东西，你真的很厉害啊！」你可以笑而不语，也可以大声说道：「你妹，你不知道我开始的时候多么痛苦！」</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">让你长久地去跑步，你可能做不到；让你每个月看一本书，你也可能做不到；但让你持续地写一个博客，你可以做得到。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">你不相信？你不试试你怎么知道？</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">默默地持续做一件事是一种难得的能力，也是一种难得的品质。</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">讨论反思</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">每人都会有思维的盲点，就好像这篇文章一样，可能你觉得我可能说得不对，你可以反驳我，我欢迎这种讨论，因为讨论的过程中会产生各种的思维的碰撞，这种碰撞会让你反思，也会激发出你新的灵感，这种讨论反思给自己的带来巨大的受益。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">互联网给你的反馈就是让你承受更多，接受更多，成为一个更好的人。</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">搜寻到你意想不到东西</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">世界不止是你的家，你的公司，你的朋友圈，你应该去发现一个更大的世界，通过写博客，你会知道世界上还有很多人像你一样在写博客，这些人和知识正在世界的某个角落在等着你。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">例如，在写这篇文章的过程中，我才知道了Gabriel Weinberg，我才要将阳志平的博客重读一遍。写的过程会让你有很多新的发现，这些新的发现都值得你去再写下来，总结分享出去。</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">一个人在做一件属于自己的事</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">很多你认为自己很牛逼的事情都是自己一个人做出来。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">别人在刷微博，你在看书，别人在看穿越剧，你在学英文，别人在去唱K，你在写个人总结。吃饭也要找同伴，出游要找同伴，看电影要找同伴，你上一次一个人在做一件属于自己的事是在什么时候？</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">如果你想要清晰地思考，就必须远离人群。但是走得越远，你的处境就会越困难，收到的阻力也会越大。因为你没有迎合社会习俗，而是一步步地与它背道而驰。如果自己就是潮水的一部分 ，怎么能看见潮流的方向呢？你只能永远保持质疑，问自己，什么话是我不能说的？为什么？——Paul Graham《不能说的话》</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">互联网的身份识别：</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">一个长期的价值博客是一份很好的简历。这里的“简历”并非是狭义上的求职简历，毕竟现在还没有到价值博客的时代，很多人写博客都是到处转载或者干脆碎碎念，正因此面试官未必拿个人博客当成了解一个人的更可靠窗口。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">这里的“简历”是指一个让别人了解自己的窗口，虽然我们未必做得到像罗永浩、Keso这样的博客，个人的影响力已经足以支撑出一份事业（牛博和5gme），但至少你会因此而结识更多的人，你的博客价值越高，你结识的人就越牛，跟牛人交流又会让你的眼界得到极大的开阔，打开一扇又一扇你原本不知道的门，于是你就变得更牛… 这是一个良性循环。by 刘未鹏</span></p><h3 style="text-align: left;"><span style="background-color: #FFFFFF;">最后</span></h3><p style="text-align: left;"><span style="background-color: #FFFFFF;">你可能想不到在白纸的左边（不值得写博客的原因）写什么了，想不到写个「博客时代已经过去」或者「我没有时间」也可以，但与此同时，你也可以用那些时间去思考一下「怎么做到长期写一个价值博客」。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">如果你不想思考，也可以回复「价值」看看别人的建议。</span></p><p style="text-align: left;"><span style="background-color: #FFFFFF;">推荐写作平台：</span></p><ul class=" list-paddingleft-2"><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">简书（推荐）</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">自己搭建一个独立博客</span></p></li><li><p style="text-align: left;"><span style="background-color: #FFFFFF;">新浪博客</span></p></li></ul></div></blockquote><hr/><p>可能稍微有点长，讲述的很详细了，那么下面的引用是关于，我为什么选择独立博客：</p><hr/><blockquote style="text-align: left;"><div style="text-align: left;"><strong>第三方BSP永远不靠谱。</strong>只要你有钱，还是用独立域名和空间，可以保证你30年后还可以访问你的文件。blogcn不过六七年就没了，微软的Space、雅虎的360、地球村，都证明，公司再大，服务也不靠谱。<br style="text-align: left;"/>用微博的人多了，写博客的人少了，但这和博客式微是两码事。微博只是把原先并不适应写博客的人吸引走了，博客依然有自己的生存空间。为了推广你的博客，也可能用长微博之类的方式嘛。<br style="text-align: left;"/>但博客从来都不是专门写给别人看的，因为微博比博客更适合写给别人看。如果你觉得写博客得到的回音少了，或者别的什么，那你理所应当转去微博。否则，你选啥BSP都行，反正是写给自己看。<br style="text-align: left;"/><br style="text-align: left;"/>作者：李书航<br style="text-align: left;"/>链接：http://www.zhihu.com/question/21140875/answer/17314663<br style="text-align: left;"/>来源：知乎<br style="text-align: left;"/>著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</div></blockquote><hr/><p>当然，种种原因，还要归结于自己对建设站点的爱好。我不能保证可以坚持多长时间，但我由衷地希望自己可以坚持很长，很长的时间，就算是为了曾经的自己，现在的自己，未来的自己，以及，未出现的你。</p><p style="text-align: left;">最后，再来看一个引用，“作为技术人员为什么要写博客”：</p><hr/><p>&nbsp;</p><blockquote style="text-align: left;"><h3 style="margin: 15px auto; padding: 4px 0px; text-align: left; color: rgb(51, 51, 51); text-transform: none; line-height: 32px; text-indent: 0px; letter-spacing: normal; font-family: Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; font-style: normal; font-variant: normal; font-weight: bold; word-spacing: 0px; border-top-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-top-width: 1px; border-bottom-width: 1px; border-top-style: dashed; border-bottom-style: dashed; white-space: normal; widows: 1; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;">一 我心中的博客</h3><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-family: Helvetica,Arial,sans-serif; font-size: 14px;">我所以指的写博客，不单只是写一篇文章出来这一结果。而应该是写的这一过程，写过技术文章的朋友应该跟我一样有这么一个过程。</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-family: Helvetica,Arial,sans-serif; font-size: 14px;">1 自己了解学习，文章所涉及到的知识点，及知识点衍生出来的知识点。</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-family: Helvetica,Arial,sans-serif; font-size: 14px;">2 对学习的知识点进行验证，以确保理论值与实践值保持一致</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-family: Helvetica,Arial,sans-serif; font-size: 14px;">3 构思文章的大纲，哪些部分需要重点写，需要配合实例代码，图片等信息</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">4 动手写，写完后再次检查校正并排版，然后发表</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">5 针对网友的评论中提出的问题进行回复</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">我写文章一般都会经历以上5上步，最终以上5步融合成一个结果那就是&quot;一篇文章&quot; 这一过程也是我心中对的&quot;写博客&quot;一词的诠释</span></p><h3 style="margin: 15px auto; padding: 4px 0px; text-align: left; color: rgb(51, 51, 51); text-transform: none; line-height: 32px; text-indent: 0px; letter-spacing: normal; font-family: Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; font-style: normal; font-variant: normal; font-weight: bold; word-spacing: 0px; border-top-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-top-width: 1px; border-bottom-width: 1px; border-top-style: dashed; border-bottom-style: dashed; white-space: normal; widows: 1; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;">二 为什么要写博客</h3><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;"><strong style="margin: 0px; padding: 0px;">2.1 为自己</strong></span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">写博客对自己的提升是很大的，可能写一篇体现不出来，但是只要你坚持写效果就很明显，好处人个认为有以下几点</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;"><strong style="margin: 0px; padding: 0px;">2.1.1 强化知识点：</strong></span><span style="font-size: 14px;">在写一篇文章前，你必定是要把以文章中心为主的知识点及衍生的知识点都详细了解一 篇，在这一过程中必须会涉及到自己以前所了解过的知识，人的记忆是存在记忆曲线的需要不断的重复记忆才能长久的记住某一事物，而每写一篇文章时都会查阅资 料，在这一过程中必然会遇到以前记住了而现在渐渐淡忘的知识点，当你再次看到时瞬间就会回想起，此时以前的知识点就得到了强化。</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;"><strong style="margin: 0px; padding: 0px;">2.1.2 提升学习能力：</strong></span><span style="font-size: 14px;">同一样的人，了解同一知识点，用不同的方 法，产生的结果必然会不一样，找到最佳的学习方法，这也是一种能力，这种能力是经过多次实践探索之后总结出来的，以前我每次需了解某一种技术时都会先</span><a title="百度" style="margin: 0px; padding: 0px; color: rgb(69, 10, 17); font-size: 14px; text-decoration: underline;" href="http://lusongsong.com/tags/baidu.html" target="_blank"><span style="font-size: 14px;">百度</span></a><span style="font-size: 14px;">&nbsp;看各种搜索结果，发现没有想要的之后，再Google因为Google的结果与百度的会有所不同，Google结果中国外的文章相对会多一点，而偶然点了 一个链接进入了博客园，发现就是自己想要的东西，而且把概念，代码，及经验都写上去了，看完之后对我帮助很大。</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">渐渐的我便开始采这种方法了解新知识概念性的直接看百度百科，实质性的直接 上博客园的 找找看 ，群里的朋友还推荐了一种方法，比如我要学MVC 园子里很多人都写了 关于MVC的一系列文章，把那一系列的文章都看一遍，对于MVC就基本有了了解了，这便是学习能力的提升,对于某种技术用最短的时间做到了比较全面的了解</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;"><strong style="margin: 0px; padding: 0px;">2.1.3 提升文字组织能力：</strong></span><span style="font-size: 14px;">这个就不用说了，写博客，既然是写，就必然会有大量的文字，而如何组织文字表达出自己想表达的意思，是长期练习的，而写博客正好帮助你提高了你的文字组织能力，</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;"><strong style="margin: 0px; padding: 0px;">2.1.4 提升逻辑思维能力：</strong></span><span style="font-size: 14px;">不用说，技术性的东西从来就没的单独存 在的，都一层层技术相结合，那在了解某种技术时，自己的思维也是要顺着这种关系逐渐深入的，比如MVC，你不能只知道 M是什么V是什么 C是什么就行了吧，你得知道 M V C 这三者关系是怎样的，又是怎样交互，而你了解之后再把它写出来时，需要清晰逻辑。</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;"><strong style="margin: 0px; padding: 0px;">2.2 为他人</strong></span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;"><strong style="margin: 0px; padding: 0px;">2.2.1 有意的：</strong></span>&nbsp;<span style="font-size: 14px;">园子里有很多人都写过关于 MVC 框架 WCF 等等系列文章，目的就在于帮助新人快速上手，这个我深有体会，当初我开始学习MVC时就是看的T2噬菌体的MVC系　　列文章，整篇看完后再配合自己动手对于MVC就有了基本的了解了，在次感谢园子里无私献的大牛们。而以上行为就是有意的帮助</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;"><strong style="margin: 0px; padding: 0px;">2.2.2 无意的：</strong></span><span style="font-size: 14px;">很多时候在开发项目的过程中，遇到了技术问题，花了时间解决后，有人会写博客记录，并附上解决方法旨在当再次遇到问题时直接看下文章就知道如何处理了，</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">而碰巧的是，这种问题不止他一个人遇到了。很多人在开发时也遇到了这个问题，在网上找答案时，就找到了这篇文章，并根据文章提供的解决方法，顺利的解决了问题，这种帮助就是无意的帮助</span></p><h3 style="margin: 15px auto; padding: 4px 0px; text-align: left; color: rgb(51, 51, 51); text-transform: none; line-height: 32px; text-indent: 0px; letter-spacing: normal; font-family: Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; font-style: normal; font-variant: normal; font-weight: bold; word-spacing: 0px; border-top-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-top-width: 1px; border-bottom-width: 1px; border-top-style: dashed; border-bottom-style: dashed; white-space: normal; widows: 1; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;">三 一定要写博客吗</h3><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">答案肯定是否定的，中国几百万的程序员，如果都写博客，那程序员的春天就来了，但是事实并非如此。而我所讲的 写博客 的产物并不只是一篇文章，更多的是，对自己能力的提升，自己对知识点的总结，而发表在博客上只是为了公开，还有很多人喜欢记录在云笔记里面。还有工作很 忙，没有空闲时间写出来，因为写技术性的文章，花的时间是很长的。写过的朋友都知道。</span></p><h3 style="margin: 15px auto; padding: 4px 0px; text-align: left; color: rgb(51, 51, 51); text-transform: none; line-height: 32px; text-indent: 0px; letter-spacing: normal; font-family: Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; font-style: normal; font-variant: normal; font-weight: bold; word-spacing: 0px; border-top-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-top-width: 1px; border-bottom-width: 1px; border-top-style: dashed; border-bottom-style: dashed; white-space: normal; widows: 1; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;">四 博客会给你带来哪些收获</h3><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">古人云:一份耕耘,一份收获</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">以下这些是帮助他人而得到的一些认可，并非主观上去追求的</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">MVP：微软每年都颁发MVP给那些经常与其他专业人士分享知识和专业技能，受人尊敬、信任，而且平易近人的专家。而这个称号则是对你写的博客质量的肯定</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">知名度:文章写得好的人，技术水平肯定也很好，知道的人多了，知名度就有了，比如园子里排名前10的大家都知道，都看过他们的文章。</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">尊敬:对于技术界的大神，都是受人敬仰的，在园子里或者工作中也是一样的，在心里对大神们都是默默的佩服!至少我是这样啦，哈哈~也是我学习的榜样!</span></p><h3 style="margin: 15px auto; padding: 4px 0px; text-align: left; color: rgb(51, 51, 51); text-transform: none; line-height: 32px; text-indent: 0px; letter-spacing: normal; font-family: Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; font-style: normal; font-variant: normal; font-weight: bold; word-spacing: 0px; border-top-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-top-width: 1px; border-bottom-width: 1px; border-top-style: dashed; border-bottom-style: dashed; white-space: normal; widows: 1; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 16px;">五 总结</span></h3><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">我所认的写博客是对自己所了解知识的强化，分享，自身能力的提升。当然 写 博客只是一种方法而以，只要能达到提升自我的效果什么方法都是可以的</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">之前有看过一则新闻：即便没有读者，你也要写博客 ，文章也讲解了很多写博客的好处。</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">而我写博客是希望，能提升自己的综合能力，并把自己的知识与经验分享给大家，如果有幸我的分享帮助了一些人，那将使我更加欣慰</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">最后附上一句名言：<em style="margin: 0px; padding: 0px;">有些事情你现在不去做，可能以后都不会有机会了!</em></span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">注：我代表不了大家，所以以上观点只代表我个人。</span></p><p style="font: 18px/34.2px Arial, Helvetica, &quot;Microsoft Yahei&quot;, &quot;Hiragino Sans GB&quot;, sans-serif; margin: 0px; padding: 8px 0px; text-align: left; color: rgb(42, 42, 42); text-transform: none; text-indent: 2em; letter-spacing: normal; word-spacing: 0px; white-space: normal; widows: 1; font-size-adjust: none; font-stretch: normal; background-color: rgb(255, 255, 255); -webkit-text-stroke-width: 0px;"><span style="font-size: 14px;">本文作者：</span><span style="margin: 0px; padding: 0px; color: #450A11; font-size: 14px; text-decoration: underline;"><a style="margin: 0px; padding: 0px; color: rgb(69, 10, 17); font-size: 14px; text-decoration: underline;" href="https://www.cnblogs.com/zery/p/3343893.html" target="_blank" rel="nofollow">Zery</a></span></p></blockquote><hr/><p>&nbsp;就是这样。</p>]]></content>
  </entry>
  <entry>
    <title>欢迎使用Z-BlogPHP!</title>
    <link href="https://old-blog.smallyu.net/index681a.html?id=1"/>
    <id>old-blog:https://old-blog.smallyu.net/?id=1</id>
    <published>2016-05-22T16:00:00.000Z</published>
    <updated>2016-05-22T16:00:00.000Z</updated>
    <category term="旧博客"/>
    <summary type="html"><![CDATA[<p>欢迎使用Z-Blog,这是程序自动生成的文章.您可以删除或是编辑它:) 系统总共生成了一个&amp;quot;留言本&amp;quot;页面,和一个&amp;quot;欢迎使用Z-BlogPHP!&amp;quot;文章,祝您使用愉快!</p>]]></summary>
    <content type="html"><![CDATA[<p>欢迎使用Z-Blog,这是程序自动生成的文章.您可以删除或是编辑它:)</p><p>系统总共生成了一个&quot;留言本&quot;页面,和一个&quot;欢迎使用Z-BlogPHP!&quot;文章,祝您使用愉快!</p>]]></content>
  </entry>
  <entry>
    <title>数学的重要性</title>
    <link href="https://crazy.smallyu.net/2015/09/27/%E6%95%B0%E5%AD%A6%E7%9A%84%E9%87%8D%E8%A6%81%E6%80%A7/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2015/09/27/%E6%95%B0%E5%AD%A6%E7%9A%84%E9%87%8D%E8%A6%81%E6%80%A7/</id>
    <published>2015-09-27T09:30:00.000Z</published>
    <updated>2025-08-16T03:27:11.436Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>由于学识浅薄，把数学的重要性概括出来确实有心无力。在百度上并没能直接搜到这个问题的答案，图书馆也没有哪本书是论述高数与通信工程之间关系的。
前些天认识一位大四的学长说，他现在的成绩比较差，很后悔没有学好高数。事实胜于雄辩，高数的重要性可见一斑。</p>
<p>目前对我们来说]]></summary>
    <content type="html"><![CDATA[<p>由于学识浅薄，把数学的重要性概括出来确实有心无力。在百度上并没能直接搜到这个问题的答案，图书馆也没有哪本书是论述高数与通信工程之间关系的。前些天认识一位大四的学长说，他现在的成绩比较差，很后悔没有学好高数。事实胜于雄辩，高数的重要性可见一斑。</p><p>目前对我们来说数学的重要性有两部分，一个是课程学习方面，一个是能力学习方面。</p><p>课程学习上。</p><p>只要是学校安排的课程，就没有哪门是不重要的。很多学校都把高数作为公共基础课程，相信那些教育界的老师教授这样做肯定是有道理的，多数人认同的做法正确率就比较高。高等数学有5个学分，成绩对我们学生来说自然是很重要的，想要有好成绩，就得好好学，如果拿不到高数的学分绩点的话，影响也是很大的，而且考研数学中高等数学好像要占60%左右，所以这是高数重要的一点。</p><p>能力学习上。</p><p>首先通信工程专业是要求学习C语言的，对编程来说，最重要的就是数学。看一本书《C++从入门到精通》，其中序言里面有一句话:”程序主要是用来完成计算的。”从书里面的教程也能看出来，一开始是将数据类型分类，然后介绍各种运算符、进行各种逻辑计算，当然很重要的一部分内容就是函数的使用。不只是C语言，像PHP、JS等其他编程语言也都大量用到”函数”这样的概念，虽然程序里面的函数不只是进行数字的计算，但自变量、因变量这种关系对应的原理是恒定的。在数学运算中，一丝不苟是重要的，一个数学或一个符号写错就会引起结果的错误，而编程中只要写错一个字符程序就会运行错误，数学对我们能力的培养也算是专业素养上的契合。</p><p>由于并不是很了解通信工程这个专业，只是开学后有一节课提到，这个专业差不多是和模电、数电、单片机、DSP等有关的。</p><p>和电有关的话，就离不开三角函数和它们峰值的计算。</p><p>无意间翻到叫《超声波电机的原理与设计》的书，几乎看不懂，也不知道和我们专业有关系没，前面一部分在计算等效电容时就用的时间积分来计算。另外，《通信原理》类的书里，尤其是信号的那部分，大量用到了带着积分那个符号的函数关系式，起码可见微分和积分的应用广泛。</p><p>我想，在我们更深入地学习数学和专业知识后，知道专业中会出现什么问题，高数可以用来解决专业中什么样的问题后，再来思考这个问题，一定会有更多的收获。</p><br>学号:152027114]]></content>
  </entry>
  <entry>
    <title>（上）雪花谣 • 陈缘</title>
    <link href="https://crazy.smallyu.net/2014/10/04/%E4%B8%8A-%E9%9B%AA%E8%8A%B1%E8%B0%A3%E2%80%A2%E9%99%88%E7%BC%98/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2014/10/04/%E4%B8%8A-%E9%9B%AA%E8%8A%B1%E8%B0%A3%E2%80%A2%E9%99%88%E7%BC%98/</id>
    <published>2014-10-04T08:03:00.000Z</published>
    <updated>2026-07-25T13:10:22.073Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<style>
h1 {
    font-size: 32px;
}
div, p {
    line-height: 1.1;
}
p {
    text-indent: 2em;
    font-size: 16px;
}
body.mobile p {
   ]]></summary>
    <content type="html"><![CDATA[<style>h1 {    font-size: 32px;}div, p {    line-height: 1.1;}p {    text-indent: 2em;    font-size: 16px;}body.mobile p {    font-size: 30px;}</style><br/><p>衣带飘舞雪纷飞，伊人红醉点落晖。</p><p>城园桃前花色美，月雨情萌不同归。</p><br/><br/><p>“红颜薄命？”</p><p>师父说，红颜薄命。师母红颜，当真薄命，就在行动当晚，离开人世。</p><br/><p>“天注定？”</p><p>匆匆忙忙赶到，现场已一片狼藉。战斗声声不息，师父已毫无生气。</p><br/><p>“红颜薄命，天注定。”</p><p>师母永远地走了，离开了师父。</p><p>师父永远的走了，离开了尘世。</p><br/><br/><p>寒风凛冽。雪，漫无目的地飘曳。天，黯淡无光，大地，满目苍凉。雪花，遮住眼睛，看不清前进的方向。前行的脚步越加沉重，心头越感迷茫。身后远方，是昨天路经的村庄。</p><p>……</p><br/><p>“客官，进来坐吧。来碗烧酒暖暖身子吧？”</p><p>不由环视一周。客人稀散，红色灯火映照下，小小酒馆倒显得格外温暖。冰天雪地，竟有如此楼畔？多半是信不过的。不过连日赶路，身心疲惫不堪，歇歇也好。不觉伸手握了握身后的宝剑，一把大大的宝剑。</p><br/><p>“客官，来，这边坐吧。”</p><p>门内柔嫩的招呼声而至，才渐渐把目光转移到眼前人身上。只见从头到脚，一身红装，宽松长袍，轻纱薄绸，带有玉佩沙沙作响，清脆叮当，亮得惹眼，天寒地冻，这般服饰，奇怪足矣。</p><p>找个闲惬的角落就坐，解下束缚在腰上的剑鞘。记得当年师父说，还是有个剑鞘行路方便，不好拿，就背在背上吧。况且这人心险恶，以防不测，作为一个剑客，学会隐藏也是一门必修课。</p><br/><p>“只有酒吗？”</p><p>信手把剑放在桌上，佳人已端酒来。</p><p>“只有酒，我这儿啊，可都是好酒。”</p><p>放下碗，伸手便要倒酒。</p><p>白晢的肌肤展露眼底，红绸薄纱褪下，一段皓腕如霜雪凝恰。抬头，纯美的微笑迎面而来，美，真美，美得像梦中的天使，白里透红的脸，看得叫人发呆。一举一动，一颦一笑，尽让人神魂一炬。</p><br/><p>“看我干嘛……好看呀？”浅浅笑意笑容越加灿烂。</p><p>“姑娘……免贵贵姓？”</p><br/><br/><p>依稀记得，那还是在没有离开师父的时候。师父他，一生只爱一个女人，只爱一个早早就不得不离他而去的女人。那个女人，也非常美，美得如同眼前的红衣女子，让人情不自禁陶醉。</p><p>师父第一次讲述他和师母的故事，是在行动的前一天。先准许代称之为师母吧。</p><p>师父说，他爱错了人。</p><p>……</p><br/><br/><p>天地辽，山河娇，夜色妖娆，秋去彩颜凋；</p><p>天地辽，山河娇，夜色妖娆，屈指数浪涛；</p><p>天地辽，山河娇，夜色妖娆，折花尽逍遥；</p><p>天地辽，山河娇，尘缘难断，雪花独飘摇。</p><p>……</p><br/><br/><p>“歌声婉转悠扬，余音绕梁，浓情心芳，那是一曲《雪花谣》。”</p><br/><p>“那个地方，有个美丽的名字，叫做桃花镇。她说，她喜欢镇上盛开的桃花朵朵，喜欢漫漫雪花伴随桃花飞舞自由飘落，便把那小镇叫做桃花镇。名字美丽不？”</p><br/><p>“美丽美丽……可是师父，桃树在冬天还开花吗？”</p><p>“谁告诉你是冬天了！”</p><p>“冬天才下雪……桃树不嫌冷吗？”</p><p>“谁告诉你是桃树了！”</p><p>“那是什么树？”</p><p>“柳树！”</p><p>“柳树会开桃花吗？”</p><p>“会就是会！”</p><p>“哦……”</p><br/><p>“师父第一次见她的地方，也有个美丽的名字，叫做幽月桥。她说，她喜欢在月光下站在那座桥上看雪，喜欢月光下湖水泛起的点点涟漪，便把它叫做幽月桥。名字美丽不？”</p><br/><p>“美丽美丽……可是师父，都下雪了，还会有月光吗？”</p><p>“有就是有！”</p><p>“湖水不会结冰吗？”</p><p>“不会就是不会！”</p><p>“哦……”</p><br/><p>“她美若天仙。冬季时节，寂静无声月色妖娆的夜晚，桃花朵朵，银装素裹，纤纤身影正衬雪花飘落。明月下，小桥上，轻轻歌声悠然附和。多么美的场景……美吧？”</p><br/><p>“美，美，可是师父……”</p><p>“闭嘴！”</p><p>“哦……”</p><br/><p>云烟雾笼月光寒，雪花纷飞的天气，轻纱薄绸，她只穿单衣。衣带飘舞，歌声飞舞，独自一人，在雪中，在桥上，悠悠歌唱，翩翩起舞。师父被那样的场景迷住，心已飞到九天云浦。</p><br/><p>“如果有可能，为她做什么都行。”</p><br/><p>醉意红颜，垂涎欲滴，娇嫩的美丽，谁不想要。自古英雄爱美人，更何况是绝世倾城的美人。师父情不自禁。</p><br/><p>“只是后来，发生了一些事情。”</p><br/><p>一切都发生地太快。转眼间，浩浩荡荡，兵马如潮水般奔涌而至。发生了什么？总之桥的两边已经挤满人马。</p><br/><p>任师父怎样呼叫拉扯，她始终不肯离开幽月桥。</p><p>为什么？师父不明白。</p><p>落得无奈，师父一把将她抱起，想要逃开，逃开那里，离开那座桥。</p><p>师父说，他清楚地记得，当时她对他微微一笑。或许是感激，又或许是嘲笑。</p><p>师父说，四围已大队人马，想逃开？还抱着一个人？</p><p>师父说，那么多人，人那么多，怎么可能逃得了。</p><p>师父说，他抱着她。</p><p>师父说，她没有说一句话。</p><p>师父说，真的好傻。</p><p>……</p><br/><br/><p>“免贵应该我说！”</p><p>“好，那你说……”</p><p>“……”</p><br/><p>碗里的酒，清澈透明。火光的倒影，是一团冉冉燃烧着的、永不熄灭的焰影。身边，久违的温暖。是红色火光映照红色衣裳显出的暖意，还是红色衣裳倒映在红色酒碗显出的醉意？</p><br/><p>“客官，怕我的酒不好不成？”</p><p>只手端起酒碗，顿了顿，缓了缓，放到嘴边。</p><p>目光穿过黑暗的栈道，落在酒馆的尽头。盏盏油灯闪动着微弱的光亮。光明处更加温暖，黑暗处更加黑暗。突然发现，来酒馆的竟然都是青年人，还大都是行装。</p><p>出门在外，不得不小心谨慎。</p><br/><p>“姑娘，你到底叫什么名字？”</p><p>端在手里的酒，放在唇边，始终没有动口。</p><p>也是，这样的天气，赶路的自然都是年轻人。虽说是村庄，总不会有多少人在这样的天气出来到酒馆喝酒。至于赶路的，当然只会是年轻力壮的年轻人。也可能正因为人少，身为老板娘的红衣女子才会有空亲自来招呼吧？</p><p>一口下去，碗里的酒已喝掉一半。</p><br/><p>“客官，酒怎么样？”</p><p>再一口下去，碗里的酒被喝完。</p><br/><p>“痛快，来，给您倒上。”</p><p>不等开口，一把夺过酒碗，拿起抱在怀里的酒罐，第二次很不熟练地把酒倒满。</p><p>纤细修长的手指映入眼帘，慢慢点放在酒碗边缘。一不小心酒洒在桌面，脸蛋变得绯红嫣然。</p><br/><p>“客官，酒怎么样，好吗？”</p><p>“好酒，好，可是……”</p><p>可是终究没有说出来。</p><br/><p>“再来一碗吧？”</p><p>“嗯。”</p><br/><p>其实，做什么都行。</p><br/><br/><p>听到师母要出嫁的消息，师父口口声声说要报仇。</p><p>雪花飘舞，衣带飞舞，大雪纷飞的天气，没命练武。师父立志要杀掉那个师母不喜欢的人。身上的单衣凛然萧瑟，或许是为了遮盖内心的痛苦。</p><p>一般人也就算了，师父一个资深剑客，谁打不过。可这次的目标却不寻常，是一个国王。刺杀，毫不简单。</p><br/><p>能赢吗？</p><p>当然失败了。就在师母出嫁的当天，师父一早出发，回去已是半夜，结果不言而喻，师父没能改变什么。</p><p>其实，能活着回去便是万幸。</p><br/><p>“当浩浩荡荡的迎亲队伍轰轰烈烈地路过城市的大街，我悄悄尾随在后，紧盯着在队伍前面的国王，那场面，那叫一个壮观……真是壮观，壮观吧？”</p><br/><p>“壮观壮观，可是师父……国王纳妃还迎亲？”</p><p>“迎就是迎！”</p><p>“那您尾随在后，能看到在队伍前面的国王？”</p><p>“能就是能！”</p><p>“可是……”</p><p>“闭嘴！”</p><p>“哦……”</p><br/><p>“师父这次忍辱负重回来，就是因为明白了一个大道理，有了一个更加远大的目标，也找到了一个能报仇的好办法。要不然，我还回来干嘛？？死了算了！”</p><br/><p>“对对，死了算了……”</p><p>“闭嘴！”</p><p>“哦……”</p><br/><p>自从那天，师父真的有所不同。或许因为就是在那天知道了另一个人的存在——月幽国国王。</p><br/><p>师父说，他开始有点明白，为什么师母把那座桥叫做幽月桥，为什么大队人马去抓她时，她不愿意离开那座桥。她没有反抗，不知道是知道自己反抗也无济于事，还是一直在等人去救她？</p><br/><p>师父决定帮助月幽国。</p><br/><p>进入一个国家很简单，加入一个国家的军队也很容易。师父技艺超群，剑术过人，出头自然也不难。</p><br/><p>师父说，想要战胜一个国家，光靠武力是不够的，要智慧。</p><br/><p>至于再后面的事情，师父没有详细说。</p><br/><br/><p>“客官，怎么不喝酒？”</p><p>端起酒碗，放在唇边，没有动口。旁边的佳人，半抱酒罐，笑脸依旧。</p><p>下意识瞟了一眼桌面上放着的宝剑，“告诉我你的名字我就喝。”</p><br/><br/><p>依稀记得，师父好像说过，师母后来为月幽国国王生下了一个孩子。现在想想，师母的孩子，如果没有发生意外，也该有眼前的红衣女子这么大了吧。</p><br/><br/><p>她第三次倒酒。</p><p>她的第三碗酒。</p><br/><br/><p>师父说，师母非常非常的漂亮。如果当初师母生的是个女孩，恐怕那个女孩也会非常非常漂亮吧，就像眼前的红衣女子一样漂亮。</p><br/><br/><p>她仍然没有说出她的名字。</p><br/><br/><p>怎么？</p><p>身为一个酒馆的老板娘，长得这样娇美,连倒酒都不会？</p><p>落座这么长时间，发现酒馆里竟然连个伙计都没有？</p><p>……</p><br/><br/><p>师父没有详细讲述他在月幽国的那段经历，只是零丁提及。只知道月幽国最终战胜了霸占了师母的千尺国。</p><br/><p>可是，赢了又怎样呢？师父依然得不到想要的东西。师母成了月幽国国王的妃子。</p><br/><p>是啊，其实师父早该知道会有那样的结局，也或许师父早就知道。有些东西，不是拼命努力就可以换得来的。</p><br/><p>于是，再后来，师父收养了我。为什么？师父没说。师父收养我的时候，那些事情已经成为过去。</p><br/><br/><p>“客官？”红衣女子笑脸盈然，陪伴身边。</p><br/><p>终于有点明白师父当时的心情。——如果有可能，做什么都行。</p><br/><p>原来佳人的美丽，如此难以抗拒。</p><br/><p>不由在心里默念一句：如果有可能，做什么都行。</p><br/><p>可惜，心里清楚地知道，没有可能。</p><br/><br/><p>“客官喝酒……”</p><br/><br/><p>喝酒吗？已经没有心情继续喝下去。一喝酒，难免会想起那些陈年旧事。</p><br/><br/><p>天地辽，山河娇，夜色妖娆，秋去彩颜凋；</p><p>天地辽，山河娇，夜色妖娆，屈指数浪涛；</p><p>天地辽，山河娇，夜色妖娆，折花尽逍遥；</p><p>天地辽，山河娇，尘缘难断，雪花独飘摇。</p><p>……</p><br/><p> “歌声婉转悠扬，余音绕梁，浓情心芳，那是一曲《雪花谣》。”师父的身影，浮现眼前。</p><br/><br/><p>无声无息，透过暖暖的火光，红衣女子手里的匕首，闪着冷冷的寒光，如笑容般迎面而来，悄然而至……</p><br/><br/><p>师母是我亲手杀掉的……</p><br/><br/>]]></content>
  </entry>
  <entry>
    <title>《第一传说》</title>
    <link href="https://crazy.smallyu.net/2014/06/20/%E3%80%8A%E7%AC%AC%E4%B8%80%E4%BC%A0%E8%AF%B4%E3%80%8B/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2014/06/20/%E3%80%8A%E7%AC%AC%E4%B8%80%E4%BC%A0%E8%AF%B4%E3%80%8B/</id>
    <published>2014-06-20T09:01:00.000Z</published>
    <updated>2026-07-25T13:10:22.072Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<style>
h1 {
    font-size: 32px;
}
div, p {
    line-height: 1.1;
}
p {
    text-indent: 2em;
    font-size: 16px;
}
body.mobile p {
   ]]></summary>
    <content type="html"><![CDATA[<style>h1 {    font-size: 32px;}div, p {    line-height: 1.1;}p {    text-indent: 2em;    font-size: 16px;}body.mobile p {    font-size: 30px;}</style><h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>网游时代浩然崛起，风靡全球，群雄争霸，谁主沉浮？</p><p>一身宠爱万千威望，极品菜鸟，超级大神，认谁作主？</p><p>仙侠战争时空穿越，古时今日，天上地下，屈指谁赢？</p><h3 id="第一卷-风雨初程"><a href="#第一卷-风雨初程" class="headerlink" title="第一卷 风雨初程"></a>第一卷 风雨初程</h3><p><strong>001 游戏开服</strong></p><p>现如今，人类社会发展的必然过程中，随着恩格尔系数的不断下降，世界物欲横流的特性反而变得不怎么明显，代之而来的是文化娱乐、精神生活日益提上议程。由于网络通信传输、计算机制作技术的高速发展，广大高端科技成果也越趋于平民化，商家的竞争则更以用户体验为主要动力。</p><p>新时代的发展，自然需要新一代青少年来给经济脉搏灌输新鲜血液。在日常生活日渐电子化的背景下，电子游戏免不了轮番出现，制作更加精美，效果更加震撼，经久不衰，毁人不倦，残害了一代又一代青年。谁都无法避免以网络和应用软件为载体的游戏的泛滥，甚至已经有国家立法明令禁止厂家不被允许制作、传播、销售游戏软件，但游戏和软件没有明确的界限，小型办公室游戏、文字游戏、网页游戏等等依旧出现。</p><p>任何科技成果都是一把双刃剑。游戏本有着愉悦、放松身心的优点作用，可以在工作之余缓解紧张的心情，但对一些放弃工作放弃学业，整天沉迷游戏的人来说，就具有了很大的威胁，尤其是内含暴力、色情等不健康内容的游戏。地方政府插手干涉也无从制止。为了解决这样的现状，国家的力量最终出动。联合多方意见，初步制定用疏导的方法进行管理、控制局面的方针。说来奇怪，想要消除游戏的负面影响，却开发了一个游戏出来——</p><p>《第一传说》，天联公司呕心沥血耗费亿单位资金倾力打造，世界范围通线网络游戏。</p><p>举国上下，几乎所有人都感受到了这款游戏的非同寻常。首先是它的宣传，光宣传就历时五年，街道的墙壁上铺天盖地是第一传说的海报，超市、大商店、小商店，公共厕所的墙上都是它的贴图。大众媒体就更不用说，电视的各个频道、电脑上的各个网站、广告，第一传说的踪迹遍布整个世界。上到四五十岁的中年人，下到四五岁的小孩，闲谈之余难免聊到游戏，第一传说就成了风头浪尖的话题，其它游戏貌似变得逊色。</p><p>尽管第一传说的宣传效果如日中天，但第一传说游戏本身并未发行销售，也没有上线应用，连公测的消息都没有，内侧就更别说了。话说回来，虽然国家插手此事，实质上也不过是一次商业行动，并非实际意义上的政治行动。天联公司，是由世界商业巨头、联合多个发达国家的企业大亨，联手组合的一个活动性集团公司，取名天联。天联公司高调上市，经济实力本就强大，首屈一指，影响到世界范围，国家想不干预都不行。</p><p>第一传说一直在调动人们的积极性，从海报到图片，再到宣传片，最后是游戏实景，内容大多都是游戏里面或者反映游戏主题的一些东西。天联公司的成立本就吸引众多目光，第一传说的关注性可想而知。直到之前的一段时间，天联公司官方网站一条消息犹如重磅炸弹传播蔓延开来：</p><p>《第一传说》两个月后正式上线！</p><p>网站是必不可少的，天联也有官方网站，用于发布一些游戏相关的消息，宣传画什么的有很多都是从网站上来的，网站上也有论坛，游戏还没上线就已经很火了，大多是一些讨论游戏会有什么内容、询问游戏什么时候出的闲话。</p><p>重点不是网站，是消息：第一传说终于要上线了！盼天盼地盼星星盼月亮，谁都想看看这第一传说有什么靓人之处。这一消息，当然激起无数热血青年的兴致，游戏时间具体在两个月后的某天晚上8点，除了发行时间，官方没有其他任何关于游戏的咨询，只有一句“一切敬请玩家自行探索”。</p><p>同时，论坛上议论大起，游戏体裁是热点之一。到现在天联都没有透漏游戏是什么体裁，仙侠？军事？还有热点就是关于游戏角色的讨论，游戏视角、游戏情节，都是讨论的对象，但所有人都知道谈论是没有用的，游戏就快发布了，万众一心齐心协力期待两个月后的某一天。</p><p>时间匆匆，天联公司开始销售第一传说游戏账号。不详平常的一些游戏，网上注册就可以玩，第一传说的游戏是通过第一传说专用插卡扫描仪连接主机后，才可以用自己惟一仅有的账号登陆。用来和主机连接的插卡器可以公用，但账号卡是唯一的，买账号卡还需要身份证，一张身份证只能买一张账号卡。这样一来就苦了没有身份证的孩子们，不过办法还是有的，可以拿父母的身份证。身份证验证注册账号制度只是为了防止一人多号的情况，虽然不可避免，但总要想办法较少。身份证本身没有任何标识作用。</p><p>天联旗下分店账号卡销售窗口前，车水马龙，长长的队伍排出两条街外。第一批账号卡数量有限，大陆限量10万。物以稀为贵，虽然玩第一传说还需要买专用的读卡器，但读卡器管够，况且已经有网吧准备了不少的第一传说专用读卡器，很多玩家都没有为读卡器发愁。倒是账号卡，账号卡才是真正抢手的东西。而且，人们都会有一个常识，那就是像账号那种有编号的东西买越早越好，大概迎合了人们的虚荣心理吧。</p><p>在首都、沿海地区等一线发达城市，账号卡开售两天就被就被抢购一空，二三线城市也毫不逊色，账号卡卖得非常快。开售当天，那叫一个壮观，场面比春运买车票还惨烈，有的人开售前天就蹲点去了。不过，那肯定是有钱人的做法，如果是一个屌丝，无车无房无钱无女友，会傻到支付不少的金钱去玩一款潮流网络游戏，并且开售账号前一天就去蹲点买账号的吗？话说眼前——</p><p>夜黑风高，月色妖娆，一个少年偷偷尾随在一个漂亮少女的身后，不时回头环顾四周。漂亮少女长发披肩，T恤衫短牛仔裤，肌肤白晢如雪。少女安静地一路向前行走，好像并没有发现尾随的少年。少年依旧尾行，安静地笑。最终，少女走啊走啊走啊走，走到城市中心的露天广场后，径直走进居民中心住宅区。少年快步跟上。</p><p>“咦？”……</p><p>好吧，他是来买账号卡的。卖账号卡的窗口就在市中心旁边。由于担心找不到市中心怎么走，于是他尾随一个居民区的人，保险一点。他清晰地记得，账号卡是在那天晚上8点开始开放窗口销售，8点10分，怎么窗口没人呢？来早了？时间推迟了？还是已经卖完了？</p><p>铃铃铃！一阵警报声突然急促响起。是卖账号卡需要保安来维持秩序吗？看来这第一传说还真不是盖的，看来自己没有来晚。咦？不对，怎么保安冲自己过来了？</p><p>“站住别跑！”</p><p>“嗯？”</p><p>少年倒也干脆，看到住宅区的保安朝自己过来，撒腿就跑。你叫我站住我就站住，叫我别跑我就别跑啊！</p><p>“哼，都说了我是来买账号卡的！”两条腿跑不过四条腿，少年最终还是被抓住了，口舌之战由此展开。他一路尾随人家一个漂亮大姑娘，不被怀疑心怀不轨才怪。少女告诉住宅保安有危险，保安就冲着他来了。</p><p>“那你跑什么！”少年那叫一个郁闷，“你叫我站住我就站住，叫我别跑我就别跑啊！”他只好这么说。保安当然不信，直要报警。为了证明他就是买账号卡来的，他跟保安说，那就在这儿等等吧，买了就回去了。保安其实也不想多生事，有个台阶下就行。于是，他开始了漫长的等待。</p><p>难道我会告诉你账号卡开售是在第二天早上8点吗？一般来说，保安在值班室一晚上值班，有的值班室里面还有床，可以休息。这里的保安也不例外，抓少年的那几个都是值夜班的，一晚上不睡觉，那是他们的工作。8点到9点，到10点，到11点，12点，保安说，算了吧，回去吧。少年倒好，赌气，一直等啊等啊等啊等，他还以为开售时间推迟了。保安当然更不着急，反正他们晚上也不睡觉，赌气？等？等就等！</p><p>有志青年就是这么炼成的，他真的很有毅力，2点,3点，4点，5点……直到早上8点。如愿以偿地，他买到了账号卡，阳光袭来，看着闪闪发光的账号卡发射出金灿灿的光芒，满身疲倦的他会心一笑。保安真的无奈了。</p><p>回到家，开门，关门，啪，倒头就睡。（第二天早上8点才开售，怎么没人告诉我丫！）</p><p>涛声依旧，销售窗口前排了长长的队伍。高兴的，不高兴的，欢笑的，抱怨的，不时听到有人买到编号靠后、编号不好的抱怨声传来，不过毕竟买到就好，在你抱怨你没有买到好号码的时候，应该想到世界上还有很多人没有游戏账号……或许不会有人知道，这个地区的第一张账号卡，卖给了一个在这里等了整整12个小时的人吧。像身份证一样，第一传说账号卡是按地区发行的，编号分好几个部分，前面一部分是地区编号，后面一部分是顺序编号。</p><p>账号卡发行之后，自然就是进入游戏玩游戏了。不知不觉，两个月匆匆过去，游戏正式运营的一天来了。拿出账号卡，红色的“第一传说”四个大字深深印刻在金黄色的账号卡身。插入账号卡，电脑屏幕自动弹出天联官网的页面，大大的“天联网络游戏客户端下载”标题出现在首页。点击进入，像往常下载游戏一样，迅雷弹出窗口，提示下载任务。</p><p>很多人都喜欢游戏一开服就进入游戏，第一时间抢注ID。少年自然也不例外，问题是，客户端文件有点大啊，怎么没人告诉他玩网络游戏还需要下载客户端的！眼看游戏正式开始的时间到了：</p><p>3！</p><p>2！</p><p>1！</p>]]></content>
  </entry>
  <entry>
    <title>莫泊桑《项链》一文中的不合理情节</title>
    <link href="https://crazy.smallyu.net/2014/02/13/%E8%8E%AB%E6%B3%8A%E6%A1%91%E3%80%8A%E9%A1%B9%E9%93%BE%E3%80%8B%E4%B8%80%E6%96%87%E4%B8%AD%E7%9A%84%E4%B8%8D%E5%90%88%E7%90%86%E6%83%85%E8%8A%82/"/>
    <id>blog-crazy:https://crazy.smallyu.net/2014/02/13/%E8%8E%AB%E6%B3%8A%E6%A1%91%E3%80%8A%E9%A1%B9%E9%93%BE%E3%80%8B%E4%B8%80%E6%96%87%E4%B8%AD%E7%9A%84%E4%B8%8D%E5%90%88%E7%90%86%E6%83%85%E8%8A%82/</id>
    <published>2014-02-13T10:20:00.000Z</published>
    <updated>2026-07-25T13:10:22.074Z</updated>
    <category term="疯狂版"/>
    <summary type="html"><![CDATA[<p>高中年级的小说选修课本里有一篇叫《项链》的小说，世界小说巨匠莫泊桑写的，上课的时候就发现有些不合常理的情节，或者说剧情需要，巧合性的情节，现在回忆着写一下。</p>
<p>首先罗塞尔太太丢失项链就是一个相当巧合的巧合。她晚会后匆匆忙忙离开会场，之后顺着马路租车子，然后打车回]]></summary>
    <content type="html"><![CDATA[<p>高中年级的小说选修课本里有一篇叫《项链》的小说，世界小说巨匠莫泊桑写的，上课的时候就发现有些不合常理的情节，或者说剧情需要，巧合性的情节，现在回忆着写一下。</p><p>首先罗塞尔太太丢失项链就是一个相当巧合的巧合。她晚会后匆匆忙忙离开会场，之后顺着马路租车子，然后打车回家，官方解释说这是为后文罗塞尔太太丢失项链埋下的伏笔，罗塞尔太太因为贫穷，所以慌张离开，是为了别人不识破真相。确实是相当精妙的构思，合情合理合逻辑。可问题来了，既然他们穷，那么一定会格外珍惜这串价格不菲的项链，慌忙之中，他们没有再注意一下项链吗？或许可以模糊的理解成他们真的大意了？（剧情需要）</p><p>第二个是关于罗塞尔太太陪项链的事。当时罗塞尔太太和她的丈夫几乎已经可以确定项链是找不到了，便决定买一条真的赔给弗莱士杰太太（就是借的项链的主人）。问题来了，它们为什么要隐瞒呢？她们既然已经决定要赔了，为什么不大大方方地告诉弗莱士杰太太真相呢？被身份的卑微和贫穷让他们自卑到不敢说吗？明明白白的说，我丢了你的项链，不过你别担心，我会再买一条还给你的。这样不可以吗？如果这样的话，主人公的命运会怎样发展呢？（剧情需要）</p><p>第三个是罗塞尔太太还了真项链之后。罗塞尔太太还项链之后和弗莱士杰太太竟然十年没有见面吗？！原文里说，十年后，罗塞尔太太在街上看到了正在散步的弗莱士杰太太，由于已经还情了债款，便大大方方的上前打招呼。弗莱士杰太太在散步，说明罗塞尔太太和弗莱士杰太太住的差不是很远，原来罗塞尔太太躲了弗莱士杰太太整整十年啊！？（不合常理）</p><p>最后一个，让人奇怪的情节。文章的最后弗莱士杰太太揭露真相，说，“可怜的马蒂尔德！我原来的那串项链是假的呀！”问题：为什么弗莱士杰太太要说出真相，告诉罗塞尔太太原来的项链是假的呢？她完全可以不说出来，把那条项链据为己有。现在说出来了，猜猜罗塞尔一家会要回项链吗？当时是资产阶级横行的时代，况且可以让罗塞尔一家还十年的债务，也不会是小数目，就算弗莱士杰太太再富有，谁会嫌自己钱多呢，为什么要说出真相呢？为什么呢为什么呢？（剧情需要 不合常理）</p><p>（来打酱油的）</p>]]></content>
  </entry>
</feed>
