关于程序运行效率的一点见解

最近在看计算机组成原理等 4 本考研书籍...发现其实回过头来看这些当年没认真学的书的话还是有不少收获的. 当年小白的我只知道编程看语言类的书籍,无法理解数据结构,计算机组成原理一类书对编程的影响. 刚开始学这本书的时候就感觉我一个搞软件编程的看硬件干嘛.又是指令又是寄存器啥的,还有那可怕的电路图... 看的真头大啊,不过其实想想,这门课要是真没用学校也不会开考研也不会考啊!当年真是图样图森破啊...

大一的时候一直以为搞软件的就要多学点编程语言...我现在倒是学了不少.到头来没一个拿的出手的,还真是可悲, 广度是有了但是没深度,同样的语言人家编程风格和效率就是比你高.这个是在什么 C#本质论 C++ primer 里面学不到的东西,说深了就是编程素养.是不断积累的,不是看一本书就能迅速提升的东西.只上过培训班的程序员永远也不可能明白学习计算机组成原理会对编程有更深入的了解.最终写的代码也只是知其然而不知其所以然.

编程素养是通过各方面计算机知识的综合培养才能得到提高的.接下来我就举个例子来谈谈学过组成原理对编程的理解和 提高.例子很简单,就是关于数组的遍历.一个二维数组,假定是 10*10 的吧.那么遍历输出的话,大家肯定都会的,很简单.

for(i=0;i<10;i++)
  for(j=0;j<10;j++)
      printf(a[i][j]);
1
2
3

这个是很简单的两层 for 循环,我写的是伪代码,变量定义输出什么的就不要吐槽了.学过数据结构的同学应该都明白虽然二维 数组都用矩阵来表示,但是实际储存的时候一般都是按照行优先的方式储存的.我的这个版本是先行遍历再列遍历的.

for(j=0;j<10;j++)
    for(i=0;i<10;i++)
        printf(a[i][j]);
1
2
3

那么先列遍历再行遍历呢?大家一般都会觉得这个其实没什么差别吧.用数据结构的思想来说,空间复杂度和时间复 杂度都是一样的,运行起来没啥区别的.当然对于现在的高速 CPU 和这个元素比较少的数组来说其实也没多大差别,但是不能 因为这个就去忽略程序的效率问题.

为了讲述这个问题,首先得了解计算机的基本运行原理.首先程序是放在内存中的,但是执行程序需要用 CPU 来计算.因为 CPU 运行 速度极快,但是内存速度却没有显著的提高.所以引入了高速缓存也就是 Cache,首先把内存中的程序调入高速缓存中.然后 CPU 再从 Cache 中取出数据进行运算.但是因为 Cache 的容量极小,但是内存很大,根据程序访问的局部性原理.指令通常是顺序存放, 顺序执行的,数据一般也是聚集的存储在一起的.所以调入 Cache 中的数据基本上会是一段时间内 CPU 欲调用的数据.

当 CPU 发出度数据的请求时,如果访问的地址在 Cache 中即命中,那么直接从 Cache 中读取数据,和主存无关;如果 Cache 不命中, 则仍需访问主存,并把此地址所在的块一次性都调入 Cache 内.

显然,如果命中率高的话,那么程序直接的速度就更快.对比行遍历和列遍历.发现行遍历每次都是按顺序取数据的,因为是按照行优先方式 进行存储的嘛,所以命中率必然高.而列遍历的话每次取的都不是相邻的数据,会导致命中率大大降低,运行效率低.所以一会写程序的话 遇到数组遍历的话肯定要使用行遍历更好.

类似的问题还有 GOTO 语句,大一的时候老师明令禁止不准在程序中使用 GOTO 语句,但是就是不说为什么...学过计算机组成原理也就 明白了,因为 GOTO 语句违反了程序顺序执行的原则,使程序运行效率不高,而且程序读起来也很麻烦.

到此,对编程效率的见解就结束了,如果有什么纰漏的地方,还请大家指正,感谢您能读到最后~

Archlinux下有关无损音乐的折腾

最近发现一些旧番的音乐只有无损的了...MP3 的已经无法满足大众的需求了么....
但是在 Linux 下直接用 MPD 播放无损音乐不能分轨播放实在是不能接受. 于是就开始找寻切割的方法...Archwiki 有相关的条目APE+CUE Splitting (opens new window) 但是,有个明显的缺陷是分轨之后的文件居然不是用歌曲名字命名的! 而且还是我不怎么喜欢的 wav 格式... 不过我还是在菊苣的帮助下找到了完美的解决方案~

# 无损音乐的分轨

Linux 下有个 shntool 的工具非常实用,可以完美解决无损音乐分轨的问题. 根本不需要 wiki 里面说的 cuebreakpoints

shntool split -f example.cue -t %n_%p_%t -o 'cust ext=mp3 lame --quiet - %f' example.ape
1

