Google搜索指令

1. site site: 搜索指定站点 用法: site:[example.com] 示例: golang site:github.com 2. source source: 在谷歌新闻中指定来源 用法: source:[sourcesite] 示例: COVID source:yahoo 3. intext intext: 查询的内容必须出现在正文中 用法: intext:[somewords] 示例: intext:xiaomi 4. allintext allintext: 查询的每个单词都必须包含在页面中 用法: allintext:[somewords] 示例: allintext:Quantum Network Coding 5. intitle intitle: 标题中包含要查询的内容 用法: intitle:[somewords] 示例: intitle:Quantum 6. allintitle allintitle: 类似allintext 7. url url:结果的url中必须包含某些内容 用法: url:[somewords] 示例: url:airpods 8. allinurl allinurl: 结果的url必须包含所有查询内容 9. filetype filetype: 查询的结果满足某种文件类型 用法: filetype:[filetype] 示例: golang filetype:pdf 10. related related: 查找有关内容...

December 22, 2021 · 2 min · 李昌

croc: 跨网络、跨系统的空投

1. install curl https://getcroc.schollz.com | bash 或 go install github.com/schollz/croc/v9@latest 2. basic usage sender: $ croc send [file(s)-or-folder] Sending 'file-or-folder' (X MB) Code is: code-phrase receiver: croc code-phrase 3. comment 可用于替代ftp上传文件,用于不同主机之间文件共享,类似“空投”的效果

December 21, 2021 · 1 min · 李昌

z

install z # Download to latest to home dir wget https://raw.githubusercontent.com/rupa/z/master/z.sh -O ~/z.sh # Add to .bashrc echo . /path/to/z.sh >> ~/.bashrc # Add to .zshrc echo . /path/to/z.sh >> ~/.zshrc

December 12, 2021 · 1 min · 李昌

HTTP2简介

这是一篇理论性较强的文章 1. HTTP/1的不足与面临的问题 此部分内容来自:https://segmentfault.com/a/1190000013519925 1.1 HTTP/1概述 1.2 队头阻塞 浏览器很少只从一个域名获取一份资源。大多数时候,它希望能同时获取许多资源。设想这样一个网站,它把所有图片放在单个特定域名下。HTTP/1 并未提供机制来同时请求这些资源。如果仅仅使用一个连接,它需要发起请求、等待响应,之后才能发起下一个请求。这显然会在加载页面时造成较大的延迟,降低了用户体验。 h1 有个特性叫 管道化(pipelining),允许一次发送一组连续的请求,而不用等待应答返回。这样可以避免连接延迟。但是该特性只能按照发送顺序依次接收响应。而且,管道化备受互操作性和部署的各种问题的困扰,基本没有实用价值。 在请求应答过程中,如果出现任何状况,剩下所有的工作都会被阻塞在那次请求应答之后。这就是队头阻塞(Head-of-line blocking或缩写为HOL blocking),它会阻碍网络传输和 Web 页面渲染,直至失去响应。 为了防止这种问题,现代浏览器会针对单个域名开启 6 个连接,通过各个连接分别发送请求。它实现了某种程度上的并行,但是每个连接仍会受到 队头阻塞 的影响。另外,这也没有高效利用有限的设备资源。 1.3 TCP复用 传输控制协议(TCP) 的设计思路是:对假设情况很保守,并能够公平对待同一网络的不同流量的应用。它的避免拥塞机制被设计成即使在最差的网络状况下仍能起作用,并且如果有需求冲突也保证相对公平。这是它取得成功的原因之一。 它的成功并不是因为传输数据最快,而是因为它是最可靠的协议之一,涉及的核心概念就是 拥塞窗口(congestion window) 。拥塞窗口是指,在接收方确认数据包之前,发送方可以发出的 TCP 包的数量。 例如,如果拥塞窗口指定为 1,那么发送方发出 1 个数据包之后,只有接收方确认了那个包,才能发送下一个。 一般来讲,每次发送一个数据包并不是非常低效。TCP 有个概念叫 慢启动(Slow Start), 它用来探索当前连接对应拥塞窗口的合适大小。慢启动的设计目标是为了让新连接搞清楚当前网络状况,避免给已经拥堵的网络继续添乱。它允许发送者在收到每个确认回复后额外发送 1 个未确认包。这意味着新连接在收到 1 个确认回复之后,可以发送 2 个数据包; 在收到 2 个确认回复之后,可以发 4 个;以此类推。这种几何级数增长很快就会到达协议规定的发包数上限,这时候连接将进入拥塞避免阶段 这种机制需要几次往返数据请求才能得知最佳拥塞窗口大小。但在解决性能问题时,就这 区区几次数据往返也是非常宝贵的时间(成本)。现代操作系统一般会取 4~10 个数据包作为初始拥塞窗口大小。如果你把一个数据包设置为最大值下限 1460 字节(也就是 最大有效负载),那么只能先发送 5840 字节(假定拥塞窗口为 4),然后就需要等待接收确认回复。 如今的 Web 页面平均大小约 2MB,包括 HTML 和所有依赖的资源。在理想情况下, 这需要大约 9 次往返请求来传输完整个页面。除此之外,浏览器一般会针对同一个域名开启 6 个并发连接,这意味着拥塞窗口波动也会并行发生 6 次。TCP 协议保证那些连接都能正常工作, 但是不能保证它们的性能是最优的。...

