2020年11月

相比于用C++写Qt,PyQt更加适合小项目入手,在单文件/单窗口的情况下更容易入手。

静态加载.ui文件需要使用pyuic5进行编译,然后作为库引入,使用一个类去继承该类即可使用。在这个类中,组件可以通过使用ui中指定的objectName直接进行获取,类似于Android中的findViewById

接下来是一些坑:

  1. 组件具有线程绑定性,只能在主线程内更新组件(包括设置组件内容),否则好的情况抛出Exception,坏的情况直接Segmentation Fault退出了,此时只能通过Qt的信号/槽机制来;
  2. 即便是新建QMessageBox也最好在主线程中进行(同样是信号/槽机制),否则可能可以展示信息,但是会出一些奇奇怪怪的错误,我这里遇到的情况就有诸如包含空格就段错误的情景。

接上文换硬盘。换完硬盘之后,顺手把之前装的Windows 8一起复制过来了,当作大号的PE使用,甚至还能放办公,打游戏。结果修复完引导(EasyBCD选择在当前系统下的盘符,不会修改系统挂载的盘符),一开机,发现锁屏界面是有的,但是壁纸不见了。输入密码登录,卡在“正在准备Windows”,即使不登录,想使用系统关机键关机,程序都会报错,连关机按钮都见不到。

然后在网上找,听到别人说可能是系统配置的问题,有不少人在系统备份前会主动将系统设置到sysprep模式下,在该模式中,系统会检测当前硬件,且根据现有的硬件生成合适的配置文件。然而,我遇到了两个问题:第一,该模式只能在系统内部进入,所以需要先把硬件配置完全改回原来的样子才能启动;第二,这种方法不一定成功,且失败后果很严重,尤其是当作为双系统安装在非C盘的时候,之前的配置文件会全部丢掉,无法回到原样。因为不愿浪费更多的时间在那块SMR硬盘上,只好作罢。

后来开始考虑是不是可能是根分区(借用Linux术语,这里指Windows系统所在分区)挂载出错的问题,因为Linux的GRUB配置出错的时候也会这样,系统一部分功能是正常的(因为已经加载到了内存),但是剩下的完全不可用。