-t 指的是文件的标题,%n 代表编号,%p 表示 Performer,%t 表示 Title.都是从 cue 里面读取的信息,shntool 默认不支持 mp3 格式的,所以需要指定用 lame 编码器进行编码.当然很多人只是想分轨,并不想转换成压缩的 mp3 格式.

shntool split -f example.cue -t %n_%p_%t -o flac example.ape
1

直接转换成 flac 格式就好了,因为 flac 格式是开源的无损音乐格式,播放器对它支持的肯定比较好. 如果出现 warning: failed to read data from input file using format: [ape] 这样的错误可能需要安装mac (opens new window)

# 给每个音乐文件打 TAG

转换之后的文件只是单纯的音乐文件,每个音乐并没有包含想关的 TAG 信息,这时候需要用 cuetag.sh 给每个音乐文件打 TAG
cuetag.sh 脚本 (opens new window) 最新版貌似有问题不能使用.
cuetag.sh file.cue *.mp3
命令很简单,在转换好的音乐文件夹下指定 cue 文件和 mp3 文件即可自动打 TAG,但是需要注意的一点是,这个脚本打的是 ID3v1 的标签,如果是非英语语言的话, 会出现乱码问题.详情请戳Mp3 标签乱码问题分析与解决方案 (opens new window) 所以,之后我们还是要使用mp3tagiconv (opens new window) 这个工具来进行标签的转换使得所有的播放器都能够正确识别 mp3 音乐的标签.
for i in *.mp3; do echo "y"| mp3tagiconv "${i}" ;done
因为 mp3tagiconv 这个工具每次更新标签都会提示 yes or no ,所以我就修改了下执行方式,使得批量自动化修改.flac 格式的音乐不存在 TAG 编码问题.

# flac 转换为 mp3

虽然在 PC 上听无损比较爽,但是放在手机上受制于存储空间和 CPU 性能,还是转换成 Mp3 比较好.

flac -d -c example.flac | lame -q 0 -b 320 - example.mp3
1

如果想保留 flac 的回放增益特性的话可以在转换的时候加上--apply-replaygain-which-is-not-lossless 参数.

到此,折腾完毕...

Archlinux下使用airbase和dhcpd建立虚拟AP

Linux 下的 wicd 本身自带一个创建 Ad-Hoc network 功能的,但是这个功能太不实用了, 首先,Ad-Hoc 只能把笔记本的无线通过有线进行共享,而且 Ad-Hoc 网络无法被安卓原生系统识别,CM 倒是可以用.hostapd 也是一样.只能把有线网络通过无线进行共享. 但是我经常是电脑连接 WIFI,并且想把 WIFI 共享给手机进行使用,于是我又开始折腾了 >_>

# 首先安装所需要的软件

net-tools
iptables
aircrack-ng
dhcpd
1
2
3
4

# 然后启动虚拟 AP

airmon-ng start wlp5s0 # 启动无线网卡的monitor模式 wlp5s0是我网卡的设备名 这时候会看到输出 monitor mode enabled on mon0 mon0便是虚拟出来的一个网卡设备
airbase-ng -e FreeWifi  -v mon0 & # 在mon0设备上创建Fake AP -e选项是设置SSID名字 -v是启动DEBUG模式 最后是设备名字,想进行后台运行请按Ctrl+D
1
2

# 激活 tap insterface 并添加路由表

执行上面的名字之后会输出 Created tap interface at0 然后执行下面的命令

ifconfig at0 up
ifconfig at0 10.0.0.254 netmask 255.255.255.0
route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.0.0.254
1
2
3

# 设置 iptables

iptables --flush
iptables --table nat --flush
iptables --delete-chain
iptables --table nat --delete-chain
iptables -P FORWARD ACCEPT
iptables -t nat -A POSTROUTING -o wlp5s0 -j MASQUERADE
//这里wlp5s0是我额外要连接到互联网的网卡设备名
1
2
3
4
5
6
7

# 配置 DNS 服务器

没有 DNS 服务器即使能搜到 AP 也无法连接,因为获取不到 IP 地址. 首先列出 dhcpd.conf 的内容

ddns-update-style none;
default-lease-time 600;
max-lease-time 7200;
authoritative;
subnet 10.0.0.0 netmask 255.255.255.0 {
option subnet-mask 255.255.255.0;
option broadcast-address 10.0.0.255;
option routers 10.0.0.254;
option domain-name-servers 114.114.114.114;
range 10.0.0.1 10.0.0.140;
}
1
2
3
4
5
6
7
8
9
10
11

然后执行下面的命令

echo > '/var/lib/dhcp/dhcpd.leases'
dhcpd -d -f -cf dhcpd.conf at0 &
1
2

# 最后启用 IP forwarding

echo "1" > /proc/sys/net/ipv4/ip_forward
1

# 写在最后

虽然能创建虚拟 AP,但是安卓原生系统连接获取到 IP 一段时间后又会自动掉线,原因不明,希望知道的菊苣能告诉咱一声~