December 11, 2021 · 3 min · 李昌

量子关联与量子失协

1. 互信息量 信息熵(香农熵) $$ H(A) = - \sum_{x\in X}p(x)\log p(x) $$ 信息熵度量了信息量的多少。如英语有26个字母,加入每个字母在文章中出现次数相同的话,每个字母的信息量为: $$ I_e = -\log_2{\frac{1}{26}}=4.7 $$ 若有一个字母出现次数为总次数的一半,则其信息熵为: $$ I_e = -\log_2{\frac{1}{2}} = 1 $$ 以上例子说明,某一个信息出现次数越多,其信息量就越少。直观的说,某一篇文章中,“的”,“我”等词语可能出现次数最多,但其能为我们带来的信息可能并不是那么多。 经典互信息量 假定我们在一系列的不同时刻$(t_1, t_2, \dots, t_N)$对一个给定的系统进行连续测量,把每次测量结果记为$x_1, x_2,\dots, x_N$,每个测量序列的结果都有不同的概率输出,将之记为$p(x_1), p(x_2), \dots, p(x_N)$. 则关联就意味着对于任意的$1\le n \le N$,这些概率分布不会以乘积的形式出现,即$p(x_1, x_2, \dots, x_n)*p(x_n+1, x_n+2, \dots, x_N)$。用通俗易懂的话来说,就是这些概率分布不是相互独立的。 简单起见,我们将所有测量分为两组A和B,这样A和B之间的互信息量就定义为: $$ I(A:B) = H(A)+H(B) - H(A,B), where\ H(A) = - \sum_{x\in X}p(x)\log p(x) $$ 又,根据贝叶斯定理$H(A|B)=H(A,B)-H(B)$,经典互信息量还有一个等价的表达方式: $$ C(A:B)=H(A)-H(A|B) $$ 其中$H(A|B)$表示在知道B体系测量结果情况下A体系的条件熵。因此,经典互信息量度量了在对B测量时所能提取的A的信息量。 2. 量子互信息量 将经典互信息量的理论推广到量子系统,这样就能得到量子互信息量的概念,考虑一个两体的量子态$\rho_{AB}$,量子互信息量定义为: $$ I(\rho_{AB})=S(\rho_{A})+S(\rho_{B})-S(\rho_{AB}) $$ 其中$S(\rho)=-tr\rho\log(\rho)$为冯·诺伊曼熵,($tr$指求迹,即求矩阵对角线元素之和),$\rho_A$和$\rho_B$分别为$\rho_{AB}$的约化密度矩阵。...

November 28, 2021 · 1 min · 李昌

体验过的最好的云笔记方式

