Happy New Year!

2024 is coming!

I had moved back to Xi’an-China for 7.5 years, we just celebrated the 8th years birthday, and my daughter is 1 year old. It’s always happy to stay and play with children, they make my life more interest out of the busy work.

COVID finally terminated at the end of 2023, we don’t need to waste time and money for COVID tests, the additional limitations in many areas started to cancel. It’s a little bit delay than other countries, but it’s the decision of our government, which we have to follow.

The economic concern is a hot topic around me in 2023, our company also cut stuffs, it’s very hard for young graduate to find a job, unless they are very very outstanding. We are on the way to improve the GPU production, and become more competitive in the market.

Amos Jan 4th, 2024

转:Go语言必知的90个知识点

Go语言必知的90个知识点
1. 函数可以返回函数类型
func test() func(int) {
return func(x int) {
println(“x:”, x)
}
}
2. defer定义延迟调用,无论函数是否出错都确保结束前被调用
3. ok-idiom(A跌目)模式:多返回值中用一个名为ok的布尔值来标记操作是否成功
4. 结构中的匿名字段,结构的实例可以直接调用匿名字段的方法和属性
5. 计算机中变量是一段或者多段用来存储数据的内存,类型决定变量内存的长度和存储格式,所以我们只能修改变量值不能修改类型
6. 内存分配发生在运行时,编译后的机器码不使用变量名而是直接使用内存地址访问目标数据,所以编码阶段采用易于阅读的变量名
7. 惯例建议以组的方式整理多行变量定义 var {x,y int } type{ xxx }
8. 简短声明一般用于函数多返回值,以及if for switch等语句中定义局部变量
9. 未使用的局部变量会编译出错,全局变量不报错
10. 命名建议字母或下划线开始,多字母数字和下划线组合,局部变量优先短名
11. 常量实在预处理阶段展开成指令数据,变量是在运行期分配存储内存.(所以常量无法寻址,没有地址)
12. byte是uint8的别名 rune是int32的别名 别名直接可以相互赋值不需要类型转换
13. 拥有相同的底层结构不代表就属于别名
14. new为指定类型分配零值内存返回指针;make是引用类型专用的创建函数(内存分配和属性初始化)
15. 未命名类型:数组、切片、字典、通道等类型与具体元素类型或长度等属性相关的类型,可以用type将其改变成命名类型
16. 对于未命名类型 struct tag不同也属于不同类型,字段顺序不同也属于不同类型。
17. 乘幂和绝对值运算在math包的Pow和Abs中
18. 自增自减只能作为独立语句
19. 指针是实体会分配内存空间,内存地址是内存中每个字节单元的唯一编号
20. 指针类型指向相同地址或nil则相等,但是不能做加减和类型转换
21. unsafe.Pointer将指针转换为uintptr进行加减运算,但可能造成非法访问
22. 指针不能用->,统一使用.
23. 复合类型初始化,必须包含类型标签;左花括号必须在类型尾部;多成员都好隔开;多行右侧必须是逗号或者花括号
24. switch 无需显式执行break,但是想顺序执行需要显式执行fallthrough
25. range迭代是复制数据
26. goto只能跳转到同级代码,不能跨级别
27. break用于switch for select,终止整个语句块执行
28. continue只用于for循环,终止后续逻辑立即进入下一轮循环
29. 函数无需前置声明;不支持命名嵌套定义;不支持同名重载;不支持默认参数;支持不定长参数;支持多返回值;支持命名返回值;支持匿名函数和闭包
30. 函数类型只支持nil判断,不支持其他比较操作
31. 从函数返回局部变量指针是安全的,编译器会通过逃逸分析来决定是否在堆上分配内存;所以参数尽量减少值拷贝
32. 函数建议命名规则:动词+名称;避免不必要的缩写(printError优于printErr);避免使用类型关键字;使用习惯用语(init表示初始化,is/has返回布尔值);用反义词命名行为相反的函数
33. 不管是指针、引用类型还是其天涯类型参数,都是值拷贝传递,区别在于拷贝的目标对象
34. 指针传递坏处在于延长该变量的声明周期,也可能导致他分配到堆上增加性能消耗
35. 函数参数在函数内部有效,作用域是整个函数内部
36. 变参 func test(a …int){} test(a[:]…)
37. 命名返回值的问题: 新定义的同名局部变量会引起同名遮蔽:xx is shadowed during return ;此时实名return即可
38. 闭包 匿名函数能够使用上下文的环境中的数据(最终数据)
39. 延迟调用defer 常用于资源释放 解除锁定 错误处理等 先入后出。 延迟调用开销很大,性能要求高压力大的算法尽量避免使用
40. error是接口类型
41. panic会引发函数中断执行defer ,在defer中使用recover捕获panic提交的错误对象(recover只能在defer中执行才有效)
42. 多个panic仅最后一个被捕获
43. runtime/debug.PrintStrack()可以打印完整的堆栈信息
44. 不可恢复性、导致系统无法正常工作的错误才会使用panic (文件系统没权限操作、服务端口被占用、数据库未启动等)
45. 字符串是不可变字节(byte)序列,可用len获取长度,不可用cap; ` 支持跨行;允许字节数组访问,单不允许字节数组取地址
46. 用切片指向数组时,底层还是指向该字符串
47. range遍历可以打印出汉字,len遍历出的汉字是乱码
48. append可以向[]byte追加 =》var bs []byte bs=append(bs,”abc”…)
49. 字符串加法运算每次都会重新分配内存,构建大字符串性能极差;方法1:strings.Join 方法2:bytes.Buffer 小字符串拼接使用fmt.Sprintf text/template等
50. utf8.RuneCountInString(s)代替len获取带汉字的字符串长度
51. 长度是数组的类型组成部分,元素类型相同长度不同的数组不是同一类型
52. 多维数组,只第一维支持… => […][10]
53. 如果元素支持== !=操作,则数组也支持
54. 数组是值类型
55. 切片:不是动态数组或数组指针;内部通过指针引用底层数组,设定相关属性将数据读写操作限定在指定区域内。可以理解为数组指针的包装
56. 切片本身是只读对象,工作机制类似数组指针的包装 右半开区间 数组必须addressable
type slice struct{
array unsafe.Pointer
len int
cap int
}
57. 切片引用数组时,切片指针会指向数组地址;访问越界会报错;append会追加数组,当长度大于cap时会重新分配地址,则切片和数组就相互独立了
58. 切片 var a[]int 为nil,仅代表他为初始化,但依旧分配内存;且a[:]依旧是nil
59. 如果切片长时间占用大数组的少量数据,建议切片单独分配地址,以让大数组尽早释放
60. 可将字符串直接复制到[]byte => b:=make([]byte,3) n:=copy(b,”abcdefhg”)=>n=3,b=[97 98 99]
61. 字典的key必须支持== != 如数字、字符串、指针、数组、结构、接口
62. if v,ok:=m[“d”];ok{存在} 使用ok-idiom模式判断key是否存在
63. delete(m,”d”),删除不存在的key不报错
64. map使用range迭代每次顺序不定
65. map被设计成 no addressable,所有没法修改value的成员(如果value是个结构或者数组等) ;改进方法1:先获取完整value,修改后再赋值回去;方法2:value采用指针类型。因为value是指针,所有可以通过指针修改指针指向的数据。
66. map并发操作,某任务针对map写操作,其他任务对该map的读写删除都会导致进程崩溃;可用sync.RWMutex实现同步(不要使用defer)
67. map对象本身就是指针包装,传参不需要取地址
68. map创建时和slice一样要预选分配足够地址,减少扩张时不必要的内存分配和重新哈希操作=>make(map[int]int,1000)
69. 对于海量小对象,应该直接用字典存储键值数据拷贝而不是指针,这样减少扫描对象的数量缩短垃圾回收时间。
70. 字典不会收缩内存,适当替换新对象是有必要的
71.

结构推荐命名初始化,以防扩充结构时报错
匿名结构:
u:=struct{
name string
}{
name:”xxx”,
}
72. 只有所有成员都支持==操作时,结构才支持相等操作
73. 匿名字典隐式的以类型名为字段名称,使用时可以直接饮用匿名字段的成员,但是初始化时必须当做独立字段。(但是隐式字段是外部类型的话,隐式名称不包含包名)
74. 除接口指针 多级指针外的任何命名类型都可作为匿名类型
75. 字段标签是对字段描述的元数据,是类型的组成部分;运行期间可用反射获取标签信息,通常作为格式校验和数据库关系映射等
p1:=p{
name:”xxx”,
sex:1,
}
v:=reflect.ValueOf(p1)
t:=v.Type()
for i,n:=0,t.NumField();i<n;i++{
fmt.Printf(“%s:%v\n”,t.Field(i).Tag,v.Field(i))
}
76. reflect.StructTag提供了更完善的功能
77. 前置实例接收参数-receiver
78. receiver是基础类型则会被复制,指针类型则必须能获取实例地址
79. receiver类型选择:不修改的小对象或固定值用T;引用类型、字符串、函数等指针包装对象用T;修改实例状态用T;包含Mutex等同步字段用T,大对象或不确定情况用*T;
80. 匿名类型的方法也存在同名遮蔽的特性。(可实现类似覆盖操作)
81. T的方法集是 receiver T;*T的方法集是receiver T+*T
82. 匿名嵌入S,T包含 receiver S;匿名嵌入*S,T包含 receiver S+S; 匿名嵌入S或S,*T都包含 receiver S+*S;
83. 方法集仅影响接口实现和方法表达式转换。匿名字段就是为方法集准备的
84. Chan:
一次性事件使用chan的close效率更高
向close的chan发数据panic
从已关闭的chan接收数据返回已缓存数据或零值
无论收发,nil通道都会阻塞
85. Chan和锁的选择:
同步问题应该用锁或原子变量来操作
对性能要求较高时,赢避免使用defer unlock
读写并发时,用RWMutex性能更好
对单个数据的读写保护建议使用读写锁
严格测试,尽可能打开数据竞争检查
通道倾向于解决逻辑层次的并发处理架构
锁用来保护局部范围内的数据安全
86. FieldByName不支持多级名称,如有同名遮蔽需要匿名字段二级获取
87. 可用发射提取struct tag还能自动分解,常用于ORM映射或数据格式验证
88. 反射可通过Interface方法进行类型推断和转换
89. 对性能要求较高的地方需要谨慎使用反射
90. Go语言1.5版本实现的自举

Fedora 29: dbus bug系统无法启动

https://bugzilla.redhat.com/show_bug.cgi?id=1623781
Bug 1623781 – dbus-1:1.12.10-2.fc29 breaks system boot

昨天中午用 `sudo dnf update -y`升级了Fedora 29系统软件,下午开机时卡在登陆界面之前了。内核日志没有啥明显异常,而且还能正常识别USB的插入拔出,所以内核应该没有panic或者死锁。
最后用上下键切换到systemd的日志输出,发现是dbus启动失败。于是从grub里自带的救援模式下,查看了/var/log/dnf.log里dbus更新前的版本号,然后用`sudo dnf downgrade dbus-1.12.10-1.fc29`把dbus降级后就正常了。

在救援模式下不能直接使用wifi,可能是缺驱动或者需要手动加载配置。于是想到用手机通过usb线共享网络,手机就成了一个usb网卡,`if ethx up; dhclient ethx`,网络就正常了。

体操课

上周去锻炼,老婆自己去练瑜伽,派我去参加搏击体操,开始我是拒绝的,除了教练其他都是女生。第一次跳,感觉跟不上节奏,现在最后面的角落,生怕被人嘲笑。一些拉伸放松和保持平衡的动作还是不错,有点像是借鉴瑜伽的。练习结束,教练还和我聊了几句,我两的手套居然同款,那是很久以前闲鱼上买了一套健身器材里带的,适教练说适合拳击手套,我两带的是内胆。练完第二天感觉腰背困,动作做扎实到位还是挺累的。

今天去锻炼,慢跑十分钟后去操房拉伸,一来空间大、有垫子,二来没有其他器械的干扰,也相对安全些。我还没拉伸完,那个教练进来了,说我们5分钟后开始,看看身后只有一个女生,我勉强的说好的。当然后来还来了几个女生。

这次索性就站第一排,动作和上次一样,但感觉套路少了很多,也可能是比上次熟悉了。能跟上音乐的节拍了,动作连贯后也觉得轻松了很多。感觉自己跳的比几个女生都到位,莫名其妙的被拉下水了,以后接着参加吧,还不错。单纯练器械,有氧确实枯燥,动感单车太疯狂,搞不好还伤膝盖。

Fedora 28 touchpad feature: secondary click

Quote from https://help.gnome.org/misc/release-notes/3.28/

  • All touchpads now use a gesture for secondary click (the equivalent to right click on a mouse) by default. To use the gesture, keep one finger in contact with the touchpad and tap with another finger. In many cases this replaces tapping areas of the touchpad as the default secondary click method. A choice between the two behaviors is available in the Tweaks application.

非root用户使用virt-manager关闭root认证

参考:https://ask.fedoraproject.org/en/question/45805/how-to-use-virt-manager-as-a-non-root-user/

从Fedora20开始,virt-manager实现了PlocyKit,所以普通用户使用virt-manager需要root权限验证。
如果想让某个组的用户使用virt-manager免去root权限验证,可以新增一个polkit规则。

polkit.addRule(function(action, subject) {
  if (action.id == "org.libvirt.unix.manage" && subject.local && subject.active && subject.isInGroup("wheel")) {
      return polkit.Result.YES;
  }
});