[{"data":1,"prerenderedAt":273},["ShallowReactive",2],{"archive-2023-2-1":3},{"title":4,"articles":5,"hot_article":58,"month_arch":121,"total":269,"cover":270},"2023年2月 - 独孤影的博客",[6,18,29,38,48],{"id":7,"title":8,"uri":9,"author":10,"tags":11,"created_at":15,"view_count":16,"content":17},94,"golang程序并发读写全局变量，导致空指针异常","concurrent-reading-and-writing-global-var-caused-nil-pointer-dereference-panic","duguying",[12,13,14],"golang","数据竞争","线程安全","2023-02-28 19:27:48",365,"\u003Cp>最近将一个golang程序由原本的单线程改为双线程处理日志解析，在生产环境节点上运行发现出现了一个空指针异常，异常信息如下：\u003C\u002Fp>\n\n\u003Cpre style=\"color:#e6edf3;background-color:#0d1117;white-space:pre-wrap;word-break:break-word;\">\u003Ccode>\u003Cspan style=\"display:flex;\">\u003Cspan>[E] 2023\u002F02\u002F27 11:53:25 panic.go:838: parse error:runtime error: invalid memory address or nil pointer dereference,line:Feb 27 11:53:25 xxxxx.site nginx: [xxxxxxxxxxxxxxxxxxx] [27\u002FFeb\u002F2023:11:53:25 +0800] [https] [120.232.31.196:443] [xxxxx.map.xx.com] [39.144.41.41:37647] [200] [30.171.153.132:10000] [200] [3339597] [POST \u002Ftr?mllc HTTP\u002F1.1] [621] [152] [xxxxxxx.map.xx.com] [Dalvik\u002F2.1.0 (Linux; U; Android 10; HMA-AL00 Build\u002FHUAWEIHMA-AL00)] [-] [0.008] [0.008] [0.004] [0.008] [46795] [311532943564] [1][1:46:0:0:0:0:0] [ECDHE-RSA-AES128-GCM-SHA256] [TLSv1.2] [r][-] [-] [n] [2358837] [-1] [1677470005.398|5|51|126|-1|-1|126|126|130|-1|-1|130|134|134|134|134#200|200|8|152|120.232.31.196|30.171.153.132:10000|0|0] [POST] [\u002Ftr] [mllc] [HTTP\u002F1.1] [39.144.41.41] [-] [-] [-] [-] [-] [-] [-] [-] [-] [-] [169.254.213.29:50937] [0]\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>修改程序，打印出异常栈\n\u003Cimg src=\"https:\u002F\u002Fimage.duguying.net\u002F2023\u002F02\u002Fx7s4uzea.webp\" alt=\"x7s4uzea\" \u002F>\u003C\u002Fp>\n\n\u003Cp>发现异常发生在代码133行，代码如下\n\u003Cimg src=\"https:\u002F\u002Fimage.duguying.net\u002F2023\u002F02\u002F0zhhoxbp.png\" alt=\"0zhhoxbp\" \u002F>\u003C\u002Fp>\n\n\u003Cp>很明显这里不太可能出现空指针，除非运行到这一行的时候\u003Ccode class=\"inline-code\">sl\u003C\u002Fcode>对象被置为\u003Ccode class=\"inline-code\">nil\u003C\u002Fcode>，但是我很确定这里不存在其他线程共享\u003Ccode class=\"inline-code\">sl\u003C\u002Fcode>的情况，也就是不可能被其他线程置为\u003Ccode class=\"inline-code\">nil\u003C\u002Fcode>，何况，我这里没有任何操作将sl置为\u003Ccode class=\"inline-code\">nil\u003C\u002Fcode>，百思不得其解。最后发现\u003Ccode class=\"inline-code\">key1\u003C\u002Fcode>，\u003Ccode class=\"inline-code\">key2\u003C\u002Fcode>这两个变量是全局变量，全局变量在多线程环境下会存在数据竞争问题。原本定义如下\u003C\u002Fp>\n\n\u003Cpre style=\"color:#e6edf3;background-color:#0d1117;white-space:pre-wrap;word-break:break-word;\">\u003Ccode>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#ff7b72\">var\u003C\u002Fspan> (\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\turiSep \u003Cspan style=\"color:#ff7b72;font-weight:bold\">*\u003C\u002Fspan>regexp.Regexp = \u003Cspan style=\"color:#79c0ff\">nil\u003C\u002Fspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\tkey1 = \u003Cspan style=\"color:#a5d6ff\">&#34;&#34;\u003C\u002Fspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\tkey2 = \u003Cspan style=\"color:#a5d6ff\">&#34;&#34;\u003C\u002Fspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>)\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>可以看到\u003Ccode class=\"inline-code\">key1\u003C\u002Fcode>,\u003Ccode class=\"inline-code\">key2\u003C\u002Fcode>被定义为全局变量，忘记修改了。修改之后，神奇的发现，空指针异常已经不再存在了。\u003C\u002Fp>\n\n\u003Cp>我在发现这个问题之前，在本地开发服务器上尝试重现，但是一直未能重现出来，估计是我本地qps不够高，所以难以复现，生产环境qps是3w到4w左右，这个空指针异常呈现无规律的隔几秒钟出现一次。\u003C\u002Fp>\n\n\u003Cp>golang中，双协程（绑定在双M和双cpu上）中同时读写一个共享变量导致空指针异常，这种情况我还是第一次遇见，以前遇到这种双协程读写一个共享变量的情况都是数据错乱，并没有空指针。据说这种线程安全、数据竞争导致的空指针异常在C++中也是常见的情况。所以，我在想，这里会不会是因为我将2个协程绑核了，所以在双线程绑双核的情况下更容易复现呢。\u003C\u002Fp>\n",{"id":19,"title":20,"uri":21,"author":10,"tags":22,"created_at":26,"view_count":27,"content":28},93,"初学rust，如何在线程中调用成员方法","how-to-calling-a-method-in-a-thread",[23,24,25],"rust","线程","方法","2023-02-24 23:01:24",239,"\u003Cp>如何在线程中调用成员方法？\u003C\u002Fp>\n\n\u003Cp>普通调用习惯写法\u003C\u002Fp>\n\n\u003Cpre style=\"color:#e6edf3;background-color:#0d1117;white-space:pre-wrap;word-break:break-word;\">\u003Ccode>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#ff7b72\">fn\u003C\u002Fspan> \u003Cspan style=\"color:#d2a8ff;font-weight:bold\">watch_receiver\u003C\u002Fspan>(\u003Cspan style=\"color:#ff7b72\">mut\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>self,\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>rx: \u003Cspan style=\"color:#f0883e;font-weight:bold\">Receiver\u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72;font-weight:bold\">&lt;\u003C\u002Fspan>String\u003Cspan style=\"color:#ff7b72;font-weight:bold\">&gt;\u003C\u002Fspan>)\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>{\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">    \u003C\u002Fspan>thread::spawn(\u003Cspan style=\"color:#ff7b72\">move\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72;font-weight:bold\">|\u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72;font-weight:bold\">|\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>{\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">        \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72\">for\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>line\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72\">in\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>rx.iter()\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>{\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">            \u003C\u002Fspan>self.push(line);\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">        \u003C\u002Fspan>}\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">    \u003C\u002Fspan>});\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>}\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>会报错\u003C\u002Fp>\n\n\u003Cpre style=\"color:#e6edf3;background-color:#0d1117;white-space:pre-wrap;word-break:break-word;\">\u003Ccode>\u003Cspan style=\"display:flex;\">\u003Cspan>p.watch_receiver\u003Cspan style=\"color:#ff7b72;font-weight:bold\">(\u003C\u002Fspan>rx\u003Cspan style=\"color:#ff7b72;font-weight:bold\">)\u003C\u002Fspan>;\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>    |           ------------------ \u003Cspan style=\"color:#a5d6ff\">`\u003C\u002Fspan>p\u003Cspan style=\"color:#a5d6ff\">`\u003C\u002Fspan> moved due to this method call\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#a5d6ff\">70\u003C\u002Fspan>  |         p.watch_poly\u003Cspan style=\"color:#ff7b72;font-weight:bold\">(\u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72;font-weight:bold\">)\u003C\u002Fspan>;\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>    |         ^^^^^^^^^^^^^^ value borrowed here after move\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>这里需要把形参\u003Ccode class=\"inline-code\">self\u003C\u002Fcode>改为指针\u003Ccode class=\"inline-code\">&amp;self\u003C\u002Fcode>，然后在方法体中克隆这个指针，就可以在方法中的线程里直接通过这个指针的克隆成员方法。\u003C\u002Fp>\n\n\u003Cp>改为\u003C\u002Fp>\n\n\u003Cpre style=\"color:#e6edf3;background-color:#0d1117;white-space:pre-wrap;word-break:break-word;\">\u003Ccode>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#ff7b72\">fn\u003C\u002Fspan> \u003Cspan style=\"color:#d2a8ff;font-weight:bold\">watch_receiver\u003C\u002Fspan>(\u003Cspan style=\"color:#ff7b72;font-weight:bold\">&amp;\u003C\u002Fspan>self,\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>rx: \u003Cspan style=\"color:#f0883e;font-weight:bold\">Receiver\u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72;font-weight:bold\">&lt;\u003C\u002Fspan>String\u003Cspan style=\"color:#ff7b72;font-weight:bold\">&gt;\u003C\u002Fspan>)\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>{\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">    \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72\">let\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72\">mut\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>me\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72;font-weight:bold\">=\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>self.clone();\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">    \u003C\u002Fspan>thread::spawn(\u003Cspan style=\"color:#ff7b72\">move\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72;font-weight:bold\">|\u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72;font-weight:bold\">|\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>{\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">        \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72\">for\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>line\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72\">in\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>rx.iter()\u003Cspan style=\"color:#6e7681\"> \u003C\u002Fspan>{\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">            \u003C\u002Fspan>me.push(line);\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">        \u003C\u002Fspan>}\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>\u003Cspan style=\"color:#6e7681\">    \u003C\u002Fspan>});\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#6e7681\">\u003C\u002Fspan>}\u003Cspan style=\"color:#6e7681\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>即可通过。\u003C\u002Fp>\n\n\u003Cp>但是要注意，这里的\u003Ccode class=\"inline-code\">clone\u003C\u002Fcode>，真的是克隆。所以clone前后的变量，即\u003Ccode class=\"inline-code\">self\u003C\u002Fcode>与\u003Ccode class=\"inline-code\">me\u003C\u002Fcode>是2个不同的变量，里面的成员也是在不同的内存空间上，修改\u003Ccode class=\"inline-code\">self\u003C\u002Fcode>中的成员属性，\u003Ccode class=\"inline-code\">me\u003C\u002Fcode>中对应的成员属性并不会跟着变。所以，如果里面的成员属性需要跟随变化，必须把成员属性定义为指针，这样修改指正所指的值，\u003Ccode class=\"inline-code\">self\u003C\u002Fcode>和\u003Ccode class=\"inline-code\">me\u003C\u002Fcode>中成员属性所指的值是相同的。\u003C\u002Fp>\n",{"id":30,"title":31,"uri":32,"author":10,"tags":33,"created_at":35,"view_count":36,"content":37},92,"为go程序的协程绑核","set-cpu-affinity-binding-for-golang-program",[12,34],"绑核","2023-02-23 10:22:23",1773,"\u003Cp>最近在公司的日志处理程序上做性能优化，用到了绑核的情况。背景是这样的，nginx进行http转发，产生日志，然后我们的程序读取日志，用lexer分词器对日志分隔字段，并且对字段进行统计聚合上报，生成监控。日志处理程序最开始是在单个goroutine里进行读取并且解析操作了，但是在核数比较多的大机器上，发现日志生成太快，解析程序处理不过来，在日志rotate的过程中会发生丢失日志的情况。于是针对这个情况进行了优化。\u003C\u002Fp>\n\n\u003Cp>用pprof发现，性能消耗最大的部分是lexer，lexer其实就是个分词器，编译器中常用的技术，逐字符读取每行日志，然后基于状态机状态标记对日志的字段进行分割，中间涉及到的状态也不算太多，主要是双引号(&ldquo;&rdquo;)作为定界符提取字符串字段，方括号([])作为定界符提取字符串字段，空字符(空格、\\t)和竖线符(|)作为分隔符分隔字段，转义符()对字符串中的字符串定界符(&rdquo;[])进行转义，总体来说，状态不算复杂，其中也针对lexer优化过尽量减少变量分配和杜绝变量逃逸，lexer实在是已经无可优化了。\u003C\u002Fp>\n\n\u003Cp>于是只好从其他方面下手，首先就是cpu切换的性能损耗。众所周知golang中没有线程的，golang中只有协程（goroutine），而防止cpu切换的性能损耗只有绑核这个方法，具体就是讲指定的核绑定到某个线程上，这样这个线程就会只在这个指定的核上运行，不会被系统切换到其他核上，这样也就不会产生切换的损耗了。但是golang程序中只有goroutine，不能直接操作线程。其实我们是有办法对goroutine进行绑核的。\u003C\u002Fp>\n\n\u003Cp>首先，使用go里面的\u003Ccode class=\"inline-code\">runtime.LockOSThread()\u003C\u002Fcode>将当前goroutine绑定到它所在的M线程，这样，这个goroutine就不会在M线程之间切换了；然后，我们可以使用cgo，调用\u003Ccode class=\"inline-code\">pthread_self\u003C\u002Fcode>获取当前协程所在M线程的线程ID，并调用\u003Ccode class=\"inline-code\">CPU_SET\u003C\u002Fcode>对这个线程ID设置cpuid绑定。具体如下\u003C\u002Fp>\n\n\u003Cpre style=\"color:#e6edf3;background-color:#0d1117;white-space:pre-wrap;word-break:break-word;\">\u003Ccode>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#ff7b72\">package\u003C\u002Fspan> affinity\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">\u002F*\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">#define _GNU_SOURCE\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">#include &lt;sched.h&gt;\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">#include &lt;pthread.h&gt;\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">int lock_thread(int cpuid) {\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  pthread_t tid;\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  cpu_set_t cpuset;\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  tid = pthread_self();\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  CPU_ZERO(&amp;cpuset);\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  CPU_SET(cpuid, &amp;cpuset);\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  return  pthread_setaffinity_np(tid, sizeof(cpu_set_t), &amp;cpuset);\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">}\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">pthread_t current_thread_id() {\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  pthread_t tid;\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  tid = pthread_self();\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">  return tid;\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">}\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">*\u002F\u003C\u002Fspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#ff7b72\">import\u003C\u002Fspan> \u003Cspan style=\"color:#a5d6ff\">&#34;C&#34;\u003C\u002Fspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#ff7b72\">import\u003C\u002Fspan> (\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\t\u003Cspan style=\"color:#a5d6ff\">&#34;fmt&#34;\u003C\u002Fspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\t\u003Cspan style=\"color:#a5d6ff\">&#34;runtime&#34;\u003C\u002Fspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>)\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">\u002F\u002F SetAffinity 设置CPU绑定\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\u003Cspan style=\"color:#8b949e;font-style:italic\">\u003C\u002Fspan>\u003Cspan style=\"color:#ff7b72\">func\u003C\u002Fspan> \u003Cspan style=\"color:#d2a8ff;font-weight:bold\">SetAffinity\u003C\u002Fspan>(cpuID \u003Cspan style=\"color:#ff7b72\">int\u003C\u002Fspan>) (\u003Cspan style=\"color:#ff7b72\">uint64\u003C\u002Fspan>, \u003Cspan style=\"color:#ff7b72\">error\u003C\u002Fspan>) {\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\truntime.\u003Cspan style=\"color:#d2a8ff;font-weight:bold\">LockOSThread\u003C\u002Fspan>()\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\tret \u003Cspan style=\"color:#ff7b72;font-weight:bold\">:=\u003C\u002Fspan> C.\u003Cspan style=\"color:#d2a8ff;font-weight:bold\">lock_thread\u003C\u002Fspan>(C.int(cpuID))\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\ttid \u003Cspan style=\"color:#ff7b72;font-weight:bold\">:=\u003C\u002Fspan> uint64(C.\u003Cspan style=\"color:#d2a8ff;font-weight:bold\">ulong\u003C\u002Fspan>(C.\u003Cspan style=\"color:#d2a8ff;font-weight:bold\">current_thread_id\u003C\u002Fspan>()))\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\t\u003Cspan style=\"color:#ff7b72\">if\u003C\u002Fspan> ret &gt; \u003Cspan style=\"color:#a5d6ff\">0\u003C\u002Fspan> {\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\t\t\u003Cspan style=\"color:#ff7b72\">return\u003C\u002Fspan> \u003Cspan style=\"color:#a5d6ff\">0\u003C\u002Fspan>, fmt.\u003Cspan style=\"color:#d2a8ff;font-weight:bold\">Errorf\u003C\u002Fspan>(\u003Cspan style=\"color:#a5d6ff\">&#34;set cpu core affinity failed with return code %d&#34;\u003C\u002Fspan>, ret)\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\t}\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\t\u003Cspan style=\"color:#ff7b72\">return\u003C\u002Fspan> tid, \u003Cspan style=\"color:#79c0ff\">nil\u003C\u002Fspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>}\n\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan style=\"display:flex;\">\u003Cspan>\n\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>这样一来，我们只需要在goroutine中调用\u003Ccode class=\"inline-code\">SetAffinity\u003C\u002Fcode>就可以将指定的cpuid和当前goroutine进行绑定。这样就实现了goroutine的绑定。\u003C\u002Fp>\n\n\u003Cp>我将日志处理程序改为在主协程中读取文件并且通过channel分发日志行，然后在2个goroutine执行最占cpu的lexer及后续处理，并且在这两个goroutine中绑定cpuid为1,2。\u003C\u002Fp>\n\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fimage.duguying.net\u002F2023\u002F02\u002Fqdx9l7z5.webp\" alt=\"qdx9l7z5\" \u002F>\u003C\u002Fp>\n\n\u003Cp>图中可以看到，两个处理日志的goroutine绑定了1,2两个cpu，并且不会切为其他cpu，这两个cpu都在处理日志，所以cpu占用都比较高，相当于把原来一个核处理的任务分担到2个核上了。\u003C\u002Fp>\n",{"id":39,"title":40,"uri":41,"author":10,"tags":42,"created_at":45,"view_count":46,"content":47},91,"观澜版画村春游记","spring-journey-to-guanlan-printmaking-village",[43,44],"观澜","春游","2023-02-21 18:49:29",145,"\u003Cp>春天已经悄悄到来，南方大城市中很难感受到春的变化。除非出游去远离都市的郊区，本着去看油菜花的目的，上周末去逛了一下深圳边缘的观澜版画村。\u003C\u002Fp>\n\n\u003Cp>\u003Cstrong>勤劳的小蜜蜂🐝\u003C\u002Fstrong>\n\u003Cimg src=\"https:\u002F\u002Fimage.duguying.net\u002F2023\u002F02\u002Fbetv6288.webp\" alt=\"betv6288\" \u002F>\u003C\u002Fp>\n\n\u003Cp>\u003Cstrong>油菜花田\u003C\u002Fstrong>\n\u003Cimg src=\"https:\u002F\u002Fimage.duguying.net\u002F2023\u002F02\u002Fkcxao9mw.webp\" alt=\"kcxao9mw\" \u002F>\u003C\u002Fp>\n\n\u003Cp>\u003Cstrong>芦苇\u003C\u002Fstrong>\n\u003Cimg src=\"https:\u002F\u002Fimage.duguying.net\u002F2023\u002F02\u002Fx47lhgk3.webp\" alt=\"x47lhgk3\" \u002F>\u003C\u002Fp>\n\n\u003Cp>这天天气很炎热，人也很多。\u003C\u002Fp>\n",{"id":49,"title":50,"uri":51,"author":10,"tags":52,"created_at":55,"view_count":56,"content":57},90,"M1 Macbook Pro 使用初体验","first-experience-in-m1-macbook-pro",[53,54],"M1","Macbook","2023-02-20 21:38:29",201,"\u003Cp>最近体验了一段时间 M1 芯片的 Macbook Pro，我不得不承认，是我当初低估了它。简单的聊一下使用体验。\u003C\u002Fp>\n\n\u003Cp>首先说一下我的日常使用电脑场景，vscode 窗口若干（3到5个窗口），远程开发。chrome 3到4组，每组20-30个tab，微信，QQ，企业微信（消息量4k+），基于electron的ssh终端，Microsoft TODO，Microsoft Remote Desktop，基于Chrome插件的youtube客户端（偶尔划个水）。\u003C\u002Fp>\n\n\u003Cp>我原来的 Macbook Pro 是 Intel i7 的，内存32G，用起来不卡顿，但是风扇能够听到明显的声音，键盘很热，Touchbar位置的外壳烫手。\u003C\u002Fp>\n\n\u003Cp>我现在体验的 Macbook Pro 14寸是M1处理器（8核，4E4P）,16G内存。虽然只有16G内存，使用起来一点也不卡顿，并且键盘几近冰凉，Touchbar位置外壳仅有一点点温度。\u003C\u002Fp>\n\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fimage.duguying.net\u002F2023\u002F02\u002Fp9uz43hp.webp\" alt=\"p9uz43hp\" \u002F>\u003C\u002Fp>\n\n\u003Cp>可以看到，温度只有43度，风扇根本没转起来，事实上这台电脑从我拿到手到现在一个多星期风扇几乎一直是没转过。当然，还有一个很明显的地方就是，不插电的情况下续航时间明显比我原来的 Macbook Pro 长多了。\u003C\u002Fp>\n\n\u003Cp>对比一下我 Intel 处理器的 Macbook Pro。\u003C\u002Fp>\n\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fimage.duguying.net\u002F2023\u002F02\u002Fjpttxbxw.webp\" alt=\"jpttxbxw\" \u002F>\u003C\u002Fp>\n\n\u003Cp>注意，这是我使用 Turbo Boost Switcher 强制关闭了 CPU 的 Boost 能力之后的表现，且是开机5分钟后的温度（并没有重度使用），然而多使用一会儿之后，温度很快就到达60度以上了。\u003C\u002Fp>\n\n\u003Cp>总结一下，M1是真香，流畅、凉爽、持久。\u003C\u002Fp>\n",{"title":59,"list":60},"最热文章",[61,67,73,79,85,91,97,103,109,115],{"id":62,"title":63,"uri":64,"author":10,"created_at":65,"view_count":66},28,"docker容器目录与主机目录同步","\u002Farticle\u002Fdocker容器目录与主机目录同步","2014-12-31 12:34:08",15589,{"id":68,"title":69,"uri":70,"author":10,"created_at":71,"view_count":72},21,"beego中使用fis","\u002Farticle\u002Fbeego中使用fis","2014-12-03 10:47:56",9270,{"id":74,"title":75,"uri":76,"author":10,"created_at":77,"view_count":78},20,"用github登录，oauth开发","\u002Farticle\u002F用github登录，oauth开发","2014-11-23 13:33:37",9145,{"id":80,"title":81,"uri":82,"author":10,"created_at":83,"view_count":84},18,"windows服务注册工具nssm","\u002Farticle\u002Fwindows服务注册工具nssm","2014-10-31 21:34:39",9071,{"id":86,"title":87,"uri":88,"author":10,"created_at":89,"view_count":90},49,"用latex排版中文书籍","\u002Farticle\u002F用latex排版中文书籍","2016-10-31 11:12:02",8687,{"id":92,"title":93,"uri":94,"author":10,"created_at":95,"view_count":96},19,"texlive中文书签乱码","\u002Farticle\u002Ftexlive中文书签乱码","2014-11-15 02:54:01",8484,{"id":98,"title":99,"uri":100,"author":10,"created_at":101,"view_count":102},6,"Windows上的软件包管理器chocolatey","\u002Farticle\u002FWindows上的软件包管理器chocolatey","2014-08-10 15:55:22",8023,{"id":104,"title":105,"uri":106,"author":10,"created_at":107,"view_count":108},3,"利用开源和免费资源搭建CI环境","\u002Farticle\u002F利用开源和免费资源搭建CI环境","2014-07-04 16:54:58",7759,{"id":110,"title":111,"uri":112,"author":10,"created_at":113,"view_count":114},16,"php-fpm网站目录权限配置","\u002Farticle\u002Fphp-fpm网站目录权限配置","2014-10-18 01:36:10",7287,{"id":116,"title":117,"uri":118,"author":10,"created_at":119,"view_count":120},27,"sublime text 2插件开发，外部修改文件无法重新加载","\u002Farticle\u002Fsublime text 2插件开发，外部修改文件无法重新加载","2014-12-26 20:24:13",7063,{"title":122,"list":123},"按月归档",[124,128,131,134,137,140,143,147,151,154,157,160,164,167,170,174,177,180,183,187,190,193,196,199,202,205,208,211,214,217,220,223,226,229,232,235,238,241,244,247,251,254,257,260,263,266],{"title":125,"uri":126,"view_count":127},"2026年7月","\u002Farchive\u002F2026\u002F7\u002F1","[1]",{"title":129,"uri":130,"view_count":127},"2026年1月","\u002Farchive\u002F2026\u002F1\u002F1",{"title":132,"uri":133,"view_count":127},"2025年4月","\u002Farchive\u002F2025\u002F4\u002F1",{"title":135,"uri":136,"view_count":127},"2024年6月","\u002Farchive\u002F2024\u002F6\u002F1",{"title":138,"uri":139,"view_count":127},"2024年5月","\u002Farchive\u002F2024\u002F5\u002F1",{"title":141,"uri":142,"view_count":127},"2024年4月","\u002Farchive\u002F2024\u002F4\u002F1",{"title":144,"uri":145,"view_count":146},"2023年12月","\u002Farchive\u002F2023\u002F12\u002F1","[6]",{"title":148,"uri":149,"view_count":150},"2023年11月","\u002Farchive\u002F2023\u002F11\u002F1","[2]",{"title":152,"uri":153,"view_count":127},"2023年10月","\u002Farchive\u002F2023\u002F10\u002F1",{"title":155,"uri":156,"view_count":127},"2023年7月","\u002Farchive\u002F2023\u002F7\u002F1",{"title":158,"uri":159,"view_count":150},"2023年6月","\u002Farchive\u002F2023\u002F6\u002F1",{"title":161,"uri":162,"view_count":163},"2023年5月","\u002Farchive\u002F2023\u002F5\u002F1","[3]",{"title":165,"uri":166,"view_count":150},"2023年4月","\u002Farchive\u002F2023\u002F4\u002F1",{"title":168,"uri":169,"view_count":150},"2023年3月","\u002Farchive\u002F2023\u002F3\u002F1",{"title":171,"uri":172,"view_count":173},"2023年2月","\u002Farchive\u002F2023\u002F2\u002F1","[5]",{"title":175,"uri":176,"view_count":127},"2023年1月","\u002Farchive\u002F2023\u002F1\u002F1",{"title":178,"uri":179,"view_count":150},"2022年12月","\u002Farchive\u002F2022\u002F12\u002F1",{"title":181,"uri":182,"view_count":173},"2022年11月","\u002Farchive\u002F2022\u002F11\u002F1",{"title":184,"uri":185,"view_count":186},"2022年10月","\u002Farchive\u002F2022\u002F10\u002F1","[4]",{"title":188,"uri":189,"view_count":146},"2022年9月","\u002Farchive\u002F2022\u002F9\u002F1",{"title":191,"uri":192,"view_count":173},"2022年8月","\u002Farchive\u002F2022\u002F8\u002F1",{"title":194,"uri":195,"view_count":127},"2019年7月","\u002Farchive\u002F2019\u002F7\u002F1",{"title":197,"uri":198,"view_count":127},"2019年2月","\u002Farchive\u002F2019\u002F2\u002F1",{"title":200,"uri":201,"view_count":127},"2018年9月","\u002Farchive\u002F2018\u002F9\u002F1",{"title":203,"uri":204,"view_count":127},"2018年8月","\u002Farchive\u002F2018\u002F8\u002F1",{"title":206,"uri":207,"view_count":127},"2017年11月","\u002Farchive\u002F2017\u002F11\u002F1",{"title":209,"uri":210,"view_count":127},"2017年8月","\u002Farchive\u002F2017\u002F8\u002F1",{"title":212,"uri":213,"view_count":127},"2017年5月","\u002Farchive\u002F2017\u002F5\u002F1",{"title":215,"uri":216,"view_count":127},"2017年4月","\u002Farchive\u002F2017\u002F4\u002F1",{"title":218,"uri":219,"view_count":127},"2016年11月","\u002Farchive\u002F2016\u002F11\u002F1",{"title":221,"uri":222,"view_count":127},"2016年10月","\u002Farchive\u002F2016\u002F10\u002F1",{"title":224,"uri":225,"view_count":150},"2016年9月","\u002Farchive\u002F2016\u002F9\u002F1",{"title":227,"uri":228,"view_count":127},"2016年8月","\u002Farchive\u002F2016\u002F8\u002F1",{"title":230,"uri":231,"view_count":150},"2016年7月","\u002Farchive\u002F2016\u002F7\u002F1",{"title":233,"uri":234,"view_count":173},"2016年6月","\u002Farchive\u002F2016\u002F6\u002F1",{"title":236,"uri":237,"view_count":127},"2015年12月","\u002Farchive\u002F2015\u002F12\u002F1",{"title":239,"uri":240,"view_count":127},"2015年10月","\u002Farchive\u002F2015\u002F10\u002F1",{"title":242,"uri":243,"view_count":150},"2015年2月","\u002Farchive\u002F2015\u002F2\u002F1",{"title":245,"uri":246,"view_count":127},"2015年1月","\u002Farchive\u002F2015\u002F1\u002F1",{"title":248,"uri":249,"view_count":250},"2014年12月","\u002Farchive\u002F2014\u002F12\u002F1","[8]",{"title":252,"uri":253,"view_count":150},"2014年11月","\u002Farchive\u002F2014\u002F11\u002F1",{"title":255,"uri":256,"view_count":173},"2014年10月","\u002Farchive\u002F2014\u002F10\u002F1",{"title":258,"uri":259,"view_count":163},"2014年9月","\u002Farchive\u002F2014\u002F9\u002F1",{"title":261,"uri":262,"view_count":163},"2014年8月","\u002Farchive\u002F2014\u002F8\u002F1",{"title":264,"uri":265,"view_count":163},"2014年7月","\u002Farchive\u002F2014\u002F7\u002F1",{"title":267,"uri":268,"view_count":150},"2013年9月","\u002Farchive\u002F2013\u002F9\u002F1",5,{"url":271,"title":272},"https:\u002F\u002Fimage.duguying.net\u002F2022\u002F09\u002Fij6x8o4s.webp","老家 摄于2020年秋",1793790238725]