0. 前记 作为一个技术人员, 一个笔记软件对于我们来说必不可少,每个人对笔记软件的需求又各不相同。对于我来说,我希望一个云笔记的功能包括:markdown支持、latex公式编辑、很好的版本控制、可以方便的分享、可以方便的导出/导入、代码块支持、图片插入等。 我用过很多云笔记软件,印象笔记、为知笔记、有道云、Notion、OneNote等,这些市面上常见的云笔记软件均有一个问题,就是你用了一段时间后,发现自己被限制在里面了,你无法对你的笔记进行导出,更换一个你觉得更好的笔记软件。这对我来说是不可接受的,我希望我的笔记可以满足三个要求: 好用,能够支持markdown通用格式 数据完全受我控制,我可以任意移动、复用等 数据要能安全的存储在云端,有备份 因此,我后来又使用了jupyter notebook,用过jupyter的同学知道,我们可以在上面编辑代码,markdown和latex也被很好的支持,而又由于jupyter的源文件是文本文件,因此我们可以方便的使用git对其进行版本控制,这种方式可以说满足了我的绝大部分需要,是一种非常nice的笔记方式。 但今天我们要说的是另一种非常纯粹的方式,只把笔记源文件存储为markdown,这样我们可以用任何编辑器书写,然后用git进行版本控制,用Github Pages进行展示与分享,具体过程如下。 1. hugo的使用 为什么要用hugo?首先我们需要一种分享展示笔记的方式,将其编译为静态网站是一个不错的选择。除了hugo,我们也可以使用hexo等类似的静态网站编译工具。 1.1 安装hugo 到GitHub上hugo的release页面下载你的系统需要的版本,比如我的系统为64位Linux,那么我需要下载hugo_*.**.*_Linux-64bit.tar.gz(中间的星号为版本号,这里代表你可以任意选择)。 将其下载到本地之后,解压安装。 tar -zxvf hugo_0.89.2_Linux-64bit.tar.gz sudo mv hugo /usr/local/bin 安装完成 1.2 开始 hugo的使用炒鸡简单,你只需要使用 hugo new site MySite # 你可以取一个好听的名字 即可新建一个名为MySite的网站 1.2 为你的网站选择一个theme 进入到我们刚才建立的网站目录 cd Mysite/ 从GitHub导入你想应用的主题 git submodule add git@github.com:adityatelange/hugo-PaperMod.git themes/PaperMod --depth=1 待下载完成后,还需要修改你的配置文件 baseURL = "http://your-user-name.github.io/Mysite/" # 使用你自己的用户名 languageCode = "en-us" title = "My New Hugo Site" theme = "PaperMod" 1....

November 13, 2021 · 2 min · 李昌

本地事务的隔离

摘抄自:极客时间《周志明的软件架构课》 1. 数据库中的三种锁 写锁(Write Lock,也叫做排他锁 eXclusive Lock,简写为 X-Lock):只有持有写锁的事务才能对数据进行写入操作,数据加持着写锁时,其他事务不能写入数据,也不能施加读锁。 读锁(Read Lock,也叫做共享锁 Shared Lock,简写为 S-Lock):多个事务可以对同一个数据添加多个读锁,数据被加上读锁后就不能再被加上写锁,所以其他事务不能对该数据进行写入,但仍然可以读取。对于持有读锁的事务,如果该数据只有一个事务加了读锁,那可以直接将其升级为写锁,然后写入数据。 范围锁(Range Lock):对于某个范围直接加排他锁,在这个范围内的数据不能被读取,也不能被写入。如下语句是典型的加范围锁的例子: SELECT * FROM books WHERE price < 100 FOR UPDATE; 2. 本地事务的四种隔离级别 以下隔离级别从高到低 可串行化 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。 串行化访问提供了强度最高的隔离性。可串行化比较符合普通程序员对数据竞争加锁的理解,如果不考虑性能优化的话,对事务所有读、写的数据全都加上读锁、写锁和范围锁即可(这种可串行化的实现方案称为 Two-Phase Lock)。 但数据库显然不可能不考虑性能,并发控制理论(Concurrency Control)决定了隔离程度与并发能力是相互抵触的,隔离程度越高,并发访问时的吞吐量就越低。现代数据库一定会提供除可串行化以外的其他隔离级别供用户使用,让用户调节隔离级别的选项,这样做的根本目的是让用户可以调节数据库的加锁方式,取得隔离性与吞吐量之间的平衡。 可重复读 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。 可串行化的下一个隔离级别是可重复读(Repeatable Read)。可重复读的意思就是对事务所涉及到的数据加读锁和写锁,并且一直持续到事务结束,但不再加范围锁。 可重复读比可串行化弱化的地方在于幻读问题(Phantom Reads),它是指在事务执行的过程中,两个完全相同的范围查询得到了不同的结果集。比如现在准备统计一下书店中售价小于 100 元的书有多少本,就可以执行以下第一条 SQL 语句: SELECT count(1) FROM books WHERE price < 100 /* 时间顺序:1,事务: T1 */ INSERT INTO books(name,price) VALUES ('深入理解Java虚拟机',90) /* 时间顺序:2,事务: T2 */ SELECT count(1) FROM books WHERE price < 100 /* 时间顺序:3,事务: T1 */ 可重复读级别对事务涉及到的数据加读锁和写锁,但不再加范围锁。这里事务T1中涉及的数据是原来数据库中已经存在的数据,但新插入的条目显然不在这个范围内。因此在事务T1再次执行读的时候就会与第一次读的结果不同。原因就是,可重复读没有范围锁来禁止在该范围内插入新的数据。...

October 8, 2021 · 2 min · 李昌

TCMalloc : Thread-Caching Malloc

