<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on 所以然</title>
    <link>https://1221.tech/posts/</link>
    <description>Recent content in Posts on 所以然</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 09 Mar 2020 13:50:10 +0800</lastBuildDate>
    <atom:link href="https://1221.tech/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>《Redis设计与实现》数据结构与对象小记</title>
      <link>https://1221.tech/posts/redis-struct/</link>
      <pubDate>Mon, 09 Mar 2020 13:50:10 +0800</pubDate>
      <guid>https://1221.tech/posts/redis-struct/</guid>
      <description>&lt;p&gt;本文是&lt;a href=&#34;https://book.douban.com/subject/25900156/&#34;&gt;《Redis设计与实现》&lt;/a&gt;的数据结构与对象部分的&lt;strong&gt;流水账记录&lt;/strong&gt;。建议先阅读该书。&lt;/p&gt;&#xA;&lt;h2 id=&#34;数据结构&#34;&gt;数据结构&lt;/h2&gt;&#xA;&lt;h3 id=&#34;简单动态字符串sds-simple-dynamic-string&#34;&gt;简单动态字符串(SDS, simple dynamic string)&lt;/h3&gt;&#xA;&lt;p&gt;用处：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;key&lt;/li&gt;&#xA;&lt;li&gt;value&lt;/li&gt;&#xA;&lt;li&gt;aof 缓冲区&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&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;li&gt;性能更高（空间预分配，惰性空间释放）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;结构：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;int free&lt;/code&gt;，可用空间&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;int len&lt;/code&gt;，字符串长度&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;char buf[]&lt;/code&gt;，保存字符串&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;链表&#34;&gt;链表&lt;/h3&gt;&#xA;&lt;p&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;li&gt;监视器&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;结构：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ListNode&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;listNode * pre&lt;/code&gt;，前置节点&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;listNode * next&lt;/code&gt;，后置节点&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;void * value&lt;/code&gt;，值&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;list&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;listNode * head&lt;/code&gt;，列表头&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;listNode * tail&lt;/code&gt;，列表尾&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;unsigned long len&lt;/code&gt;,列表长度&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;字典&#34;&gt;字典&lt;/h3&gt;&#xA;&lt;p&gt;依赖算法：使用 &lt;code&gt;MurmurHash2&lt;/code&gt; 算法计算哈希值，速度快，分布随机&lt;/p&gt;&#xA;&lt;p&gt;用处：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;整个 redis 底层就使用字典&lt;/li&gt;&#xA;&lt;li&gt;hash&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;结构：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;dictht&lt;/code&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;dictEntry **table&lt;/code&gt;，哈希表数组&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;unsigned long size&lt;/code&gt;，哈希表大小，table 数组大小&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;unsigned long sizemask&lt;/code&gt;，哈希表大小掩码，用于计算索引，等于 &lt;code&gt;size - 1&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;unsigned long used&lt;/code&gt;，已有节点数&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;dictEntry&lt;/code&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;void *key&lt;/code&gt;, 键&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;union&lt;/code&gt;，值&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;dictEntry *next&lt;/code&gt;，指向下一个哈希表节点（解决冲突问题）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;dict&lt;/code&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;type，提供为特定类型的键值对的函数&lt;/li&gt;&#xA;&lt;li&gt;private，传递给type中函数的特定参数&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;dictht ht[2]&lt;/code&gt;,一般只用 &lt;code&gt;ht[0]&lt;/code&gt;, rehash 的使用会用 &lt;code&gt;ht[1]&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;rehashidx&lt;/code&gt;, rehash 进度，没有 rehash 时为 -1&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;行为：&lt;/p&gt;</description>
    </item>
    <item>
      <title>《正则表达式必知必会》读书笔记——脑图</title>
      <link>https://1221.tech/posts/re-must-know/</link>
      <pubDate>Sun, 08 Mar 2020 23:53:47 +0800</pubDate>
      <guid>https://1221.tech/posts/re-must-know/</guid>
      <description>&lt;p&gt;之前读&lt;a href=&#34;https://book.douban.com/subject/2269648/&#34;&gt;《正则表达式必知必会》&lt;/a&gt;整理的脑图。不记得有些功能的时候可以翻一翻。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://1221.tech/static/re.png&#34; alt=&#34;脑图&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://1221.tech/static/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BF%85%E7%9F%A5%E5%BF%85%E4%BC%9A%E8%84%91%E5%9B%BE.xmind&#34;&gt;xmind 格式下载&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Golang 中字典的 Comma Ok 是如何实现的</title>
      <link>https://1221.tech/posts/golang-comma-ok/</link>
      <pubDate>Sat, 29 Feb 2020 14:41:14 +0800</pubDate>
      <guid>https://1221.tech/posts/golang-comma-ok/</guid>
      <description>&lt;p&gt;众所周知，Golang 中函数的返回值的数量是固定的，而不是像 Python 中那样，函数的返回值数量是不固定的。&lt;/p&gt;&#xA;&lt;p&gt;如果我们把 Golang 中对 map 的取值看作是一个函数的话，那么直接取值和用 comma ok 方式取值的实现就变得很意思。&lt;/p&gt;&#xA;&lt;p&gt;Golang 中 map 的取值方式&lt;/p&gt;&#xA;&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-Golang&#34; data-lang=&#34;Golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;test&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:#a6e22e&#34;&gt;v2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m2&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;先看看汇编是如何实现的。&lt;/p&gt;&#xA;&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-Golang&#34; data-lang=&#34;Golang&#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;log&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;m1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&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;    &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m1&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;test&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:#a6e22e&#34;&gt;v2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m1&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;test&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:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存上述文件为 map_test.go，执行&lt;code&gt;go tool compile -S map_test.go&lt;/code&gt;，截取关键部分&lt;/p&gt;&#xA;&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-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#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:#960050;background-color:#1e0010&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x00a9&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;00169&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;map_test.go&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;)&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;CALL&lt;/span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;runtime.mapaccess2_faststr&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;SB&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;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x00f8&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;00248&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;map_test.go&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;)&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;CALL&lt;/span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;runtime.mapaccess1_faststr&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;SB&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;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到，虽然都是 &lt;code&gt;m1[&amp;quot;test&amp;quot;]&lt;/code&gt;，但是却调用了 runtime 中不同的方法。&#xA;可以在 &lt;code&gt;go/src/runtime/map_faststr.go&lt;/code&gt; 文件中看到&lt;/p&gt;&#xA;&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-golang&#34; data-lang=&#34;golang&#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;mapaccess2_faststr&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;maptype&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hmap&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ky&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&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:#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;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mapaccess1_faststr&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;maptype&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hmap&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ky&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&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; {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样明显就对上了，但是 Golang 又是如何实现把 &lt;code&gt;m[&amp;quot;test&amp;quot;]&lt;/code&gt; 替换为 &lt;code&gt;mapaccess2_faststr&lt;/code&gt; 或者 &lt;code&gt;mapaccess1_faststr&lt;/code&gt; 的呢？&lt;/p&gt;&#xA;&lt;p&gt;这就涉及 Golang 的编译过程了。查看&lt;a href=&#34;https://github.com/golang/go/tree/master/src/cmd/compile&#34;&gt;官方文档&lt;/a&gt;，我们知道编译的过程包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Parsing，包括词法分析，语法分析，抽象语法树的生成。&lt;/li&gt;&#xA;&lt;li&gt;Type-checking and AST transformations，包括类型检查，抽象语法树转换。&lt;/li&gt;&#xA;&lt;li&gt;Generic SSA，中间代码生成&lt;/li&gt;&#xA;&lt;li&gt;Generating machine code，生成机器码&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;现在我们就一步一步的看一看，&lt;code&gt;m[&amp;quot;test&amp;quot;]&lt;/code&gt;是如何变成&lt;code&gt;mapaccess2_faststr&lt;/code&gt;的。（&lt;code&gt;mapaccess1_faststr&lt;/code&gt;同理，故不赘述）&lt;/p&gt;</description>
    </item>
    <item>
      <title>Golang 中 slice cap 增长模式小记</title>
      <link>https://1221.tech/posts/slice-append-grow-analyze/</link>
      <pubDate>Mon, 13 Jan 2020 00:43:30 +0800</pubDate>
      <guid>https://1221.tech/posts/slice-append-grow-analyze/</guid>
      <description>&lt;p&gt;在 Golang 中，我们知道数组是固定长度的。一般我们在使用时，大多数情况下使用的其实都是 slice，但是 slice 的底层的数据其实还是数组。所以我们在向 slice append 数据的时候，Golang 会检查底层的数组的长度是否已经不够，如果长度不够，Golang 则会新建一个数组，把原数组的数据拷贝过去，再将 slice 中的指向数组的指针指向新的数组。&lt;/p&gt;&#xA;&lt;p&gt;但是，新数组的长度该如何确定呢？如果每次新数组长度只增加 1，那么每次 append 数据都需要新建一个数组。但是如果每次新增数组的长度太大的，又会造成内存的浪费。先写一个简单的代码看看内存如何增长。&lt;/p&gt;&#xA;&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; (&#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;fmt&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:#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;slice&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&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;    &lt;span style=&#34;color:#a6e22e&#34;&gt;lastCapSize&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;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&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;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100000&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; {&#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;slice&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&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;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lastCapSize&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; cap(&lt;span style=&#34;color:#a6e22e&#34;&gt;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:#66d9ef&#34;&gt;if&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;0&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:#a6e22e&#34;&gt;i&lt;/span&gt;, cap(&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt;), float32(cap(&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt;))&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;float32(&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;            &lt;span style=&#34;color:#a6e22e&#34;&gt;lastCapSize&lt;/span&gt; = cap(&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果如下：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;last&lt;/th&gt;&#xA;          &lt;th&gt;current&lt;/th&gt;&#xA;          &lt;th&gt;percent&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;1&lt;/td&gt;&#xA;          &lt;td&gt;2&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2&lt;/td&gt;&#xA;          &lt;td&gt;4&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;4&lt;/td&gt;&#xA;          &lt;td&gt;8&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;8&lt;/td&gt;&#xA;          &lt;td&gt;16&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;16&lt;/td&gt;&#xA;          &lt;td&gt;32&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;32&lt;/td&gt;&#xA;          &lt;td&gt;64&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;64&lt;/td&gt;&#xA;          &lt;td&gt;128&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;128&lt;/td&gt;&#xA;          &lt;td&gt;256&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;256&lt;/td&gt;&#xA;          &lt;td&gt;512&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;512&lt;/td&gt;&#xA;          &lt;td&gt;1024&lt;/td&gt;&#xA;          &lt;td&gt;200.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;1024&lt;/td&gt;&#xA;          &lt;td&gt;1280&lt;/td&gt;&#xA;          &lt;td&gt;125.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;1280&lt;/td&gt;&#xA;          &lt;td&gt;1696&lt;/td&gt;&#xA;          &lt;td&gt;132.50%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;1696&lt;/td&gt;&#xA;          &lt;td&gt;2304&lt;/td&gt;&#xA;          &lt;td&gt;135.85%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2304&lt;/td&gt;&#xA;          &lt;td&gt;3072&lt;/td&gt;&#xA;          &lt;td&gt;133.33%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;3072&lt;/td&gt;&#xA;          &lt;td&gt;4096&lt;/td&gt;&#xA;          &lt;td&gt;133.33%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;4096&lt;/td&gt;&#xA;          &lt;td&gt;5120&lt;/td&gt;&#xA;          &lt;td&gt;125.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;5120&lt;/td&gt;&#xA;          &lt;td&gt;7168&lt;/td&gt;&#xA;          &lt;td&gt;140.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;7168&lt;/td&gt;&#xA;          &lt;td&gt;9216&lt;/td&gt;&#xA;          &lt;td&gt;128.57%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;9216&lt;/td&gt;&#xA;          &lt;td&gt;12288&lt;/td&gt;&#xA;          &lt;td&gt;133.33%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;12288&lt;/td&gt;&#xA;          &lt;td&gt;15360&lt;/td&gt;&#xA;          &lt;td&gt;125.00%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;15360&lt;/td&gt;&#xA;          &lt;td&gt;19456&lt;/td&gt;&#xA;          &lt;td&gt;126.67%&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;很明显的可以看到，在 cap 长度小于 1024 之前，每次新数组的长度都是旧数组的两倍。但是在 1024 之后增长的速度，最低增长 25%，最高能达到 40%。长度在 1024 之前的很容易理解，可是为什么在 1024 之后会出现这种情况我们就需要翻翻源码了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>好书推荐《深入理解程序设计》</title>
      <link>https://1221.tech/posts/recommand-programming-from-the-ground-up/</link>
      <pubDate>Wed, 08 Jan 2020 22:37:13 +0800</pubDate>
      <guid>https://1221.tech/posts/recommand-programming-from-the-ground-up/</guid>
      <description>&lt;p&gt;上周参加了深圳 Golang 的 meetup，其中一位讲师讲了关于 Golang 汇编的知识，奈何不懂汇编，听的云里雾里。在&lt;a href=&#34;https://blog.quantumghost.me/&#34;&gt;林老师&lt;/a&gt; 的推荐下，看了&lt;a href=&#34;https://book.douban.com/subject/25789594/&#34;&gt;《深入理解程序设计》&lt;/a&gt;这本书。虽说没有面面俱到，但是读完竟有一种畅快、醍醐灌顶之感，也是颇为妙哉。之前也是尝试过去读 csapp 这种硬骨头，奈何牙齿不够硬，还是没刚下来。读完一堆八进制、二进制、十六进制、补码云云，就坚持不下去了。&lt;/p&gt;&#xA;&lt;p&gt;这本书有以下几个优点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;不整那些有的没得，简单介绍点前置知识，咱就直接写代码&lt;/li&gt;&#xA;&lt;li&gt;正文只有 150 页，三四天就能读完&lt;/li&gt;&#xA;&lt;li&gt;通俗易懂，读起来不会很吃力&lt;/li&gt;&#xA;&lt;li&gt;最后一章推荐的书很棒，已按阅读顺序整理了书单，&lt;a href=&#34;https://www.douban.com/doulist/122338798/&#34;&gt;自下而上—推荐书单&lt;/a&gt;, &lt;a href=&#34;https://www.douban.com/doulist/122339075/&#34;&gt;自顶而下—推荐书单&lt;/a&gt;, &lt;a href=&#34;https://www.douban.com/doulist/122339341/&#34;&gt;具体语言书单&lt;/a&gt;，&lt;a href=&#34;https://www.douban.com/doulist/122339514/&#34;&gt;专题书单&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;汇编中的函数调用写的很清楚（相对 csapp）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;缺点也有：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;书里的 typo 比较多，看的时候需要主注意，可结合这份&lt;a href=&#34;https://book.douban.com/review/7316690/&#34;&gt;勘误&lt;/a&gt;阅读&lt;/li&gt;&#xA;&lt;li&gt;部分例子略显复杂，自己理解的时候可以尝试写一个简单点的例子，再看书中的例子&lt;/li&gt;&#xA;&lt;li&gt;书中的汇编都是基于 32 位操作系统的，如果你的电脑是 64 位，需要安装 32 位的虚拟机运行书中的例子，选择 Linux 镜像的时候选择 i386 的安装即可。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;看完这本书，对函数调用，一个进程的内存分配，stack，heap ，系统调用，链接器，编译器等等这些知识都会有了更深的理解。看这本书之前，我知道计算机有 cpu，硬盘，内存，我也知道高级程序语言可以打开文件，编写程序。但是总觉得中间缺了一道口子，恰好，这本书就填满了这个口子。&lt;/p&gt;&#xA;&lt;p&gt;总结的话就是，瑕不掩瑜，非常推荐这本书。&lt;/p&gt;</description>
    </item>
    <item>
      <title>记 20200104 深圳 golang meetup</title>
      <link>https://1221.tech/posts/20200104-golang-meetup/</link>
      <pubDate>Sun, 05 Jan 2020 22:40:42 +0800</pubDate>
      <guid>https://1221.tech/posts/20200104-golang-meetup/</guid>
      <description>&lt;p&gt;早早报名了 gocn 组织的深圳 Golang meetup，花了一整天，听了 7 个主题。简单分享如下。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1go在工业领域的应用实践&#34;&gt;1.Go在工业领域的应用实践&lt;/h2&gt;&#xA;&lt;p&gt;首先简单叙述了下现在工业领域的痛点主要是没有进行数字化。看不到数据，之后主要介绍他们公司使用 Golang 开发了系统提供给一些制造业的公司。通过对制造业的数字化，可以收集数据，帮助辅助化决策。&lt;/p&gt;&#xA;&lt;p&gt;之后他们使用的 Golang 的原因是&lt;strong&gt;方便在各个平台部署&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;借助 Golang 的 interface 能比较方便的对接各种底层硬件等。之后 show 了一点代码。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2go性能优化之路&#34;&gt;2.Go性能优化之路&lt;/h2&gt;&#xA;&lt;p&gt;首先提出&lt;strong&gt;优化是有成本的&lt;/strong&gt;，要权衡优化的成本和价值，来决定做不做优化。&lt;/p&gt;&#xA;&lt;p&gt;其次是&lt;strong&gt;什么时候停止优化&lt;/strong&gt;，优化之前往往需要一个目标，因为优化这个过程是边际效用递减的，所以往往在优化到一定程度的时候就不需要继续优化了。&lt;/p&gt;&#xA;&lt;p&gt;如何优化，演讲者明确的给了五步，最后一步为重复第一步，作为一个循环。具体五步如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;基准&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;首先优化有个基准才能知道到底是正优化，还是负优化&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;满足基准测试之前，首先要满足单元测试，首先对，然后才是快&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;基准测试的工具主要是 benchmark&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;分析&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;主要是发现瓶颈，并定位瓶颈&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;主要工具如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;GODEBUG，通过环境变量的设置，让 Golang 打印堆栈情况&lt;/li&gt;&#xA;&lt;li&gt;go tool pprof，可以查看 heap, goroutine, cpu, memery 等情况的瓶颈&lt;/li&gt;&#xA;&lt;li&gt;go tool trace&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;优化&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;定位到瓶颈之后就是优化了&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;校验&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;主要使用 benchstat 将基准测试的数据进行对比。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;迭代&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;重复第一步。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;tips：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;使用 sync.Pool 复用对象&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;使用 atomic.Value&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;使用分区，减少共享数据的争用&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;避免使用包含指针的结构体作为 map 的 key（例如 string，可以使用 hash）&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;使用 strings.Builder 拼接字符串&lt;/p&gt;</description>
    </item>
    <item>
      <title>如何为 Mac 中不支持的快捷键的菜单栏加上快捷键</title>
      <link>https://1221.tech/posts/automation-with-applescript-and-keyboard-maestro/</link>
      <pubDate>Fri, 07 Dec 2018 23:10:38 +0800</pubDate>
      <guid>https://1221.tech/posts/automation-with-applescript-and-keyboard-maestro/</guid>
      <description>&lt;h3 id=&#34;介绍&#34;&gt;介绍&lt;/h3&gt;&#xA;&lt;p&gt;AppleScript  是苹果系统内置的一门语言，主要是可以完成很多普通脚本完成不了的工作，比如打开某个软件，点击某个菜单栏等等操作。&lt;/p&gt;&#xA;&lt;p&gt;简单学习的话，&lt;a href=&#34;https://sspai.com/post/43758&#34;&gt;可以看少数派的这篇文章&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.keyboardmaestro.com/main/&#34;&gt;Keyboard Maestro&lt;/a&gt;是一个将特定的输入和执行动作绑定的一个软件，比如在某个应用按下某个特定的快捷键执行特定的脚本。具体功能可以查看官网，使用方法在安装完软件后会有一个简短的小教程。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;主要需求：为 PDF Expert 的日间操作加上快捷键功能&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://1221.tech/static/Snipaste_2018-12-07_11-51-45.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;操作&#34;&gt;操作&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;编写 AppleScript 切换到日间模式&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&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-AppleScript&#34; data-lang=&#34;AppleScript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;tell&lt;/span&gt; application &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;System Events&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:#66d9ef&#34;&gt;tell&lt;/span&gt; process &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PDF Expert&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;click &lt;span style=&#34;color:#a6e22e&#34;&gt;menu&lt;/span&gt; item &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;日间&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;menu&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;主题&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;menu&lt;/span&gt; item &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;主题&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;menu&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;视图&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;menu&lt;/span&gt; bar item &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;视图&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;menu&lt;/span&gt; bar &lt;span style=&#34;color:#ae81ff&#34;&gt;1&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;end&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tell&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;end&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tell&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;在 Keyboard Maestro 给 PDF Expert 配置相应的快捷键对应的操作&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://1221.tech/static/Snipaste_2018-12-07_11-57-09.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;可选步骤，将快捷键操作配置为制定应用而不是全局执行。在 Groups 里面新建一个 PDF Expert 的 Group，新建的时候选择 Available in these applications ，之后选中 PDF Expert，最后将上一步新建的 Macros 拖动到 PDF Expert 文件夹。&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>豆瓣 Alfred workflow</title>
      <link>https://1221.tech/posts/douban-workflow/</link>
      <pubDate>Thu, 06 Dec 2018 23:24:38 +0800</pubDate>
      <guid>https://1221.tech/posts/douban-workflow/</guid>
      <description>&lt;p&gt;主要需求是因为经常挑书的时候想看看豆瓣评分是多少，可是又不想每次打开豆瓣去搜索。&lt;/p&gt;&#xA;&lt;p&gt;之前装的 Alfred 的豆瓣的 workflow 都因为豆瓣 API 的关闭而变得不能用了。&lt;/p&gt;&#xA;&lt;p&gt;没得办法，只能自己写一个。最开始的时候是尝试抓取电脑版页面的，结果发现豆瓣没以前那么好爬了，所以在 Chrome 里面打了半天的断点调试了半天也没解出来怎么加密数据的。&lt;/p&gt;&#xA;&lt;p&gt;后面灵机一动，既然电脑做了加密，那么手机呢？最后还是通过手机的页面撸完了这个 workflow。&lt;/p&gt;&#xA;&lt;p&gt;地址：&lt;a href=&#34;https://github.com/h3l/douban-workflow&#34;&gt;https://github.com/h3l/douban-workflow&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;主要功能：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;搜索书籍&lt;/li&gt;&#xA;&lt;li&gt;搜索电影&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;截图如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://1221.tech/static/image-20181121210316610.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://1221.tech/static/image-20181121210659883.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>一种低配版服务降级方法</title>
      <link>https://1221.tech/posts/low_level_service_downgrade/</link>
      <pubDate>Mon, 22 Oct 2018 20:30:02 +0800</pubDate>
      <guid>https://1221.tech/posts/low_level_service_downgrade/</guid>
      <description>&lt;p&gt;现在微服务是潮流，大多数时候，不管基础的微服务设施有没有搭建好，大项目能拆出来一个是一个，反正拆开了就是微服务。&lt;/p&gt;&#xA;&lt;p&gt;所以系统从原来的函数调用，变成了 http 调用或者是 rpc 的调用。&lt;/p&gt;&#xA;&lt;p&gt;原意是为了方便管理项目，提高灵活性等等，可是变为 http 调用后，服务变得不那么可靠了。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;情况一，虽然服务不可靠，但是挂了就挂了，依赖这个服务的相关服务也挂了，正常&lt;/li&gt;&#xA;&lt;li&gt;情况了，服务不可靠，而且接口响应时间很慢，那么这个时候，本身的服务可能因为这个服务拖垮。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这个时候也没有所谓的熔断器等等的基础设施。&lt;/p&gt;&#xA;&lt;p&gt;那么有一种低配版的服务降级方法，就是借助 redis 来实现。伪代码如下：&lt;/p&gt;&#xA;&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:#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;unhandledCount&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;redis&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;unhandledCount_FUNC_NAME&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;// 大于被阻塞数，直接返回失败&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;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unhandledCount&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MAX_UNHANDLED_COUNT&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:#a6e22e&#34;&gt;fail&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;else&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;redis&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Incr&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unhandledCount_FUNC_NAME)&#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:#e6db74&#34;&gt;    resp := http.get(&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//url&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:#a6e22e&#34;&gt;redis&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Decr&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unhandledCount_FUNC_NAME&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:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resp&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方法和 timeout 的方法来比的话，最大的好处就是，别的系统再怎么炸，就不会影响自己的系统。所以这种方法不仅适用与微服务的系统调用，所有依赖第三方的调用也可以通过这种方法保障自身服务稳定。&lt;/p&gt;&#xA;&lt;p&gt;最后，这也只是一个变通的，低配版的方案，要实实在在的解决这个问题，还是要靠正统的方法。&lt;/p&gt;</description>
    </item>
    <item>
      <title>一种通用型的权限系统设计</title>
      <link>https://1221.tech/posts/permission/</link>
      <pubDate>Wed, 19 Sep 2018 20:11:04 +0800</pubDate>
      <guid>https://1221.tech/posts/permission/</guid>
      <description>&lt;p&gt;先简单看一下简单的表结构以及表关系。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://1221.tech/static/UserPosition.png&#34; alt=&#34;表与表关系&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;表解释&#34;&gt;表解释&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;用户相关&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;User&lt;/code&gt; 用于存储用户信息，主要字段为 &lt;code&gt;id&lt;/code&gt; 用户信息等&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;组织相关&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Organization&lt;/code&gt; 用于存储组织架构中的单个组织，主要字段为 &lt;code&gt;id&lt;/code&gt;,&lt;code&gt;name&lt;/code&gt; 等等&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Relation&lt;/code&gt; 用于存储组织架构中的组织间关系，主要字段为&lt;code&gt;parent_id&lt;/code&gt;,&lt;code&gt;child_id&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;群组相关&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Group&lt;/code&gt; 用于存储群组信息，主要字段为 &lt;code&gt;id&lt;/code&gt; 群组名等&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Service&lt;/code&gt; 用于存储服务信息，主要字段为 &lt;code&gt;id&lt;/code&gt; 服务名称等&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Api&lt;/code&gt; 用于存储接口信息，主要字段为&lt;code&gt;id&lt;/code&gt;,&lt;code&gt;url_name,&lt;/code&gt;app_name`等&lt;/li&gt;&#xA;&lt;li&gt;另外还有两张表用于存储 &lt;code&gt;Group&lt;/code&gt; 与 &lt;code&gt;Service&lt;/code&gt; 的多对多关系以及 &lt;code&gt;Service&lt;/code&gt; 与 &lt;code&gt;Api&lt;/code&gt; 的多对多关系&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;将上述关系组织到一起&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;UserPosition&lt;/code&gt; 记录一个人在哪些组织上属于什么群组，主要字段有 &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;group_id&lt;/code&gt;, &lt;code&gt;org_id&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;概述&#34;&gt;概述&lt;/h3&gt;&#xA;&lt;p&gt;上述的那么多表，其实只是解决了一个问题『&lt;strong&gt;一个人&lt;/strong&gt;在&lt;strong&gt;什么范围&lt;/strong&gt;能做&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;即 组织相关的表&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;什么事情&lt;/strong&gt; 即 群组相关的表&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;用户相关&#34;&gt;用户相关&lt;/h3&gt;&#xA;&lt;p&gt;即权限系统中的用户，并无复杂概念&lt;/p&gt;&#xA;&lt;h3 id=&#34;组织相关&#34;&gt;组织相关&lt;/h3&gt;&#xA;&lt;p&gt;现实生活中的组织架构是一个类似树形的不规则结构，如下图所示&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://1221.tech/static/root.png&#34; alt=&#34;组织架构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;如果是存储树形结构，第一反应可能是在每个节点记录一个 &lt;code&gt;parent_id&lt;/code&gt;。这是最简单的做法，但是在查询某个节点的所有子节点的时候却是效率最差的做法。&lt;/p&gt;&#xA;&lt;p&gt;这里我们采用的方法是单独拿一张关系表记录父节点到所有子节点的数据。这样做的好处是查询效率非常高，只是在插入数据的时候稍微慢一点，但是考虑到我们的应用是读大于写，所以这样做并无不妥。按照上述说法，则可以用下表表示下图。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://1221.tech/static/root1.png&#34; alt=&#34;组织架构&#34;&gt;&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;父节点&lt;/th&gt;&#xA;          &lt;th&gt;子节点&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;root&lt;/td&gt;&#xA;          &lt;td&gt;mid_a&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;root&lt;/td&gt;&#xA;          &lt;td&gt;bottom_a&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;root&lt;/td&gt;&#xA;          &lt;td&gt;bottom_b&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;root&lt;/td&gt;&#xA;          &lt;td&gt;bottom_d&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;mid_a&lt;/td&gt;&#xA;          &lt;td&gt;bottom_a&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;mid_a&lt;/td&gt;&#xA;          &lt;td&gt;bottom_b&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;tip: 如果为了方便，可以为每个节点插入一条父节点和子节点均为自己的记录。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