然后就去查了一下Windows存不存在类似于盘符到分区UUID的缓存表一类的,结果还真找到了(https://docs.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/restore-system-boot-drive-letter)。

经过测试,解决这个问题的方法是,在任意一个可以在当前硬件配置条件下启动的系统中(比如新装的系统或者迁移的Windows 10),挂载Windows 8的SYSTEM注册表,修改其中对应的每个分区在HKLM\SYSTEM\MountedDevices中的那串二进制标识,从当前系统的值直接全选,对应覆盖复制过去就行了。

然而Windows 10可以自动在新硬件环境上自动适配分区标识,猜测可能的原因是,这个功能在Windows 10才被添加进系统的启动流程中,而Windows 8开发的时候并没有。(然而Win8能自动适配外围设备已经很强了)

2.5寸的机械硬盘可以称作近年来的笔记本之痛了。为了节省成本、扩大利润而强行(并且还是偷偷地)换上对于具有高频读写特性的普通用户不利的SMR硬盘,让不少用户可以说是痛不欲生,用着用着突然就卡着了,想强行关机又不敢。好不容易怒气冲过了理智,强行关掉了笔记本电源——结果一重启,系统修复和加载却又像是记仇一样,再次将系统卡到让人怀疑人生。

不必多言,或许相较于CMR硬盘,SMR硬盘的确没有什么缺点,但是读写性能下降这一个缺点,就足以将SMR判处死刑,可以说是瑜不掩瑕。古云“千金难买寸光阴”,如今S、W两厂为了利益,不惜牺牲用户体验,这是我万万没想到的。截至本文写作时间2020-11-22,国际金价60.15USD/g,你一块盘能挣到用户六万刀我是不信的。

然而,天道有轮回,风水轮流转,NAND闪存技术近年的快速发展为磁记录机械硬盘的退场打下了基础。物理抗震性、随机读写速率、盘体质量等指标大幅优化,硬盘寿命也控制在了较为合理的范围内当场宣布QLC开除NAND籍,现在可以说是不论手机、平板还是个人电脑都必有的标准配置了。但是因为众所周知的原因,国外闪存厂商风水向来不是很好,隔不隔几年总得出点什么事,一直以来价格高居不下,让我望而却步。

近年来随着漂亮国加带搞事力度,大量的优质国产商品源源不断地涌现(?),其中之一就是长芯/长鑫存储——自研存储芯片可不是闹着玩的,作为计算机两大基础之一,生产技术还没有握在手上,无异于看别人眼色吃饭,说饿死就饿死了。

在今年9月份,当我听到国产芯片的SSD发布的时候,内心自然是激动无比的,并下定决心今后有条件买国产的话,都尽量选择国产,甚至当起了免费的affman。不仅如此,在商品发布了两个月过后,当我仔细浏览狗东上的商品页面时,都没有发现差评,况且价格还很诱人地没有比国外成熟厂商的高上很多,不到1RMB/GB。当然,商品销量并不高(当时只有大约2000+),也不能排除控评的可能性。差评?想找到一个没有差评的商品,你先给我找一个没有憨憨的世界.jpg。能做到尽可能降低翻车概率到千分之一以下,对于新商品来说已经不错了。毕竟数据备份是基本操作,丢了不能全怪别人。反正我是做好了翻车的准备的。

最后在实际行动上,双十一当天抄了个底,700入手了一块1T的致钛 Active SC001,SATA接口的。结果和预期一样,Q1T1读写都是400MB/s多,Q8T8读能上500MB/s,写好像就下去了,400还是200MB/s来着,4K20多MB/s,已经比机械舒服到不知道哪里去了。现在笔记本开个盖子终于不用先和别人聊天了。

起因在于之前使用全键盘进行Linux操作的时候,无意间碰到了Page Up按键,开启了奇妙体验。把一条命令打到一半,然后按Page Up/Page Down就可以匹配历史记录,实在是太舒服了。

然而在使用Ubuntu的时候,突然发现就没有这个功能了,StackOverflow一查,才发现原来是需要手动配置的。

修改/etc/inputrc或者~/.inputrc,这么修改一下,就能把这个功能和Page Up/Page Down按键绑定:

$if mode=emacs

"\e[5~": history-search-backward
"\e[6~": history-search-forward

$endif

简单码两句。

主要是解决了对于Android多线程机制默认操作的疑惑。

学过Android开发的大概大部分知道,Android的前台线程是UI线程。但是根据开发组的意图来看,这个线程应该是空闲率越高越好。如果学过计算机网络的话,这点可以很轻松的理解,越高的资源占用率意味着越大的延迟,只有当占用率尽可能低的时候,才能满足快速、及时响应的需求。

而多线程在解决了线程占用率问题(通过将大部分高时延的任务下放到后台线程完成,这些线程的响应实验要求相对较小)的同时,也带来了同步问题。Android解决同步问题的方法非常简单粗暴,“谁创建,谁拥有”。换个说法,只有创建线程不安全对象的线程本身才具有修改线程数据的权利。

那么,如果外界有修改线程不安全对象数据的需求的话,那么就必须由所有者线程主动提供一个入口,以所有者线程的身份对资源进行操作。Android为这个理论提供的时间就是Message, MessageQueue, Looper, Handler四件套。四件套的具体功能就不做赘述了,网上到处都是,而其中最为关键的,也是最常见到的组件之一,就是Handler。作为外部线程来说,调用Handler的各类message方法可以向所有者线程发送申请以修改资源;作为所有者线程来说,实现handleMessage方法可以从外部接收,并且自定义地处理请求。

然后困惑之处就在于,按照书上的方法,只要实现一个Handler类就能完成对这种资源的访问。四个组件既然是一套,那为什么只要四分之一就能完成功能呢?最重要的绑定线程的工作,又是在何处完成?

带着这个疑问,去网上转了一圈,最后在官方文档找到了答案( https://developer.android.com/reference/kotlin/android/os/Handler )。其中的奥妙就在于,我们的确只需要实现Handler就行了,在Handler类实体化的时候,内部就定义了一系列的操作,包括创建四件套中除Message外的其他两件(Message在四件套中主要作为数据型,而非逻辑型组件,只用于传递Handler请求)。根据书上所说,Looper类的构造器甚至还是私有的,一看就是不希望别人去动的那种。在IDE中多按几次ctrl看看源码,就能发现Handler的无参构造器会调用Looper.myLooper()方法,继续刨的话可以看见,Looper对象已经被ThreadLocal作为线程私有变量保管得好好的了。

总而言之,在日常使用Android Handler的时候,只要实现这个类就行了,其他工作其实是已经由Android框架本身完成了的,放心大胆使用即可。