Month: 十一月 2017

bug 错题本

发现有一些错误是自己经常犯的,不记录下来回顾一下,总是会一直犯。高中的时候还有习惯来记录错题,然而这么好的习惯,到了大学里却莫名其妙的没有了,知道毕业两年后的今天才突然想起。所以第一个场贩的错误就是思想上的——学习是一件终身的事,要延续好习惯。

对于各种持有资源的连接池对象等,要时刻注意它们是否是线程安全的。

# Python

## 更新变量的value的时候,变量名写错了,导致创建了一个没有用的新变量,老变量的value却没有更新

解决:

1. 使用pylint 检查代码,会提示 unused variable;
2. 在写代码的时候多用自动补全,而不要手动打出每一个变量。

Python 的变量声明和赋值没有分开,这个是一个坑,只能通过多用工具检查来实现

# 故障排查

* 有时候删文件删不掉但是空间还在占用是因为还有程序在使用这个文件

* CPU wait 比较高说明在做io

* 操作系统相关问题(OOM)

`dmesg -T` 或 `tail -200 /var/log/kern.log` 查看系统kill进程的日志,可以看到被kill掉时候的内存占用,再用free -m 查看一下是否超出了内存

使用 ipdb 单步调试 Python 代码

pdb 是 Python 标准库中自带的 debugger,ipdb 是基于 ipython 的增强版 pdb。

常用命令

  • [n]ext 下一步
  • [s]tep into 进入函数
  • [r]eturn 跳出函数
  • [b]reakpoint 打断点

pdb

pdb is fine, just don’t have so many features

Usage: import pdb; pdb.set_trace()

Ipdb is better

Usage: import ipdb; ipdb.set_trace()
n next
p print
pp pprint
s setp into
c continue to next breakpoint
b breakpoint
a args

暂时没用到的软件清单

DNS

* [PowerDNS 拥有web管理界面的DNS][1]

* [bcache][2] [另一篇][3]