翻译自:TCMalloc : Thread-Caching Malloc(性能测试部分没有翻译) 动机 在我测试过的所有malloc(动态内存分配器)中,TCMalloc比glibc 2.3 malloc(作为一个单独的库称作ptmalloc2)以及其他内存分配器都要快。对于小内存对象来说,在Intel® Pentium® 4 Processor 2.80 GHzCPU上ptmalloc2执行一次内存分配/回收操作需要大约300ns,而TCMalloc完成相同的操作只需要50ns。显然对于内存分配操作来说,速度十分重要,因为如果内存分配不够及时,开发人员就倾向于在malloc上编写他们自己的空闲列表,这会造成额外的复杂性以及更多的内存占用,除非开发人员非常小心的估算空闲列表的大小并清理其中的空闲对象。 TCMalloc也降低了多线程应用中的锁冲突。对于小内存对象来说几乎不存在冲突。对于大内存对象来说,TCMalloc尝试使用细粒度和高效的自旋锁。ptmalloc2也尝试通过一些方法降低锁冲突,其为每个线程分配一个arena空间,但ptmalloc2对于arena空间的使用存在一个大问题:在ptmalloc2中内存将不可能从一个arena空间转移到另一个arena空间,也即内存不可以在线程之间进行二次分配。这会导致巨大的内存浪费。例如,在一个Google应用中,阶段一为其数据结构分配了大约300MB。当其第一阶段结束后,阶段二将在相同的地址空间上开始。如果阶段二分配了一个与阶段一不同的arena空间,那么阶段二的计算将不会重复使用阶段一留下的任何内存空间,而是重新分配另一个300MB内存空间。这种内存的“blowup”问题同样出现在其他应用中。 TCMolloc的另一个优点是针对小内存对象的空间的有效利用。例如,可以将8N bytes大小的对象分配到8N*1.01bytes的空间上,即只需要1%的空间开销。ptmalloc2对每一个对象分配一个4bytes的头,(我认为)这种方式将本来只需要8N bytes大小对象变成了需要16N bytes 用法 要想使用TCMalloc,只要使用-l tcmalloc标志将tcmalloc链接到你的应用。 你也可以在不是你编译的应用中使用tcmalloc,通过使用LD_PRELOAD环境变量 LD_PRELOAD="/usr/lib/libtcmalloc.so" 但我们不推荐在非必要的情况下使用这种方式。 TCMalloc也包括一个堆检查器和一个堆分析器。 如果你只想要链接一个没有堆检查器和分析器的TCMalloc版本(可能想要减小二进制包的大小),你可以链接libtcmalloc_minimal 概览 TCMalloc为每个线程分配一个本地线程缓存thread-local cache。小的内存分配将直接被本地线程缓存满足。对象按需从中间部件central data structure移动到本地线程缓存。定期的垃圾收集被用来把内存从本地线程缓存放回中间部件central data structure。 TCMalloc对于大小<=32K的(小)对象的处理方式与大对象不同。大对象由顶层堆管理器central heap使用页级的分配器直接分配。(一个页面是一个4K对齐的内存区域),同时,大对象总是页对齐并且占据整数个页面。 页面可被一系列的小对象瓜分为大小相同的区域。例如:一个4K的内存将被32个对象分割为每个128bytes的内存序列。 小对象的分配 每个小对象都对应于170个可分配内存大小size-classes中的一种,例如,大小范围在961-1024bytes的对象将占据1024bytes。这些内存大小级别被不同大小的间距分隔开,其中较小尺寸为8bytes,大尺寸为16bytes,更大的是32bytes,以此类推。最大的空间是256bytes(对于size-classes)大于等于2k。 本地线程缓存thread-local cache持有不同size-class的空闲链表。 当分配一个小对象时: 将其大小映射到相应的size-class 为当前线程在其thread-local cache的(内存)空闲链表中寻找对应size-class链表 如果空闲链表非空,那么我们将链表的第一个对象移出并返回之,当执行这种快速路径时,TCMalloc不需要任何锁,因为加锁解锁这一对操作在2.8GHz的机器上大约需要100ns,这使得内存分配速度明显加快。 如果空闲链表为空: 从central free list(central data structure)获取一系列对应大小的内存。(central data structure被所有线程共享) 将获取到的内存放入thread-local cache的空闲链表。 返回其中一个新获取的内存对象给应用 如果central free list也为空: 从central page allocator(central heap)分配一系列页面 将这些页面分割为对应size-class大小的内存对象 将这些新的内存对象放入central free list 像之前所说将内存对象放入thread-local free list 大内存的分配 大对象被对齐到页大小(4K),并且被central page heap管理。central page heap同样是一个空闲列表数组。当数组下标i小于256时,第k个数组元素是一个每个节点包含k个页的空闲列表,而第256个数组元素中,链表的节点长度大于256页...

