<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Golang | w3xse7en</title>
    <link>https://w3xse7en.github.io/docs/lang/</link>
      <atom:link href="https://w3xse7en.github.io/docs/lang/index.xml" rel="self" type="application/rss+xml" />
    <description>Golang</description>
    <generator>Wowchemy (https://wowchemy.com)</generator><language>zh</language>
    <image>
      <url>https://w3xse7en.github.io/images/icon_hua2ec155b4296a9c9791d015323e16eb5_11927_512x512_fill_lanczos_center_2.png</url>
      <title>Golang</title>
      <link>https://w3xse7en.github.io/docs/lang/</link>
    </image>
    
    <item>
      <title>Go</title>
      <link>https://w3xse7en.github.io/docs/lang/go/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://w3xse7en.github.io/docs/lang/go/</guid>
      <description>&lt;h2 id=&#34;select&#34;&gt;select&lt;/h2&gt;
&lt;p&gt;go select思想来源于网络IO模型中的select，本质上也是IO多路复用，只不过这里的IO是基于channel而不是基于网络，同时go select也有一些自己不同的特性。&lt;/p&gt;
&lt;h3 id=&#34;特性&#34;&gt;特性:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;每个case都必须是一个通信&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所有channel表达式都会被求值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所有被发送的表达式都会被求值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果任意某个通信可以进行，它就执行；其他被忽略。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果有多个case都可以运行，select会随机公平地选出一个执行。其他不会执行。否则执行default子句(如果有)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果没有default字句，select将阻塞，直到某个通信可以运行；Go不会重新对channel或值进行求值。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;冷知识：select 使用 c语言 的AsyncCall2函数 该函数执行时间为 200ms&lt;/p&gt;
&lt;p&gt;问题：分别指定耗时50ms，200ms，3000ms，select打印最先完成的异步调用耗时，预想：50ms 先 200ms 后，结果：50ms 与 200ms 随机出现&lt;/p&gt;
&lt;h3 id=&#34;用途&#34;&gt;用途&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;结合特性5,6，可以通过带 default 语句的 select 实现非阻塞读写&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结合特性2，每次 select 都会对所有通信表达式求值，因此可通过 time.After简洁实现定时器功能，并且定时任务可通过 done channel 停止&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结合特性4，如果多个case满足读写条件，select会随机选择一个语句执行&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;br&gt;
&lt;h2 id=&#34;context&#34;&gt;context&lt;/h2&gt;
&lt;p&gt;context.Context 是用来设置截止日期、同步信号，传递请求相关值的结构体。&lt;/p&gt;
&lt;p&gt;在 Goroutine 构成的树形结构中对信号进行同步以减少计算资源的浪费是 context.Context 的最大作用&lt;/p&gt;
&lt;p&gt;每一个 context.Context 都会从最顶层的 Goroutine 一层一层传递到最下层。context.Context 可以在上层 Goroutine 执行出现错误时，将信号及时同步给下层&lt;/p&gt;
&lt;p&gt;当最上层的 Goroutine 因为某些原因执行失败时，下层的 Goroutine 由于没有接收到这个信号所以会继续工作；但是当我们正确地使用 context.Context 时，就可以在下层及时停掉无用的工作以减少额外资源的消耗&lt;/p&gt;
&lt;h1 id=&#34;defer&#34;&gt;defer&lt;/h1&gt;
&lt;p&gt;defer 是否会在panic后执行&lt;/p&gt;
&lt;h1 id=&#34;interface&#34;&gt;interface&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;writing generic algorithm&lt;/li&gt;
&lt;li&gt;hiding implementation detail&lt;/li&gt;
&lt;li&gt;providing interception points&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;interface拥有两个指针
一个指向类型 一个指向具体值&lt;/p&gt;
&lt;h1 id=&#34;slice&#34;&gt;slice&lt;/h1&gt;
&lt;p&gt;分配在连续的内存地址上&lt;/p&gt;
&lt;p&gt;元素类型一致，元素存储宽度一致&lt;/p&gt;
&lt;p&gt;空间大小固定，不能修改&lt;/p&gt;
&lt;p&gt;可以通过索引计算出元素对应存储的位置（只需要知道数组内存的起始位置和数据元素宽度即可）&lt;/p&gt;
&lt;p&gt;会出现数据溢出的问题（下标越界）&lt;/p&gt;
&lt;h2 id=&#34;slice扩容&#34;&gt;slice扩容&lt;/h2&gt;
&lt;p&gt;如果新的slice大小是当前大小2倍以上，则大小增长为新大小&lt;/p&gt;
&lt;p&gt;如果当前slice cap 小于1024，按每次2倍增长，否则每次按当前大小1/4增长。直到增长的大小超过或等于新大小&lt;/p&gt;
&lt;p&gt;append的实现是在内存中将slice的array值赋值到新申请的array上&lt;/p&gt;
&lt;p&gt;性能&lt;/p&gt;
&lt;p&gt;通过上面我们知道slice的扩容涉及到内存的拷贝，这样带来的好处是数据存储在连续内存上，比随机访问快很多，最直接的性能提升就是缓存命中率会高很多,这也就是为什么slice不采用动态链表实现的原因吧&lt;/p&gt;
&lt;p&gt;我们知道拷贝内存数据是有开销的， 而其中最大的开销不在 memmove&lt;/p&gt;
&lt;p&gt;数据上，而是在开辟一块新内存malloc及之后的GC压力&lt;/p&gt;
&lt;p&gt;拷贝连续内存是很快的，随着cap变大，拷贝总成本还是 O(N) ,只是常数大了&lt;/p&gt;
&lt;p&gt;假如不想发生拷贝，那你就没有连续内存。此时随机访问开销会是：链表 O(N)&lt;/p&gt;
&lt;p&gt;当你能大致知道所需的最大空间（在大部分时候都是的）时，在make的时候预留相应的 cap 就好
如果需要的空间很大，而且每次都不确定，那就要在浪费内存和耗 CPU 在 malloc + gc 上做权衡
链表的查找操作是从第一个元素开始，所以相对数组要耗时间的多，因为采用这样的结构对读的性能有很大的提高&lt;/p&gt;
&lt;h2 id=&#34;mysql&#34;&gt;mysql&lt;/h2&gt;
&lt;h3 id=&#34;性能调优&#34;&gt;性能调优&lt;/h3&gt;
&lt;h4 id=&#34;sql优化&#34;&gt;SQL优化&lt;/h4&gt;
&lt;p&gt;小表驱动大表
limit限定
索引添加
适当添加冗余字段，减少表关联。&lt;/p&gt;
&lt;h4 id=&#34;系统优化&#34;&gt;系统优化&lt;/h4&gt;
&lt;p&gt;max_connections 最大连接数&lt;/p&gt;
&lt;p&gt;innodb_buffer_pool_size 数据缓冲区buffer pool大小&lt;/p&gt;
&lt;p&gt;sort_buffer_size 排序缓冲区内存大小&lt;/p&gt;
&lt;p&gt;join_buffer_size 使用连接缓冲区大小&lt;/p&gt;
&lt;p&gt;read_buffer_size 全表扫描时分配的缓冲区大小&lt;/p&gt;
&lt;h1 id=&#34;缓存&#34;&gt;缓存&lt;/h1&gt;
&lt;p&gt;主动式缓存
用户更新数据 同时更新缓存&lt;/p&gt;
&lt;p&gt;被动式缓存
用户更新数据 删除缓存，被读取时载入缓存&lt;/p&gt;
&lt;h1 id=&#34;maps&#34;&gt;Maps&lt;/h1&gt;
&lt;p&gt;线程不安全&lt;/p&gt;
&lt;p&gt;底层使用的hash结构&lt;/p&gt;
&lt;p&gt;hash算法使用aes hash hash值分为 高位hash和低位hash&lt;/p&gt;
&lt;p&gt;高位哈希值：是用来确定当前的bucket（桶）有没有所存储的数据的 bmap a bucket for a Go map&lt;/p&gt;
&lt;p&gt;低位哈希值：是用来确定，当前的数据存在了哪个bucket（桶）hmap a header for a go map&lt;/p&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://wudaijun.com/2017/10/go-select/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;go select机制与常见的坑&lt;/a&gt;&lt;/p&gt;
&lt;br/&gt;
&lt;hr&gt;
</description>
    </item>
    
    <item>
      <title>Goroutine</title>
      <link>https://w3xse7en.github.io/docs/lang/goroutine/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://w3xse7en.github.io/docs/lang/goroutine/</guid>
      <description>&lt;h1 id=&#34;goroutine&#34;&gt;goroutine&lt;/h1&gt;
&lt;p&gt;leak 协程泄露
Goroutine为什么没有ID号&lt;/p&gt;
&lt;h2 id=&#34;goroutine调度&#34;&gt;Goroutine调度&lt;/h2&gt;
&lt;p&gt;G P M
抢占式调度&lt;/p&gt;
&lt;p&gt;动态栈&lt;/p&gt;
&lt;h1 id=&#34;协程线程进程的区别&#34;&gt;协程，线程，进程的区别&lt;/h1&gt;
&lt;h1 id=&#34;进程&#34;&gt;进程&lt;/h1&gt;
&lt;p&gt;进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间，不同进程通过进程间通信来通信。由于进程比较重量，占据独立的内存，所以上下文进程间的切换开销（栈、寄存器、虚拟内存、文件句柄等）比较大，但相对比较稳定安全。&lt;/p&gt;
&lt;h4 id=&#34;线程&#34;&gt;线程&lt;/h4&gt;
&lt;p&gt;线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存，上下文切换很快，资源开销较少，但相比进程不够稳定容易丢失数据。&lt;/p&gt;
&lt;h4 id=&#34;协程&#34;&gt;协程&lt;/h4&gt;
&lt;p&gt;协程是一种用户态的轻量级线程，协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时，将寄存器上下文和栈保存到其他地方，在切回来的时候，恢复先前保存的寄存器上下文和栈，直接操作栈则基本没有内核切换的开销，可以不加锁的访问全局变量，所以上下文的切换非常快。&lt;/p&gt;
&lt;h2 id=&#34;channel&#34;&gt;channel&lt;/h2&gt;
&lt;h2 id=&#34;select&#34;&gt;select&lt;/h2&gt;
&lt;h2 id=&#34;sync&#34;&gt;sync&lt;/h2&gt;
</description>
    </item>
    
    <item>
      <title>Q&amp;A</title>
      <link>https://w3xse7en.github.io/docs/lang/qa/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://w3xse7en.github.io/docs/lang/qa/</guid>
      <description>&lt;h1 id=&#34;qa&#34;&gt;Q&amp;amp;A&lt;/h1&gt;
</description>
    </item>
    
  </channel>
</rss>
