<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>源码 on </title>
    <link>http://blog.chuckchan.top/tags/%E6%BA%90%E7%A0%81/</link>
    <description>Recent content in 源码 on </description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-cn</language>
    <copyright>© 2026 Chuck Chan</copyright>
    <lastBuildDate>Thu, 12 Oct 2023 00:00:00 +0000</lastBuildDate><atom:link href="http://blog.chuckchan.top/tags/%E6%BA%90%E7%A0%81/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Golang之系统排查</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E7%B3%BB%E7%BB%9F%E6%8E%92%E6%9F%A5/</link>
      <pubDate>Thu, 12 Oct 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E7%B3%BB%E7%BB%9F%E6%8E%92%E6%9F%A5/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;系统排查&#xA;    &lt;div id=&#34;系统排查&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e7%b3%bb%e7%bb%9f%e6%8e%92%e6%9f%a5&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;1. 先确定出现问题的进程&#xA;    &lt;div id=&#34;1-先确定出现问题的进程&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#1-%e5%85%88%e7%a1%ae%e5%ae%9a%e5%87%ba%e7%8e%b0%e9%97%ae%e9%a2%98%e7%9a%84%e8%bf%9b%e7%a8%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;先排查是否因为程序服务导致的CPU/内存保障，可以使用top命令来排查。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;top&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;确定是服务出问题后，可以使用如下命令持续监测服务进程，$pid即为服务进程的pid。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;top -Hp $pid&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;可以使用top默认根据CPU使用率来排序，可以使用shitft + m 改成使用内存占用率来排序。&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;2. 使用PProf排查程序内部的问题&#xA;    &lt;div id=&#34;2-使用pprof排查程序内部的问题&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#2-%e4%bd%bf%e7%94%a8pprof%e6%8e%92%e6%9f%a5%e7%a8%8b%e5%ba%8f%e5%86%85%e9%83%a8%e7%9a%84%e9%97%ae%e9%a2%98&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;确定了服务进程的问题后，就可以通过PProf来排查CPU、内存、互斥锁、Goroutines的问题了。下面展示一个demo来简单使用PProf。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http/pprof&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;do something...&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt; )&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ListenAndServe&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0.0.0.0:6060&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;//pprof包的init函数里注册了handler &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;使用web界面查看pprof信息&#xA;    &lt;div id=&#34;使用web界面查看pprof信息&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e4%bd%bf%e7%94%a8web%e7%95%8c%e9%9d%a2%e6%9f%a5%e7%9c%8bpprof%e4%bf%a1%e6%81%af&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;经过上述步骤后，在浏览器打开http://127.0.0.1:6060/debug/pprof/，就能看到pprof界面了。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之内存管理</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</link>
      <pubDate>Mon, 10 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之内存管理&#xA;    &lt;div id=&#34;golang之内存管理&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8b%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;概述&#xA;    &lt;div id=&#34;概述&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e6%a6%82%e8%bf%b0&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Go的内存分配借鉴了Google的TMalloc，其核心思想是&lt;strong&gt;内存池+多级对象管理&lt;/strong&gt;，&lt;strong&gt;能加快分配速度，降低资源竞争。&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;内存分配的方法&#xA;    &lt;div id=&#34;内存分配的方法&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%86%85%e5%ad%98%e5%88%86%e9%85%8d%e7%9a%84%e6%96%b9%e6%b3%95&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;线性分配法&lt;/strong&gt;：只需要在内存中维护一个指针，这个指针指向下一片未使用内存的起始位置，如果程序需要新分配一片内存，只要找到这个指针直接分配内存即可。&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;low&#34;&#xA;    alt=&#34;Xnip2022-06-20_12-25-14.jpg&#34;&#xA;    src=&#34;http://storage.chuckchan.top/uploads/Xnip2022-06-20_12-25-14.jpg&#34;&#xA;    &gt;&lt;/figure&gt;&#xA;&#xA;这种方法实现虽然简单，但有一个致命的缺点，就是无法利用曾经使用过但后面被释放的内存。&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;low&#34;&#xA;    alt=&#34;Xnip2022-06-20_12-25-29.jpg&#34;&#xA;    src=&#34;http://storage.chuckchan.top/uploads/Xnip2022-06-20_12-25-29.jpg&#34;&#xA;    &gt;&lt;/figure&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;空闲链表分配法&lt;/strong&gt;：会在内部维护一个类似链表的数据结构，当程序需要申请内存时，空闲链表分配器会一次遍历空闲的内存块，找到足够大的内存，然后申请新的资源并修改链表。&#xA;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;low&#34;&#xA;    alt=&#34;Xnip2022-06-20_12-26-39.jpg&#34;&#xA;    src=&#34;http://storage.chuckchan.top/uploads/Xnip2022-06-20_12-26-39.jpg&#34;&#xA;    &gt;&lt;/figure&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Go使用的是空闲链表分配法，再配合&lt;strong&gt;隔离适应策略&lt;/strong&gt;，将内存分割成多个链表，每个链表中内存块大小相等，申请内存时先找到合适的链表，再在链表中找到合适的内存块。&lt;/p&gt;&#xA;&lt;p&gt;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;low&#34;&#xA;    alt=&#34;Xnip2022-06-20_12-26-07.jpg&#34;&#xA;    src=&#34;http://storage.chuckchan.top/uploads/Xnip2022-06-20_12-26-07.jpg&#34;&#xA;    &gt;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;基础结构&#xA;    &lt;div id=&#34;基础结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%9f%ba%e7%a1%80%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;内存单元相关&lt;/strong&gt;：mspan、arena&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;内存池相关&lt;/strong&gt;：mcache、mcentral、mheap&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h5 class=&#34;relative group&#34;&gt;内存单元&#xA;    &lt;div id=&#34;内存单元&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%86%85%e5%ad%98%e5%8d%95%e5%85%83&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h5&gt;&#xA;&lt;p&gt;首先，在Go程序初始化时，会先将申请到的虚拟内存分为如下几个部分。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之内存逃逸</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E9%80%83%E9%80%B8/</link>
      <pubDate>Mon, 10 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E9%80%83%E9%80%B8/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之内存逃逸&#xA;    &lt;div id=&#34;golang之内存逃逸&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8b%e5%86%85%e5%ad%98%e9%80%83%e9%80%b8&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;内存分配&#xA;    &lt;div id=&#34;内存分配&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%86%85%e5%ad%98%e5%88%86%e9%85%8d&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;在Golang中，程序申请的一个对象，是在栈上分配，还是在堆上分配，&lt;strong&gt;这个是由编译器决定的&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;在栈上分配&lt;/strong&gt;：在程序中，每个函数块都会有自己的内存区域来存储局部变量、返回值等数据，这一块内存区域有特定的数据结构与存储方式，其大小在程序编译的时候就已经分配好了，且这块区域寻址快，开销少，这块内存区域就称为栈区。因为栈的大小在编译的时候就已经确定了，所以当栈存储的数据过大时，会发生“栈溢出”。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;在堆上分配&lt;/strong&gt;：在程序中，全局变量，内存占用大的局部变量，发生了内存逃逸的局部变量就分配在堆上，这一块内存区域没有特定的结构，也没有固定的大小，可以根据需要进行调整。当一个变量分配在堆上的时候，开销会比较大，对Golang这种自带GC的语言来说，会增加GC压力，同时也会带来内存碎片。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;内存逃逸&#xA;    &lt;div id=&#34;内存逃逸&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%86%85%e5%ad%98%e9%80%83%e9%80%b8&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;在计算机语言编译器优化原理中，逃逸分析是指分析指针动态范围的方法，它同编译器优化原理的指针分析和外形分析相关联。当变量（或者对象）在方法中分配后，其指针有可能被返回或者被全局引用，这样就会被其他过程或者线程所引用，这种现象称作指针（或者引用）的逃逸（Escape）。&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;Golang中的内存逃逸&#xA;    &lt;div id=&#34;golang中的内存逃逸&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b8%ad%e7%9a%84%e5%86%85%e5%ad%98%e9%80%83%e9%80%b8&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;在Golang中可以使用go run -gcflags &amp;ldquo;-m -l&amp;rdquo; (-m打印逃逸分析信息，-l禁止内联编译)来分析内存逃逸。使用如下代码来分析内存逃逸：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;foo&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;foo&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;执行结果如下：&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之内存泄漏</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/</link>
      <pubDate>Sat, 18 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之内存泄漏&#xA;    &lt;div id=&#34;golang之内存泄漏&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8b%e5%86%85%e5%ad%98%e6%b3%84%e6%bc%8f&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;内存泄漏&#xA;    &lt;div id=&#34;内存泄漏&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%86%85%e5%ad%98%e6%b3%84%e6%bc%8f&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;内存泄漏说白了就是分配的内存(或者变量)不再使用，但是并没有被gc回收，而是继续占用内存。在Golang中内存泄漏大部分都跟channel的不正确使用有关。泄漏的原因是goroutine操作channel后，处于发送阻塞或者接收阻塞状态，而channel处于满或者空的状态，一直得不到改变。同时，垃圾回收器也不会回收此类资源，进而导致goroutine会处于一个一直等待的队列中，不见天日。&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;场景分析&#xA;    &lt;div id=&#34;场景分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%9c%ba%e6%99%af%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&#xA;&lt;h5 class=&#34;relative group&#34;&gt;案例1: channel没有接收者&#xA;    &lt;div id=&#34;案例1-channel没有接收者&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e6%a1%88%e4%be%8b1-channel%e6%b2%a1%e6%9c%89%e6%8e%a5%e6%94%b6%e8%80%85&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h5&gt;&#xA;&lt;p&gt;下面这段程序展示了并发地向3个站点请求资源，接收者只接收最快返回的那个。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;goroutineLeak1&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;responses&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;//正确姿势：responses := make(chan string, 3)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//3个发送者&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; {&lt;span style=&#34;color:#a6e22e&#34;&gt;responses&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;asia.gopl.io&amp;#34;&lt;/span&gt;)}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; {&lt;span style=&#34;color:#a6e22e&#34;&gt;responses&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;europe.gopl.io&amp;#34;&lt;/span&gt;)}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; {&lt;span style=&#34;color:#a6e22e&#34;&gt;responses&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;americas.gopl.io&amp;#34;&lt;/span&gt;)}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//1个接收者&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;responses&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;goroutineLeak1能正确地接收到最快返回的站点资源，但两个慢的goroutien会因为没有人接收而永远卡住，造成这两个goroutine永远没法被回收。正确的姿势是创建一个带3个buffer的channel，可以回收两个返回比较慢的goroutine。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>GPM&lt;4&gt;-场景分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/gpm4-%E5%9C%BA%E6%99%AF%E5%88%86%E6%9E%90/</link>
      <pubDate>Wed, 08 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/gpm4-%E5%9C%BA%E6%99%AF%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;GPM&amp;lt;4&amp;gt;场景分析&#xA;    &lt;div id=&#34;gpm4场景分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#gpm4%e5%9c%ba%e6%99%af%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;场景分析&#xA;    &lt;div id=&#34;场景分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%9c%ba%e6%99%af%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;场景一: 创建/执行G&#xA;    &lt;div id=&#34;场景一-创建执行g&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%9c%ba%e6%99%af%e4%b8%80-%e5%88%9b%e5%bb%ba%e6%89%a7%e8%a1%8cg&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;当某个G1创建一个新的G2时：&lt;/p&gt;&#xA;&lt;p&gt;1.运行一个G&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/34db10cbbff2208498f39e38f30a487a.png&#34; alt=&#34;34db10cbbff2208498f39e38f30a487a.png&#34; style=&#34;zoom:33%;&#34; /&gt;&#xA;&lt;p&gt;2.当本地队列未满，则直接加入本地队列(满足局部性)&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/1919bb661a05f0dd8737e40411276c5f.png&#34; alt=&#34;1919bb661a05f0dd8737e40411276c5f.png&#34; style=&#34;zoom: 50%;&#34; /&gt;&#xA;&lt;p&gt;3.如果本地队列已满，则将P1本地队列中的 前一半(G3/G4)+G7顺序打乱，一同放到全局队列中去。&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/8196d1a3ed00915544d679c1f8b4fd25.png&#34; alt=&#34;8196d1a3ed00915544d679c1f8b4fd25.png&#34; style=&#34;zoom:33%;&#34; /&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;场景二: 唤醒正在休眠的M&#xA;    &lt;div id=&#34;场景二-唤醒正在休眠的m&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%9c%ba%e6%99%af%e4%ba%8c-%e5%94%a4%e9%86%92%e6%ad%a3%e5%9c%a8%e4%bc%91%e7%9c%a0%e7%9a%84m&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;当创建一个G时，会尝试唤醒M的休眠队列，假定G2唤醒了M2，M2绑定了P2，此时P2本地队列里没有G，M2此时为&lt;strong&gt;自旋线程&lt;/strong&gt;（没有G可以运行，不断地寻找可运行的G）。&lt;strong&gt;自旋线程的存在是为了通过短期的自旋来防止线程被销毁。但过多的自旋线程会白白浪费CPU，所以结合两种情况，系统中最多存在GOMAXPROCS个自旋线程。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/151aa47f882f1b5ca92cffb7cc097a9c.png&#34; alt=&#34;151aa47f882f1b5ca92cffb7cc097a9c.png&#34; style=&#34;zoom:33%;&#34; /&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;场景三: 被唤醒的M从全局队列取G&#xA;    &lt;div id=&#34;场景三-被唤醒的m从全局队列取g&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%9c%ba%e6%99%af%e4%b8%89-%e8%a2%ab%e5%94%a4%e9%86%92%e7%9a%84m%e4%bb%8e%e5%85%a8%e5%b1%80%e9%98%9f%e5%88%97%e5%8f%96g&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;在场景二中被唤醒的M会从全局队列取出n个G来运行，n的计算法则：n = min(len(GQ)/GOMAXPROCS + 1, len(GQ/2))，至少从全局队列取1个G，但每次不要从全局队列移动太多的G到P本地队列，这是&lt;strong&gt;从全局队列到P本地队列的负载均衡&lt;/strong&gt;。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之gin源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bgin%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Tue, 07 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bgin%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;gin&#xA;    &lt;div id=&#34;gin&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#gin&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;p&gt;gin是一个用Go语言编写的web框架。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;demo&#xA;    &lt;div id=&#34;demo&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#demo&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gin-gonic/gin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Default&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GET&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/ping&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;H&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pong&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Run&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;流程分析&#xA;    &lt;div id=&#34;流程分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e6%b5%81%e7%a8%8b%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;以下分析基于：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;github.com/gin-gonic/gin v1.5.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;1. 创建Engin&#xA;    &lt;div id=&#34;1-创建engin&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#1-%e5%88%9b%e5%bb%baengin&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Engin即引擎，Engin是 Web Server 的基础支持，也是&lt;strong&gt;服务的入口&lt;/strong&gt;和&lt;strong&gt;根级的数据结构&lt;/strong&gt;。下面是Engin的定义。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之slice</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bslice/</link>
      <pubDate>Tue, 07 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bslice/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;slice&#xA;    &lt;div id=&#34;slice&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#slice&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;简介&#xA;    &lt;div id=&#34;简介&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e7%ae%80%e4%bb%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;本文旨在讲解slice的数据结构及扩容策略，以下内容基于：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go version go1.16.2 darwin/amd64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;slice数据结构&#xA;    &lt;div id=&#34;slice数据结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#slice%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;array&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//指向底层数组的指针&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;len&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;//slice的长度 len(s)的返回值 for range 遍历slice的话也是以这个为终点&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;cap&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;//slice的容量 cap(s)的返回值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;slice扩容策略&#xA;    &lt;div id=&#34;slice扩容策略&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#slice%e6%89%a9%e5%ae%b9%e7%ad%96%e7%95%a5&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;可以使用append函数给slice添加元素&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之GC</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bgc/</link>
      <pubDate>Thu, 23 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bgc/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之GC&#xA;    &lt;div id=&#34;golang之gc&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8bgc&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;为什么要有GC&#xA;    &lt;div id=&#34;为什么要有gc&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e6%9c%89gc&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;当程序启动的时候，操作系统会给程序分配堆区与栈区，栈区里的内存是可以自动管理的，当栈区变量的作用域结束，可以被自动收回。堆区属于程序员自己管理的区域，即使堆区变量的作用域结束，后续可能继续使用。所以对于堆区的内存，程序员需要实时关注，如果内存一直增长没有释放，则会溢出，如果内存释放后还继续访问，则会出现非法访问。那有没有一种机制能够让堆区的闲置的内存自动回收？GC可以帮我们做到。GC(Ggrbage Collect)即垃圾回收，它可以通过一定的策略，让程序自动管理内存，让开发者更增加专注业务的开发。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;GC常用的策略&#xA;    &lt;div id=&#34;gc常用的策略&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#gc%e5%b8%b8%e7%94%a8%e7%9a%84%e7%ad%96%e7%95%a5&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;引用计数法&lt;/strong&gt;。引用计数法为对象维护一个计数器，当对象被引用时，计数器加1，引用被释放，计数器减1，当计数器为0时，表示没有被引用，清除这个对象。引用计数法实现简单，但频繁更新计数器会带来一定开销，且无法解决循环引用的弊端。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;标记-清除法&lt;/strong&gt;。标记-清除法是对对象定时进行标记，标记为“正在使用”与“没有被使用”两种，标记完后对标记为“没有被使用”的进行清除。由于程序是动态在运行的，随时有可能改变对象引用指向，因此，在标记的时候需要STW(Stop The World)，即程序停止一段时间，这段时间专门用来做标记。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;Golang中的GC策略&#xA;    &lt;div id=&#34;golang中的gc策略&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b8%ad%e7%9a%84gc%e7%ad%96%e7%95%a5&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Golang在v1.5之前是使用&lt;strong&gt;清除-标记法&lt;/strong&gt;的策略进行GC，但v1.5使用了&lt;strong&gt;三色标记法&lt;/strong&gt;，所谓三色标记法就是通过三个阶段来去定对象的状态（黑色/白色/灰色分别代表三个不同的状态）。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;白色：初始对象&lt;/li&gt;&#xA;&lt;li&gt;灰色：要被清除的对象&lt;/li&gt;&#xA;&lt;li&gt;黑色：任然在使用的对象&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;1.创建新对象，全部为白色&lt;/p&gt;&#xA;&lt;p&gt;&lt;figure&gt;&lt;img&#xA;    class=&#34;my-0 rounded-md&#34;&#xA;    loading=&#34;lazy&#34;&#xA;    decoding=&#34;async&#34;&#xA;    fetchpriority=&#34;low&#34;&#xA;    alt=&#34;096d844d693cc098943cc0f29e774e9c.png&#34;&#xA;    src=&#34;http://storage.chuckchan.top/uploads/096d844d693cc098943cc0f29e774e9c.png&#34;&#xA;    &gt;&lt;/figure&gt;&#xA;&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之channel源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bchannel%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Mon, 20 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bchannel%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之channel源码分析&#xA;    &lt;div id=&#34;golang之channel源码分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8bchannel%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;1.  channel&#xA;    &lt;div id=&#34;1--channel&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#1--channel&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;channel是支撑Go语言高性能并发编程模型的重要结构，channel是一个用于同步和通信的&lt;strong&gt;有锁环形队列&lt;/strong&gt;，使用互斥锁解决程序中可能存在的线程竞争问题。以下内容基于：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go version go1.16.2 darwin/amd64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;2. channel的数据结构&#xA;    &lt;div id=&#34;2-channel的数据结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#2-channel%e7%9a%84%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;channel其是用runtime.hchan来表示的。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hchan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;qcount&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;uint&lt;/span&gt;           &lt;span style=&#34;color:#75715e&#34;&gt;// 缓冲区buffer里有几个元素&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;dataqsiz&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint&lt;/span&gt;           &lt;span style=&#34;color:#75715e&#34;&gt;// 缓冲区buffer最多有几个元素 即缓冲区大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;buf&lt;/span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 指向底层循环数组的指针&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;elemsize&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16&lt;/span&gt;         &lt;span style=&#34;color:#75715e&#34;&gt;// 元素大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;closed&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 是否关闭&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;elemtype&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;_type&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 元素的类型&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;sendx&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint&lt;/span&gt;         &lt;span style=&#34;color:#75715e&#34;&gt;// 已发送元素在环形数组中的索引&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;recvx&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint&lt;/span&gt;         &lt;span style=&#34;color:#75715e&#34;&gt;// 已接收元素在环形数组中的索引&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;recvq&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;waitq&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 等待接收的goroutine队列&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;sendq&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;waitq&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 待发送的goroutine队列&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;lock&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mutex&lt;/span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//锁 保护数据&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;recvq与sendq是waitq类型的数据，分别代表接受的g队列与发送的g队列，waitq是一个双端链表。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之boltdb源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bboltdb%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Wed, 15 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bboltdb%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;blotdb&#xA;    &lt;div id=&#34;blotdb&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#blotdb&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;1. 简介&#xA;    &lt;div id=&#34;1-简介&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#1-%e7%ae%80%e4%bb%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;boltdb是一个纯go编写的支持事务的文件型单机kv数据库。&lt;/strong&gt; 其具有以下特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;单机部署：不需要考虑&lt;strong&gt;CAP&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;支持事物：仅允许&lt;strong&gt;多个只读事务和最多一个读写事务&lt;/strong&gt;同时运行&lt;/li&gt;&#xA;&lt;li&gt;索引结构：因为是kv型的数据库，所以天然地只有主键索引（&lt;strong&gt;B+树实现&lt;/strong&gt;），减少了磁盘IO&lt;/li&gt;&#xA;&lt;li&gt;缓存管理：仅管理写缓存，利用&lt;strong&gt;mmap&lt;/strong&gt;管理读缓存&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;2. 核心数据结构分析&#xA;    &lt;div id=&#34;2-核心数据结构分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#2-%e6%a0%b8%e5%bf%83%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;先从介绍一下bolt使用的一些底层的数据结构。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;db&lt;/li&gt;&#xA;&lt;li&gt;page&lt;/li&gt;&#xA;&lt;li&gt;node&lt;/li&gt;&#xA;&lt;li&gt;bucket&lt;/li&gt;&#xA;&lt;li&gt;cursor&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;&lt;u&gt;&lt;em&gt;1. db&lt;/em&gt;&lt;/u&gt;&#xA;    &lt;div id=&#34;1-db&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#1-db&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;在boltdb中，它的数据全部都是存储在文件上，一个db对应一个真实的磁盘文件。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之context源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bcontext%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Wed, 15 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bcontext%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之context源码分析&#xA;    &lt;div id=&#34;golang之context源码分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8bcontext%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;Context是什么&#xA;    &lt;div id=&#34;context是什么&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#context%e6%98%af%e4%bb%80%e4%b9%88&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Context是Golang中独特的数据结构，可以用来设置截至日期、同步信号、传递请求相关值，&lt;strong&gt;总地来说就是在goroutine构成的树形结构中对信号进行同步以减少计算资源的浪费&lt;/strong&gt;。以下内容基于：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go version go1.16.2 darwin/amd64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;Context的数据结构&#xA;    &lt;div id=&#34;context的数据结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#context%e7%9a%84%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Context是一个接口，来看下它的接口定义&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//Deadline方法是获取设置的截至时间，到了这个截至时间，&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//Context会自动发起取消，第二个返回值ok代表是否有设置&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//截至时间&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Deadline&lt;/span&gt;() (&lt;span style=&#34;color:#a6e22e&#34;&gt;deadline&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Time&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//Done方法返回一个只读的chan，当这个chan收到消息时代&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//表Parent Context已经发起了取消请求，当前goroutine&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//要开始做清理操作了&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{} &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//Err返回Context被取消的原因&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Err&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//Value方法返回Context绑定的对应的key的值，这个是线程安全的&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}) &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;context包提供了6种创建Context的方法。每个方法都会返回一种类型的结构体，这些结构体都实现了Context接口。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之map源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bmap%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Wed, 15 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bmap%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之map源码分析&#xA;    &lt;div id=&#34;golang之map源码分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8bmap%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;哈希表&#xA;    &lt;div id=&#34;哈希表&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%93%88%e5%b8%8c%e8%a1%a8&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;map即哈希表，也称为散列表，是根据关键码值(key value)而直接进行访问的数据结构。也就是说，它通过把关键码值映射（哈希函数）到表中一个位置来访问记录，以加快查找的速度。&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;哈希碰撞&#xA;    &lt;div id=&#34;哈希碰撞&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%93%88%e5%b8%8c%e7%a2%b0%e6%92%9e&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;哈希函数是整个哈希表的关键。所以为了更好的性能，我们希望在尽可能短的时间内，相同的key经过哈希函数的计算，可以得到相同的索引，不同的key经过哈希函数的计算，可以得到不同的索引，但在实际中往往事与愿违，不同的key小概率会计算出相同的索引，这就是哈希冲突（collision），几乎所有的哈希函数都存在这个问题。常见的解决哈希冲突的方法有：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;em&gt;开放寻址法&lt;/em&gt;：开放寻址法是如果通过哈希函数计算出的key所对应的空间已经被占用了，就从数组尾部再找一个还没被占用的空间将数据存进去。&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;拉链法&lt;/em&gt;：实现拉链法一般会使用数组加上链表，数组的每个索引位置装的是一个链表，当发生hash冲突时，将新的kv挂在这个链表的尾部。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;版本&#xA;    &lt;div id=&#34;版本&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e7%89%88%e6%9c%ac&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;以下内容基于&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go version go1.16.2 darwin/amd64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;map的数据结构&#xA;    &lt;div id=&#34;map的数据结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#map%e7%9a%84%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Golang里map由runtime.hmap实现。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之sync.Once源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bsync.once%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Wed, 15 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bsync.once%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之sync.Once源码分析&#xA;    &lt;div id=&#34;golang之synconce源码分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8bsynconce%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;sync.Once简介&#xA;    &lt;div id=&#34;synconce简介&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#synconce%e7%ae%80%e4%bb%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;sync.Once 是 Go 语言实现的一种对象，用来**保证某种行为只会被执行一次。**sync.Once通常用来实现单例模式的初始化。&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;源码分析&#xA;    &lt;div id=&#34;源码分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;以下内容基于：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go version go1.16.2 darwin/amd64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;sync.Once结构&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Once&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//用来表示是否已经执行 0-未执行 1-以执行&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Mutex&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;//互斥锁&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;Sync.Once只提供了一个Do的方法。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;o&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Once&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Do&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;()) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 一种错误的方式是使用cas锁 atomic.CompareAndSwapUint32&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//&#x9;if atomic.CompareAndSwapUint32(&amp;amp;o.done, 0, 1) {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//&#x9;&#x9;f()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//&#x9;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// cas锁虽然保证了原子操作，但可能会出现Do里的流程还没执行完就返回的情况&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 比如：A号groutine先执行了cas操作，将o.done改为1，然后执行Do流程，B号goroutine&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 也执行cas操作，发现o.done已经为1了，直接返回，但这时Do流程可能还未执行完！sync.Once&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 是要保证函数返回后Do流程一定是执行完的，所以这违反了它设计的原则。&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;atomic&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;LoadUint32&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;o&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; { &lt;span style=&#34;color:#75715e&#34;&gt;//如果 o.done==1 则说明方法已执行 直接返回 &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 如果是0 说明还未执行 进入执行doSlow流程（注意！！！这里可能有好几个goroutine进入这里去执行）&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;o&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;doSlow&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;once.doSlow是正真执行Do流程的函数。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之sync.Map源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bsync.map%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Mon, 13 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bsync.map%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之sync.Map源码分析&#xA;    &lt;div id=&#34;golang之syncmap源码分析&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8bsyncmap%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;map的并发操作&#xA;    &lt;div id=&#34;map的并发操作&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#map%e7%9a%84%e5%b9%b6%e5%8f%91%e6%93%8d%e4%bd%9c&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;从前面文章的分析可以看到，原生的map如果并发读写的话，会抛出异常。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;flags&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hashWriting&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;throw&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;concurrent map read and map write&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;也就是说原生的map不是并发安全的。如果要实现并发安全，可以在操作map的时候加一把mutex锁。但官方提供了更高效的sync.Map，使其能在并发安全的前提下更加高效地读写。sync.Map使用了&lt;strong&gt;写时复制（即Copy On Write）技术&lt;/strong&gt;来实现安全的高并发的map。sync.Map适用于&lt;strong&gt;读多写少&lt;/strong&gt;的场景。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;sync.Map数据结构&#xA;    &lt;div id=&#34;syncmap数据结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#syncmap%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Mutex&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//互斥锁 保护dirty字段&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;atomic&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//只读数据 实际类型为sync.readOnly&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;dirty&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;entry&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//写入数据 操作前需先加锁&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;misses&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//每次从read读取失败（read穿透） misses+1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;其中sync.readOnly的数据结构&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>GPM&lt;1&gt;-进程-线程-协程</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/gpm1-%E8%BF%9B%E7%A8%8B-%E7%BA%BF%E7%A8%8B-%E5%8D%8F%E7%A8%8B/</link>
      <pubDate>Thu, 09 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/gpm1-%E8%BF%9B%E7%A8%8B-%E7%BA%BF%E7%A8%8B-%E5%8D%8F%E7%A8%8B/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;GPM&amp;lt;1&amp;gt;  进程/线程/协程&#xA;    &lt;div id=&#34;gpm1--进程线程协程&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#gpm1--%e8%bf%9b%e7%a8%8b%e7%ba%bf%e7%a8%8b%e5%8d%8f%e7%a8%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;进程/线程/协程&#xA;    &lt;div id=&#34;进程线程协程&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e8%bf%9b%e7%a8%8b%e7%ba%bf%e7%a8%8b%e5%8d%8f%e7%a8%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;进程&#xA;    &lt;div id=&#34;进程&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e8%bf%9b%e7%a8%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程，&lt;strong&gt;是操作系统进行资源分配和调度的一个独立单位&lt;/strong&gt;，是应用程序运行的载体。每一个进程都有自己独立的地址空间。&lt;/p&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;线程&#xA;    &lt;div id=&#34;线程&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e7%ba%bf%e7%a8%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;线程是进程的一个实体，&lt;strong&gt;是CPU调度和分派的基本单位&lt;/strong&gt;，线程自己基本上不拥有系统资源，但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程的上下文切换比进程的上下文切换快得多，所以对他的调度的开销会小很多，从而提高系统资源的利用率和吞吐量。&lt;/p&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;进程/线程联系与区别&#xA;    &lt;div id=&#34;进程线程联系与区别&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e8%bf%9b%e7%a8%8b%e7%ba%bf%e7%a8%8b%e8%81%94%e7%b3%bb%e4%b8%8e%e5%8c%ba%e5%88%ab&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;其实Linux下并没有线程，只是为了迎合开发口味，搞了个轻量级进程出来就叫做了线程。轻量级进程和进程一样，都有自己独立的task_struct进程描述符，也都有自己独立的pid。&lt;strong&gt;从操作系统视角看，调度上和进程没有什么区别，都是在等待队列的双向链表里选择一个task_struct切到运行态而已&lt;/strong&gt;。只不过轻量级进程和普通进程的区别是可以共享同一&lt;strong&gt;内存地址空间、代码段、全局变量、同一打开文件集合&lt;/strong&gt;而已。线程切换和进程切换之间的主要区别在于，在线程切换期间，&lt;strong&gt;虚拟内存空间保持不变&lt;/strong&gt;，而在进程切换期间则不然。那么CPU从一个task_struct切换到另一个task_struct时，是如何断定它进程间切换还是线程间切换呢？我我们可以通过task_struct里的&lt;strong&gt;tgid&lt;/strong&gt; （thread group id）这个字段来判断。&lt;strong&gt;tgid&lt;/strong&gt;这个字段在task_struct里代表线程的组id，即同一组（同一进程下）的线程拥有相同的tgid，当CPU切换task_struct时发现两个task_struct的tgid不同，则认为是进程切换，&lt;strong&gt;需要重新加载虚拟内存空间&lt;/strong&gt;。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>GPM&lt;2&gt;-协程的实现</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/gpm2-%E5%8D%8F%E7%A8%8B%E7%9A%84%E5%AE%9E%E7%8E%B0/</link>
      <pubDate>Thu, 09 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/gpm2-%E5%8D%8F%E7%A8%8B%E7%9A%84%E5%AE%9E%E7%8E%B0/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;GPM&amp;lt;2&amp;gt; 协程的实现&#xA;    &lt;div id=&#34;gpm2-协程的实现&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#gpm2-%e5%8d%8f%e7%a8%8b%e7%9a%84%e5%ae%9e%e7%8e%b0&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;协程的实现&#xA;    &lt;div id=&#34;协程的实现&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%8d%8f%e7%a8%8b%e7%9a%84%e5%ae%9e%e7%8e%b0&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;协程&#xA;    &lt;div id=&#34;协程&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%8d%8f%e7%a8%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;前面我们说过利用协程具有轻量/上下文切换成本低等特点，那么他是如何在计算机中体现的? 到底协程是在那里被承载的?&lt;/p&gt;&#xA;&lt;p&gt;线程分为&lt;strong&gt;用户态线程&lt;/strong&gt;与&lt;strong&gt;内核态线程&lt;/strong&gt;，一个用户态线程必须绑定一个内核态线程，但CPU并不知道用户态线程的存在，也就是说CPU没法管到用户空间的事。既然CPU管不到用户空间的事，那用户空间就成了“三不管”地带了，那就决定在用户空间搞点事情。&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/9a93c749faa8d17d91fbdbf7d6bdc954.png&#34; alt=&#34;9a93c749faa8d17d91fbdbf7d6bdc954.png&#34; style=&#34;zoom:33%;&#34; /&gt;&#xA;&lt;p&gt;这样内核线程依然叫“线程”，用户线程就叫“协程”。&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/Xnip2022-04-20_15-49-10.jpg&#34; alt=&#34;Xnip2022-04-20_15-49-10.jpg&#34; style=&#34;zoom: 50%;&#34; /&gt;&#xA;&lt;p&gt;既然一个协程能绑定到一个线程上，那为什么不能将多个协程绑定到一个或多个线程上呢？下面分析三种协程与线程的绑定关系。&lt;/p&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;N:1模式&#xA;    &lt;div id=&#34;n1模式&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#n1%e6%a8%a1%e5%bc%8f&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;N个协程绑定在一个线程上，优点是协程的切换都在用户态，不用陷入内核态，切换迅速且切换的成本低。但其也有很明显的缺点。&lt;/p&gt;&#xA;&lt;p&gt;因为N个协程都绑定到一个线程上了，即使是多核的计算也没有办法实现并行，&lt;strong&gt;浪费了计算机的性能&lt;/strong&gt;。一旦某个协程阻塞，本线程下的其他协程都无法执行，&lt;strong&gt;没有了并发能力&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/N_1.jpg&#34; alt=&#34;N_1.jpg&#34; style=&#34;zoom:33%;&#34; /&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;1:1模式&#xA;    &lt;div id=&#34;11模式&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#11%e6%a8%a1%e5%bc%8f&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;解决了N:1模式没有并发能力的不足，但每次切换协程都要切换线程，&lt;strong&gt;成本太高&lt;/strong&gt;，&lt;strong&gt;失去了协程存在的意义。&lt;/strong&gt;&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>GPM&lt;3&gt;-调度设计</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/gpm3-%E8%B0%83%E5%BA%A6%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Thu, 09 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/gpm3-%E8%B0%83%E5%BA%A6%E8%AE%BE%E8%AE%A1/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;GPM&amp;lt;3&amp;gt; 调度设计&#xA;    &lt;div id=&#34;gpm3-调度设计&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#gpm3-%e8%b0%83%e5%ba%a6%e8%ae%be%e8%ae%a1&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;GPM&#xA;    &lt;div id=&#34;gpm&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#gpm&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;&lt;strong&gt;G:&lt;/strong&gt; Goroutine，Goroutine这个概念来自协程，一个Goroutine必须必须绑定到P上才能被CPU执行。Goroutine非常轻量，创建一个Goroutine只需要几kb的内存资源(实际上这个内存资源是动态的，如果有需要runtime会为goroutine自动分配资源)。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;P:&lt;/strong&gt; Processer, 即为G和M的调度对象，用来调度G和M之间的关联关系，其数量可通过GOMAXPROCS()来设置，默认为CPU核心数。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;M:&lt;/strong&gt; Machine, OS &lt;strong&gt;内核线程&lt;/strong&gt;抽象，代表着真正执行计算的资源，在绑定有效的 P 后，执行P调度出来的G。M的数量由runtime决定(默认最大1000)。M 并不保留 G 状态，这是 G 可以跨 M 调度的基础。&lt;/p&gt;&#xA;&lt;p&gt;Go调度器的是由GPM构成的。&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/5222b5764897654fbf27748150333658.png&#34; alt=&#34;5222b5764897654fbf27748150333658.png&#34; style=&#34;zoom:33%;&#34; /&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;调度器初期设计&#xA;    &lt;div id=&#34;调度器初期设计&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e8%b0%83%e5%ba%a6%e5%99%a8%e5%88%9d%e6%9c%9f%e8%ae%be%e8%ae%a1&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;调度器初期的设计是并没有P，仅有G与M，造成了如下弊端。&lt;/p&gt;&#xA;&lt;p&gt;1.如每次M调度G都需要获G全局队列的锁，造成了激烈的锁竞争。&lt;/p&gt;&#xA;&lt;p&gt;2.无法实现G的局部性（即从当M1执行G1时，G1创建出来的G1&amp;rsquo;无法保证任然被M1执行）&lt;/p&gt;&#xA;&lt;p&gt;3.M需要经常互相传递可运行的 G，引入了大量的延迟；&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/ecf0f428060329355a09d01e8f9423a9.png&#34; alt=&#34;ecf0f428060329355a09d01e8f9423a9.png&#34; style=&#34;zoom:33%;&#34; /&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;调度器进阶设计&#xA;    &lt;div id=&#34;调度器进阶设计&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e8%b0%83%e5%ba%a6%e5%99%a8%e8%bf%9b%e9%98%b6%e8%ae%be%e8%ae%a1&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;p&gt;基于旧的调度器的弊端，Go设计了一个全新的调度器。再新的调度器中，加入了P。M是G运行的实体，P负责把G分配到M上进行执行，M才是真真正正的“干活者”。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之内存管理2</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%862/</link>
      <pubDate>Wed, 08 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%862/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之内存管理&#xA;    &lt;div id=&#34;golang之内存管理&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8b%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;概述&#xA;    &lt;div id=&#34;概述&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e6%a6%82%e8%bf%b0&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Golang的内存分配借鉴了Google的TMalloc，其核心思想是&lt;strong&gt;内存池+多级对象管理&lt;/strong&gt;，&lt;strong&gt;能加快分配速度，降低资源竞争。&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;Golang内存模型层次结构&#xA;    &lt;div id=&#34;golang内存模型层次结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e5%86%85%e5%ad%98%e6%a8%a1%e5%9e%8b%e5%b1%82%e6%ac%a1%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/image.png&#34; alt=&#34;image&#34; style=&#34;zoom: 33%;&#34; /&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;MCache&#xA;    &lt;div id=&#34;mcache&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#mcache&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;访问mcache依然不需要加锁而是直接访问，且MCache中依然保存各种大小的Span。MCache是与Golang协程调度模型GPM中的P所绑定，而不是和线程绑定。因为Golang调度的GPM模型，真正可运行的线程M的数量与P的数量一致，即GOMAXPROCS个，所以MCache与P进行绑定更能节省内存空间使用，可以保证每个G使用MCache时&lt;strong&gt;不需要加锁&lt;/strong&gt;就可以获取到内存。&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/image (1).png&#34; alt=&#34;image (1)&#34; style=&#34;zoom: 50%;&#34; /&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;MCentral&#xA;    &lt;div id=&#34;mcentral&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#mcentral&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;当MCache中某个Size Class对应的Span被一次次Object被上层取走后，如果出现当前Size Class的Span空缺情况，MCache则会向MCentral申请对应的Span。Goroutine、MCache、MCentral、MHeap互相交换的内存单位是不同，向Mcentral申请内存是&lt;strong&gt;需要加锁&lt;/strong&gt;的。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之内存对齐</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90/</link>
      <pubDate>Tue, 07 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8B%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之内存对齐&#xA;    &lt;div id=&#34;golang之内存对齐&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8b%e5%86%85%e5%ad%98%e5%af%b9%e9%bd%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;现象&#xA;    &lt;div id=&#34;现象&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e7%8e%b0%e8%b1%a1&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;foo&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;//1字节&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//4字节&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int8&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;//1字节&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//8字节&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;//1字节&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;foo&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;size of foo: &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sizeof&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;这个输出结果是各个字段占用内存的和15字节吗？答案并不是，输出的结果是32字节，要大于所有字段占用内存大小的总和15字节。&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;内存对齐&#xA;    &lt;div id=&#34;内存对齐&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%86%85%e5%ad%98%e5%af%b9%e9%bd%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;可能很多人认为在结构体中各个字段的内存是连续的，cpu按各个字段的大小按需读取相应的值。&lt;/p&gt;&#xA;&lt;img src=&#34;image/.png&#34; alt=&#34;.png&#34; style=&#34;zoom:50%;&#34; /&gt;&#xA;&lt;p&gt;但实际上，cpu读取内存是以块为单位的，块的大小可以为 2、4、6、8、16 字节等大小（也称为内存粒度），cpu每次都读去内存里的“若干块”数据。在内存分布上，内存也是“一块一块”分布的，数据不是按照其本身的大小排布，而是按照内存粒度的来排布，以方便cpu快速读取数据，这就是内存对齐。&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;为什么需要内存对齐？&#xA;    &lt;div id=&#34;为什么需要内存对齐&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81%e5%86%85%e5%ad%98%e5%af%b9%e9%bd%90&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;1.平台原因：不是所有硬件平台都能访问任意地址上的任意数据。例如：特定的硬件平台只允许在特定地址获取特定类型的数据，否则会导致异常情况。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之mutex源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bmutex%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Fri, 03 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bmutex%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之mutex&#xA;    &lt;div id=&#34;golang之mutex&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8bmutex&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;互斥锁Mutex&#xA;    &lt;div id=&#34;互斥锁mutex&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e4%ba%92%e6%96%a5%e9%94%81mutex&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;在Golang中用于表示互斥锁的是sync.Lock，其作用是保护临界区，确保任意时间只有一个goroutine能拿到锁。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;正常模式&amp;amp;饥饿模式&#xA;    &lt;div id=&#34;正常模式饥饿模式&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e6%ad%a3%e5%b8%b8%e6%a8%a1%e5%bc%8f%e9%a5%a5%e9%a5%bf%e6%a8%a1%e5%bc%8f&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;为了保证公平性，Golang在v1.9的互斥锁版本中引入了&lt;strong&gt;饥饿模式&lt;/strong&gt;与&lt;strong&gt;正常模式&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;如果当前锁正在被持有，抢不到锁就会进入一个等待的队列，当锁被释放后，从这个队列的队头里唤醒一个goroutine（等待者），但是锁不会直接给这个等待者，而是必须与&lt;strong&gt;正在获取锁但还未进入等待队列&lt;/strong&gt;的goroutine竞争这把锁，与刚唤醒的等待者相比，这个goroutine正持有CPU，所以获取到锁的概率较大。如果等待者抢锁失败，那么它就会被放回队列头部，如果它超过1ms都还没获取到锁，就从&lt;strong&gt;正常模式&lt;/strong&gt;切换为&lt;strong&gt;饥饿模式&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;在饥饿模式下，当锁释放后，锁会直接交给等待队列的第一个等待者，不必再与新来的goroutine竞争，新来的goroutine会直接加到等待队列的队尾。当满足以下两个条件时，&lt;strong&gt;饥饿模式&lt;/strong&gt;将切换回&lt;strong&gt;正常模式&lt;/strong&gt;。&#xA;（1）当前被唤醒的等待者获得锁后，发现队列只剩它自己一个了，那么&lt;strong&gt;切换回正常模式&lt;/strong&gt;。&#xA;（2）当前被唤醒的等待者获得锁后，发现自己的等待时间不超过1ms，那么&lt;strong&gt;切换回正常模式&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在正常模式下，当前拥有CPU的goroutine比起等待队列里的goroutine&lt;strong&gt;有很大几率获得锁&lt;/strong&gt;，&lt;strong&gt;这样可以避免协程上下文的频繁切换&lt;/strong&gt;。但这样又会导致等待队列里的goroutine活活“饿死”，所以又必须有饥饿模式，保证等待已久的goroutine能够获取到锁，&lt;strong&gt;以保证公平性&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;sync.Lock&#xA;    &lt;div id=&#34;synclock&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#synclock&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Mutex&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;state&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//表示锁的状态，有锁定、饥饿、唤醒等状态&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;sema&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//表示信号量 用于实现mutex阻塞队列的定位&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mutexLocked&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;iota&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//1 state &amp;amp; 1 == 1 表示上锁状态&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mutexWoken&lt;/span&gt;&#x9;            &lt;span style=&#34;color:#75715e&#34;&gt;//2 state &amp;amp; 2 == 1 表示唤醒状态 &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mutexStarving&lt;/span&gt;           &lt;span style=&#34;color:#75715e&#34;&gt;//4 state &amp;amp; 4 == 1 表示饥饿状态&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mutexWaiterShift&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;iota&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//3 state &amp;gt;&amp;gt; 3 获取等待者的数量&#x9;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;starvationThresholdNs&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1e6&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//进入饥饿状态的阈值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;state字段总共占用32个bit，其中用前三位表示三个状态，后29个bit表示等待的goroutine个数。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之ants源码分析</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bants%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Tue, 24 Jan 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bants%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;ants&#xA;    &lt;div id=&#34;ants&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#ants&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&lt;hr&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;1. 简介&#xA;    &lt;div id=&#34;1-简介&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#1-%e7%ae%80%e4%bb%8b&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;ants 是一个高性能的协程池，实现了对大规模 goroutine 的调度管理、goroutine 复用，允许使用者在开发并发程序的时候限制协程数量，复用资源，达到更高效执行任务的效果。其具体特点如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;自动调度海量的 goroutines，复用 goroutines&lt;/li&gt;&#xA;&lt;li&gt;定期清理过期的 goroutines，进一步节省资源&lt;/li&gt;&#xA;&lt;li&gt;提供了大量有用的接口：任务提交、获取运行中的 goroutine 数量、动态调整 Pool 大小、释放 Pool、重启 Pool&lt;/li&gt;&#xA;&lt;li&gt;优雅处理 panic，防止程序崩溃&lt;/li&gt;&#xA;&lt;li&gt;资源复用，极大节省内存使用量；在大规模批量并发任务场景下比原生 goroutine 并发具有更高的性能&lt;/li&gt;&#xA;&lt;li&gt;非阻塞机制&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;本文从pool顶层方法开始，到底层workArray的实现，由上至下分析整个ants的工作流程。以下代码分析基于：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;github.com/panjf2000/ants/v2 v2.6.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;2. 项目结构&#xA;    &lt;div id=&#34;2-项目结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#2-%e9%a1%b9%e7%9b%ae%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ants                &#x9;&#x9;       root directory&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── interal                    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── spinlock                  自实现的自旋锁&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── ants.go                 &#x9;&#x9;  定义常量、errors显示、默认goroutine池、封装一些方便用户操作查看goroutine池的函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── options.go                    goroutine池的相关配置&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── pool.go &#x9;&#x9;&#x9;&#x9;&#x9;&#x9;&#x9;&#x9;&#x9;&#x9;&#x9;普通pool&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;不绑定特定函数&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;的创建以及对pool相关的操作&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── pool_func.go                  创建绑定某个特定函数的pool以及对pool相关的操作&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── worker.go                     goWorker的定义及方法&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── worker_array.go               workerArray的接口和一个能返回实现该接口的函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── worker_loop_queue.go &#x9;&#x9;&#x9;&#x9;&#x9;loopQueue的定义及方法 loopQueue实现了workerArray&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── worker_stack.go               workerStack的定义及方法 workerStack实现了workerArray&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;3. 数据结构及实现原理&#xA;    &lt;div id=&#34;3-数据结构及实现原理&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#3-%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e5%8f%8a%e5%ae%9e%e7%8e%b0%e5%8e%9f%e7%90%86&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;3.1 概念&#xA;    &lt;div id=&#34;31-概念&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#31-%e6%a6%82%e5%bf%b5&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;首先需要明白ants代码两个概念，worker及task（任务）&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golang之defer</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bdefer/</link>
      <pubDate>Sun, 18 Sep 2022 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golang%E4%B9%8Bdefer/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之defer&#xA;    &lt;div id=&#34;golang之defer&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8bdefer&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;defer&#xA;    &lt;div id=&#34;defer&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#defer&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;Golang的defer会在函数返回前去执行传入的函数，它会经常被用于关闭文件描述符、关闭数据库连接以及解锁资源。&lt;/p&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;常见使用场景&#xA;    &lt;div id=&#34;常见使用场景&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%b8%b8%e8%a7%81%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;1.关闭文件&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;foo1&lt;/span&gt;()  {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;OpenFile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;your file path&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_RDONLY&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0755&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//use file do something&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;2.解锁&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;foo2&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Mutex&lt;/span&gt;)  {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Lock&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unlock&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//do something&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h4 class=&#34;relative group&#34;&gt;defer数据结构&#xA;    &lt;div id=&#34;defer数据结构&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#defer%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_defer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;siz&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//参数和结果的内存大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;sp&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//栈指针&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;pc&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//调用方的程序计数器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fn&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;funcval&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//defer中传入的函数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_panic&lt;/span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;_panic&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//触发延迟调用的结构体，可能为空&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;_defer&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//指向下一个defer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&#xA;&lt;h3 class=&#34;relative group&#34;&gt;defer调用链&#xA;    &lt;div id=&#34;defer调用链&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#defer%e8%b0%83%e7%94%a8%e9%93%be&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h3&gt;&#xA;&lt;p&gt;当goroutine获取到一个defer，就会创建一个runtime._defer结构体，然后将runtime._defer追加到当前goroutine的defer链表的最前面。&lt;/p&gt;</description>
      
    </item>
    
    <item>
      <title>Golnag之interface</title>
      <link>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golnag%E4%B9%8Binterface/</link>
      <pubDate>Tue, 23 Aug 2022 00:00:00 +0000</pubDate>
      
      <guid>http://blog.chuckchan.top/posts/golang/%E6%BA%90%E7%A0%81%E7%B3%BB%E5%88%97/golnag%E4%B9%8Binterface/</guid>
      <description>&lt;h1 class=&#34;relative group&#34;&gt;Golang之interface&#xA;    &lt;div id=&#34;golang之interface&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#golang%e4%b9%8binterface&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h1&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;接口&#xA;    &lt;div id=&#34;接口&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e6%8e%a5%e5%8f%a3&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;接口（interface）是一组仅包含方法名、参数、返回值的&lt;strong&gt;未具体实现的方法的集合&lt;/strong&gt;。接口只定义规范而不去实现，细节由具体的对象来实现。Golang中&lt;strong&gt;接口是一种抽象的类型&lt;/strong&gt;。&lt;/p&gt;&#xA;&#xA;&lt;h2 class=&#34;relative group&#34;&gt;实现&#xA;    &lt;div id=&#34;实现&#34; class=&#34;anchor&#34;&gt;&lt;/div&gt;&#xA;    &#xA;    &lt;span&#xA;        class=&#34;absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none&#34;&gt;&#xA;        &lt;a class=&#34;text-primary-300 dark:text-neutral-700 !no-underline&#34; href=&#34;#%e5%ae%9e%e7%8e%b0&#34; aria-label=&#34;锚点&#34;&gt;#&lt;/a&gt;&#xA;    &lt;/span&gt;&#xA;    &#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Golang中interface通常分为两大类，一种是空接口，这种接口不带任何方法。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;另一种是非空接口，这种接口带有方法&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;duck&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;quack&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;这两种类型的接口底层分别对应两个不同的结构，空接口对应runtime.eface，非空接口对应runtime.iface&lt;/p&gt;&#xA;&lt;img src=&#34;http://storage.chuckchan.top/uploads/Golang之内存管理.jpeg&#34; alt=&#34;Golang之内存管理&#34; style=&#34;zoom:50%;&#34; /&gt;&#xA;&lt;p&gt;eface的定义如下&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eface&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_type&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;_type&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//记录类型信息（_type是GO语言中所有类型的公共描述，Go语言几乎所有的数据结构都可以抽象成 _type，是所有类型的公共描述，type负责决定data应该如何解释和操作）&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//指向数据的指针&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;iface的定义如下&lt;/p&gt;&#xA;&lt;div class=&#34;highlight-wrapper&#34;&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;iface&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;tab&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;itab&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;//&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#x9;data unsafe.Pointer //指向数据的指针&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#xA;&lt;p&gt;itab是最重要的结构，每一个 &lt;code&gt;itab&lt;/code&gt; 都占 32 字节的空间。itab里面包含了interface的一些关键信息，比如method的具体实现。&lt;/p&gt;</description>
      
    </item>
    
  </channel>
</rss>
