《#诗盗#·我类么张》:教主威名顶天扬,挪移失踪烂教纲。殷郎油尽淡淡伤,杨逍无奈朱元璋。
注解
-
我类么:Whatever。
-
挪移失踪烂教纲:领导常年消失不见一般会烂掉。
《#诗盗#·我类么张》:教主威名顶天扬,挪移失踪烂教纲。殷郎油尽淡淡伤,杨逍无奈朱元璋。
我类么:Whatever。
挪移失踪烂教纲:领导常年消失不见一般会烂掉。
最近 MBP15 的硬盘空间告急,打开“磁盘工具”查看,却发现居然有两个“宗卷”!从没认真研究过 macOS 磁盘管理的稣疑惑了。
“磁盘工具”默认“仅显示宗卷”,“显示所有设备”后是这样的:
肉眼观测 disk1 是放在 disk0 里的……嗯,想起容器!但 GUI 有时候是会骗人的,用 diskutil 来检查一下:
1 | $ diskutil list |
以上可知,只有 disk0 是物理的,disk1 是由 disk0s2 这个分区虚拟出来的。
下面查看两者详细信息对比:
1 | $ diskutil info /dev/disk0 |
两者 Virtual 属性的不同,说明前面的猜测是对的。
搜到如下参考:
推理正确!
Bloom filter 是由 Howard Bloom 在 1970 年提出的二进制向量数据结构,具有很好的空间和时间效率,被用来检测一个元素是不是集合的成员。
Bloom filter 采用的是哈希函数的方法,将一个元素映射到一个 m 长度的阵列上的一个点,当这个点是 1 时,那么这个元素可能在集合内,反之则一定不在集合内。
libbloom 是 Bloom filter 的 C 语言实现库,其中哈希函数是 MurmurHash2。
如果检测结果为是,该元素不一定在集合中;但如果检测结果为否,该元素一定不在集合中。
优点:插入和查询时间都是常数。它查询元素却不保存元素本身,节省大量的存储空间。当元素是密码时,不保存元素的特征使其具有良好的安全性。
缺点:存在误报(false positive)。当插入的元素越多,错判“在集合内”的概率就越大。另外 Bloom filter 也不能删除一个元素,因为多个元素哈希的结果可能在 Bloom filter 结构中占用的是同一个位,如果删除了一个比特位,可能会影响多个元素的检测。
以官方 test-basic 为例,简化的代码如下:
1 |
|
输出为:
1 | ->entries = 1002 |
数学原理参考:《Bloom Filter概念和原理》
bytes 是最容易理解的,4802 位需要 601 字节存储。
bits = bits per elem * entries,每个元素需要多少位 * 元素个数。
hash functions = ceil(-ln(error) / ln(2))
bits per elem = -ln(error) / ln(2)^2
Rust 三大设计宗旨:内存安全、零成本抽象、实用。本文从所有权角度来学习师兄妹的爱恨情仇“内存安全”。
值归变量所有。
当变量超出使用范围时,变量值所占用的内存将被释放。这是类似于 C++ 的 RAII 概念。
变量值可以由其他变量使用,但需遵守由编译器强制要求的若干规则。
前两条是其它语言也有的,没啥好说,重点放在第三条。
克隆(clone):此处将值复制到新的变量。新变量拥有新的复制值的所有权,而原始变量保留其原始值的所有权。
你有一本书,稣按照你那本书,买了一样的书。你的书是你的书,稣的书是稣的书。
移动(move):所有权被转移到另一个要使用该值的变量,原始变量不再拥有所有权。
学姐含情脉脉地把她的书送给稣。
不可变借用(immutable borrow):没有发生所有权转移,但是可以通过另一个变量读取该值。当借用变量超出范围,内存不会被回收,因为借用变量没有所有权。
学长不太情愿地把书借给稣,并交代:“书借你,只能看,绝壁不要在上面做笔记,被我发现会砍死你的哦!我偶尔会找你查查。”
可变借用(mutable borrow):可以通过另一个变量对该值进行读取和写入操作。当借用变量超出范围,内存也不会回收,因为借用变量没有所有权。
稣把书借给学妹时说:“这书你随便用,把稣的书当做你自己的书,等到用不上时再还。”
重点在于一个“借”字:书的所有权属于其主人,但主人将书借出之后,自己是无法再在书上做笔记啦!
借出期间,借方不能写:学长说过,在书上乱画,要砍死稣!
借出期间,所有者不能写:这书学长已经学完,偶尔要复习,但已经不需要写笔记,借出去之后就更不会写了。
1 | fn main() { |
不能多次可变借用:只能有一个独占的学妹(active borrow),稣不能同时承诺给多个学妹“随便用”,不然学妹们可能打起来……
所有者不能再读写:书在学妹手里随便蹂躏,稣虽然心疼,但不能说!等她爽(huan)了再说吧。
1 | fn main() { |
《#诗盗#·隐玊》:诗码中年初白头,科技人生稳如狗。神之八哥思千虑,一算钱袋拮九周。
玊:通“士”。
稳如狗:稳妥地像狗,不是稳定。
神之八哥思千虑:要解决的问题是神级的难,脑力消耗很大。
一算钱袋拮九周:收入不行,只能过着拮据的生活。
改编自霹雳角色玉龙隐士诗号:
书剑青眼初白头,
智殊相悬问机难,
波澜困守役千虑,
一算龙隐决九川。
在《优化思维【3】消除没必要步骤》提到一个对象转化的例子:A 对象要转为 B 对象,实现时先把 A 对象转为中间对象 T,再将 T 转为 B 对象,由于两步都很容易实现,一个现有函数即可,所以很多人可能会采用这个思路。
下面要介绍的“合并步骤”,类似于优等生解应用题时“跳步”(一行合并多个步骤),可以作为前文的补充。
以下命令 UMU 经常看到,其实它可以用 grep UMU test
来优化,减少一次管道交互。
1 | cat test | grep UMU |
再看下面例子是从一个命令行里移除 A 和 C 两个选项:
1 | cmd="EXE A=1 B=2 C=3 D=4" |
其中两次 sed
可以合并为一次:
sed -e 's/ A=[^ ]*//;s/ C=[^ ]*//'
或 sed -e 's/ [\(A\)\(C\)]=[^ ]*//g'
或 sed -e 's/ \(A\|C\)=[^ ]*//g'
,这个 macOS 上不行。
或 sed -E -e 's/ (A|C)=[^ ]*//g'
,这个适合 macOS。
先查一下 sysctl net.ipv4.tcp_fastopen
,一般应该是 1,说明客户端支持 TFO;如果是 2 则说明服务端支持;3 是同时支持。
TFO (TCP Fast Open) 是一种能够在 TCP 连接建立阶段传输数据的机制。使用这种机制可以将数据交互提前,降低应用层事务的延迟。
这其实也是一种合并步骤的思想,把传输数据合并到三次握手期间。
参考:
Shell 不适合某些复杂运算,尤其是 OpenWRT 用的 ash。
Lua 缺乏某些 SDK,比如说阿里云 SDK 就没有 Lua 版。
Python2 已经过时。
Node.js 在小型设备上不如 Python3 高效。
C、C++ 之流太难了!Go、Rust 还得编译,麻烦。
Perl、Ruby 已没落。
当 IPv6 地址变化时,将地址发送到钉钉:https://github.com/UMU618/openwrt-ipv6-addresses
1 | opkg install python3-base |
安装 python3-base
之后,就可以运行 python3
了。
1 | root@UMU:~# python3 |
用以下 Python 代码,打印目前已有的模块:
1 | import sys |
结果为:
1 | 1 sys built-in |
下面来实现获取 IPv6 地址的功能:
1 | def net_hex_to_ipv6(h): |
以上代码有个“美中不足”:只能打印地址的“首选格式”,不支持“压缩格式”。下面改进!
UMU 打算使用 socket 模块的工具函数格式化 IPv6 地址,但目前已安装的 python3-base
不带 socket 模块:
1 | import socket |
所以需要安装 python3-light
:
1 | opkg install python3-light |
装完即可愉快地玩耍:
1 | import socket |
以上代码打印:0618:0618:0618:0618:0000:0000:0000:0618 -> 618:618:618:618::618
。
如果 python3-light
还不能满足您,推荐来个全家桶:
1 | opkg install python3 |
PS: 不要以为只要上面这句就全装上了,前面的 opkg install python3-base
是必要的!如果只装 python3
,则 /usr/bin/python3
并不存在!
(完)
如果您看得懂,那么,这是 Node.js 程序员的 C++ 进修指南。
如果您没看懂,那么,这是学 C++ 的劝退书!
用 C++ 改写 Node.js 程序,主要目的可能有两个:保密、提高性能。
那么您肯定要问:为什么不用 Go 或者 Rust 改写?UMU 是推荐用 Go 或 Rust 的,而且相对改写为 C++ 要简单得多,本系列文章,可能从反面论证:您应该选择用 Go 或者 Rust 改写!
https://github.com/UMU618/cpp-for-nodejs-programmers
在《学习 Rust【2】减少代码嵌套》中,UMU 提到一个使代码平坦化的例子,咱们把其中最基本的功能提炼出来,成为最简单的例子:
1 | setTimeout(() => { |
这段代码实现的功能是:一秒后打印 step1
,再一秒后打印 step2
,再一秒后打印 step3
,退出。
首先明确一点:JavaScript 是 JIT 语言,不用编译,语言宿主直接解释运行。C++ 是 AOT 语言,需要编译。所以我们需要编译器(比如 g++、clang++)和编译脚本(比如 make、cmake)。下面我们会选择在 macOS 上使用 clang++ 和 cmake 来编译 C++ 代码。其中,cmake 其实是用来产生 Makefile 的,如果您学过 Makefile,可以直接用它。
安装 Xcode,以获取 MacOSX.sdk。
安装 clang++ 和 cmake:
1 | brew install llvm |
1 | // set_timeout.cc |
1 | cmake_minimum_required (VERSION 3.5) |
1 | ## cd to source code directory |
小结:以上代码,可用,但不推荐。首先它是用多线程模拟的定时器,当设置 N 个定时器时,将创建 N 个线程,这不够优雅。其次,当您取消定时器时,会发现它无法立刻取消并退出线程。
我们知道,Nodejs 内部使用 libuv 作为异步 IO 库,它是 C 实现的,用 C++ 调用 libuv 就显得不那么 C++,所以我们决定用和 libuv 同类且更强大的 Boost Asio 来代替。
1 | brew install boost |
1 |
|
1 | cmake_minimum_required (VERSION 3.5) |
小结:好很多,但太难了……这真是劝退书!
改剧本。2019 年 8 月时,《八哥之神前传【1】》识界大战时就提到“心灵生化病毒”,后来要解释识界之外的识界是怎么毁灭的,人类为何移居太阴之背时,原剧本也是延续这个套路。但不幸的是作者所处的宇宙遭遇病毒疫情,为了不造成恐慌,急忙连夜做梦改剧本。目前倾向于 11.7 级地震。
是还没写,但早已梦见。本剧的真正创作时间是作者大学时期,距今已经 15 年。
没错!大学时代就打的草稿,故事来源于自己的梦和听闻周边的故事。原本计划剧名:《一睡千秋》、《一梦千年》或者《魔脑在世三千年》的,但由于当时阅历不够,自觉写不好,所以写个故事发展路线就放弃。2018 年底无意间在老硬盘里翻出来,感慨良多,决定把“概要”升级成“初稿”。
没错!故意起这样奇葩的名字,主要是因为稣低调。另外,这个剧本里的中心思想太过玄幻,不适合一般人,当然不能起个易懂的名字。
想太多,写不出来!
“概要”只是一个青春言情剧,后来想写的是一个人的一生……但是一个人不够精彩,干脆把一堆人写成一个“稣”。本质上说“稣”其实是一群人,而不是一个。比如《八哥之神【4】》魔性山军犬养殖训练基地那个场景,其实就暗示男主角是个精分。
有差别吗?
有的!一直在充电!
哦弄!是给 MBP15 和手机充电!
没错!这是为了按公共电梯的按钮。您想,现在都 PHEIC 了,直接用手指接触?那面积好大的,多危险呀!
没错,这是事实。因为《八哥之神》其实是《八哥之神前传》的续集,一般续集都是变差的。稣很机智地采用倒叙,先写比较差的续集,这样别人就不会喷:“续集写烂了!”而是说“前传的角色居然更多,剧情更复杂!”
出现的角色:李冰月、李心觎,一对双胞胎姐妹;孟长生,一个不婚主义的男子。
剧情:爷要被捅死了……这应该不算剧透,《八哥之神》已经明确这点,开场时圣小开就是一个 60 多岁的年轻人,和周易类似,但更惨一些,毕竟这是一部“探讨生命悲剧色彩”的言情科幻喜剧。
本剧的人生观:死亡并不长久,轮回再度孤独。请注意这里的“度”是个动词。
别慌!一个人的一生虽然意义不大,但放在无尽时间洪流里就有意义了,您可以以一辈子为单位进行迭代,这辈子尽量做得更好,让下辈子起点高一些。太上大道,我稣慈悲!
嗯……这些故事全都有现实原型!就是时间点改改,人名随便起一个,把几个现实故事重组。但是,这些故事没有一个是发生在作者本人身上的,作者只是擅长蹭热点,沾点人间俗气,以对抗挨踢无情。
上辈子死前,死神劝稣要放下,稣回答:不,稣要追求永恒!
然而稣还是死了,还是被洗脑洗得一点都不剩。为什么有些感觉转瞬即逝,再也回忆不起来?不行!稣要再体验一次,然后把它写下来。于是稣养成写日记的习惯。
有一天,稣发现如果按照中国人的平均寿命计算,稣已经过掉一半,回忆起自己的前半生,稣发现人生是孤独的最终奥义。每个阶段都会新朋友,也会失去一些旧朋友。就是上一次转变的时机来临前,稣突然领悟到一个真谛,我们无法选择不失去,但可以选择阶段性先失去的是什么!比如哪类朋友应该舍去——那些无法互相理解的。
接着稣又发现,理解不是一件容易的事情,互相理解这个要求有点高。只要能合作就行,应该舍去那些无法合作的。最终稣终于理解人间的一个催化剂:嫉妒。于是稣感觉人间的故事学习得差不多了,可以总结一下,于是开始写剧本。
身为天族,不能过度体验和干预人间。写代码比较正经。
个币。
真的。
古思:怎么……这么快?爷不是要敲代码么?
圣小开:一日之计在于晨,美好的早晨当然是睡回笼眯最好了!说不定还能再见到狐狸精。
古思:那我先去洗澡!
圣小开:大早上的洗啥澡,又没让你侍寝。
古思:哦,我也换睡衣陪爷躺躺。
圣小开:好多年没和别人睡眯眯了,有点不习惯。
古思:那我们聊天吧!床除了睡觉,另一个大用途就是聊天。
圣小开眼神一撇:你会聊啥?C 还是 C++?
古思:C++!而且我真学过,贾老师特地要求我学的。
圣小开:反应真快。爷还是亲手确认一下……
古思:爷的手好冰呀!
圣小开:嗯,爷还是稣的时候体温就低于常人,当爷后体温就更低了,需要一个暖手宝。
古思:这点我看过的资料并没有提到。
圣小开:贾总是不是和你说了爷很多八卦?
古思:是有一些基本介绍,也没啥特别八卦的!我还得多直接从爷处了解。
圣小开:有啥问题就问吧,如果问得不好爷可能就眯过去了。
古思:爷刚才提到好几次“眯”,为什么睡觉要说成睡眯眯呢?这种骚里嗲气叫法不符合爷的人设!
圣小开:骚里嗲气?眯眯——其实是爷的绯闻女友!
古思:哇哦……原来如此,看来田心挖到第一个八卦咯。
9102 年的春天,一个风雨交加的夜晚,稣和王博士聊完一个关于人工智能的天后,精神还有点紧崩,边低头走路边思考科技的变幻和人生的虚幻。
突然偶遇现在被人称为稣的绯闻前女友的月光女神卢眯眯。距离上次见面过去快一年,相逢自是有缘,人生到底是虚幻,还是真实,尽在研究自己和参考他人,何不乘机聊聊人生?然而附近像样的小资消遣场所都已打烊,也没地方坐,她提议去她宿舍。稣心想那是员工宿舍,应该很安全,稣不可能被人暗杀,如果被仙人跳,稣只要大喊一声,这破地方认识稣的少说也有 60 个!于是果断去了。
进屋后温暖许多,在温差作用下,居然一时犯困。她去洗澡的时候,稣不小心就在她床上睡着。
醒来已经快凌晨五点。她就躺在身边。稣想:楼下宿舍门没有门禁卡是出不去的,又不忍心叫醒她,于是一个果断的决策:睡眯眯。
这一觉睡得很好,是稣一生中少数几个质量极佳还能记得的觉之一,于是稣从此改口称睡觉为睡眯眯。
唯一美中不足的是……
古思:吓醒了?
圣小开:不是……稣偷偷摸摸摸了一下,眯眯的咪咪原来只比六舅大一点点!
古思:六舅?
圣小开:嗯,是爷的舅舅,他很六,所以叫他六舅。不说他,总之就是比你小挺多的……
古思:原来爷喜欢这个!田心还可以去加大一些。
圣小开:不用,不用。适可而止!适可而止!爷只是用理性的眼光衡量!
古思:爷到底是正经还是不正经呢?好难分辨!
圣小开:一名男性整形医生整天研究女人的胸,你说他正不正经?
古思:这没有不正经呀!
圣小开:一个男孩整天研究女人的胸,因为他立志成为一名整形医生,你说他正不正经?
古思:好像有不正经的味道。
圣小开:嗯哼!区别在于专不专业!如果一个人业余研究异性心理,多半会被判定为不正经,而一名专业的心理学家,怎么研究异性心理,都是正经的。
古思:爷想说什么?
圣小开:只有假不正经,才能知道谁是假正经!这是一种调试八哥人生的方法。
古思:听起来,其实爷是很正经的人,故意表现得有些不正经?
圣小开:是的,正经得无趣,无趣得没朋友。爷还是要假装有朋友的。
古思:调试八哥人生是什么意思?
圣小开:很多时候,很多人,是不会说实话的,需要一些研究手段。比如陪他们演戏,但又不能表现得不自然,所以爷研究过这本《悲剧演员的自我修养》。
古思:贾老师说爷的好奇心很重,原来如此呐!
圣小开:不!这是大部分人对爷的误解。这个误解好大,大到爷每次解释都会被当成蛇精病。
古思:em?怎么回事?
圣小开:爷是质疑,不是好奇。别人是什么样的,爷都可以接受!爷从这个世界的基础开始质疑,以致于对别人的存在和真伪也质疑。比如,偶尔发现别人好像喜欢自己,就会去研究她是不是真实存在的,是不是有主观意志,是不是真的喜欢,以及为什么她会喜欢爷。反过来,爷喜欢别人也一样各种质疑。
古思:这是不是多疑?不自信?
圣小开:肯定是多疑。爷连自己都质疑,有时甚至怀疑“我思故我在”也有八哥!是在思考,但在哪里思考呢?在自己脑里,还是在远方的某处?不自信有点,但也不他信呀!
古思:田心喜欢爷是基因和洗脑程序决定的,是真实的。
圣小开:哦?你不抗拒一下这种安排吗?
古思:贾老师说,爷要是死了,我会进入重置状态,记忆可能全部丢失,和死掉无异。
圣小开:那爷睡眯眯后,你会怎么样?
古思:没有特别设定。可以一起睡呗。【心想:以前是不敢抗拒,现在看来没必要抗拒。】
圣小开心想:在爷的床上,没人可以比爷晚睡!等你丫睡着后,爷就用各种反侦察仪器检查你。