* [vdso](http://man7.org/linux/man-pages/man7/vdso.7.html)

* [clickhouse][4]

* [Mysql Tunner][5]

* [切割地图 maptiler](https://www.maptiler.com/)

[1]: https://mp.weixin.qq.com/s?__biz=MzIwMzg1ODcwMw==&mid=2247487141&idx=1&sn=d8e3d8bb867e65d0f09ed38f58949956&chksm=96c9b8c5a1be31d3368334a5c0b7ade1cad89185f4a643d1be2778fe0198f6a48dc593792ae1#rd

[2]: http://xiaqunfeng.cc/2017/02/03/Dm-cache-vs-Bcache/

[3]: https://blog.lilydjwg.me/2015/5/11/self-made-sshd-with-bcache.92025.html

[4]: https://zhuanlan.zhihu.com/clickhouse

[5]: https://github.com/major/MySQLTuner-perl

sklearn 入门笔记

前一阵看了一个叫做 [莫烦Python][1] 的教程,还有 [sklearn的官方教程][2] 初步了解了一下 sklearn 的基本概念,不过教程毕竟有些啰嗦,还是自己记录一下关键要点备忘。

# 机器学习要解决的问题

## 什么是机器学习?

sklearn 给了一个定义

> In general, a learning problem considers a set of n samples of data and then tries to predict properties of unknown data. If each sample is more than a single number and, for instance, a multi-dimensional entry (aka multivariate data), it is said to have several attributes or features.

翻译过来:

总的来说,“学习问题”通过研究一组 n 个样本的数据来预测未知数据的属性。比如说,如果每个样本都不止包含一个数字,而是多维的向量,那么就称它为有多个feature属性。

## 问题

机器学习的方法不外乎这几类,现在自己用到的应该是分类比较多。

1. Classification 分类,也就是离散的
2. Regression 回归,也就是连续的
3. Clustering 聚类
4. Dimensionality reduction 数据降维

要实现上面几个目标,可能需要下面的步骤

1. Model Selection 模型选择
2. Preprocessing 数据预处理

要去判定自己的任务需要用哪种方法,优先参考 sklearn 官方推出的 [cheatsheet](http://scikit-learn.org/stable/tutorial/machine_learning_map/index.html)(小抄)

![sklearn-leanr cheatsheet](http://scikit-learn.org/stable/_static/ml_map.png)

# sklearn 的数据库

sklearn 为了方便学习自带了一些数据库,可以说是非常方便了。包括了 iris 花瓣数据库,手写数字数据库等。这些例子可以说相当于编程语言的 hello world 或者是图形学届的 utah teapot 了。

除了真实的数据集,还可以使用`datasets.make_*`系列函数来直接生成一些数据集用来测试。

代码:

“`
>>> from sklearn import datasets
>>> iris = datasets.load_iris() # iris 花瓣数据库
>>> digits = datasets.load_digits() # 手写数字数据库
>>> print(digits.data) # 数据库的输入
[[ 0. 0. 5. …, 0. 0. 0.]
[ 0. 0. 0. …, 10. 0. 0.]
[ 0. 0. 0. …, 16. 9. 0.]
…,
[ 0. 0. 1. …, 6. 0. 0.]
[ 0. 0. 2. …, 12. 0. 0.]
[ 0. 0. 10. …, 12. 1. 0.]]
>>> digits.target # 数据库的输出
array([0, 1, 2, …, 8, 9, 8])
“`

其中data属性是一个二维数组,格式是`(n_samples, n_features)`.

关于如何载入外部数据库,可以看这里,实际上我也还没看,科科

# 学习与预测

以识别手写数字为例,我们要做的是根据图像识别出数字是什么来。我们需要 *fit* (训练)出来一个 estimator,然后用来 *predict* (预测)未知数据的类型。在 sklearn 中,一个 `estimator` 就是一个实现了 `fit` 和 `predict` 方法的 object。estimator 常用的属性还有 `get_params`, `score` 等。

比如我们使用支持向量机模型:

“`
>>> from sklearn import svm
>>> classifier = svm.SVC(gamma=0.001, C=100.)

>>> classifier.fit(digits.data[:-1], digits.target[:-1]) # 注意第一个参数是数据,第二个参数是结果
SVC(C=100.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=’ovr’, degree=3, gamma=0.001, kernel=’rbf’,
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)

# 现在我们开始预测最后一个数据
>>> classifier.predict(digits.data[-1:])
array([8]) # 得出的结果是 8

“`

实际上的图像是

![last digit](http://scikit-learn.org/stable/_images/sphx_glr_plot_digits_last_image_001.png)

刚刚的例子是使用前面的数据做训练,然后识别了最后一个数字,其实我们还可以使用 sklearn 自带的 `train_test_split` 函数来分割数据

“`
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
iris_X, iris_y, test_size=0.3)

# 注意其中训练数据被sklearn打乱了. 在机器学习中, 数据比较乱是比较好的, 算法其实也一样, 数组是乱的最好.
“`

完整的例子在这里:http://scikit-learn.org/stable/auto_examples/classification/plot_digits_classification.html

## 保存模型

训练模型还是很花费时间的,我们不可能每次都去训练一个模型,所以一般都是离线训练好了之后,保存下模型来,然后在线调用。保存模型可是直接使用 Python 内置的 pickle 模块,但是一般模型数据都比较大,pickle 对大文件支持不好,最好采用 sklearn 自带的 joblib.

“`
>>> from sklearn.externals import joblib
>>> joblib.dump(classifier, ‘filename.pkl’)

>>> clf = joblib.load(‘filename.pkl’)
“`

很简单吧

# 其他的一些技巧

## 一些约定

上面说到 sklearn 约定了 fit 和 predict 方法,还有一些其他的约定

1. 所有的输入都会被转化为 float64 类型
2. 一半习惯用 `X` 表示样本数据, `y` 表示预测结果

## 可视化

“`
>>> X, y = datasets.make_regression(n_samples=100, n_features=1, n_targets=1, noise=10)
>>> plt.scatter(X, y)
>>> plt.show()
“`

会有下面的图

![](https://morvanzhou.github.io/static/results/sklearn/2_3_3.png)

[1]: https://morvanzhou.github.io/tutorials/machine-learning/sklearn/1-1-why/
[2]: http://scikit-learn.org/stable/tutorial/basic/tutorial.html

如何评价红黄蓝事件?

“`
作者:夏木
链接:https://www.zhihu.com/question/68546899/answer/264622524
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
“`

红黄蓝粉碎了我阶层跃迁的梦,即便年薪百万,也保护不了在意的人。
不久之前,上海的携程幼儿园爆出虐童丑闻,因为孩子不好管,就喂孩子吃芥末、安眠药,对孩子拳打脚踢,我很愤怒,但我并不绝望。
因为我想,我才二十多岁,只要我够努力,我就能让我的孩子上一个好点的私立幼儿园,那个幼儿园会请特别好的老师,带着我的孩子做游戏,给他讲道理。
可是这次红黄蓝幼儿园真的彻彻底底粉碎了我的白日梦。
不是说我不能完成阶层跃迁,不能从一个农村的穷小子变成一个中产,不是说我供不起孩子上每个月5000的幼儿园,而是就算我有钱了,那我也保护不了我爱的人。
而且他们不仅会对我的孩子拳打脚踢,还会把他们送到一群狼的嘴里。
注射药剂、喂不明白色药丸、针扎、裸体罚站、拳打脚踢……
对不起,我真的害怕了。

作为一个男生,我不用经历怀胎十月,也不用体验分娩的剧痛。
我只需要多多赚钱,给孩子买最好的奶粉,这样,他就不会被毒奶粉弄成大头娃娃;
我买最好的家具,给他弄一个没有污染的房间,不让他接触甲醛;
我把他能触碰到的地方全都铺上软垫,不让他磕碰撞到;
我给他请最好的最有良心的保姆,每天照顾好她的心情,不让孩子被纵火烧死;
我把他送进最好的幼儿园,为了让老师好好对他,我不仅每个月交5000块,还“无偿捐赠”给幼儿园几十万;
每次放学的时候,我都提前半小时,自己去接孩子,这样他就不会被人贩子拐走了;
路上我都开车,遵守交通规则,安两个行车记录仪,这样即便被碰瓷,也能尽快解决,不给孩子留下坏的印象;
我请健身教练、武术教练、跆拳道教练,教孩子健身、武术、跆拳道,这样学校里有人欺负他的时候,他就能够反击了……
你看,这一路上,我避开了毒奶粉、污染、碰撞,躲开了纵火的保姆、黑心的幼教、人贩子,赶走了碰瓷的老人、校园的霸凌,我就像玩一个大型的游戏一样,小心翼翼,步步为营,哪怕一步走错,就全盘皆输。
我害怕了,我真的害怕了,我怕我走不对,我怕那些我信任的奶粉、保姆、老师会像饿狼一样,我稍不注意,他们就对我的孩子露出獠牙。

我以为,只要我能够从一个穷小子变成中产,我就能保护好我的爱人,保护好我可能会有的孩子。
可是这次红黄蓝幼儿园的家长,正是我朝思暮想心心念念想要成为的中产。
多么讽刺啊。
毫无疑问,我是爱国的,毫无疑问,我也是能够看到国家不足并且想要努力改变那些的。但是每天都会看到一些负面新闻,我觉得我活在一个很矛盾的世界上。
我知道哪里都有好人和坏人,可是当他们出现的时候,我要怎么保护自己,保护自己在乎的人呢?
美国有枪,有毒品,我害怕,我不想去。
欧洲有难民,有绿色,我害怕,我不想去。
可是在国内,我就能安全地活下来吗?我会不会在火灾中被迫让领导先走?我会不会在医院被医闹打得头破血流?我会不会被碰瓷的碰到倾家荡产?
我一直在告诉自己,会好的会好的,人渣到处都有,只要过几年就会好。
可是一个私立幼儿园啊,中国中上阶层才能供得起,我这一辈子可能也就只能完成从一穷二白到中层的跨越,可是我这样的跨越又有什么用呢?最稚嫩最该保护的人被最残忍最肆无忌惮地对待,我又该怎么保护在意的人不受那样的虐待呢?

我可以想象到十年之后的我的样子。
为了钱,为了尊严,我心甘情愿地过上了996的生活。我把自己的开销压到最低,贷款买一套学区房,跟爱人省吃俭用把孩子送去了一家连锁的上市的幼儿园。
我以为,这样的我,是有尊严的。
可是我没想到,我有的,只是自己的白日梦。
事情出现了,媒体们都在避重就轻,说什么幼教虐童,可事实上更严重的,是对幼儿的集体猥亵,集体强奸。
我也不知道为什么事情被爆出来了之后,知乎禁止提问,微博删除热搜,人民日报的评论也一度消失不见。
我更不知道为什么好多次采访里,施虐者的脸上都是马赛克,而被害人就是一张全脸,我们保护的究竟是谁呢?是被害人的隐私更重要,还是施虐者的隐私更重要?
国家强大了,我知道。这二十几年我深切体会到了国家的强大和富裕,从土坯房住到砖瓦房再住到楼房,我是中国发展的红利的享受者。可是这种时候,我就可以不要尊严、不要未来了吗?
看着那些被迫离开北京的人,看着那些徘徊在幼儿园门口的家长,我好像看到了未来。

安卓开发中的Context

在安卓当中,Context几乎是无处不在的,每一个Activity是一个Context,每一个Service也是一个Context。

但是如果你新起了一个线程的话,你需要显式地把Context传递进去。

比如下面的例子:

“`
public class DumpLocationLog extends Thread {
LocationManager lm;
LocationHelper loc;
public DumpLocationLog(Context context) {
loc = new LocationHelper();
lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
public void run() {
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f, loc);
}
}
“`

然后使用这个线程的时候,把this,也就是一个context的实例传递进去

`new DumpLocationLog(this);`

if you are in a fragment, use getAcitvity()

if you are in an anoynmous onclicklistener, `this` is MainActivity.this

为安卓编译64位的dropbear

## 如何使用dropbear

这里主要是需要在安卓上生成 host key,以及把自己的公钥传到安卓上

“`
dropbearkey -t rsa -f /data/local/dropbear_host_key # 在安卓上生成key
adb push ~/.ssh/id_rsa.pub /data/local/authorized_keys # 在宿主机把自己的密钥传过去
dropbear -F -E -r /data/local/dropbear_host_key -A -N root -C jk -R /data/local/authorized_keys # 按照给定的key启动dropbear
dropbear -P /data/local/dropbear.pid -r /data/local/dropbear_host_key -A -N root -C jk -R /data/local/authorized_keys # 以daemon形式启动dropbear
“`

## 如何为64位的安卓机器编译 dropbear

需要更改如下代码(svr-chansession.c):

“`
addnewvar(“LD_LIBRARY_PATH”, “/system/lib”);

to:

addnewvar(“LD_LIBRARY_PATH”, “/system/lib64”);
“`

## 使用AIL把dropbear添加为服务

“`
service sshd /system/xbin/dropbear -s
user root
group root
oneshot
“`
试过了,但是没有成功

## 如何重启adb(wifi)

“`
setprop service.adb.tcp.port 5555
stop adbd
start adbd
“`

# 关闭 ssh key 验证

“`
Host *
StrictHostKeyChecking no
“`

mount -o remount,rw /system

参考

1. http://forum.xda-developers.com/nexus-7-2013/general/guide-compiling-dropbear-2016-73-t3351671
2. http://forum.xda-developers.com/nexus-7-2013/general/guide-compiling-dropbear-2015-67-t3142412/page3

安卓的 AsyncTask

asynchronusally run task without explicitly creating thread.

# Usage

“`
doInBackground(Params…)
onProgressUpdate(Progress…)
onPostExecute(Result)
“`

Here is an example of subclassing:

“`
 private class DownloadFilesTask extends AsyncTask {
     protected Long doInBackground(URL… urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {              totalSize += Downloader.downloadFile(urls[i]);              publishProgress((int) ((i / (float) count) * 100));              // Escape early if cancel() is called              if (isCancelled()) break;          }          return totalSize;      }      protected void onProgressUpdate(Integer... progress) {          setProgressPercent(progress[0]);      }      protected void onPostExecute(Long result) {          showDialog("Downloaded " + result + " bytes");      }  } ```   Once created, a task is executed very simply: ``` new DownloadFilesTask().execute(url1, url2, url3); ``` template parameters can be `Void, Void, Void` see https://developer.android.com/reference/android/os/AsyncTask.html

Linux 内存与进程管理(ps/top/kill…)

# ps 命令

比较有用的选项有

“`
-e 显示所有的进程
-f 显示 uid, pid, ppid, cpu, starttime, tty, cpu usage, command
-j 显示 user, pid, ppid, pgid, sess, jobc, state, tt, time, command。个人更喜欢 -j 一点
-l 显示 uid, pid, ppid, flags, cpu, pri, nice, vsz=SZ, rss, wchan, state=S, paddr=ADDR, tty, time, and command=CMD.
-v 显示 pid, state, time, sl, re, pagein, vsz, rss, lim, tsiz, %cpu, %mem, and command

-L 显示能够排序的关键字(mac)
L 显示能排序的关键字(Linux)
-o/-O 指定显示的列,-o 只显示指定的列,-O有默认的几列,等价于:-o pid,format,state,tname,time,command

-S 把所有已经退出的进程的时间计算到父进程上(mac)
S 把所有已经退出的进程的时间计算到父进程上(Linux)
-u 按照 uid/username 过滤
-p/–pid 限制 pid
-g/–gid 限制 gid
-C 按照命令过滤
–ppid 按照 ppid 过滤
–ssid 按照 ssid 过滤
–tid 按照 tty 过滤

-E 显示环境变量
-H/–forest 按照进程树显示

–sort 按照某一列排序

-ww 不要限制显示的输出宽度
“`

## 例子

1. 使用ps显示占用内存最多的进程

“`
% ps -eo pid,ppid,cmd,%mem,%cpu –sort=-%mem | head
“`

2. 显示所有进程树

“`
% ps -ejH
“`

## 其他相关命令

pstree 查看进程树

pgrep process_name 按照名字查找进程 pid

# top 命令

定时刷新系统的进程状态的监控程序。mac 上的默认排序是pid,Linux 上是 %CPU。mac 上的 top 程序和 Linux 上非常不一样。

– top 教程:https://linoxide.com/linux-command/linux-top-command-examples-screenshots/
– htop 教程:http://www.cnblogs.com/lizhenghn/p/3728610.html
– atop 教程:http://www.cnblogs.com/bangerlee/archive/2011/12/23/2294090.html

## atop

atop 用来分析机器在历史上的负载情况。通过 crontab 固定时间采样,组合起来形成一个 atop 日志文件,可以使用 atop -r XXX 对日志文件查看。

atop 每天以一个 `/var/log/atop/atop_YYYYMMDD` 的形式生成一个日志文件。

常用命令

* b mm:ss 到指定时间
* t 查看后十秒
* T 查看前十秒
* m 按照内存排序
* C 按照CPU排序
* c 查看详细命令

# kill 命令系列

kill -s SIGNAL pid

或者 pkill xxx,不要使用 killall ,[use pkill over killall](https://unix.stackexchange.com/questions/91527/whats-the-difference-between-pkill-and-killall)

# 调整 nice 值

使用 nice 和 renice。nice 的范围是 -20 ~ 19,nice值越低,优先级越高。

nice -n 10 COMMAND # 以 10 为初始nice值启动命令
renice 10 -p pid

# jobs 命令相关

`jobs` list all jobs

`command &` put job in the background

`fg N` to put it in the foreground

`bg N` to put it in the background

`ctrl-z` to put a job to sleep

`kill %n` to kill job number n

# lsof

lsof -i:port 列出指定端口对应的进程

lsof -u username 指定用户

lsof -c process_name 指定进程名

lsof -p pid 指定pid

使用dmesg 查看当前的内核日志,debian上可以查看 /var/log/kern.log /var/log/dmesg.0

RSS is Resident Set Size (physically resident memory – this is currently occupying space in the machine’s physical memory), and VSZ is Virtual Memory Size (address space allocated – this has addresses allocated in the process’s memory map, but there isn’t necessarily any actual memory behind it all right now).[1]

[1] https://stackoverflow.com/questions/7880784/what-is-rss-and-vsz-in-linux-memory-management

分布式系统中的锁

分布式系统需要使用分布锁。首先我们来回忆一下在单机情况下的锁。

当我们的程序在需要访问临界区的时候,我们可以加一个锁,如果是多线程程序,可以使用线程锁,如果是多进程程序,可以使用进程级别的锁。但是在分布式的环境中,如果在不同主机上部署的程序要访问同一个临界区是该怎么做呢?这时候我们需要分布式的锁。

当部署的服务或者脚本不在同一台机器上时,使用分布式的锁,可以使用zookeeper或者redis实现一个分布式锁。这里主要介绍一下基于redis的分布式锁。

redis 官方给出的单机redis分布式锁:

加锁

NX 命令指定了只有在不存在的时候才会创建,如果已经存在,则会返回失败。EX指定了过期时间,避免进程挂掉后死锁。值设定为了一个随机数,这样只有加锁的进程才知道锁的值是多少

“`
SET resource-name my_random_string NX EX max-lock-time
“`

解锁

因为解锁时会检查是否提供了随机数的值,所以只有创建锁的进程才能够解锁。

“`
if redis.call(“get”,KEYS[1]) == ARGV[1] then
return redis.call(“del”,KEYS[1])
else
return 0
end
“`

“`
EVAL ‘script…’ 1 resource-name my_random_string
“`

参考:

[1] https://redis.io/topics/distlock