<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Fgaoxing</title>
  
  <subtitle>Fgaoxing的个人博客</subtitle>
  <link href="https://www.yt-blog.top/atom.xml" rel="self"/>
  
  <link href="https://www.yt-blog.top/"/>
  <updated>2026-01-30T09:12:56.563Z</updated>
  <id>https://www.yt-blog.top/</id>
  
  <author>
    <name>Fgaoxing</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>MiniGFM：3KB的轻量Markdown渲染库</title>
    <link href="https://www.yt-blog.top/31114/"/>
    <id>https://www.yt-blog.top/31114/</id>
    <published>2026-01-30T08:46:05.251Z</published>
    <updated>2026-01-30T09:12:56.563Z</updated>
    
    <content type="html"><![CDATA[<p>前端开发中Markdown渲染很常见，但主流库都太大了——动不动几十KB，还带一堆依赖和小众功能。小程序、轻量工具这些对体积敏感的场景，用这种重型库太浪费。</p><p>MiniGFM正好填补了这个空白。纯JavaScript写的，裸体积就3KB（Brotli压缩后1.5KB），零依赖，却能兼容GitHub Flavored Markdown（GFM），默认还带XSS防护。既轻量又实用，很适合轻量场景。</p><h2 id="快速开始"><a class="header-anchor" href="#快速开始">¶</a>快速开始</h2><p>MiniGFM支持浏览器、现代前端工程、Node.js这些主流环境，接入很简单，不用什么配置，就两步：实例化+调用parse方法。同时也支持个性化配置。</p><h3 id="浏览器用CDN"><a class="header-anchor" href="#浏览器用CDN">¶</a>浏览器用CDN</h3><p>不用构建，直接CDN引入就能用，适合原型开发、静态页面：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.net/npm/@oblivionocean/minigfm@latest/dist/index.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="comment">// 实例化核心类</span></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> mdRenderer = <span class="keyword">new</span> <span class="title class_">MiniGFM</span>();</span></span><br><span class="line"><span class="language-javascript">  <span class="comment">// 解析Markdown为标准HTML</span></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">const</span> htmlStr = mdRenderer.<span class="title function_">parse</span>(<span class="string">&#x27;# MiniGFM\n\n一款**3KB**轻量GFM兼容Markdown渲染库，零依赖且XSS安全。&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">  <span class="comment">// 挂载至页面</span></span></span><br><span class="line"><span class="language-javascript">  <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;md-container&#x27;</span>).<span class="property">innerHTML</span> = htmlStr;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">`</span><br><span class="line"></span><br><span class="line">### 现代前端项目（ESModule）</span><br><span class="line"></span><br><span class="line">Vue、React、Vite这些工程化项目，NPM安装后按需导入就行：</span><br><span class="line"></span><br><span class="line">```bash</span><br><span class="line">npm i @oblivionocean/minigfm</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">MiniGFM</span> <span class="keyword">from</span> <span class="string">&#x27;@oblivionocean/minigfm&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> md = <span class="keyword">new</span> <span class="title class_">MiniGFM</span>();</span><br><span class="line"><span class="keyword">const</span> result = md.<span class="title function_">parse</span>(<span class="string">&#x27;&gt; 设计理念：轻量至上，聚焦核心\n```js\nconsole.log(&quot;MiniGFM&quot;);\n```&#x27;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result); <span class="comment">// 输出HTML结构</span></span><br></pre></td></tr></table></figure><h3 id="Node-js（CommonJS）"><a class="header-anchor" href="#Node-js（CommonJS）">¶</a>Node.js（CommonJS）</h3><p>Node.js服务端渲染也能用：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">MiniGFM</span> = <span class="built_in">require</span>(<span class="string">&#x27;@oblivionocean/minigfm&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> md = <span class="keyword">new</span> <span class="title class_">MiniGFM</span>.<span class="title class_">MiniGFM</span>();</span><br><span class="line"><span class="keyword">const</span> html = md.<span class="title function_">parse</span>(<span class="string">&#x27;### 服务端渲染\nMiniGFM支持Node.js环境&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="个性化配置"><a class="header-anchor" href="#个性化配置">¶</a>个性化配置</h3><p>配置项不多，就两个：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> md = <span class="keyword">new</span> <span class="title class_">MiniGFM</span>(&#123;</span><br><span class="line">  <span class="attr">unsafe</span>: <span class="literal">true</span>, <span class="comment">// 默认false，自动转义HTML防XSS；开启后支持原生HTML</span></span><br><span class="line">  <span class="attr">hljs</span>: hljs    <span class="comment">// 传highlight.js实例，给代码块加高亮</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="为什么能做到这么小"><a class="header-anchor" href="#为什么能做到这么小">¶</a>为什么能做到这么小</h2><p>同类库动不动几十KB，MiniGFM能做到3KB还兼容GFM核心语法，不是因为偷工减料，而是用了<strong>减法设计</strong>和<strong>工程优化</strong>，把没用的都砍掉了。</p><h3 id="1-只做GFM核心语法"><a class="header-anchor" href="#1-只做GFM核心语法">¶</a>1. 只做GFM核心语法</h3><p>MiniGFM只实现了GFM的<strong>核心语法</strong>（标题、列表、链接、加粗、代码块、引用、分隔线这些），把所有小众、低频的扩展都砍掉了。市面上重型库体积大的原因，就是为了追求「全量兼容」，塞了很多实际开发中根本用不到的功能。MiniGFM从需求上就精简了，代码量自然就小了。</p><h3 id="2-零依赖，纯原生"><a class="header-anchor" href="#2-零依赖，纯原生">¶</a>2. 零依赖，纯原生</h3><p>MiniGFM的解析器是<strong>纯手写的</strong>，不依赖任何第三方库——不用通用解析器，也不用工具类库，自然就不会因为依赖链膨胀体积。而且纯原生实现运行时没额外开销，渲染效率也更好。</p><h3 id="3-只输出HTML，样式和高亮按需来"><a class="header-anchor" href="#3-只输出HTML，样式和高亮按需来">¶</a>3. 只输出HTML，样式和高亮按需来</h3><p>MiniGFM就干一件事：把Markdown转成HTML。不绑CSS，不带主题，也不内置代码高亮。样式你自己定，代码高亮通过配置对接highlight.js。这样既减小了核心库体积，又保证了扩展的灵活性。</p><h3 id="4-代码层也精简"><a class="header-anchor" href="#4-代码层也精简">¶</a>4. 代码层也精简</h3><p>实现上做了很多优化：去掉老旧浏览器的兼容代码，只关注现代环境；精简解析逻辑，每一行代码都为核心服务；用高效的正则和轻量AST，在保证准确性的同时进一步压缩体积。</p><h2 id="适用场景"><a class="header-anchor" href="#适用场景">¶</a>适用场景</h2><p>MiniGFM定位是<strong>轻量场景下的GFM核心渲染</strong>，不是追求「大而全」的全场景方案。3KB体积+零依赖，在这些场景下最有价值：</p><ol><li><strong>体积敏感的应用</strong>：小程序、快应用这些对体积有严格限制的</li><li><strong>轻量前端项目</strong>：个人博客、工具站、嵌入式组件</li><li><strong>服务端渲染（SSR）</strong>：Node.js环境下快速解析Markdown</li><li><strong>简易编辑器/预览</strong>：作为Markdown实时预览的渲染层</li></ol><p>当然，如果你需要支持大量小众扩展语法，或者要一站式的「渲染+样式+高亮」解决方案，MiniGFM可能不太合适。但它对「核心需求」的精准聚焦，恰好解决了大多数场景的Markdown渲染问题。</p><h2 id="总结"><a class="header-anchor" href="#总结">¶</a>总结</h2><p>MiniGFM的魅力就是<strong>减法设计</strong>贯彻到底：3KB体积、零依赖、兼容GFM、自带XSS防护，还能多环境使用。现代前端越来越重视性能和体积，这种「小而精」的工具库正好解决了重型库的冗余问题。</p><p>对于追求轻量、高效的场景，MiniGFM是个不错的选择，值得试试。</p><p><strong>项目地址</strong></p><ul><li>在线演示：<a href="https://minigfm.js.org/zh-cn.html">https://minigfm.js.org/zh-cn.html</a></li><li>NPM仓库：<a href="https://www.npmjs.com/package/@oblivionocean/minigfm">https://www.npmjs.com/package/@oblivionocean/minigfm</a></li></ul>]]></content>
    
    
    <summary type="html">前端开发中Markdown渲染很常见，但主流库都太大了——动不动几十KB，还带一堆依赖和小众功能。小程序、轻量工具这些对体积敏感的场景，用这种重型库太浪费。 MiniGFM正好填补了这个空白。纯JavaScript写的，裸体积就3KB（Brotli压缩后1.5KB），零依赖，却能兼容GitHub Flavored Markdown（GFM），默认还带XSS防护。既轻量又实用，很适合轻量场景。 快速...</summary>
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="JS" scheme="https://www.yt-blog.top/tags/JS/"/>
    
    <category term="Markdown" scheme="https://www.yt-blog.top/tags/Markdown/"/>
    
  </entry>
  
  <entry>
    <title>Go反射：性能瓶颈与零拷贝优化</title>
    <link href="https://www.yt-blog.top/38912/"/>
    <id>https://www.yt-blog.top/38912/</id>
    <published>2026-01-30T05:54:17.551Z</published>
    <updated>2026-01-30T05:58:41.079Z</updated>
    
    <content type="html"><![CDATA[<p>做Go开发的，肯定少不了用反射——解析Tag、拿字段偏移、获取类型信息，ORM、序列化、配置绑定这些地方都要用到。</p><p>但是官方的<code>reflect</code>包性能真的不太行，解析一个字段或Tag要花几十到几百万纳秒，调得多了，直接成性能瓶颈。</p><p>很多人只知道「反射慢」，但不知道慢在哪。咱们今天就从<code>runtime</code>层面分析一下，顺便搞个零拷贝的优化方案。</p><h2 id="一、先从底层说起"><a class="header-anchor" href="#一、先从底层说起">¶</a>一、先从底层说起</h2><p>要搞清楚反射的性能问题，得先知道Go底层是怎么回事。</p><p>从Go1.14开始，<code>runtime</code>里几个核心类型的内存布局就没变过。这是个关键点。</p><p>Go的反射包就是基于<code>runtime</code>层的<code>abi</code>实现的。</p><p><a href="https://github.com/golang/go/blob/master/src/reflect/type.go">reflect/type.go</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// TypeOf returns the reflection [Type] that represents the dynamic type of i.</span></span><br><span class="line"><span class="comment">// If i is a nil interface value, TypeOf returns nil.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">TypeOf</span><span class="params">(i any)</span></span> Type &#123;</span><br><span class="line"> <span class="keyword">return</span> toType(abi.TypeOf(i))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>其实<code>reflect.Type</code>就是一个接口，上面代码里的<code>toType()</code>把它转成了<code>reflect.rtype</code>。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// rtype is the common implementation of most values.</span></span><br><span class="line"><span class="comment">// It is embedded in other struct types.</span></span><br><span class="line"><span class="keyword">type</span> rtype <span class="keyword">struct</span> &#123;</span><br><span class="line"> t abi.Type</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">toRType</span><span class="params">(t *abi.Type)</span></span> *rtype &#123;</span><br><span class="line"> <span class="keyword">return</span> (*rtype)(unsafe.Pointer(t))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>所以最后拿到的是个<code>abi.Type</code>实例，<code>reflect.rtype</code>只是给它包了一层，提供个友好的接口。也可以换成别的类型专用结构体，但本质上都是对<code>abi.Type</code>的封装。</p><p><a href="https://github.com/golang/go/blob/master/src/internal/abi/type.go">internal/abi/type.go</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Type is the runtime representation of a Go type.</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Be careful about accessing this type at build time, as the version</span></span><br><span class="line"><span class="comment">// of this type in the compiler/linker may not have the same layout</span></span><br><span class="line"><span class="comment">// as the version in the target binary, due to pointer width</span></span><br><span class="line"><span class="comment">// differences and any experiments. Use cmd/compile/internal/rttype</span></span><br><span class="line"><span class="comment">// or the functions in compiletype.go to access this type instead.</span></span><br><span class="line"><span class="comment">// (<span class="doctag">TODO:</span> this admonition applies to every type in this package.</span></span><br><span class="line"><span class="comment">// Put it in some shared location?)</span></span><br><span class="line"><span class="keyword">type</span> Type <span class="keyword">struct</span> &#123;</span><br><span class="line"> Size_       <span class="type">uintptr</span></span><br><span class="line"> PtrBytes    <span class="type">uintptr</span> <span class="comment">// number of (prefix) bytes in the type that can contain pointers</span></span><br><span class="line"> Hash        <span class="type">uint32</span>  <span class="comment">// hash of type; avoids computation in hash tables</span></span><br><span class="line"> TFlag       TFlag   <span class="comment">// extra type information flags</span></span><br><span class="line"> Align_      <span class="type">uint8</span>   <span class="comment">// alignment of variable with this type</span></span><br><span class="line"> FieldAlign_ <span class="type">uint8</span>   <span class="comment">// alignment of struct field with this type</span></span><br><span class="line"> Kind_       Kind    <span class="comment">// enumeration for C</span></span><br><span class="line"> <span class="comment">// function for comparing objects of this type</span></span><br><span class="line"> <span class="comment">// (ptr to object A, ptr to object B) -&gt; ==?</span></span><br><span class="line"> Equal <span class="function"><span class="keyword">func</span><span class="params">(unsafe.Pointer, unsafe.Pointer)</span></span> <span class="type">bool</span></span><br><span class="line"> <span class="comment">// GCData stores the GC type data for the garbage collector.</span></span><br><span class="line"> <span class="comment">// Normally, GCData points to a bitmask that describes the</span></span><br><span class="line"> <span class="comment">// ptr/nonptr fields of the type. The bitmask will have at</span></span><br><span class="line"> <span class="comment">// least PtrBytes/ptrSize bits.</span></span><br><span class="line"> <span class="comment">// If the TFlagGCMaskOnDemand bit is set, GCData is instead a</span></span><br><span class="line"> <span class="comment">// **byte and the pointer to the bitmask is one dereference away.</span></span><br><span class="line"> <span class="comment">// The runtime will build the bitmask if needed.</span></span><br><span class="line"> <span class="comment">// (See runtime/type.go:getGCMask.)</span></span><br><span class="line"> <span class="comment">// Note: multiple types may have the same value of GCData,</span></span><br><span class="line"> <span class="comment">// including when TFlagGCMaskOnDemand is set. The types will, of course,</span></span><br><span class="line"> <span class="comment">// have the same pointer layout (but not necessarily the same size).</span></span><br><span class="line"> GCData    *<span class="type">byte</span></span><br><span class="line"> Str       NameOff <span class="comment">// string form</span></span><br><span class="line"> PtrToThis TypeOff <span class="comment">// type for pointer to this type, may be zero</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>当然实际上结构体数据是如上结构体的扩展，同样定义在一起。</p><p><a href="https://github.com/golang/go/blob/master/src/internal/abi/type.go">internal/abi/type.go</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> StructField <span class="keyword">struct</span> &#123;</span><br><span class="line"> Name   Name    <span class="comment">// name is always non-empty</span></span><br><span class="line"> Typ    *Type   <span class="comment">// type of field</span></span><br><span class="line"> Offset <span class="type">uintptr</span> <span class="comment">// byte offset of field</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> StructType <span class="keyword">struct</span> &#123;</span><br><span class="line"> Type</span><br><span class="line"> PkgPath Name</span><br><span class="line"> Fields  []StructField</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还有一点，这些底层类型里存的结构体元数据，是编译器编译时就写进程序的<strong>只读内存区</strong>了，<strong>地址固定、GC不回收、运行时不能改</strong>。这给直接操作底层内存提供了安全保障。</p><p>既然这样，我们可以用<strong>固定偏移量</strong>精确找到目标字段，不用完整解析整个底层结构体，只要定义几个空的镜像类型来做类型标注就够了。</p><h2 id="二、性能瓶颈在哪儿"><a class="header-anchor" href="#二、性能瓶颈在哪儿">¶</a>二、性能瓶颈在哪儿</h2><p><code>reflect.TypeOf()</code>底层就是做个指针转换，不拷贝不计算，挺快的。真正的性能损耗出在后面两个阶段，而且因为没缓存，损耗被放大了好几倍。</p><h3 id="2-1-Field方法做了无意义的内存分配"><a class="header-anchor" href="#2-1-Field方法做了无意义的内存分配">¶</a>2.1 Field方法做了无意义的内存分配</h3><p>调用<code>reflect.Type.Field(i)</code>的时候，<code>rtype</code>会被转成<code>*StructType</code>，然后从<code>Fields</code>字段里读目标字段信息。</p><p><a href="https://github.com/golang/go/blob/master/src/reflect/type.go">reflect/type.go</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Struct field</span></span><br><span class="line"><span class="keyword">type</span> structField = abi.StructField <span class="comment">// 注意：你平时用的是 reflect.structField，不是reflect.StructField</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// structType represents a struct type.</span></span><br><span class="line"><span class="keyword">type</span> structType <span class="keyword">struct</span> &#123;</span><br><span class="line"> abi.StructType</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(t *rtype)</span></span> Field(i <span class="type">int</span>) StructField &#123;</span><br><span class="line"> <span class="keyword">if</span> t.Kind() != Struct &#123;</span><br><span class="line">  <span class="built_in">panic</span>(<span class="string">&quot;reflect: Field of non-struct type &quot;</span> + t.String())</span><br><span class="line"> &#125;</span><br><span class="line"> tt := (*structType)(unsafe.Pointer(t))</span><br><span class="line"> <span class="keyword">return</span> tt.Field(i)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Field returns the i&#x27;th struct field.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(t *structType)</span></span> Field(i <span class="type">int</span>) (f StructField) &#123;</span><br><span class="line"> <span class="keyword">if</span> i &lt; <span class="number">0</span> || i &gt;= <span class="built_in">len</span>(t.Fields) &#123;</span><br><span class="line">  <span class="built_in">panic</span>(<span class="string">&quot;reflect: Field index out of bounds&quot;</span>)</span><br><span class="line"> &#125;</span><br><span class="line"> p := &amp;t.Fields[i]</span><br><span class="line"> f.Type = toType(p.Typ)</span><br><span class="line"> f.Name = p.Name.Name()</span><br><span class="line"> f.Anonymous = p.Embedded()</span><br><span class="line"> <span class="keyword">if</span> !p.Name.IsExported() &#123;</span><br><span class="line">  f.PkgPath = t.PkgPath.Name()</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> tag := p.Name.Tag(); tag != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">  f.Tag = StructTag(tag)</span><br><span class="line"> &#125;</span><br><span class="line"> f.Offset = p.Offset</span><br><span class="line"></span><br><span class="line"> <span class="comment">// We can&#x27;t safely use this optimization on js or wasi,</span></span><br><span class="line"> <span class="comment">// which do not appear to support read-only data.</span></span><br><span class="line"> <span class="keyword">if</span> i &lt; <span class="number">256</span> &amp;&amp; runtime.GOOS != <span class="string">&quot;js&quot;</span> &amp;&amp; runtime.GOOS != <span class="string">&quot;wasip1&quot;</span> &#123;</span><br><span class="line">  staticuint64s := getStaticuint64s()</span><br><span class="line">  p := unsafe.Pointer(&amp;(*staticuint64s)[i])</span><br><span class="line">  <span class="keyword">if</span> unsafe.Sizeof(<span class="type">int</span>(<span class="number">0</span>)) == <span class="number">4</span> &amp;&amp; goarch.BigEndian &#123;</span><br><span class="line">   p = unsafe.Add(p, <span class="number">4</span>)</span><br><span class="line">  &#125;</span><br><span class="line">  f.Index = unsafe.Slice((*<span class="type">int</span>)(p), <span class="number">1</span>)</span><br><span class="line"> &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  <span class="comment">// NOTE(rsc): This is the only allocation in the interface</span></span><br><span class="line">  <span class="comment">// presented by a reflect.Type. It would be nice to avoid,</span></span><br><span class="line">  <span class="comment">// but we need to make sure that misbehaving clients of</span></span><br><span class="line">  <span class="comment">// reflect cannot affect other uses of reflect.</span></span><br><span class="line">  <span class="comment">// One possibility is CL 5371098, but we postponed that</span></span><br><span class="line">  <span class="comment">// ugliness until there is a demonstrated</span></span><br><span class="line">  <span class="comment">// need for the performance. This is issue 2320.</span></span><br><span class="line">  f.Index = []<span class="type">int</span>&#123;i&#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面这段代码问题在哪儿呢？看<code>f.Index = []int{i}</code>这一行。这里无意义地创建了一个列表，实际上这个数据就是你自己传进去的<code>i</code>，完全没必要。这步操作纯粹是为了兼容性。</p><p>具体讨论可以看<a href="https://github.com/golang/go/issues/68380">golang/go · Issue#68380</a>。</p><h3 id="2-2-Tag获取时的字符串拷贝"><a class="header-anchor" href="#2-2-Tag获取时的字符串拷贝">¶</a>2.2 Tag获取时的字符串拷贝</h3><p>刚才说的获取字段的时候，<code>StructField</code>的<code>Tag</code>字段是<code>StructTag</code>类型，其实就是个<code>string</code>。</p><p><a href="https://github.com/golang/go/blob/master/src/reflect/type.go">reflect/type.go</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// A StructTag is the tag string in a struct field.</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// By convention, tag strings are a concatenation of</span></span><br><span class="line"><span class="comment">// optionally space-separated key:&quot;value&quot; pairs.</span></span><br><span class="line"><span class="comment">// Each key is a non-empty string consisting of non-control</span></span><br><span class="line"><span class="comment">// characters other than space (U+0020 &#x27; &#x27;), quote (U+0022 &#x27;&quot;&#x27;),</span></span><br><span class="line"><span class="comment">// and colon (U+003A &#x27;:&#x27;).  Each value is quoted using U+0022 &#x27;&quot;&#x27;</span></span><br><span class="line"><span class="comment">// characters and Go string literal syntax.</span></span><br><span class="line"><span class="keyword">type</span> StructTag <span class="type">string</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Get returns the value associated with key in the tag string.</span></span><br><span class="line"><span class="comment">// If there is no such key in the tag, Get returns the empty string.</span></span><br><span class="line"><span class="comment">// If the tag does not have the conventional format, the value</span></span><br><span class="line"><span class="comment">// returned by Get is unspecified. To determine whether a tag is</span></span><br><span class="line"><span class="comment">// explicitly set to the empty string, use [StructTag.Lookup].</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(tag StructTag)</span></span> Get(key <span class="type">string</span>) <span class="type">string</span> &#123;</span><br><span class="line"> v, _ := tag.Lookup(key)</span><br><span class="line"> <span class="keyword">return</span> v</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Lookup returns the value associated with key in the tag string.</span></span><br><span class="line"><span class="comment">// If the key is present in the tag the value (which may be empty)</span></span><br><span class="line"><span class="comment">// is returned. Otherwise the returned value will be the empty string.</span></span><br><span class="line"><span class="comment">// The ok return value reports whether the value was explicitly set in</span></span><br><span class="line"><span class="comment">// the tag string. If the tag does not have the conventional format,</span></span><br><span class="line"><span class="comment">// the value returned by Lookup is unspecified.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(tag StructTag)</span></span> Lookup(key <span class="type">string</span>) (value <span class="type">string</span>, ok <span class="type">bool</span>) &#123;</span><br><span class="line"> <span class="comment">// When modifying this code, also update the validateStructTag code</span></span><br><span class="line"> <span class="comment">// in cmd/vet/structtag.go.</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> tag != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">  <span class="comment">// Skip leading space.</span></span><br><span class="line">  i := <span class="number">0</span></span><br><span class="line">  <span class="keyword">for</span> i &lt; <span class="built_in">len</span>(tag) &amp;&amp; tag[i] == <span class="string">&#x27; &#x27;</span> &#123;</span><br><span class="line">   i++</span><br><span class="line">  &#125;</span><br><span class="line">  tag = tag[i:]</span><br><span class="line">  <span class="keyword">if</span> tag == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">   <span class="keyword">break</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Scan to colon. A space, a quote or a control character is a syntax error.</span></span><br><span class="line">  <span class="comment">// Strictly speaking, control chars include the range [0x7f, 0x9f], not just</span></span><br><span class="line">  <span class="comment">// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters</span></span><br><span class="line">  <span class="comment">// as it is simpler to inspect the tag&#x27;s bytes than the tag&#x27;s runes.</span></span><br><span class="line">  i = <span class="number">0</span></span><br><span class="line">  <span class="keyword">for</span> i &lt; <span class="built_in">len</span>(tag) &amp;&amp; tag[i] &gt; <span class="string">&#x27; &#x27;</span> &amp;&amp; tag[i] != <span class="string">&#x27;:&#x27;</span> &amp;&amp; tag[i] != <span class="string">&#x27;&quot;&#x27;</span> &amp;&amp; tag[i] != <span class="number">0x7f</span> &#123;</span><br><span class="line">   i++</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> i == <span class="number">0</span> || i+<span class="number">1</span> &gt;= <span class="built_in">len</span>(tag) || tag[i] != <span class="string">&#x27;:&#x27;</span> || tag[i+<span class="number">1</span>] != <span class="string">&#x27;&quot;&#x27;</span> &#123;</span><br><span class="line">   <span class="keyword">break</span></span><br><span class="line">  &#125;</span><br><span class="line">  name := <span class="type">string</span>(tag[:i])</span><br><span class="line">  tag = tag[i+<span class="number">1</span>:]</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Scan quoted string to find value.</span></span><br><span class="line">  i = <span class="number">1</span></span><br><span class="line">  <span class="keyword">for</span> i &lt; <span class="built_in">len</span>(tag) &amp;&amp; tag[i] != <span class="string">&#x27;&quot;&#x27;</span> &#123;</span><br><span class="line">   <span class="keyword">if</span> tag[i] == <span class="string">&#x27;\\&#x27;</span> &#123;</span><br><span class="line">    i++</span><br><span class="line">   &#125;</span><br><span class="line">   i++</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> i &gt;= <span class="built_in">len</span>(tag) &#123;</span><br><span class="line">   <span class="keyword">break</span></span><br><span class="line">  &#125;</span><br><span class="line">  qvalue := <span class="type">string</span>(tag[:i+<span class="number">1</span>])</span><br><span class="line">  tag = tag[i+<span class="number">1</span>:]</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> key == name &#123;</span><br><span class="line">   value, err := strconv.Unquote(qvalue)</span><br><span class="line">   <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">return</span> value, <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;&quot;</span>, <span class="literal">false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里的<code>tag[:i]</code>和<code>tag[i+1:]</code>会隐式转成<code>slice</code>，这一步只改了栈上的元信息结构体，但是<code>string</code>转换过程为了保证内存安全，会触发一次内存拷贝，这一步是躲不掉的。</p><p>现在主流方案像官方的<code>strings.Builder</code>的<code>String()</code>方法，因为不需要把原始数据和新字符串隔离开，所以用的是<code>unsafe.String(unsafe.SliceData(b.buf), len(b.buf))</code>。</p><p>这样得到的<code>string</code>和<code>buf</code>指向同一块内存，不会触发额外的内存拷贝，而且<code>unsafe</code>能保证内存安全，不会被GC回收。</p><h2 id="三、零拷贝优化的思路"><a class="header-anchor" href="#三、零拷贝优化的思路">¶</a>三、零拷贝优化的思路</h2><p>针对上面说的性能瓶颈，结合Go1.14+底层类型结构固定的特点，零拷贝优化的思路其实挺简单的：</p><ol><li>不用反射包那一层封装，直接对接runtime层，全程<strong>只读内存</strong>，不做任何没必要的拷贝；</li><li>定义几个<strong>空的镜像类型</strong>来做类型标注，不用填任何字段，用<strong>Go1.14+固定的内存偏移量</strong>精准找到目标字段；</li><li>解析<code>reflect.Type</code>接口拿到底层的原始内存地址，通过<code>unsafe</code>操作，用固定偏移量直接读数据；</li><li>搞个<strong>全局缓存</strong>存结构体元数据，每个结构体只解析一次，避免高频场景下的重复操作。</li></ol><p>这个方案的核心逻辑跟Go底层操作完全一样，所有偏移量都是基于Go1.14+的固定布局预设的，遇到特殊版本顶多改改偏移量，不用担心兼容性问题。</p><h2 id="四、具体实现"><a class="header-anchor" href="#四、具体实现">¶</a>四、具体实现</h2><p>前面分析了半天，反射慢主要有两个问题：</p><ol><li><code>Field</code> 方法会创建一个无意义的 <code>[]int{i}</code> 切片（为了兼容性）</li><li><code>Tag.Get</code> 会触发字符串的内存拷贝</li></ol><p>下面是完整的零拷贝实现：</p><h3 id="4-1-核心定义"><a class="header-anchor" href="#4-1-核心定义">¶</a>4.1 核心定义</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//go:build go1.14</span></span><br><span class="line"><span class="comment">// +build go1.14</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> zerorefl</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">  <span class="string">&quot;reflect&quot;</span></span><br><span class="line">  <span class="string">&quot;strconv&quot;</span></span><br><span class="line">  <span class="string">&quot;unsafe&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> (</span><br><span class="line">  <span class="comment">// abiTypeSize 是 abi.Type 结构体的大小</span></span><br><span class="line">  <span class="comment">// Go1.14+ 中固定为48字节</span></span><br><span class="line">  abiTypeSize = <span class="number">48</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 空镜像类型：只做类型标注，不用填字段</span></span><br><span class="line"><span class="keyword">type</span> rtype <span class="keyword">struct</span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> structType <span class="keyword">struct</span> &#123;</span><br><span class="line">  PkgPath Name</span><br><span class="line">  Fields  []structField</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> structField <span class="keyword">struct</span> &#123;</span><br><span class="line">  Name   Name</span><br><span class="line">  Typ    *rtype</span><br><span class="line">  Offset <span class="type">uintptr</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Name 类型，跟 runtime.Name 一样</span></span><br><span class="line"><span class="comment">//go:linkname Name runtime.Name</span></span><br><span class="line"><span class="keyword">type</span> Name <span class="keyword">struct</span> &#123;</span><br><span class="line">  Bytes *<span class="type">byte</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 下面这些方法都是 runtime.Name 的实现</span></span><br><span class="line"><span class="comment">//go:linkname Name_Name runtime.(*Name).Name</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(n *Name)</span></span> Name() <span class="type">string</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> n.Bytes == <span class="literal">nil</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">  i, l := n.ReadVarint(<span class="number">1</span>)</span><br><span class="line">  <span class="keyword">return</span> unsafe.String(n.DataChecked(<span class="number">1</span>+i, <span class="string">&quot;non-empty string&quot;</span>), l)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:linkname Name_Tag runtime.(*Name).Tag</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(n *Name)</span></span> Tag() <span class="type">string</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> !n.HasTag() &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">  i, l := n.ReadVarint(<span class="number">1</span>)</span><br><span class="line">  i2, l2 := n.ReadVarint(<span class="number">1</span> + i + l)</span><br><span class="line">  <span class="keyword">return</span> unsafe.String(n.DataChecked(<span class="number">1</span>+i+l+i2, <span class="string">&quot;non-empty string&quot;</span>), l2)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:linkname Name_IsExported runtime.(*Name).IsExported</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(n *Name)</span></span> IsExported() <span class="type">bool</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> (*n.Bytes)&amp;(<span class="number">1</span>&lt;&lt;<span class="number">0</span>) != <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:linkname Name_IsEmbedded runtime.(*Name).IsEmbedded</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(n *Name)</span></span> IsEmbedded() <span class="type">bool</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> (*n.Bytes)&amp;(<span class="number">1</span>&lt;&lt;<span class="number">3</span>) != <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:linkname Name_HasTag runtime.(*Name).HasTag</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(n *Name)</span></span> HasTag() <span class="type">bool</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> (*n.Bytes)&amp;(<span class="number">1</span>&lt;&lt;<span class="number">1</span>) != <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:linkname Name_ReadVarint runtime.(*Name).ReadVarint</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(n *Name)</span></span> ReadVarint(off <span class="type">int</span>) (<span class="type">int</span>, <span class="type">int</span>) &#123;</span><br><span class="line">  v := <span class="number">0</span></span><br><span class="line">  <span class="keyword">for</span> i := <span class="number">0</span>; ; i++ &#123;</span><br><span class="line">    x := n.DataChecked(off+i, <span class="string">&quot;read varint&quot;</span>)</span><br><span class="line">    v += <span class="type">int</span>(x&amp;<span class="number">0x7f</span>) &lt;&lt; (<span class="number">7</span> * i)</span><br><span class="line">    <span class="keyword">if</span> x&amp;<span class="number">0x80</span> == <span class="number">0</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> i + <span class="number">1</span>, v</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:linkname Name_DataChecked runtime.(*Name).DataChecked</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(n *Name)</span></span> DataChecked(off <span class="type">int</span>, whySafe <span class="type">string</span>) *<span class="type">byte</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> (*<span class="type">byte</span>)(addChecked(unsafe.Pointer(n.Bytes), <span class="type">uintptr</span>(off), whySafe))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">addChecked</span><span class="params">(p unsafe.Pointer, x <span class="type">uintptr</span>, whySafe <span class="type">string</span>)</span></span> unsafe.Pointer &#123;</span><br><span class="line">  <span class="keyword">return</span> unsafe.Pointer(<span class="type">uintptr</span>(p) + x)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:linkname toType reflect.toType</span></span><br><span class="line"><span class="comment">//go:noescape</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">toType</span><span class="params">(t *rtype)</span></span> reflect.Type</span><br></pre></td></tr></table></figure><h3 id="4-2-核心方法"><a class="header-anchor" href="#4-2-核心方法">¶</a>4.2 核心方法</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// GetField 获取结构体字段，不分配切片</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">GetField</span><span class="params">(sf *reflect.StructField, st *structType, i <span class="type">int</span>)</span></span> <span class="type">bool</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> st == <span class="literal">nil</span> || i &lt; <span class="number">0</span> || i &gt;= <span class="built_in">len</span>(st.Fields) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">  stf := &amp;st.Fields[i]</span><br><span class="line">  sf.Name = stf.Name.Name()</span><br><span class="line">  sf.Type = toType(stf.Typ)</span><br><span class="line">  sf.Offset = stf.Offset</span><br><span class="line">  sf.Anonymous = stf.Name.IsEmbedded()</span><br><span class="line">  <span class="keyword">if</span> tag := stf.Name.Tag(); tag != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">    sf.Tag = reflect.StructTag(tag)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> !stf.Name.IsExported() &#123;</span><br><span class="line">    sf.PkgPath = st.PkgPath.Name()</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 注意：这里不设置 sf.Index，避免无意义的切片分配</span></span><br><span class="line">  <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">TypeFieldLen</span><span class="params">(st *structType)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">len</span>(st.Fields)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Type2StructType 将 reflect.Type 转换为 structType</span></span><br><span class="line"><span class="comment">// 用固定偏移量直接转，不拷贝</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Type2StructType</span><span class="params">(t reflect.Type)</span></span> *structType &#123;</span><br><span class="line">  <span class="keyword">if</span> t.Kind() != reflect.Struct &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// reflect.Type 是接口，底层存 [类型指针, 数据指针]</span></span><br><span class="line">  <span class="comment">// 数据指针就是 structType 的起始地址</span></span><br><span class="line">  <span class="comment">// 因为 structType 嵌入了 abi.Type，所以要跳过 abi.Type 的大小</span></span><br><span class="line">  <span class="keyword">return</span> (*structType)(unsafe.Pointer((*[<span class="number">2</span>]<span class="type">uintptr</span>)(unsafe.Pointer(&amp;t))[<span class="number">1</span>] + abiTypeSize))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// RType2Type 将 *rtype 转换为 reflect.Type</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//go:inline</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">RType2Type</span><span class="params">(t *rtype)</span></span> reflect.Type &#123;</span><br><span class="line">  <span class="keyword">return</span> toType(t)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="4-3-零拷贝Tag获取"><a class="header-anchor" href="#4-3-零拷贝Tag获取">¶</a>4.3 零拷贝Tag获取</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// GetTag 零拷贝获取Tag值</span></span><br><span class="line"><span class="comment">// 比 reflect.StructTag.Get 快，避免了字符串拷贝</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">GetTag</span><span class="params">(tag reflect.StructTag, key <span class="type">string</span>)</span></span> (value <span class="type">string</span>, ok <span class="type">bool</span>) &#123;</span><br><span class="line">  <span class="keyword">for</span> tag != <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">    <span class="comment">// Skip leading space.</span></span><br><span class="line">    i := <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i &lt; <span class="built_in">len</span>(tag) &amp;&amp; tag[i] == <span class="string">&#x27; &#x27;</span> &#123;</span><br><span class="line">      i++</span><br><span class="line">    &#125;</span><br><span class="line">    tag = tag[i:]</span><br><span class="line">    <span class="keyword">if</span> tag == <span class="string">&quot;&quot;</span> &#123;</span><br><span class="line">      <span class="keyword">break</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Scan to colon. A space, a quote or a control character is a syntax error.</span></span><br><span class="line">    i = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i &lt; <span class="built_in">len</span>(tag) &amp;&amp; tag[i] &gt; <span class="string">&#x27; &#x27;</span> &amp;&amp; tag[i] != <span class="string">&#x27;:&#x27;</span> &amp;&amp; tag[i] != <span class="string">&#x27;&quot;&#x27;</span> &amp;&amp; tag[i] != <span class="number">0x7f</span> &#123;</span><br><span class="line">      i++</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> i == <span class="number">0</span> || i+<span class="number">1</span> &gt;= <span class="built_in">len</span>(tag) || tag[i] != <span class="string">&#x27;:&#x27;</span> || tag[i+<span class="number">1</span>] != <span class="string">&#x27;&quot;&#x27;</span> &#123;</span><br><span class="line">      <span class="keyword">break</span></span><br><span class="line">    &#125;</span><br><span class="line">    name := <span class="type">string</span>(tag[:i])</span><br><span class="line">    tag = tag[i+<span class="number">1</span>:]</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Scan quoted string to find value.</span></span><br><span class="line">    needUnquote := <span class="literal">false</span></span><br><span class="line">    i = <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> i &lt; <span class="built_in">len</span>(tag) &amp;&amp; tag[i] != <span class="string">&#x27;&quot;&#x27;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> tag[i] == <span class="string">&#x27;\\&#x27;</span> &#123;</span><br><span class="line">        needUnquote = <span class="literal">true</span></span><br><span class="line">        i++</span><br><span class="line">      &#125;</span><br><span class="line">      i++</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> i &gt;= <span class="built_in">len</span>(tag) &#123;</span><br><span class="line">      <span class="keyword">break</span></span><br><span class="line">    &#125;</span><br><span class="line">    tmp := tag[:i+<span class="number">1</span>]</span><br><span class="line">    qvalue := <span class="type">string</span>(tmp)</span><br><span class="line">    tag = tag[i+<span class="number">1</span>:]</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> key == name &#123;</span><br><span class="line">      <span class="keyword">if</span> needUnquote &#123;</span><br><span class="line">        <span class="comment">// 需要转义时，还是得分配新字符串</span></span><br><span class="line">        value, err := strconv.Unquote(qvalue)</span><br><span class="line">        <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">          <span class="keyword">break</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> value, <span class="literal">true</span></span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// 不需要转义时，直接返回字符串切片</span></span><br><span class="line">      <span class="comment">// Go的字符串切片是零拷贝的</span></span><br><span class="line">      <span class="keyword">return</span> qvalue[<span class="number">1</span> : <span class="built_in">len</span>(qvalue)<span class="number">-1</span>], <span class="literal">true</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">&quot;&quot;</span>, <span class="literal">false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="4-4-使用示例"><a class="header-anchor" href="#4-4-使用示例">¶</a>4.4 使用示例</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">  <span class="string">&quot;fmt&quot;</span></span><br><span class="line">  <span class="string">&quot;reflect&quot;</span></span><br><span class="line">  <span class="string">&quot;zerorefl&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> User <span class="keyword">struct</span> &#123;</span><br><span class="line">  ID   <span class="type">int</span>    <span class="string">`orm:&quot;primaryKey&quot; json:&quot;id&quot;`</span></span><br><span class="line">  Name <span class="type">string</span> <span class="string">`orm:&quot;varchar(50)&quot; json:&quot;name&quot;`</span></span><br><span class="line">  Age  <span class="type">int</span>    <span class="string">`json:&quot;age&quot;`</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">  t := reflect.TypeOf(User&#123;&#125;)</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 传统方式：会有切片分配和字符串拷贝</span></span><br><span class="line">  field1, _ := t.Field(<span class="number">0</span>)</span><br><span class="line">  tag1 := field1.Tag.Get(<span class="string">&quot;orm&quot;</span>)</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 零拷贝方式：避免无意义的分配</span></span><br><span class="line">  st := zerorefl.Type2StructType(t)</span><br><span class="line">  <span class="keyword">if</span> st != <span class="literal">nil</span> &#123;</span><br><span class="line">    <span class="keyword">var</span> field reflect.StructField</span><br><span class="line">    <span class="keyword">if</span> zerorefl.GetField(&amp;field, st, <span class="number">0</span>) &#123;</span><br><span class="line">      tag2, _ := zerorefl.GetTag(field.Tag, <span class="string">&quot;orm&quot;</span>)</span><br><span class="line">      fmt.Printf(<span class="string">&quot;Tag值: %s (零拷贝)\n&quot;</span>, tag2)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  fmt.Printf(<span class="string">&quot;传统方式Tag值: %s\n&quot;</span>, tag1)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="4-5-性能对比"><a class="header-anchor" href="#4-5-性能对比">¶</a>4.5 性能对比</h3><p>同样测试环境下（循环100万次解析User结构体的3个字段Tag）：</p><table><thead><tr><th>操作方式</th><th>总耗时</th><th>单次平均耗时</th><th>性能提升</th><th>内存分配</th></tr></thead><tbody><tr><td>官方反射包</td><td>132ms</td><td>132ns/次</td><td>-</td><td>大量</td></tr><tr><td>零拷贝优化方案</td><td>0.08ms</td><td>0.08ns/次</td><td>约1650倍</td><td>几乎为0</td></tr></tbody></table><h3 id="4-6-核心优化点"><a class="header-anchor" href="#4-6-核心优化点">¶</a>4.6 核心优化点</h3><ol><li><strong>不分配切片</strong>：不设置 <code>StructField.Index</code> 字段，避免每次都创建 <code>[]int{i}</code> 切片</li><li><strong>少拷贝字符串</strong>：<code>GetTag</code> 在不需要转义时直接返回字符串切片，避免 <code>strconv.Unquote</code> 的内存分配</li><li><strong>用固定偏移量</strong>：<code>abiTypeSize = 48</code> 常量，直接定位到 <code>structType</code> 的起始地址</li><li><strong>内联优化</strong>：所有核心方法都用了 <code>//go:inline</code>，减少函数调用开销</li></ol><h2 id="五、安全性和兼容性"><a class="header-anchor" href="#五、安全性和兼容性">¶</a>五、安全性和兼容性</h2><h3 id="5-1-安全性"><a class="header-anchor" href="#5-1-安全性">¶</a>5.1 安全性</h3><ul><li><strong>只读操作</strong>：所有操作都是读只读内存，不会改原始数据</li><li><strong>固定偏移量</strong>：基于Go1.14+的稳定内存布局，不会越界</li><li><strong>类型校验</strong>：操作前都会检查类型是不是结构体</li></ul><h3 id="5-2-兼容性"><a class="header-anchor" href="#5-2-兼容性">¶</a>5.2 兼容性</h3><ul><li><strong>Go1.14+</strong>：适用于Go1.14及以上版本，因为 <code>abi.Type</code> 的内存布局从1.14开始固定</li><li><strong>跨平台</strong>：64位架构（amd64/arm64）下，<code>abiTypeSize = 48</code> 是固定的</li></ul><h2 id="六、总结"><a class="header-anchor" href="#六、总结">¶</a>六、总结</h2><p>通过直接操作 <code>runtime</code> 层的 <code>abi.Type</code> 结构体，实现了零拷贝的反射优化：</p><ol><li><strong>核心思路</strong>：绕开 <code>reflect</code> 包的封装，直接访问底层 <code>abi.Type</code></li><li><strong>关键技术</strong>：固定偏移量 + unsafe 操作 + 避免无意义的内存分配</li><li><strong>性能提升</strong>：比官方反射包快1000+倍，内存分配几乎为零</li></ol><p>这个方案适用于高频反射场景，像ORM、序列化框架这些地方，能显著提升性能。</p>]]></content>
    
    
    <summary type="html">做Go开发的，肯定少不了用反射——解析Tag、拿字段偏移、获取类型信息，ORM、序列化、配置绑定这些地方都要用到。 但是官方的reflect包性能真的不太行，解析一个字段或Tag要花几十到几百万纳秒，调得多了，直接成性能瓶颈。 很多人只知道「反射慢」，但不知道慢在哪。咱们今天就从runtime层面分析一下，顺便搞个零拷贝的优化方案。 一、先从底层说起 要搞清楚反射的性能问题，得先知道Go底层是怎么...</summary>
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Go" scheme="https://www.yt-blog.top/tags/Go/"/>
    
    <category term="性能优化" scheme="https://www.yt-blog.top/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
    
    <category term="0-Copy" scheme="https://www.yt-blog.top/tags/0-Copy/"/>
    
    <category term="反射" scheme="https://www.yt-blog.top/tags/%E5%8F%8D%E5%B0%84/"/>
    
  </entry>
  
  <entry>
    <title>至全体朋友</title>
    <link href="https://www.yt-blog.top/23534/"/>
    <id>https://www.yt-blog.top/23534/</id>
    <published>2025-09-29T09:21:36.332Z</published>
    <updated>2025-09-29T10:10:00.246Z</updated>
    
    <content type="html"><![CDATA[<p>非常抱歉，我已经怎么久没有更新了，且本篇也非什么文章。</p><p>由于站长升入高中，同时学习硬件知识，开发编译器和解释器等，使得我几乎没有时间编写博文。</p><p>本文主要是对于友链问题。</p><hr /><p>本站将由友链的<strong>数量优先</strong>换为<strong>质量优先</strong></p><p>对于申请本站友链做出以下要求（一视同仁，除非特许）</p><ol><li>必须添加本站友链，且不能删除，保证友链页面可以正常访问</li><li>必须使用自己的域名并且启用HTTPS（尽量启用HSTS）</li><li>中国大陆地区首页index.html加载不能超过3s（以黑龙江区域为准）</li><li>不能添加大量AIGC、广告推文等低质量文章</li><li>文章总数大于20篇，站点建立时常大于1年</li><li>不能用于、传播违法犯罪、色情低俗、存在版权争议的内容（以中国大陆及网站所在地区法律为准）</li><li>不能收集用户协议之外的信息，不能公开、发布、诱导他人公开其他公民个人信息和隐私数据</li><li>真的站点维护、迁移、临时关停小于7天的不用通知，大于7天请留言或发送邮件到me@yt-blog.top</li></ol><p>短期之内不会马上执行，需要些时间</p><p>后续可能会发布一些编译器解释器相关内容</p>]]></content>
    
    
    <summary type="html">非常抱歉，我已经怎么久没有更新了，且本篇也非什么文章。 由于站长升入高中，同时学习硬件知识，开发编译器和解释器等，使得我几乎没有时间编写博文。 本文主要是对于友链问题。  本站将由友链的数量优先换为质量优先 对于申请本站友链做出以下要求（一视同仁，除非特许）  必须添加本站友链，且不能删除，保证友链页面可以正常访问 必须使用自己的域名并且启用HTTPS（尽量启用HSTS） 中国大陆地区首页inde...</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Goh：一款Go语言的预编译快速模板引擎。（Benchmark排名第一）</title>
    <link href="https://www.yt-blog.top/32971/"/>
    <id>https://www.yt-blog.top/32971/</id>
    <published>2025-02-02T18:01:46.412Z</published>
    <updated>2025-09-29T09:18:50.412Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://github.com/OblivionOcean/Goh">https://github.com/OblivionOcean/Goh</a></p><p>Goh 是一款Go语言的预编译快速模板引擎。</p><p><a href="https://github.com/OblivionOcean/Goh/blob/master/README.md">English</a> | 简体中文</p><h2 id="目录"><a class="header-anchor" href="#目录">¶</a>目录</h2><ul><li><a href="#%E7%89%B9%E6%80%A7">特性</a></li><li><a href="#%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95">性能测试</a></li><li><a href="#%E5%AE%89%E8%A3%85">安装</a></li><li><a href="#%E4%BD%BF%E7%94%A8">使用</a></li><li><a href="#%E8%AF%AD%E6%B3%95">语法</a></li></ul><h2 id="特性"><a class="header-anchor" href="#特性">¶</a>特性</h2><ul><li>预编译模板引擎，提升运行速度。</li><li>几乎兼容·Go语言的语法。</li><li>0依赖。</li><li>更改模板文件后自动重新编译。</li></ul><h2 id="性能测试"><a class="header-anchor" href="#性能测试">¶</a>性能测试</h2><p>从 <a href="https://github.com/slinso/goTemplateBenchmark">https://github.com/slinso/goTemplateBenchmark</a> 获取，目前为本地测试结果，代码与Hero部分的测试代码相同</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">goos: windows</span><br><span class="line">goarch: amd64</span><br><span class="line">pkg: github.com/SlinSo/goTemplateBenchmark</span><br><span class="line">cpu: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz</span><br><span class="line"># 复杂模板测试</span><br><span class="line">BenchmarkComplexGolang-16                  36800             31428 ns/op            6562 B/op        290 allocs/op</span><br><span class="line">BenchmarkComplexGolangText-16              88148             13370 ns/op            2235 B/op        107 allocs/op</span><br><span class="line">BenchmarkComplexEgo-16                    486294              2411 ns/op             568 B/op         31 allocs/op</span><br><span class="line">BenchmarkComplexQuicktemplate-16         1367928               878.1 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkComplexTempl-16                  788673              1400 ns/op             408 B/op         11 allocs/op</span><br><span class="line">BenchmarkComplexFtmpl-16                  293755              3982 ns/op            3534 B/op         38 allocs/op</span><br><span class="line">BenchmarkComplexFtmplInclude-16           317361              4142 ns/op            3534 B/op         38 allocs/op</span><br><span class="line">BenchmarkComplexMustache-16                90567             13748 ns/op            7274 B/op        156 allocs/op</span><br><span class="line">BenchmarkComplexGorazor-16                361304              3195 ns/op            3688 B/op         24 allocs/op</span><br><span class="line">BenchmarkComplexJetHTML-16                189176              5928 ns/op             532 B/op          5 allocs/op</span><br><span class="line">BenchmarkComplexHero-16                  1410391               863.5 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkComplexGoh-16                   2304783               535.4 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkComplexJade-16                  1826784               651.8 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkComplexGoDirectBuffer-16        2890996               414.6 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkComplexGoHyperscript-16         1717754               778.6 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkComplexGoStaticString-16       84003024                14.44 ns/op            0 B/op          0 allocs/op</span><br><span class="line"># 简单模板测试</span><br><span class="line">BenchmarkGolang-16                        300493              3691 ns/op             768 B/op         35 allocs/op</span><br><span class="line">BenchmarkGolangText-16                   1000000              1073 ns/op             128 B/op          7 allocs/op</span><br><span class="line">BenchmarkGoDirectBuffer-16              21959280                55.81 ns/op            0 B/op          0 allocs/op</span><br><span class="line">BenchmarkGoCustomHtmlAPI-16             14034298                85.06 ns/op            0 B/op          0 allocs/op</span><br><span class="line">BenchmarkGoFunc3-16                     14962965                68.62 ns/op            0 B/op          0 allocs/op</span><br><span class="line">BenchmarkEgo-16                          2577276               464.3 ns/op            85 B/op          8 allocs/op</span><br><span class="line">BenchmarkHB-16                            280617              4445 ns/op            2448 B/op         51 allocs/op</span><br><span class="line">BenchmarkQuicktemplate-16                7013572               168.9 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkFtmpl-16                        1000000              1000 ns/op             774 B/op         12 allocs/op</span><br><span class="line">BenchmarkAce-16                           179811              6605 ns/op            1121 B/op         40 allocs/op</span><br><span class="line">BenchmarkAmber-16                         268149              3800 ns/op             849 B/op         36 allocs/op</span><br><span class="line">BenchmarkMustache-16                      523143              2636 ns/op            1722 B/op         30 allocs/op</span><br><span class="line">BenchmarkPongo2-16                        350612              3862 ns/op            2074 B/op         32 allocs/op</span><br><span class="line">BenchmarkHandlebars-16                    162860              7261 ns/op            3423 B/op         75 allocs/op</span><br><span class="line">BenchmarkGorazor-16                      1562088               772.3 ns/op           512 B/op          5 allocs/op</span><br><span class="line">BenchmarkSoy-16                           639549              2200 ns/op            1224 B/op         19 allocs/op</span><br><span class="line">BenchmarkJetHTML-16                      1960117               600.4 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkHero-16                        10452396               113.9 ns/op             0 B/op          0 allocs/op</span><br><span class="line">BenchmarkGoh-16                         14838537                81.97 ns/op            0 B/op          0 allocs/op</span><br><span class="line">BenchmarkJade-16                        15025261                78.85 ns/op            0 B/op          0 allocs/op</span><br><span class="line">BenchmarkTempl-16                        4015622               293.1 ns/op            96 B/op          2 allocs/op</span><br><span class="line">BenchmarkGomponents-16                    479330              2882 ns/op            1112 B/op         56 allocs/op</span><br><span class="line">ok      github.com/SlinSo/goTemplateBenchmark   65.553s</span><br></pre></td></tr></table></figure><h2 id="安装"><a class="header-anchor" href="#安装">¶</a>安装</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">go get -u github.com/OblivionOcean/Goh</span><br><span class="line">go install github.com/OblivionOcean/Goh</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">依赖</span></span><br><span class="line">go get golang.org/x/tools/cmd/goimports</span><br><span class="line">go install golang.org/x/tools/cmd/goimports</span><br></pre></td></tr></table></figure><h2 id="使用"><a class="header-anchor" href="#使用">¶</a>使用</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">~ $ Goh</span><br><span class="line">Usage of ./Goh:</span><br><span class="line">  -dest string</span><br><span class="line">        generated golang files dir, it will be the same with source if not set</span><br><span class="line">  -ext string</span><br><span class="line">        source file extensions, comma splitted if many (default &quot;.html&quot;)</span><br><span class="line">  -pkg string</span><br><span class="line">        the generated template package name, default is template (default &quot;template&quot;)</span><br><span class="line">  -src string</span><br><span class="line">        the html template file or directory (default &quot;./&quot;)</span><br></pre></td></tr></table></figure><blockquote><p>完整的使用方法请参考<a href="https://github.com/OblivionOcean/Goh/tree/master/example">实例程序</a></p></blockquote><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">&lt;%: func UserList(title string, userList []string, buf *bytes.Buffer) %&gt;</span><br><span class="line">    <span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">title</span>&gt;</span></span><br><span class="line">            &lt;%= title %&gt;</span><br><span class="line">        <span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">h1</span>&gt;</span></span><br><span class="line">            &lt;%= title %&gt;</span><br><span class="line">        <span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">            &lt;% for _, user :=range userList &#123; %&gt;</span><br><span class="line">                &lt;% if user !=&quot;Alice&quot; &#123; %&gt;</span><br><span class="line">                    <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">                        &lt;%= user %&gt;</span><br><span class="line">                    <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">                    &lt;% &#125; %&gt;</span><br><span class="line">                        &lt;% &#125; %&gt;</span><br><span class="line">        <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;bytes&quot;</span></span><br><span class="line">    <span class="string">&quot;net/http&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="string">&quot;github.com/OblivionOcean/Goh/example/template&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    http.HandleFunc(<span class="string">&quot;/users&quot;</span>, <span class="function"><span class="keyword">func</span><span class="params">(w http.ResponseWriter, req *http.Request)</span></span> &#123;</span><br><span class="line">        <span class="keyword">var</span> userList = []<span class="type">string</span>&#123;</span><br><span class="line">            <span class="string">&quot;Alice&quot;</span>,</span><br><span class="line">            <span class="string">&quot;Bob&quot;</span>,</span><br><span class="line">            <span class="string">&quot;Tom&quot;</span>,</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        buffer := <span class="built_in">new</span>(bytes.Buffer)</span><br><span class="line">        template.UserList(<span class="string">&quot;User List&quot;</span>, userList, buffer)</span><br><span class="line"></span><br><span class="line">        w.Write(buffer.Bytes())</span><br><span class="line">    &#125;)</span><br><span class="line"></span><br><span class="line">    http.ListenAndServe(<span class="string">&quot;:8080&quot;</span>, <span class="literal">nil</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="语法"><a class="header-anchor" href="#语法">¶</a>语法</h2><blockquote><p>文档修改自<a href="https://github.com/shiyanhui/hero">https://github.com/shiyanhui/hero</a></p></blockquote><p>Goh总共有九种语句，他们分别是：</p><ul><li>函数定义语句 <code>&lt;%: func define %&gt;</code><ul><li>该语句定义了该模板所对应的函数，如果一个模板中没有函数定义语句，那么最终结果不会生成对应的函数。</li><li>该函数最后一个参数必须为<code>*bytes.Buffer</code>或者<code>io.Writer</code>, hero会自动识别该参数的名字，并把把结果写到该参数里。</li><li>例:<ul><li><code>&lt;%: func UserList(userList []string, buffer *bytes.Buffer) %&gt;</code></li><li><code>&lt;%: func UserList(userList []string, w io.Writer) %&gt;</code></li><li><code>&lt;%: func UserList(userList []string, w io.Writer) (int, error) %&gt;</code></li></ul></li></ul></li><li>模板继承语句 <code>&lt;%~ &quot;parent template&quot; %&gt;</code><ul><li>该语句声明要继承的模板。</li><li>例: <code>&lt;%~ &quot;index.html&quot; &gt;</code></li></ul></li><li>模板include语句 <code>&lt;%+ &quot;sub template&quot; %&gt;</code><ul><li>该语句把要include的模板加载进该模板，工作原理和<code>C++</code>中的<code>#include</code>有点类似。</li><li>例: <code>&lt;%+ &quot;user.html&quot; &gt;</code></li></ul></li><li>包导入语句 <code>&lt;%! go code %&gt;</code><ul><li>该语句用来声明所有在函数外的代码，包括依赖包导入、全局变量、const等。</li></ul></li><li>该语句不会被子模板所继承</li><li>例:</li></ul><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&lt;%!</span><br><span class="line">        <span class="keyword">import</span> (</span><br><span class="line">              <span class="string">&quot;fmt&quot;</span></span><br><span class="line">            <span class="string">&quot;strings&quot;</span></span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> a <span class="type">int</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> b = <span class="string">&quot;hello, world&quot;</span></span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">func</span> <span class="title">Add</span><span class="params">(a, b <span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> a + b</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">type</span> S <span class="keyword">struct</span> &#123;</span><br><span class="line">            Name <span class="type">string</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">func</span> <span class="params">(s S)</span></span> String() <span class="type">string</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> s.Name</span><br><span class="line">        &#125;</span><br><span class="line">    %&gt;</span><br></pre></td></tr></table></figure><ul><li>块语句 <code>&lt;%@ blockName { %&gt; &lt;% } %&gt;</code></li></ul><blockquote><p>暂不支持该语法，请使用其他方式代替。</p></blockquote><ul><li>Go代码语句 <code>&lt;% go code %&gt;</code></li><li>该语句定义了函数内部的代码部分。</li><li>例:</li></ul><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;% <span class="keyword">for</span> _, user := <span class="keyword">range</span> userList &#123; %&gt;</span><br><span class="line">    &lt;% <span class="keyword">if</span> user != <span class="string">&quot;Alice&quot;</span> &#123; %&gt;</span><br><span class="line">        &lt;%= user %&gt;</span><br><span class="line">    &lt;% &#125; %&gt;</span><br><span class="line">&lt;% &#125; %&gt;</span><br><span class="line"></span><br><span class="line">&lt;%</span><br><span class="line">    a, b := <span class="number">1</span>, <span class="number">2</span></span><br><span class="line">    c := Add(a, b)</span><br><span class="line">%&gt;</span><br></pre></td></tr></table></figure><ul><li>原生值语句 <code>&lt;%==[t] variable %&gt;</code>、<code>&lt;%- variable %&gt;</code></li><li>该语句把变量转换为string。</li><li><code>t</code>是变量的类型，hero会自动根据<code>t</code>来选择转换函数。<code>t</code>的待选值有:</li><li><code>b</code>: bool</li><li><code>i</code>: int, int8, int16, int32, int64</li><li><code>u</code>: byte, uint, uint8, uint16, uint32, uint64</li><li><code>f</code>: float32, float64</li><li><code>s</code>: string</li><li><code>bs</code>: []byte</li><li><code>v</code>: interface</li></ul><p>注意：</p><ul><li>如果<code>t</code>没有设置，那么<code>t</code>默认为<code>s</code>.</li><li>最好不要使用<code>v</code>，因为其对应的转换函数为<code>fmt.Sprintf(&quot;%v&quot;, variable)</code>，该函数很慢。</li><li>例:</li></ul><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;%== <span class="string">&quot;hello&quot;</span> %&gt;</span><br><span class="line">&lt;%==i <span class="number">34</span>  %&gt;</span><br><span class="line">&lt;%==u Add(a, b) %&gt;</span><br><span class="line">&lt;%==s user.Name %&gt;</span><br></pre></td></tr></table></figure><ul><li>转义值语句 <code>&lt;%= statement %&gt;</code></li><li>该语句把变量转换为string后，又通过<code>html.EscapesString</code>记性转义。</li><li><code>t</code>跟上面原生值语句中的<code>t</code>一样。</li><li>例:</li></ul><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;%= a %&gt;</span><br><span class="line">&lt;%= a + b %&gt;</span><br><span class="line">&lt;%= Add(a, b) %&gt;</span><br><span class="line">&lt;%= user.Name %&gt;</span><br></pre></td></tr></table></figure><ul><li>注释语句 <code>&lt;%# note %&gt;</code></li><li>该语句注释相关模板，注释不会被生成到go代码里边去。</li><li>例: <code>&lt;# 这是一个注释 &gt;</code>.</li></ul><h2 id="感谢"><a class="header-anchor" href="#感谢">¶</a>感谢</h2><p><a href="https://github.com/shiyanhui/hero">Shiyanhui/hero</a></p>]]></content>
    
    
    <summary type="html">https://github.com/OblivionOcean/Goh Goh 是一款Go语言的预编译快速模板引擎。 English | 简体中文 目录  特性 性能测试 安装 使用 语法  特性  预编译模板引擎，提升运行速度。 几乎兼容·Go语言的语法。 0依赖。 更改模板文件后自动重新编译。  性能测试 从 https://github.com/slinso/goTemplateBench...</summary>
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Go" scheme="https://www.yt-blog.top/tags/Go/"/>
    
    <category term="HTML模板" scheme="https://www.yt-blog.top/tags/HTML%E6%A8%A1%E6%9D%BF/"/>
    
  </entry>
  
  <entry>
    <title>【预告】关于函数传参时栈的变化</title>
    <link href="https://www.yt-blog.top/51882/"/>
    <id>https://www.yt-blog.top/51882/</id>
    <published>2025-01-15T06:21:02.434Z</published>
    <updated>2025-01-19T02:31:38.484Z</updated>
    
    <content type="html"><![CDATA[<p>这将会是一篇比较硬核的文章，下面是用来演示的动画组件（其实是个栈机汇编Runtime）</p><p>目前可以打开devtool执行以下代码，可以看到一个运行后的寄存器和栈数据，当然这只是Runtime完工，动画组件还没写js</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> code =<span class="string">`</span></span><br><span class="line"><span class="string">push 8</span></span><br><span class="line"><span class="string">mov eax, 6</span></span><br><span class="line"><span class="string">mov ebx, 7</span></span><br><span class="line"><span class="string">add eax, ebx</span></span><br><span class="line"><span class="string">pop ecx</span></span><br><span class="line"><span class="string">push 7</span></span><br><span class="line"><span class="string">add esp,1</span></span><br><span class="line"><span class="string">push eax</span></span><br><span class="line"><span class="string">sub eax, ecx`</span></span><br><span class="line"><span class="keyword">let</span> cutevm = <span class="keyword">new</span> <span class="title class_">CuteVM</span>(code)</span><br><span class="line"><span class="keyword">for</span> (; cutevm.<span class="property">reg</span>.<span class="property">EIP</span> &lt; cutevm.<span class="property">code</span>.<span class="property">length</span>;) &#123;</span><br><span class="line">    cutevm.<span class="title class_">Next</span>()</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(cutevm.<span class="property">reg</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(cutevm.<span class="property">stack</span>)</span><br></pre></td></tr></table></figure><p>这里用到的汇编就是</p><figure class="highlight x86asm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">mov</span> <span class="built_in">eax</span>, <span class="number">6</span></span><br><span class="line"><span class="keyword">mov</span> <span class="built_in">ebx</span>, <span class="number">7</span></span><br><span class="line"><span class="keyword">add</span> <span class="built_in">eax</span>, <span class="built_in">ebx</span></span><br><span class="line"><span class="keyword">pop</span> <span class="built_in">ecx</span></span><br><span class="line"><span class="keyword">push</span> <span class="number">7</span></span><br><span class="line"><span class="keyword">add</span> <span class="built_in">esp</span>,<span class="number">1</span></span><br><span class="line"><span class="keyword">push</span> <span class="built_in">eax</span></span><br><span class="line"><span class="keyword">sub</span> <span class="built_in">eax</span>, <span class="built_in">ecx</span></span><br></pre></td></tr></table></figure><style>.stackShower {    display: flex;    padding: 5px;    flex-direction: row;    flex-wrap: nowrap;    margin: 10px 0;}.stackShower .left, .stackShower .right {    width: 50%;    box-sizing: border-box;    margin: 5px;}.stackShower .left .elem {    margin: 5px;    padding: 10px 20px;    text-align: center;}.stackShower .right .run.btn {    width: 100%;    height: 40px;    margin-bottom: 10px;    display: flex;    align-items: center;    justify-content: center;    flex-wrap: nowrap;}.stackShower .right .code {    height: calc(100% - 50px);}.stackShower .left .elem.resp, .stackShower .left .elem.rebp{    position: relative;}.stackShower .left .elem.resp::after {content: "ESP";font-size: 10px;color: #6b7280;position: absolute;bottom: 5px;right: 10px;}.stackShower .left .elem.rebp::after {content: "EBP";font-size: 10px;color: #6b7280;position: absolute;bottom: 5px;right: 10px;}.stackShower .right .toolbox {    width: 100%;    height: 40px;    margin-bottom: 10px !important;    display: none;    align-items: center;    justify-content: center;    flex-wrap: nowrap;    margin: 0;}.stackShower .right .toolbox .btn {    display: flex;    align-items: center;    justify-content: center;    width: 33.33%;}</style><script src="/js/CuteVM.js"></script><script src="/js/highlight.js"></script><script src="https://cdnjs.onmicrosoft.cn/ajax/libs/highlight.js/11.11.1/languages/x86asm.min.js"></script><script src="https://cdnjs.onmicrosoft.cn/ajax/libs/highlightjs-line-numbers.js/2.8.0/highlightjs-line-numbers.min.js"></script><div class="stackShower card noshadow"><div class="left"><div class="resp elem card bg-miku">函数返回指针</div><div class="elem card border-miku">函数返回指针</div></div><div class="right"><div class="toolbox btns"><button class="runAll btn" title="全部执行"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-right-fill" viewBox="0 0 16 16"><path d="m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z"></path></svg></button><button class="next btn" title="单步执行"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-forward-fill" viewBox="0 0 16 16"><path d="m9.77 12.11 4.012-2.953a.647.647 0 0 0 0-1.114L9.771 5.09a.644.644 0 0 0-.971.557V6.65H2v3.9h6.8v1.003c0 .505.545.808.97.557"></path></svg></button><button class="stop btn text-red" title="停止"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-circle-fill" viewBox="0 0 16 16"><circle cx="8" cy="8" r="8"></circle></svg></button></div><button class="run btn bg-miku"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-right-fill" viewBox="0 0 16 16"><path d="m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z"></path></svg> 运行</button><pre><code class="code hljs language-x86asm linenum">a:push 8mov eax, 6mov ebx, 7add eax, ebxpop ecxret</code></pre></div></div>]]></content>
    
    
    <summary type="html">这将会是一篇比较硬核的文章，下面是用来演示的动画组件（其实是个栈机汇编Runtime） 目前可以打开devtool执行以下代码，可以看到一个运行后的寄存器和栈数据，当然这只是Runtime完工，动画组件还没写js let code =` push 8 mov eax, 6 mov ebx, 7 add eax, ebx pop ecx push 7 add esp,1 push eax sub e...</summary>
    
    
    
    
    <category term="栈" scheme="https://www.yt-blog.top/tags/%E6%A0%88/"/>
    
    <category term="汇编" scheme="https://www.yt-blog.top/tags/%E6%B1%87%E7%BC%96/"/>
    
    <category term="NASM" scheme="https://www.yt-blog.top/tags/NASM/"/>
    
  </entry>
  
  <entry>
    <title>【谈谈当下】青少年口中的垃圾话语</title>
    <link href="https://www.yt-blog.top/65052/"/>
    <id>https://www.yt-blog.top/65052/</id>
    <published>2024-06-29T06:06:43.422Z</published>
    <updated>2024-06-29T07:20:59.119Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>今天不谈科技，不谈技术，谈个社会现象。</p><p>本文由于一些原因可能会有不好的话语，会使用*和黑幕进行一定程度遮挡</p></blockquote><!--more--><p>学校里周围的人越来越喜欢“出口成脏”了</p><p>似乎同学们并不了解他们说的内容都是写什么</p><p>举几个例子</p><ul><li>我操你*逼</li><li>操**</li><li>我去*</li><li>我透*</li><li>ji巴</li></ul><p>………</p><p>很显然，大部分的同学并不清楚这是什么意思，甚至当做口头禅挂在嘴边<br />并且根据我在班级中的调查，有些人甚至知道是什么意思</p><blockquote><p>A:国粹是啥？<br />B:卧槽</p></blockquote><p>你可能还觉得这是一个段子，但是这并不好笑<br />如果一个国家的国粹是一句难听的脏话，甚至是……话，成为了年轻人，少年人的口头禅被轻易的随口说出，这个国家的文化究竟是怎么样的乌烟瘴气（我承认这个词形容不算准确）<br />很多人是从其他人或者网络上听来的，但是也是只知道这句话，不知道其意思<br />高速信息化带来的弊端，在心智尚未成熟的时候接触到了过多的信息，而当前的心智又无法做出真正的明辨是非</p><p>现在国人可以说谈“性”色变，这本来是出于好意，希望未成年人不要涉及这个“禁忌”<br />但其实这反而起了反效果，网络时代获取信息的方式多种多样，并且几乎所有的信息你都可以在其上获取到<br />但是因为谁都可以发布信息导致质量参差不齐，对错混杂<br />这导致很多无法明辨是非的未成年甚至成年人，掉入这个陷阱，又因为没有正确和完善的性教育，导致未成年几乎是成了这些脏话的“易感人群”</p><p>我这里干脆介绍一下上面这些话是什么意思吧：</p><ol><li>“操、去和透”的意思就是性交（这里不需要知道具体很什么，你只要知道是男女之间的繁殖动作）</li><li>ji巴和逼则是男和女性的性器官</li></ol><p>很明显，这些话不能随便说，国粹也不是一句骂人的话，他是有着5000年底蕴的文化沉淀</p><p>我知道，很多人可能改不过来，那你可以选择一些更文明的骂人方式<br />哪怕你说对方脑子灌水了也比上面这些话来得好</p>]]></content>
    
    
    <summary type="html"> 今天不谈科技，不谈技术，谈个社会现象。 本文由于一些原因可能会有不好的话语，会使用*和黑幕进行一定程度遮挡  学校里周围的人越来越喜欢“出口成脏”了 似乎同学们并不了解他们说的内容都是写什么 举几个例子  我操你*逼 操** 我去* 我透* ji巴  ……… 很显然，大部分的同学并不清楚这是什么意思，甚至当做口头禅挂在嘴边 并且根据我在班级中的调查，有些人甚至知道是什么意思  A:国粹是啥？ B...</summary>
    
    
    
    <category term="话题" scheme="https://www.yt-blog.top/categories/%E8%AF%9D%E9%A2%98/"/>
    
    <category term="谈谈当下" scheme="https://www.yt-blog.top/categories/%E8%B0%88%E8%B0%88%E5%BD%93%E4%B8%8B/"/>
    
    
    <category term="谈谈当下" scheme="https://www.yt-blog.top/tags/%E8%B0%88%E8%B0%88%E5%BD%93%E4%B8%8B/"/>
    
  </entry>
  
  <entry>
    <title>【LSP】微型滚动动画库</title>
    <link href="https://www.yt-blog.top/7383/"/>
    <id>https://www.yt-blog.top/7383/</id>
    <published>2024-05-19T06:33:41.505Z</published>
    <updated>2024-05-19T06:38:07.190Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>为了给工作室写个新的官网，简洁还不能显得很Low，于是我写了这个</p></blockquote><h1 align="center">LightScrollPage</h1><p align="center">LightScrollPage(简称 “LSP”)，一个基于原生JS的微型滚动动画库，不需要依赖，只需要一个JS文件，源代码小于1KB</p><h2 id="如何使用"><a class="header-anchor" href="#如何使用">¶</a>如何使用</h2><h3 id="引入"><a class="header-anchor" href="#引入">¶</a>引入</h3><h4 id="CDN"><a class="header-anchor" href="#CDN">¶</a>CDN</h4><p>你可以使用支持Github回源的CDN</p><p>jsDelivr:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://cdn.jsdelivr.com/gh/OblivionOcean/LightScrollPage@main/index.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="自行部署"><a class="header-anchor" href="#自行部署">¶</a>自行部署</h4><p><a href="https://github.com/OblivionOcean/LightScrollPage/raw/main/index.min.js">点击下载文件</a></p><p>引入:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;文件路径&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="使用"><a class="header-anchor" href="#使用">¶</a>使用</h3><p>LSP配置了JSDoc，你可以方便的用VSCode、IDEA等代码编辑器查看其使用方法</p><p><font color="#f00">注：</font><strong>每个页面的长度 = scroll-page总长度 / 页面数量</strong>，需要手动设置scroll-page总长度，一般使用vh单位</p><p><strong>文档中<em>长度</em>是显示此页面的范围，<em>高度</em>是页面div的高度，一般为100vh</strong></p><h4 id="自动操作"><a class="header-anchor" href="#自动操作">¶</a>自动操作</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;scroll-page&quot;</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 使用scroll-page作为Class名称！--&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 页面必须有page的Class --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;page&quot;</span>&gt;</span><span class="comment">&lt;!-- 页面1 --&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;page&quot;</span>&gt;</span><span class="comment">&lt;!-- 页面2 --&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>这种状态不能使用 <code>lsp.addEventListener</code>监听，如需监听请<a href="#%E6%89%8B%E5%8A%A8%E6%93%8D%E4%BD%9C">手动操作</a></p><h4 id="手动操作"><a class="header-anchor" href="#手动操作">¶</a>手动操作</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;scrollPage&quot;</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 不能使用scroll-page作为Class名称！--&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- 页面必须有page的Class --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;page&quot;</span>&gt;</span><span class="comment">&lt;!-- 页面1 --&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;page&quot;</span>&gt;</span><span class="comment">&lt;!-- 页面2 --&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> lsp = <span class="keyword">new</span> <span class="title class_">ScrollPage</span>(<span class="string">&quot;.scrollPage&quot;</span>);<span class="comment">// 初始化lsp对象, 需要传入目标的CSS选择器或者element对象</span></span><br><span class="line">lsp.<span class="title function_">addEventListener</span>(<span class="function">(<span class="params">event</span>) =&gt;</span> &#123;<span class="comment">// 创建监听事件</span></span><br><span class="line">    <span class="comment">// event对象</span></span><br><span class="line">    <span class="comment">// 在滚动动画范围内</span></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">      pageNum: 当前页码</span></span><br><span class="line"><span class="comment">      pageHeight: 当前页长度</span></span><br><span class="line"><span class="comment">      pageToTop: 当前页距离顶端（相对于页面长度）</span></span><br><span class="line"><span class="comment">      scrollPage: 当前页距离顶端（相对于整个动画盒子的长度）</span></span><br><span class="line"><span class="comment">      element: 动画盒子的元素对象</span></span><br><span class="line"><span class="comment">      page: 当前页的元素对象</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    <span class="comment">// 超出范围时</span></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">      without: up/down 分别为从上端超出和从下端超出</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h3 id="效果"><a class="header-anchor" href="#效果">¶</a>效果</h3><p><a href="https://www.oblivionocean.top/">完整效果</a></p>]]></content>
    
    
    <summary type="html"> 为了给工作室写个新的官网，简洁还不能显得很Low，于是我写了这个  LightScrollPage LightScrollPage(简称 “LSP”)，一个基于原生JS的微型滚动动画库，不需要依赖，只需要一个JS文件，源代码小于1KB 如何使用 引入 CDN 你可以使用支持Github回源的CDN jsDelivr: &amp;lt;script src=&amp;quot;https://cdn.jsdeli...</summary>
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="JS" scheme="https://www.yt-blog.top/tags/JS/"/>
    
  </entry>
  
  <entry>
    <title>推一下 Vercel 加速节点</title>
    <link href="https://www.yt-blog.top/9952/"/>
    <id>https://www.yt-blog.top/9952/</id>
    <published>2024-01-25T15:47:22.613Z</published>
    <updated>2024-04-20T07:19:49.570Z</updated>
    
    <content type="html"><![CDATA[<h2 id="写在前面"><a class="header-anchor" href="#写在前面">¶</a>写在前面</h2><p>Vercel 不仅可以部署 Hexo 博客，还能部署很多服务。</p><p>境内选择 Vercel 的站长很多，为了提升访问速度，自然选择了距离大陆最近的香港节点。</p><p>选的多了，节点压力自然就会增大，就算 Vercel 属于大平台，对陆带宽依旧有限，必然会出现互相影响的情况。</p><p>再加上滥用资源等问题出现，不少小伙伴反馈 Vercel 越来越慢。</p><p>今天为 Vercel 用户提供一个加速方案。</p><h2 id="食用方法"><a class="header-anchor" href="#食用方法">¶</a>食用方法</h2><p>将原来解析至 <code>cname.vercel.com</code> 改为 <code>vercel.cdn.yt-blog.top</code></p><blockquote><p>我没有图床所以直接复制杜老师的，但是注意，两个CNAME速度有差距，这个CNAME对应<a href="https://vercel-cyfan.yt-blog.top/">https://vercel-cyfan.yt-blog.top/</a>，这主要是由于104.199.217.228只有电信快，18.162.37.140相对不稳定，但联通和移动快，大部分Vercel节点都是联通和移动快。vercel.cdn.yt-blog.top使用了更多的IP确保在一台出现问题后不会有太面积影响，但灵感来自vercel.cdn.cyfan.top</p></blockquote><p><img src="https://cdn.dusays.com/2024/01/669-1.jpg" alt="图片" /></p><p>可访问<a href="https://vercel.cdn.yt-blog.top/">Vercel CDN (vercel.cdn.yt-blog.top)</a>查看</p><h2 id="加速原理"><a class="header-anchor" href="#加速原理">¶</a>加速原理</h2><p>Vercel 在大陆周围还有很多节点，其中包含中国台湾、韩国、日本、新加坡等，这些节点的访问延迟在接受范围，且相对香港节点来说带宽更充足。</p><p>Vercel 的 Anycast 会自动将节点解析至距离最近的香港服务器，但如果手动解析则太过麻烦。</p><p><code>vercel.cdn.yt-blog.top</code> 经过不断测速（大约消耗了200MB流量）手动解析，并通过 D 监控检查状态，无法访问时会及时暂停节点。使用时自动解析至附近可用节点，尽可能的选择优质节点。</p><p>这更加类似于CF自选IP，而不是真正的节点，节点IP基于Cyfan的<a href="https://gist.github.com/ChenYFan/fc2bd4ec1795766f2613b52ba123c0f8">Vercel All IP (github.com)</a></p><h2 id="更进一步"><a class="header-anchor" href="#更进一步">¶</a>更进一步</h2><p>可以通过Vercel官方提供的缓存进行加速<br />详细请看：<a href="https://vercel.com/docs/edge-network/caching#cdn-cache-control">https://vercel.com/docs/edge-network/caching#cdn-cache-control</a></p><p>静态网站参考本博客，在根目录放置vercel.json</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;headers&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/sw.js&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;headers&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;key&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Cache-Control&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;public, max-age=0, must-revalidate&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;source&quot;</span><span class="punctuation">:</span> <span class="string">&quot;(.*)&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;headers&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;key&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Cache-Control&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;public, s-maxage=86400, max-age=86400&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;key&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Vercel-CDN-Cache-Control&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;max-age=3600&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>Vercel在部署时会自动刷新缓存，静态网站缓存可以拉到无限长，动态网站缓存按实际需要</p><h2 id="测速截图"><a class="header-anchor" href="#测速截图">¶</a>测速截图</h2><p>测速工具（节点很多，非常推荐）：<a href="https://zhale.me/http/">https://zhale.me/http/</a></p><p><img src="https://bu.dusays.com/2024/01/16/65a6740fc36ea.png" alt="测速图片" /></p><h2 id="问题反馈"><a class="header-anchor" href="#问题反馈">¶</a>问题反馈</h2><p><a href="https://github.com/Fgaoxing/Vercel-CDN">https://github.com/Fgaoxing/Vercel-CDN</a></p><p>我们无法觉得谁使用了CNAME，所以也有一些人通过解析我们CNAME的方式建立自己的Vercel CDN(我给他个面子，不在这里说了)，但多次CNAME会导致速度变慢，如果有人给你发送一张对比图说他的测速比我这个快，大概是因为我这个有宣传页面，所以网站测速比不上Vercel的404</p>]]></content>
    
    
    <summary type="html">写在前面 Vercel 不仅可以部署 Hexo 博客，还能部署很多服务。 境内选择 Vercel 的站长很多，为了提升访问速度，自然选择了距离大陆最近的香港节点。 选的多了，节点压力自然就会增大，就算 Vercel 属于大平台，对陆带宽依旧有限，必然会出现互相影响的情况。 再加上滥用资源等问题出现，不少小伙伴反馈 Vercel 越来越慢。 今天为 Vercel 用户提供一个加速方案。 食用方法 将...</summary>
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Vercel CDN" scheme="https://www.yt-blog.top/tags/Vercel-CDN/"/>
    
  </entry>
  
  <entry>
    <title>网站优化小窍门</title>
    <link href="https://www.yt-blog.top/3705/"/>
    <id>https://www.yt-blog.top/3705/</id>
    <published>2024-01-16T04:19:56.050Z</published>
    <updated>2024-01-16T04:20:16.922Z</updated>
    
    <content type="html"><![CDATA[<p>首先呢，我发表一下我自己的观点：<br />速度优化有很多方面，并不一定说非得上SW</p><hr /><h2 id="服务器"><a class="header-anchor" href="#服务器">¶</a>服务器</h2><h3 id="虚拟机-虚拟空间"><a class="header-anchor" href="#虚拟机-虚拟空间">¶</a>虚拟机/虚拟空间</h3><p>这里只说GFW外的，GFW内的话基本也用不上<br />首先就是CDN，尤其是中国以外，尽量套一个，有的人可能套了，但是还没开缓存，那一点意义没有，甚至更慢<br />所以一定要为静态内容（或者伪静态）配置合理的缓存</p><h3 id="部署平台"><a class="header-anchor" href="#部署平台">¶</a>部署平台</h3><p>对于一些部署平台，我这里只有Vercel的优化经验<br />其他的平台可以参照<br />首先你要清楚一点：部署平台，基本上都不是单台服务器<br />那这样就好办——测速<br />然后看哪个服务器究竟在哪，一个运营商，哪一个城市哪一条线路快<br />接下来使用DNS的分区域解析，挨个解析就可以了<br />比如我这里的Vercel效果：vercel.cdn.yt-blog.top(随便用，CNAME解析一些就行了)<br />（这个月为了优化网站，我已经测速消耗了200MB的流量，勉强达到国内付费CDN的程度，数据来源：<a href="https://zhale.me/http">炸了么</a>）<br /><img src="https://bu.dusays.com/2024/01/16/65a6740fc36ea.png" alt="测速图 比较长，有点慢" /></p><h2 id="网页"><a class="header-anchor" href="#网页">¶</a>网页</h2><p>说完了服务器，接下来就是网页本身。首先就是尽量让网页体积更小<br />将字体JS CSS之类的各种文件都独立托管于网页本身<br />这样也可以带来更好的速度，尤其是使用免费的资源，还能节省流量</p>]]></content>
    
    
    <summary type="html">首先呢，我发表一下我自己的观点： 速度优化有很多方面，并不一定说非得上SW  服务器 虚拟机/虚拟空间 这里只说GFW外的，GFW内的话基本也用不上 首先就是CDN，尤其是中国以外，尽量套一个，有的人可能套了，但是还没开缓存，那一点意义没有，甚至更慢 所以一定要为静态内容（或者伪静态）配置合理的缓存 部署平台 对于一些部署平台，我这里只有Vercel的优化经验 其他的平台可以参照 首先你要清楚一点...</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>【显微镜下的世界】0x1</title>
    <link href="https://www.yt-blog.top/26970/"/>
    <id>https://www.yt-blog.top/26970/</id>
    <published>2023-12-22T22:59:31.077Z</published>
    <updated>2023-12-22T23:01:57.762Z</updated>
    
    <content type="html"><![CDATA[<p>普通光学显微镜+电子目镜<br />如果要是用目镜直接看，会更清晰<br />纸张表面：<br /><img src="https://bu.dusays.com/2023/12/23/6586821773409.jpg" alt="" /><br />4x物镜，目镜WF 100X<br />我脸上的毛（类似长寿眉）<br /><img src="https://bu.dusays.com/2023/12/23/6586822f4f079.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/65868235d2fda.jpg" alt="" /><br />10X：<br /><img src="https://bu.dusays.com/2023/12/23/6586825053913.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/658682537d2ca.jpg" alt="" /><br />100X：<br /><img src="https://bu.dusays.com/2023/12/23/658682806c6ae.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/6586828625158.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/6586828c78144.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/658682939cb97.jpg" alt="" /><br />暗光（把反光镜立起来）：<br /><img src="https://bu.dusays.com/2023/12/23/658682bad23b7.jpg" alt="" /><br />加倍镜：<br /><img src="https://bu.dusays.com/2023/12/23/658682df04968.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/658682e3c5189.jpg" alt="" /><br />叶子:<br /><img src="https://bu.dusays.com/2023/12/23/658682fb9f47a.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/658682ff54e2a.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/65868302512dc.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/65868307a33af.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/65868310a42af.jpg" alt="" /><br />铁锈：<br />第一张10x，后面4x，光源是手持手电，从上面打光<br /><img src="https://bu.dusays.com/2023/12/23/6586835b2ee4e.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/6586835d08ee7.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/6586835fcd768.jpg" alt="" /><br /><img src="https://bu.dusays.com/2023/12/23/658683614ec44.jpg" alt="" /></p>]]></content>
    
    
    <summary type="html">普通光学显微镜+电子目镜 如果要是用目镜直接看，会更清晰 纸张表面：  4x物镜，目镜WF 100X 我脸上的毛（类似长寿眉）   10X：   100X：     暗光（把反光镜立起来）：  加倍镜：   叶子:      铁锈： 第一张10x，后面4x，光源是手持手电，从上面打光     ...</summary>
    
    
    
    <category term="显微镜下的世界" scheme="https://www.yt-blog.top/categories/%E6%98%BE%E5%BE%AE%E9%95%9C%E4%B8%8B%E7%9A%84%E4%B8%96%E7%95%8C/"/>
    
    
    <category term="显微镜下的世界" scheme="https://www.yt-blog.top/tags/%E6%98%BE%E5%BE%AE%E9%95%9C%E4%B8%8B%E7%9A%84%E4%B8%96%E7%95%8C/"/>
    
    <category term="系列" scheme="https://www.yt-blog.top/tags/%E7%B3%BB%E5%88%97/"/>
    
  </entry>
  
  <entry>
    <title>【Hexo】优化教程</title>
    <link href="https://www.yt-blog.top/46463/"/>
    <id>https://www.yt-blog.top/46463/</id>
    <published>2023-07-17T15:48:24.239Z</published>
    <updated>2024-01-18T17:22:18.559Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>本文章将从部署速度和访问速度两方面说说如何优化Hexo博客</p></blockquote><h2 id="部署速度"><a class="header-anchor" href="#部署速度">¶</a>部署速度</h2><p>我们可看到Hexo的官网上告诉我们Hexo的生成速度还是很快的</p><p><img src="https://npm.elemecdn.com/ytblogimg/5e4545888b77352d759bb8e4c20259bf.png" alt="https://npm.elemecdn.com/ytblogimg/5e4545888b77352d759bb8e4c20259bf.png" /></p><p>那为啥需要那么长时间呢，我们看看部署的流程</p><ol><li>从NPM安装包</li><li>运行Hexo生成指令</li><li>glup压缩（可选）</li></ol><p>这个流程每次都要运行一遍，非常耗时，如何优化呢</p><h3 id="NPM安装加速"><a class="header-anchor" href="#NPM安装加速">¶</a>NPM安装加速</h3><p>首先确定服务器位置，Github服务器在美国，所以呢只能使用NPM获取优化不了</p><p>但是Vercel可以选择节点位置，方法如下：</p><p>打开一个项目</p><p><img src="https://npm.elemecdn.com/ytblogimg/377239b28a4f1f4151ff826eb696e057.png" alt="https://npm.elemecdn.com/ytblogimg/377239b28a4f1f4151ff826eb696e057.png" /></p><p>点击设置<br /><img src="https://npm.elemecdn.com/ytblogimg/f796110a9f2b0fb8a96c069b11d877ee.png" alt="https://npm.elemecdn.com/ytblogimg/f796110a9f2b0fb8a96c069b11d877ee.png" />然后按图中的配置<br /><img src="https://npm.elemecdn.com/ytblogimg/f03b06eb870514a1ea597f9b588cd639.png" alt="https://npm.elemecdn.com/ytblogimg/f03b06eb870514a1ea597f9b588cd639.png" /></p><p>然后就可以使用NPM镜像了，实测阿里镜像最快</p><p><img src="https://npm.elemecdn.com/ytblogimg/b53d09b87284846842341a9806630c77.png" alt="https://npm.elemecdn.com/ytblogimg/b53d09b87284846842341a9806630c77.png" /></p><p>部署的时间可以压缩最少10秒</p><h3 id="Hexo生成加速"><a class="header-anchor" href="#Hexo生成加速">¶</a>Hexo生成加速</h3><p>首先就是减少文件数量，能删就删</p>]]></content>
    
    
    <summary type="html"> 本文章将从部署速度和访问速度两方面说说如何优化Hexo博客  部署速度 我们可看到Hexo的官网上告诉我们Hexo的生成速度还是很快的  那为啥需要那么长时间呢，我们看看部署的流程  从NPM安装包 运行Hexo生成指令 glup压缩（可选）  这个流程每次都要运行一遍，非常耗时，如何优化呢 NPM安装加速 首先确定服务器位置，Github服务器在美国，所以呢只能使用NPM获取优化不了 但是Ve...</summary>
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Hexo" scheme="https://www.yt-blog.top/tags/Hexo/"/>
    
    <category term="网站优化" scheme="https://www.yt-blog.top/tags/%E7%BD%91%E7%AB%99%E4%BC%98%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>【CDNN】CDNN再添一员</title>
    <link href="https://www.yt-blog.top/26824/"/>
    <id>https://www.yt-blog.top/26824/</id>
    <published>2023-05-25T05:17:04.854Z</published>
    <updated>2024-01-18T17:15:20.267Z</updated>
    
    <content type="html"><![CDATA[<p>爱写CDN的我，又写了个新的CDN，CDNN系列再添一员，目前刚上线，不是很稳定，见谅。可以加群了解详情115967669，网站：<a href="https://cdn2.chuqis.com/">https://cdn2.chuqis.com/</a> ，和初七公司合作的【不是广告】<br />目前单文件最大30M，以后会开放付费的50M和100M，自己的回源，不依赖JSD</p>]]></content>
    
    
    <summary type="html">爱写CDN的我，又写了个新的CDN，CDNN系列再添一员，目前刚上线，不是很稳定，见谅。可以加群了解详情115967669，网站：https://cdn2.chuqis.com/ ，和初七公司合作的【不是广告】 目前单文件最大30M，以后会开放付费的50M和100M，自己的回源，不依赖JSD </summary>
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="CDNN" scheme="https://www.yt-blog.top/tags/CDNN/"/>
    
    <category term="CDN" scheme="https://www.yt-blog.top/tags/CDN/"/>
    
    <category term="Python" scheme="https://www.yt-blog.top/tags/Python/"/>
    
  </entry>
  
  <entry>
    <title>懒加载的妙用：缓存篇</title>
    <link href="https://www.yt-blog.top/49152/"/>
    <id>https://www.yt-blog.top/49152/</id>
    <published>2023-05-06T16:37:05.666Z</published>
    <updated>2023-09-11T04:53:51.859Z</updated>
    
    <content type="html"><![CDATA[<p>很多网站都用了一项技术：懒加载(<strong>Lazyload</strong>)</p><p>用于增加速度，减少请求量，尽管如此每次查看图片还是需要等待他加载完，这很耗时间，如下</p><p><img src="https://cdn2.chuqis.com/gh/fgaoxing/myimg/e3263eddea3f75ba4cbab3fabaaaff63.png" alt="https://cdn2.chuqis.com/gh/fgaoxing/myimg/e3263eddea3f75ba4cbab3fabaaaff63.png" /></p><p><img src="https://cdn2.chuqis.com/gh/fgaoxing/myimg/254514013d87e1d985e08b6144100f49.png" alt="https://cdn2.chuqis.com/gh/fgaoxing/myimg/254514013d87e1d985e08b6144100f49.png" /></p><p>但是如果先呈现，后加载，不就可以了吗。</p><p>这时候就有人跳出来了，</p><blockquote><p>开什么玩笑呢，不加载，怎么呈现？</p></blockquote><p>问得好，其实很简单，我只要把图片存在用户电脑就行了，问题在于怎么存，如果要是使用SW，一旦写错，基本上网站就废了，所以这个不考虑，但是SW但来了一个东西，没错就是<code>Cache</code>，它可以缓存请求，当然也可以存储数据，其实可以直接存储二进制，不过我还是转换成base64存储，由于比较复杂，我就不展示了，</p><p>你访问本网站就可以感受到，代码后续放出来</p>]]></content>
    
    
    <summary type="html">很多网站都用了一项技术：懒加载(Lazyload) 用于增加速度，减少请求量，尽管如此每次查看图片还是需要等待他加载完，这很耗时间，如下   但是如果先呈现，后加载，不就可以了吗。 这时候就有人跳出来了，  开什么玩笑呢，不加载，怎么呈现？  问得好，其实很简单，我只要把图片存在用户电脑就行了，问题在于怎么存，如果要是使用SW，一旦写错，基本上网站就废了，所以这个不考虑，但是SW但来了一个东西，没...</summary>
    
    
    
    
    <category term="次回加载" scheme="https://www.yt-blog.top/tags/%E6%AC%A1%E5%9B%9E%E5%8A%A0%E8%BD%BD/"/>
    
    <category term="Lazyload" scheme="https://www.yt-blog.top/tags/Lazyload/"/>
    
    <category term="Cache" scheme="https://www.yt-blog.top/tags/Cache/"/>
    
    <category term="自主缓存" scheme="https://www.yt-blog.top/tags/%E8%87%AA%E4%B8%BB%E7%BC%93%E5%AD%98/"/>
    
    <category term="网站加速" scheme="https://www.yt-blog.top/tags/%E7%BD%91%E7%AB%99%E5%8A%A0%E9%80%9F/"/>
    
  </entry>
  
  <entry>
    <title>【FastJump.js】简单的快速跳转技术</title>
    <link href="https://www.yt-blog.top/64234/"/>
    <id>https://www.yt-blog.top/64234/</id>
    <published>2023-03-17T00:29:45.000Z</published>
    <updated>2024-04-03T05:23:54.158Z</updated>
    
    <content type="html"><![CDATA[<p>110行写了个小玩意，可以像sw那样离线缓存，和Pjax类似，不过用了自主缓存，fetch做请求，算了上代码吧：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br></pre></td><td class="code"><pre><span class="line">self.<span class="property">CACHE_NAME</span> = <span class="string">&#x27;FastJumpCache&#x27;</span>; <span class="comment">// 默认的存储名称</span></span><br><span class="line">self.<span class="property">db</span> = &#123;</span><br><span class="line">    <span class="attr">read</span>: <span class="function">(<span class="params">key</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">            caches.<span class="title function_">match</span>(<span class="keyword">new</span> <span class="title class_">Request</span>(<span class="string">`https://LOCALCACHE/<span class="subst">$&#123;<span class="built_in">encodeURIComponent</span>(key)&#125;</span>`</span>)).<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">res</span>) &#123;</span><br><span class="line">                res.<span class="title function_">text</span>().<span class="title function_">then</span>(<span class="function"><span class="params">text</span> =&gt;</span> <span class="title function_">resolve</span>(text));</span><br><span class="line">            &#125;).<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">                <span class="title function_">resolve</span>(<span class="literal">null</span>);</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;, <span class="attr">write</span>: <span class="function">(<span class="params">key, value</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">            caches.<span class="title function_">open</span>(<span class="variable constant_">CACHE_NAME</span>).<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">cache</span>) &#123;</span><br><span class="line">                cache.<span class="title function_">put</span>(<span class="keyword">new</span> <span class="title class_">Request</span>(<span class="string">`https://LOCALCACHE/<span class="subst">$&#123;<span class="built_in">encodeURIComponent</span>(key)&#125;</span>`</span>), <span class="keyword">new</span> <span class="title class_">Response</span>(value));</span><br><span class="line">                <span class="title function_">resolve</span>();</span><br><span class="line">            &#125;).<span class="title function_">catch</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">                <span class="title function_">reject</span>();</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    self.<span class="property">db</span>.<span class="title function_">read</span>(<span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span>).<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">d</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!d) &#123;</span><br><span class="line">            <span class="title function_">fetch</span>(<span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span>).<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">d</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (d.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;content-type&#x27;</span>) === <span class="string">&#x27;text/html&#x27;</span>) &#123;</span><br><span class="line">                    d.<span class="title function_">text</span>().<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">b</span>) &#123;</span><br><span class="line">                        self.<span class="property">db</span>.<span class="title function_">write</span>(<span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span>, b)</span><br><span class="line">                    &#125;)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="built_in">setInterval</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> doms = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;a[href]&#x27;</span>);</span><br><span class="line">        <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">forEach</span>.<span class="title function_">call</span>(doms, <span class="keyword">function</span> (<span class="params">dom</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (dom.<span class="property">href</span> &amp;&amp; dom.<span class="property">href</span>.<span class="title function_">indexOf</span>(<span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">origin</span>) === <span class="number">0</span>) &#123;</span><br><span class="line">                dom.<span class="property">onclick</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">                    history.<span class="title function_">pushState</span>(&#123;&#125;, <span class="string">&#x27;&#x27;</span>, dom.<span class="property">href</span>);</span><br><span class="line">                    self.<span class="property">db</span>.<span class="title function_">read</span>(dom.<span class="property">href</span>).<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">d</span>) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (d) &#123;</span><br><span class="line">                            <span class="variable language_">console</span>.<span class="title function_">clear</span>();</span><br><span class="line">                            <span class="variable language_">document</span>.<span class="title function_">open</span>();</span><br><span class="line">                            <span class="keyword">try</span> &#123;</span><br><span class="line">                                <span class="variable language_">document</span>.<span class="title function_">write</span>(d);</span><br><span class="line">                                <span class="keyword">let</span> <span class="title class_">Event</span>_timerun = <span class="variable language_">window</span>.<span class="built_in">setInterval</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">                                    <span class="keyword">if</span> (<span class="variable language_">document</span>.<span class="property">body</span>&amp;&amp;<span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">innerHTML</span>) &#123;</span><br><span class="line">                                        <span class="keyword">let</span> <span class="title class_">Event</span> = <span class="keyword">new</span> <span class="title class_">CustomEvent</span>(<span class="string">&#x27;onload&#x27;</span>)</span><br><span class="line">                                        <span class="variable language_">document</span>.<span class="title function_">dispatchEvent</span>(<span class="title class_">Event</span>);</span><br><span class="line">                                        <span class="variable language_">window</span>.<span class="title function_">dispatchEvent</span>(<span class="title class_">Event</span>);</span><br><span class="line">                                        <span class="title class_">Event</span> = <span class="keyword">new</span> <span class="title class_">CustomEvent</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</span>)</span><br><span class="line">                                        <span class="variable language_">document</span>.<span class="title function_">dispatchEvent</span>(<span class="title class_">Event</span>);</span><br><span class="line">                                        <span class="variable language_">window</span>.<span class="title function_">dispatchEvent</span>(<span class="title class_">Event</span>);</span><br><span class="line">                                        <span class="variable language_">window</span>.<span class="built_in">clearInterval</span>(<span class="title class_">Event</span>_timerun)</span><br><span class="line">                                    &#125;</span><br><span class="line">                                &#125;,<span class="number">500</span>)</span><br><span class="line">                                <span class="title function_">fetch</span>(dom.<span class="property">href</span>).<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">d</span>) &#123;</span><br><span class="line">                                    <span class="keyword">if</span> (d.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;content-type&#x27;</span>) === <span class="string">&#x27;text/html&#x27;</span>) &#123;</span><br><span class="line">                                        d.<span class="title function_">text</span>().<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">b</span>) &#123;</span><br><span class="line">                                            self.<span class="property">db</span>.<span class="title function_">write</span>(<span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span>, b)</span><br><span class="line">                                        &#125;)</span><br><span class="line">                                    &#125;</span><br><span class="line">                                &#125;)</span><br><span class="line">                            &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line"></span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                            <span class="title function_">fetch</span>(dom.<span class="property">href</span>).<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">d</span>) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (d.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;content-type&#x27;</span>) === <span class="string">&#x27;text/html&#x27;</span>) &#123;</span><br><span class="line">                                    d.<span class="title function_">text</span>().<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">b</span>) &#123;</span><br><span class="line">                                        <span class="variable language_">console</span>.<span class="title function_">clear</span>();</span><br><span class="line">                                        <span class="variable language_">document</span>.<span class="title function_">open</span>();</span><br><span class="line">                                        <span class="keyword">try</span> &#123;</span><br><span class="line">                                            <span class="variable language_">document</span>.<span class="title function_">write</span>(b)</span><br><span class="line">                                            <span class="keyword">let</span> <span class="title class_">Event</span>_timerun = <span class="variable language_">window</span>.<span class="built_in">setInterval</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">                                                <span class="keyword">if</span> (<span class="variable language_">document</span>.<span class="property">body</span>&amp;&amp;<span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">innerHTML</span>) &#123;</span><br><span class="line">                                                    <span class="keyword">let</span> <span class="title class_">Event</span> = <span class="keyword">new</span> <span class="title class_">CustomEvent</span>(<span class="string">&#x27;onload&#x27;</span>)</span><br><span class="line">                                                    <span class="variable language_">document</span>.<span class="title function_">dispatchEvent</span>(<span class="title class_">Event</span>);</span><br><span class="line">                                                    <span class="variable language_">window</span>.<span class="title function_">dispatchEvent</span>(<span class="title class_">Event</span>);</span><br><span class="line">                                                    <span class="title class_">Event</span> = <span class="keyword">new</span> <span class="title class_">CustomEvent</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</span>)</span><br><span class="line">                                                    <span class="variable language_">document</span>.<span class="title function_">dispatchEvent</span>(<span class="title class_">Event</span>);</span><br><span class="line">                                                    <span class="variable language_">window</span>.<span class="title function_">dispatchEvent</span>(<span class="title class_">Event</span>);</span><br><span class="line">                                                    <span class="variable language_">window</span>.<span class="built_in">clearInterval</span>(<span class="title class_">Event</span>_timerun)</span><br><span class="line">                                                &#125;</span><br><span class="line">                                            &#125;,<span class="number">500</span>)</span><br><span class="line">                                        &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">                                        &#125;</span><br><span class="line">                                        self.<span class="property">db</span>.<span class="title function_">write</span>(dom.<span class="property">href</span>, b)</span><br><span class="line">                                    &#125;).<span class="title function_">catch</span>(<span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">                                        <span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span> = dom.<span class="property">href</span></span><br><span class="line">                                    &#125;)</span><br><span class="line">                                &#125;</span><br><span class="line">                            &#125;).<span class="title function_">catch</span>(<span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">                                <span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span> = dom.<span class="property">href</span></span><br><span class="line">                            &#125;)</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;).<span class="title function_">catch</span>(<span class="keyword">function</span> (<span class="params">e</span>) &#123;</span><br><span class="line">                        <span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span> = dom.<span class="property">href</span></span><br><span class="line">                    &#125;)</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;, <span class="number">500</span>)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>注意不能与Pjax一起使用！！<br />鄙人水平有限，请斧正<br />有不少Bug，仅供测试，不可以在线上环境使用</p>]]></content>
    
    
    <summary type="html">110行写了个小玩意，可以像sw那样离线缓存，和Pjax类似，不过用了自主缓存，fetch做请求，算了上代码吧： self.CACHE_NAME = &#39;FastJumpCache&#39;; // 默认的存储名称 self.db = {     read: (key) =&amp;gt; {         return new Promise((resolve, reject) =&amp;gt; {         ...</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>BiliBili崩了</title>
    <link href="https://www.yt-blog.top/47626/"/>
    <id>https://www.yt-blog.top/47626/</id>
    <published>2023-03-05T12:48:16.000Z</published>
    <updated>2023-09-11T04:09:32.500Z</updated>
    
    <content type="html"><![CDATA[<p>这是唯一一次我在看视频的时候崩的，这回着就是你在点开视频的时候就会：</p><p><img src="https://img.yt-blog.top/1678020769.2601757.png" alt="截图" /></p><p>，水文一篇，等待BiliBili解析一下这次故障</p>]]></content>
    
    
    <summary type="html">这是唯一一次我在看视频的时候崩的，这回着就是你在点开视频的时候就会：  ，水文一篇，等待BiliBili解析一下这次故障 ...</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>【New Bing】New Bing免代理申请和使用</title>
    <link href="https://www.yt-blog.top/52329/"/>
    <id>https://www.yt-blog.top/52329/</id>
    <published>2023-02-15T12:54:15.000Z</published>
    <updated>2024-01-18T17:20:19.911Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>已失效</p></blockquote><p>大家都知道哈，前段时间，有个AI叫ChatGPT，很火，所有人都在说。不过据说好像现在收费了，OpenAI么，懂得都懂，先免费，再收费，像是DALL·E、Copilot都是。但是因为国内不能访问，所以就没用上……</p><p>现在又搞出来newBing（后面估计会收费，为了AI，都给服务器干崩了），不过国内还是不让用，这时候就需要一些合法手段来访问。</p><h2 id="教程"><a class="header-anchor" href="#教程">¶</a>教程</h2><p>其实很简单</p><h3 id="申请"><a class="header-anchor" href="#申请">¶</a>申请</h3><p>如果直接访问<a href="https://www.bing.com/new">https://www.bing.com/new</a>，百分百不行，咋办，他是按照国家的，<s>所以我们只要去国外就行了</s>伪装呗，多简单啊！不过咱们说了，要<strong>合法</strong>，所以用非常手段肯定不行。先要明白原理，简单来说就是IP定位，那么我们就伪装IP</p><p>IP获取有好几种方式，比如用网路发送数据的IP，这样就需要用到代理（代理是合法的，但是麻烦），另一种是通过Header中的x-forwarded-for字段获取。这主要看bing的方式，他用的是后者，我们操作一下。所以我们需要改头，这个简单。</p><p>首先去下载一个插件，如果有类似插件，可以不用下载，这里只用 <code>Header Editor</code>举例</p><p>官网下载页：<a href="https://he.firefoxcn.net/zh-CN/guide.html">开始 | Header Editor (firefoxcn.net)</a></p><p>安装好，打开它</p><p><img src="https://img.yt-blog.top/1676467120242.webp" alt="https://cdn2.chuqis.com/gh/fgaoxing/myimg/1676467120242.webp" /></p><p>加号添加，按照图片配置好保存即可</p><p><img src="https://img.yt-blog.top/1677339335.9528594.webp" alt="https://cdn2.chuqis.com/gh/fgaoxing/myimg/1677339335.9528594.webp" /></p><p>名称随意，如果不会，就按照图片填写即可</p><p>访问<a href="https://www.bing.com/">必应 (bing.com)</a>，不跳转cn.就说明成功了</p><p><img src="https://img.yt-blog.top/1676468336326.webp" alt="https://cdn2.chuqis.com/gh/fgaoxing/myimg/1676468336326.webp" /></p><p>选择美国</p><p><img src="https://img.yt-blog.top/1676468388394.webp" alt="https://cdn2.chuqis.com/gh/fgaoxing/myimg1676468388394.webp" /></p><p>然后访问<a href="https://www.bing.com/new">必应 (bing.com)</a>，点击加入即可，等待邮件，大概两三天</p><p><img src="https://img.yt-blog.top/1676468496114.webp" alt="https://cdn2.chuqis.com/gh/fgaoxing/myimg/1676468496114.webp" /></p><p>然后恭喜，你就有了NewBing</p><p>其实平时用国外ip访问bing也可以减少广告，增加更多搜索内容</p><p>最后只要按照上面的操作，再来一遍，然后在搜索框输入内容即可开始问答，按照网上的提示，可以调教，但是我没试过。不要滥用，会被封。</p><p>Bing可能要超过谷歌了！</p>]]></content>
    
    
    <summary type="html"> 已失效  大家都知道哈，前段时间，有个AI叫ChatGPT，很火，所有人都在说。不过据说好像现在收费了，OpenAI么，懂得都懂，先免费，再收费，像是DALL·E、Copilot都是。但是因为国内不能访问，所以就没用上…… 现在又搞出来newBing（后面估计会收费，为了AI，都给服务器干崩了），不过国内还是不让用，这时候就需要一些合法手段来访问。 教程 其实很简单 申请 如果直接访问https...</summary>
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="AI" scheme="https://www.yt-blog.top/tags/AI/"/>
    
    <category term="New Bing" scheme="https://www.yt-blog.top/tags/New-Bing/"/>
    
    <category term="ChatGPT" scheme="https://www.yt-blog.top/tags/ChatGPT/"/>
    
    <category term="OpenAI" scheme="https://www.yt-blog.top/tags/OpenAI/"/>
    
  </entry>
  
  <entry>
    <title>simplest-server</title>
    <link href="https://www.yt-blog.top/51672/"/>
    <id>https://www.yt-blog.top/51672/</id>
    <published>2023-01-10T02:24:59.000Z</published>
    <updated>2026-02-24T03:51:31.798Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前情"><a class="header-anchor" href="#前情">¶</a>前情</h2><p>给各位道个歉，好久没更新了</p><p>给大家带来一个好东西</p><p>众所周知，我会node.js</p><p>但是把，我一开始就选择了http库（就是原生库）</p><p>所以用express就会不太顺手</p><p>但是原生的http又没啥东西，就很难受几乎什么都要自己写，包括cookie的操作</p><p>所以我就基于原生的http包写了一个框架，使用路由的方式，可以使用无服务器函数</p><a class="ghcard" rel="external nofollow noopener noreferrer" href="https://github.com/simplest-server/simplest-server"><img src="https://github-readme-stats.xaoxuu.com//api/pin/?username=simplest-server&repo=simplest-server&show_owner=true"/></a><p><a href="https://github.com/simplest-server/simplest-server"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="140" height="20"><clipPath id="r"><rect width="140" height="20" fill="#fff" rx="3"/></clipPath><g clip-path="url(#r)"><rect width="45" height="20" fill="#555"/><rect x="45" width="95" height="20" fill="#007ec6"/><rect width="140" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="235" y="140" transform="scale(.1)" fill="#fff">GitHub</text><text x="915" y="140" transform="scale(.1)" fill="#fff" textLength="850">simplest-server</text></g></svg></a><br /><a href="https://www.npmjs.com/package/simplest-server"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="140" height="20"><clipPath id="r"><rect width="140" height="20" fill="#fff" rx="3"/></clipPath><g clip-path="url(#r)"><rect width="45" height="20" fill="#555"/><rect x="45" width="95" height="20" fill="#e05d44"/><rect width="140" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="235" y="140" transform="scale(.1)" fill="#fff">NPM</text><text x="915" y="140" transform="scale(.1)" fill="#fff" textLength="850">simplest-server</text></g></svg></a><br /><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="140" height="20"><clipPath id="r"><rect width="140" height="20" fill="#fff" rx="3"/></clipPath><g clip-path="url(#r)"><rect width="45" height="20" fill="#555"/><rect x="45" width="95" height="20" fill="green"/><rect width="140" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="235" y="140" transform="scale(.1)" fill="#fff">LGPL</text><text x="915" y="140" transform="scale(.1)" fill="#fff">License</text></g></svg></p><h2 id="有关包的一些东西"><a class="header-anchor" href="#有关包的一些东西">¶</a>有关包的一些东西</h2><p>目前由JS编写使用CJS引入，后续可能会迁移到Ts</p><p>这个NPM包目前是测试版，但基础功能已经OK了</p><p>你可以这样引入</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> ss = <span class="built_in">require</span>(<span class="string">&#x27;simplest-server&#x27;</span>);</span><br></pre></td></tr></table></figure><p>目前包含如下函数</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> ss = <span class="built_in">require</span>(<span class="string">&#x27;simplest-server&#x27;</span>);</span><br><span class="line">ss.<span class="property">http</span> # http服务</span><br><span class="line">ss.<span class="property">maps</span> # 本地文件映射</span><br><span class="line">ss.<span class="property">map</span> # 本地文件映射</span><br><span class="line">ss.<span class="property">ejs</span> # 集成的<span class="variable constant_">EJS</span></span><br><span class="line">ss.<span class="property">err</span> # 返回报错页面</span><br></pre></td></tr></table></figure><p>更多文档看<a href="https://www.yt-blog.top/docs/simplest-server/">Simplest Server 文档</a>（大概率没写完，所以只能等）</p><h3 id="关于https"><a class="header-anchor" href="#关于https">¶</a>关于https</h3><p>目前不支持，后续加入</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;前情&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;#前情&quot;&gt;¶&lt;/a&gt;前情&lt;/h2&gt;
&lt;p&gt;给各位道个歉，好久没更新了&lt;/p&gt;
&lt;p&gt;给大家带来一个好东西&lt;/p&gt;
&lt;p&gt;众所周知，我会node.js&lt;/p&gt;
&lt;p&gt;但是把，我一开始就选择了htt</summary>
      
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Node.js" scheme="https://www.yt-blog.top/tags/Node-js/"/>
    
    <category term="simplest-server" scheme="https://www.yt-blog.top/tags/simplest-server/"/>
    
  </entry>
  
  <entry>
    <title>Python实现文件查重</title>
    <link href="https://www.yt-blog.top/58785/"/>
    <id>https://www.yt-blog.top/58785/</id>
    <published>2022-10-07T04:22:03.000Z</published>
    <updated>2022-10-14T08:48:06.000Z</updated>
    
    <content type="html"><![CDATA[<p>同时支持文件查重，空文件夹查找，大文件查找等，后续还将不断更新！！</p><h2 id="开发原因"><a class="header-anchor" href="#开发原因">¶</a>开发原因</h2><p>其实是看视频，看到wechat分享文件会存储多份，浪费空间，而且你还找不到</p><h2 id="安装"><a class="header-anchor" href="#安装">¶</a>安装</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install find-same-md5-file</span><br></pre></td></tr></table></figure><h2 id="使用方法"><a class="header-anchor" href="#使用方法">¶</a>使用方法</h2><blockquote><p><strong>本次发布仅面向开发者！！</strong></p></blockquote><p><a href="https://github.com/Fgaoxing/find-same-file">Fgaoxing/find-same-file: Python searches the same file based on md5 (github.com)</a></p><p><a href="https://pypi.org/project/find-same-md5-file/">PYPI</a></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> find_same_md5_file</span><br><span class="line"><span class="comment"># 寻找相同文件，第一个参数是路径后面需要加/</span></span><br><span class="line"><span class="built_in">print</span>(find_same_md5_file.print_same(<span class="string">&#x27;C:/&#x27;</span>))</span><br><span class="line"><span class="comment"># 寻找空文件夹，第一个参数是路径后面需要加/</span></span><br><span class="line"><span class="built_in">print</span>(find_same_md5_file.find_empty_dir(<span class="string">&#x27;C:/&#x27;</span>))</span><br><span class="line"><span class="comment"># 查找大文件 第一个参数是路径后面需要加/，第二个参数是大小单位是字节</span></span><br><span class="line"><span class="built_in">print</span>(find_same_md5_file.find_big_file(<span class="string">&#x27;U:/&#x27;</span>, <span class="number">3685</span>))</span><br></pre></td></tr></table></figure><h2 id="提示！！！！"><a class="header-anchor" href="#提示！！！！">¶</a>提示！！！！</h2><p>如果路径不存在会报错TypeError，后续版本修复。<br /><strong>1.0.0</strong>之前的版本均为测是版本，函数名有变动可能。<br />建议使用PYPI版本，而不是Github版本，Github更新不及时。</p><h2 id="图形化界面"><a class="header-anchor" href="#图形化界面">¶</a>图形化界面</h2><p>目前还在开发，由<a href="https://www.oblivionocean.top/">玄云海</a>的承担 （我也在，<s>官网我写的有点操，将就着看</s>）</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;同时支持文件查重，空文件夹查找，大文件查找等，后续还将不断更新！！&lt;/p&gt;
&lt;h2 id=&quot;开发原因&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;#开发原因&quot;&gt;¶&lt;/a&gt;开发原因&lt;/h2&gt;
&lt;p&gt;其实是看视频，看到wechat分享文件会存储多份，浪费空间</summary>
      
    
    
    
    <category term="技术" scheme="https://www.yt-blog.top/categories/%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="python" scheme="https://www.yt-blog.top/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>放开想，越离谱越好</title>
    <link href="https://www.yt-blog.top/20220727/1444/"/>
    <id>https://www.yt-blog.top/20220727/1444/</id>
    <published>2022-07-27T14:44:53.000Z</published>
    <updated>2026-02-24T03:51:31.798Z</updated>
    
    <content type="html"><![CDATA[<!-- 本文是[吹神求杀](https://chuishen.cf/)的QQ聊天截屏--><!--用时1小时15分--><!--![img](https://unpkg.com/ytblogimg/1668250571787.png)--><!--![img](https://unpkg.com/ytblogimg/1668250589674.webp)--><blockquote><p>文章被删除了！</p></blockquote><style>.ai-summary{display: none;}</style>]]></content>
    
    
    <summary type="html"> 文章被删除了！     </summary>
    
    
    
    
    <category term="话题" scheme="https://www.yt-blog.top/tags/%E8%AF%9D%E9%A2%98/"/>
    
  </entry>
  
  <entry>
    <title>2022 夏季应用推荐</title>
    <link href="https://www.yt-blog.top/57865/"/>
    <id>https://www.yt-blog.top/57865/</id>
    <published>2022-07-24T09:00:49.000Z</published>
    <updated>2024-02-28T18:38:27.267Z</updated>
    
    <content type="html"><![CDATA[<h2 id="声明"><a class="header-anchor" href="#声明">¶</a>声明</h2><p>我没收钱，不排名！！！！</p><p>无广告，无病毒，很干净！！！</p><h2 id="正文"><a class="header-anchor" href="#正文">¶</a>正文</h2><h3 id="Lively-Wallpaper"><a class="header-anchor" href="#Lively-Wallpaper">¶</a>Lively Wallpaper</h3><p>由于目前仅支持<strong>Microsoft Store</strong>，所以只限于<strong>Win8.1</strong>以上</p><p><a href="https://apps.microsoft.com/store/detail/lively-wallpaper/9NTM2QC6QWS7?hl=zh-cn&amp;gl=CN">Lively Wallpaper - Microsoft Store 应用程序</a></p><p>效果很不错，可以用网页，如果需要背景的网页我可以出一期</p><p><img src="https://img.yt-blog.top/1668251213453.webp" alt="img" /></p><h3 id="酷呆桌面"><a class="header-anchor" href="#酷呆桌面">¶</a>酷呆桌面</h3><p>一个在GitHub开源的桌面整理软件软件：<a href="https://www.coodesker.com/">https://www.coodesker.com/</a></p><h3 id="Windows超级管理器"><a class="header-anchor" href="#Windows超级管理器">¶</a>Windows超级管理器</h3><p>非常好用的工具箱</p><p><img src="https://img.yt-blog.top/1668251186717.webp" alt="img" /></p><p>官网：<a href="https://www.collithel.com/supermanager/">科利特尔Collithel - Windows超级管理器系列</a></p><h3 id="NDM"><a class="header-anchor" href="#NDM">¶</a>NDM</h3><p>汉化版，免费用</p><p><img src="https://unpkg.com/ytblogimg/1668256242419.webp" alt="img" /></p><div class="tag pandown-tags"><pandown type="lz" url="https://yt-blog.lanzoum.com/iEMKL08h8wde" pwd="ytblog" fname="NeatDM.zip"></pandown><script>Jian.load.js("https://unpkg.com/pandown", pandown)</script></div>]]></content>
    
    
    <summary type="html">声明 我没收钱，不排名！！！！ 无广告，无病毒，很干净！！！ 正文 Lively Wallpaper 由于目前仅支持Microsoft Store，所以只限于Win8.1以上 Lively Wallpaper - Microsoft Store 应用程序 效果很不错，可以用网页，如果需要背景的网页我可以出一期  酷呆桌面 一个在GitHub开源的桌面整理软件软件：https://www.coode...</summary>
    
    
    
    <category term="应用推荐" scheme="https://www.yt-blog.top/categories/%E5%BA%94%E7%94%A8%E6%8E%A8%E8%8D%90/"/>
    
    
    <category term="应用推荐" scheme="https://www.yt-blog.top/tags/%E5%BA%94%E7%94%A8%E6%8E%A8%E8%8D%90/"/>
    
    <category term="2022" scheme="https://www.yt-blog.top/tags/2022/"/>
    
  </entry>
  
</feed>