September 30, 2021 · 1 min · 李昌

端口消耗问题

1. 两种端口 我们知道TCP/UDP在工作时都需要一个端口来进行收发信息,有两种类型的端口: 临时端口或者叫动态端口,是默认情况下计算机进行出站连接时所有的端口集 已知端口,是特定应用程序或服务的定义端口。 例如,文件服务器服务在端口 445 上,HTTPS 为 443,HTTP 为 80,RPC 为 135。 自定义应用程序还将具有其定义的端口号。 客户端要想连接到应用程序或服务,需要使用计算机中的临时端口去连接服务器的已知端口。如:客户端计算机上的浏览器将使用临时端口连接到端口 https://www.microsoft.com 443。 当浏览器创建与多个网站的大量连接的情况下,其所尝试的任何新连接都将使用临时端口。 一段时间之后,连接将开始失败,并且出现此故障的可能性很高,因为浏览器已使用所有可用端口进行外部连接,并且建立连接的任何新尝试都将失败,因为没有更多的端口可用。 当使用计算机上的所有端口时,我们将它视为端口耗尽。 2. TCP/IP的默认动态端口范围 window上有两种动态端口范围: 起始端口49152,结束端口65535 (新版) 起始端口1025,结束端口5000(旧版) 可使用如下命令查看计算机上动态端口范围: netsh int ipv4 show dynamicport tcp netsh int ipv4 show dynamicport udp netsh int ipv6 show dynamicport tcp netsh int ipv6 show dynamicport udp 也可以手动更改动态端口的范围: netsh int <ipv4|ipv6> set dynamic <tcp|udp> start=number num=range 其中start是起始端口号,num是范围 例如: netsh int ipv4 set dynamicport tcp start=10000 num=1000 netsh int ipv4 set dynamicport udp start=10000 num=1000 netsh int ipv6 set dynamicport tcp start=10000 num=1000 netsh int ipv6 set dynamicport udp start=10000 num=1000 这些示例命令将动态端口范围设置为从10000开始,分配1000个动态端口,即:10000-19999。可以设置的最小端口范围是255,可以设置的最小起始端口为1025。若要复制 Windows Server 2003 的默认行为,请使用 1025 作为起始端口,然后使用 3976 作为 TCP 和 UDP 的范围。 这导致起始端口为 1025,结束端口为 5000。

September 28, 2021 · 1 min · 李昌

golang中的tag

1. tag的基本介绍 字段标签可以存储元信息,这些元信息可以使用反射来访问。通常这些元信息用来提供一个字段如何从一种格式编码至另一种格式的相关信息(或是数据应如何在数据库中存储等)。但实际上标签可以存储任何你想要的元信息,无论是你自己使用还是由另一个包使用。 就像reflect.StructTag文档中提到的那样,字段标签通常是由空格分割的key:"value"列表,例如: type User struct { Name string `json:"name" xml:"name"` } 其中的key通常表示后面"value"所对应的包,例如json这个key将被encoding/json这个包使用。 如果需要在"value"中传递多个值,那么通常使用,逗号来分割,例如: Name string `json:"name,omitempty" xml:"name"` 值为破折号通常代表在处理时忽略该字段,例如在json中代表不要序列化这个字段 2. 例子:获取自定义tag 我们可以使用反射包来获取结构体字段的值。首先我们需要获取结构体的Type,然后查询字段,可以使用Type.Field(i int)或者Type.FieldByName(name string)。这些方法返回一个代表结构体字段的StructField值和一个代表tag的类型为StructTag的StructField.Tag值。 前面我们提到,字段标签通常是由空格分割的key:"value"列表,如果你的确是这么做的,你可以使用StructTag.Get(key string)这个方法来获取这个key对应的value。如果你不是这么做的,Get()方法可能不能解析key:"value"对并找到你想要的标签。如果你没有遵循字段标签通常是由空格分割的key:"value"列表,那么你可能需要实现自己的解析逻辑。 go1.7中添加了StructTag.Lookup()方法,这个方法的行为类似于Get(),但其将不包含给定键的标签与将空字符串与给定键相关联的标签区分开来。 来看下面这个例子: type User struct { Name string `mytag:"MyName"` Email stirng `mytag:"MyEmail"` } u := User{"Bob", "bob@cc.com"} t := reflect.TypeOf(u) for _ fieldName := range []string{"Name", "Email"} { field, found := t.FieldByName(fieldName) if !found { continue } fmt.Printf("\nField: User.%s\n", fieldName) fmt.Printf("\tWhole tag value : %q\n", field....

September 14, 2021 · 2 min · 李昌