记录学习过程中的点点滴滴
admin
该用户没有分享资料
admin
Latency Numbers Every Programmer Should Know
一 18th
Latency Comparison Numbers -------------------------- L1 cache reference 0.5 ns Branch mispredict 5 ns L2 cache reference 7 ns 14x L1 cache Mutex lock/unlock 25 ns Main memory reference 100 ns 20x L2 cache, 200x L1 cache Compress 1K bytes with Zippy 3,000 ns Send 1K bytes over 1 Gbps network 10,000 ns 0.01 ms Read 4K randomly from SSD* 150,000 ns 0.15 ms Read 1 MB sequentially from memory 250,000 ns 0.25 ms Round trip within same datacenter 500,000 ns 0.5 ms Read 1 MB sequentially from SSD* 1,000,000 ns 1 ms 4X memory Disk seek 10,000,000 ns 10 ms 20x datacenter roundtrip Read 1 MB sequentially from disk 20,000,000 ns 20 ms 80x memory, 20X SSD Send packet CA->Netherlands->CA 150,000,000 ns 150 ms Notes ----- 1 ns = 10-9 seconds 1 ms = 10-3 seconds * Assuming ~1GB/sec SSD Credit ------ By Jeff Dean: http://research.google.com/people/jeff/ Originally by Peter Norvig: http://norvig.com/21-days.html#answers Contributions ------------- Some updates from: https://gist.github.com/2843375 Great 'humanized' comparison version: https://gist.github.com/2843375 Visual comparison chart: http://i.imgur.com/k0t1e.png Nice animated presentation of the data: http://prezi.com/pdkvgys-r0y6/latency-numbers-for-programmers-web-development/
这里有一篇更详细,描述了各个年代相关模块的latency:
http://www.eecs.berkeley.edu/~rcs/research/interactive_latency.html
Linux中关于Cache Memory的介绍
十 19th
最近在做性能优化时,遇到一个问题,系统中进程占用的内存没有那么多,但是通过TOP看到系统对实际物理内存接近满额,十分纳闷,后来问了同事
才知道原来是Cache Memory占用了大量内存,上网查阅了相关资料,整理记录下。
什么是Cache Memory
当进程对磁盘中的文件大量读写时,Linux内核为了提升读写性能,会将文件在内存中进行缓存,这部分内存就是Cache Memory(缓存内存)。即使你的程序运行结束后,Cache Memory也不会自动释放。这就会导致你在Linux系统中程序频繁读写文件后,你会发现可用物理内存会很少。
如何释放Cache Memory(缓存内存):
用下面的命令可以释放Cache Memory:
To free pagecache:
echo 1 > /proc/sys/vm/drop_caches
To free dentries and inodes:
echo 2 > /proc/sys/vm/drop_caches
To free pagecache, dentries and inodes:
echo 3 > /proc/sys/vm/drop_caches
free命令介绍
total used free shared buffers cached
Mem: 16425996 10727220 5698776 0 380904 9389832
-/+ buffers/cache: 956484 15469512
Swap: 8273464 212 8273252
其中第一行用全局角度描述系统使用的内存状况:
total——总物理内存
used——已使用内存,一般情况这个值会比较大,因为这个值包括了cache+应用程序使用的内存
free——完全未被使用的内存
shared——应用程序共享内存
buffers——缓存,主要用于目录方面,inode值等(ls大目录可看到这个值增加)
cached——缓存,用于已打开的文件
另外这里有一篇taobao的大牛对memory使用的介绍,很详细:http://blog.yufeng.info/archives/2456
Linux下禁用Swap的方法
1. swapoff -a : 禁用swap空间
2. swapon -a : 开启swap空间
[shell学习笔记]sort、uniq、cut、paste和split用法详解
八 24th
今天学习了sort, uniq, cut, paste和split命令的用法,其中sort的选项比较多一些,其它的命令就比较简单了
关于sort,本站之前写过一篇关于sort的高级用法,请点击这里
一、Sort命令
sort [OPTION]… [FILE]…
对文件按指定的域进行排序
常用选项:
- -c: 检测文件是否已经排序
- -m: 将两个已经排序的文件进行合并
- -u: 在排序过程中,删除重复的行
- -o: 保存排序后的文件
- -t: 域分隔符,默认为空格和tab
- -n: 指定待排序的域为数字类型
- -r: 逆序排序,默认为正向排序
- -b: 按域排序时忽略第一个空格
- +n: 按照第n个域进行排序,域从第0个开始计数
- +m.n: 按照第m个域的第n个字符开始开始排序
- -k: 按照第k个域进行排序,域从第1个开始计数
常见的用法例子:
sort -o output.txt your_file.txt #对文件按第一域进行排序,将排序结果保存到output.txt sort -t: -r +2n your_file.txt #对文件按照第2个域进行逆向排序,第二个域为数字类型,同时分割符为: df | sort -b -r -k5 #按照磁盘的占用率从高到底进行排序输出
二、uniq命令
uniq [OPTION]… [INPUT [OUTPUT]]
从文件中去除或删除重复的行,在功能上和sort -u类似
常用选项:
- -u: 只显示不重复的行
- -d: 只显示重复的行
- -c: 打印每一行出现的次数
- -fn: 忽略前n个域
常用的用法例子:
uniq sort_file.txt #删除文件中重复的行 uinq -c sort_file.txt #显示每行出现的次数 uinq -d sort_file.txt #只显示出现次数>=2的行
三、join命令
join [OPTION]… FILE1 FILE2
将两个排序的文件合并为一个文件
常用选项:
- -j n m: 选择连接的域,n为文件号,m为域号
- -o n.m : 指定显示的域,n为文件号,m为域号
- -an: 显示文件n中不匹配的文件行
- -t: 定义分隔符
常见的用方法:
join sort_file1.txt sort_file2.txt #合并两个文件,以第一个键排序 join -j 1 1 -j 2 2 sort_file1.txt sort_file2.txt #按第一文件的第一个域和第二个文件的第二个域作为key,进行合并 join -o 1.1 , 2.2 sort_file1.txt sort_file2.txt #只显示第一个文件的第一个域和第二个文件的第二个域
四、cut命令
cut OPTION… [FILE]…
从文件中获取指定域
常用选项:
- -d: 分割符
- -f: 输出域的编号
- -c: 输出字符的编号
常见的用法:
cut -d: f3 file.txt #输出以:分割的第三个域 cut -d: f 1, 6 file.txt #输出以:分割的第一个和第六个域 ls -al | cut -c1-3 #显示ls输出每行的前三个字符
五、paste命令
paste [OPTION]… [FILE]…
将文件的行进行merge
常用选项:
- -d: 指定两个文件的行合并后的分割符
- -s: 将每个文件合并为一行,而不是按行进行合并
常见用法:
paste file1 file2 #将两个文件的每行合并 paste -d: file1 file2 #将两个文件的每行合并,分隔符为: paste -s file1 file2 #将file1的内容合并为一行,将file2的内容合并为一行
六、split命令
split [OPTION]… [INPUT [PREFIX]]
将文件按大小分为多份
常用选项:
- -output_file-size: 指定文件被分割的行数
- prefix: 输出文件的前缀
常见用法:
split -20 file #将文件每20行进行一次分割
[shell学习笔记]grep和find命令详解
八 13th
最新在看《Linux And Unix shell Programing 》,避免看完之后忘记,以后每看一部分都记录下。今天主要记录下linux下
最常用的两个命令grep和find。
一、Grep命令
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
查找文件中包含某个关键词的行;
常用选项:
- -c : 只输出匹配的行数
- -i : 查找不区分大小写
- -n: 显示匹配的行号
- -v: 显示不包含关键词的行
- -A Num: 显示匹配的行及其后面num行
- -B Num: 显示匹配的行及其前面的num行
- -r: 如果遇到目录递归查询
- -E :正则表达式扩展
常见的用法
grep keyword -r * # 在当前目录及其子目录下查找包含keyword的行 grep --exclude="*\.svn*" keyword -r * #功能同上,但是不查找.svn文件 #正则表达式 grep ‘48[34]’ your_file #查找包含483或者484的行 grep '4\{3,8\}' your_file #查找包含3个到8个4的行 grep -E '216|329' your_file #包含216或者329的行 #和其它程序配合使用 ps aux | grep apache2 | grep -v grep #查找apache2相关进程
二、Find命令
find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression]
在目录中查找文件
常用选项:
- -name: 按照文件名来查找
- -type: 按照文件类型查找(b: block d: directory )
- -perm: 按照权限来查找
- -user: 按照文件属主来查找
- -group: 按照组来查找
- -mtime +n -n: 按照修改时间来查找,-n代表n天以内的修改的文件,+n代表n天以前的修改的文件
- -newer fil1 !file2 : 查找比file1新的文件,但是比file2旧的文件
- -size n c: 按照文件大小查找,带c表示以字节计算
- -exec: 当匹配到文件后,执行某些命令,该命令以 {} \;结束,如果在执行命令前需要确认,请加-ok选项
常见的用法
find . -name "*.txt" -print #在当前目录及其子目录中查找以.txt文件为后缀的文件 find . -type d -print #查到当前目录中的目录文件 find . -mtime +5 -name "*.log" -exec rm {} \; #删除5天前得日志 find . -mtime +5 -name "*.log" -ok rm {} \; #功能同上,但是删除前会确认

C++插件机制的一种实现方法(对象工厂)
七 21st
背景
在我们的实际开发过程中,经常会开发一些插件,比较常见的例子如:给你 DataHandler,它是一个抽象类,提供一些数据操作的接口,然后插件开发者就需要继承DataHandler,并按需求实现对应的接口,将其作为插件,编译到最终的二进制程序中,最后通过配置文件指定生效该插件。
// data_handler.h Class DataHandler { public: virtual bool Handle(std::vector<Data*> data_list) =0; virtual ~DataHandler(){} }; REGISTER_REGISTER(DataHandler) #define REGISTER_DATA_HANDLER(name) REGISTER_CLASS(DataHandler, name)
// my_data_handler.h class MyDataHandler : public DataHandler { public: virtual bool Handle(std::vector<Data*> result_list); };
// my_data_handler.cc bool MyDataHandler::Handle(std::vector<Data*> data_list) { // Implemention... } REGISTER_DATA_HANDLER(MyDataHandler)
// configure file DataHandler{ name : MyDataHanlder, prior : 1 } DataHanlder{ name : YourDataHandler, prior : 1 }
此时你只需把你的MyDataHandler编译为动态库或者是静态库,并链接到最终二进制中,在数据处理时就会调用你的DataHandler。是不是很方便开发哈,这就是所谓的插件开发思想。下面主要介绍下具体的实现。
实现思想
想要实现上述功能的插件框架,主要从以下几个方面着手解决:
1. 如何组织不同类型的插件,如目前有DataHanlder,但是系统可能也支持ServiceHanlder等等;某类插件可能包含多个具体的实例的插 件,那又如何组织;这里很容易就想到了双层map的数据结构,如下图所示,每层Map的Key都插件类型或者具体插件名字,value为对应的工厂对象, 工厂对象生成对应的实例,具体如下图所示:
2. 如何生成对象工厂类呢? 这里首先不能将这个工作交给插件开发者,一方面开发量增大,另一方面也暴漏系统实现细节;但是也不能框架开发者手工实现,因为框架本身无法预知都有哪些插件需要开发。
所以可能的方法包括模板函数或者是宏定义了,本文使用宏定义进行实现,包括插件类型工厂和某个插件工厂。
scoped_ptr,shared_ptr和weak_ptr用法和实现方法
七 14th
scoped_ptr, shared_ptr和weak_ptr的都称为智能指针,但是各个的用法都不太一样,
本文就就详细介绍其具体用法以及具体实现方法。
-
用法介绍
- scoped_ptr: “scoped”即作用域的含义,主要用于指针在某个作用域中有效,当离开作用域时,该指针自动释放,这就避免了出现忘记回收内存的情形,同时scoped_ptr的复制构造函数和赋值函数为私有,这样就避免了指针的传递, 示例如下:
- shared_ptr: 共享所有权的智能指针,当某个对象需要在多个地方使用时,被多个指针引用,此时程序可能就无法确定在何时释放该对象,因此就需要使用“引用计数”的方法,当对象被引用的次数为0时,自动释放该对象,示例代码如下:
- weak_ptr: shared_ptr是强引用,而weak_ptr是弱引用;当使用shared_ptr出现循环引用时,造成内存无法释放,如果 你能预料到此种情况发生,你就应该使用weak_ptr类型;另外weak_ptr不会增加所指对象的引用计数,但是会增加计数器的对象引用计数,这点可以后面的实现中看到这点,详细请点击这里
scoped<T> g_ptr; { scoped_ptr<T> ptr(new T); g_ptr = ptr;//illegal, because the assign operator is private. //T* will deleted when it goes out of this scoped. }
shared_ptr<T> g_ptr; { shared_ptr<T> ptr<new T>; // reference count is 1. g_ptr = ptr; //now reference count is 2 // when it goes out of this scoped, the reference count is 1 } //the reference count is 1. g_ptr->foo();
-
实现原理
- scoped_ptr的实现:其主要是在其析构函数中delete对象,同时将copy constructure 和 assign operator设置为私有,避免了指针的传递,这点比auto_ptr安全的多;另外scoped_array是针对new[]和delete[]的只能指针,具体实现请见附件。
- shared_ptr的实现:其主要用到了引用计数,每个指向同一对象shared_ptr都指向同一个计数器,其中计数器的定义如下,当shared_ptr对象复制时,对象引用计数加1,当shared_ptr对象释放时,引用计数减1,当引用计数减为0时,delete所指的对象。具体实现请看附件。
- weak_ptr的实现:需要注意的一点weak_ptr需要使用shared_ptr构造,不能直接使用原始指针进行构造,它主要操作的是weak_count_计数器,具体实现请看附件。
// This class is an internal implementation detail for shared_ptr. class SharedPtrControlBlock { template <typename T> friend class shared_ptr; template <typename T> friend class weak_ptr; private: SharedPtrControlBlock() : refcount_(1), weak_count_(1) { } int refcount_; //对象的引用计数 int weak_count_; //weak_ptr的引用计数 };
关于pthread_cond_wait使用while循环判断的理解
六 28th
在Stevens的《Unix 环境高级编程》中第11章线程关于pthread_cond_wait的介绍中有一个生产者-消费者的例子P311,
在进入pthread_cond_wait前使用while进行条件判断,而没有直接使用if,耐人费解!
代码如下:
#include <pthread.h> struct msg { struct msg *m_next; /* value...*/ }; struct msg* workq; pthread_cond_t qready = PTHREAD_COND_INITIALIZER; pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER; void process_msg() { struct msg* mp; for (;;) { pthread_mutex_lock(&qlock); while (workq == NULL) { pthread_cond_wait(&qread, &qlock); } mq = workq; workq = mp->m_next; pthread_mutex_unlock(&qlock); /* now process the message mp */ } } void enqueue_msg(struct msg* mp) { pthread_mutex_lock(&qlock); mp->m_next = workq; workq = mp; pthread_mutex_unlock(&qlock); /** 此时另外一个线程在signal之前,执行了process_msg,刚好把mp元素拿走*/ pthread_cond_signal(&qready); /** 此时执行signal, 在pthread_cond_wait等待的线程被唤醒, 但是mp元素已经被另外一个线程拿走,所以,workq还是NULL ,因此需要继续等待*/ }
这里process_msg相当于消费者,enqueue_msg相当于生产者,struct msg* workq作为缓冲队列
解释如下
在process_msg中使用while(workq==NULL)循环判断条件,这里主要是因为在enqueue_msg中unlock之后才唤醒等待
的线程,会出现上述注释出现的情况,造成workq==NULL,因此需要继续等待。
但是如果将pthread_cond_signal移到pthread_mutex_unlock()之前执行,则会避免这种竞争,在unlock
之后,会首先唤醒pthread_cond_wait的线程,进而workq!=NULL总是成立。
因此建议使用while循环进行验证,以便能够容忍这种竞争。
shell下同时读取多个文件的方法
六 16th
1. 单个文件的读取
在shell脚本下,可以多种方式实现按行读取文件,如下:
for line in `cat ${input_filename}` do echo $line done
while read line do echo $line done < ${input_filename}
其中第二种方式是将文件重定向到标准输入中
2. 多个文件读取方法
那如何实现同时多个文件的读呢?
我们可以继续利用bash中的文件重定向功能,将文件重定向到特定的文件描述符中,语法如下:
n<file n>file n>>file n<>file
这里的n代表打开文件file的文件描述符,类似其他编程语言中的fd,如果没有指定n,则其默认行为如下:
<file #same as 0<file >file #same as 1>file <>file #same as 0<>file
我们可以通过exec命令来打开所要重定向的文件:
exec 7<file1 exec 8<file2
然后我们可以通过read命令来读取对应文件的内容:
read data <&7 #使用符合是为了区分7是文件描述符,而不是文件名 read data <&8
关闭文件
exec 7</dev/null exec 8</dev/null
多文件读取示例代码如下:
readfiles() { local FD1=7 local FD2=8 local file1=$1 local file2=$2 local count1=0 local count2=0 local eof1=0 local eof2=0 local data1 local data2 # Open files. exec 7<$file1 exec 8<$file2 while [[ $eof1 -eq 0 || $eof2 -eq 0 ]] do if read data1<&$FD1; then let count1++ printf "%s, line %d: %s\n" $file1 $count1 "$data1" else eof1=1 fi if read data2 <&$FD2; then let count2++ printf "%s, line %d: %s\n" $file2 $count2 "$data2" else eof2=1 fi done } #read file1 and file2 readfiles file1 file2
参考资料:http://www.linuxjournal.com/content/reading-multiple-files-bash
linux通过Shell获得本机ip地址方法
五 31st
通过Shell获得本机IP地址方法,直接上代码:
IP=`ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'`; echo $IP;
如果想获得第一个IP地址的话,可以在grep ‘inet addr:’增加参数-m 1即可
定时备份网站代码与数据的shell工具
四 12th
需求
鉴于国内网络环境的恶劣,本人的blog的托管在国外的vps,为了防范数据丢失,需要及时备份下网站的数据和代码,这样等哪天数据丢失即可及时恢复,数据最重要
解决方法
自己就通过查找资料,简单地写了shell脚本
- 首先打包wordpress代码,使用mysqldump导出mysql数据
- 其次使用mail命令发送数据到指定邮箱
- 最后crontab定时执行
即可搞定
另外在使用mail命令行工具时遇到了一个问题,stackoverflow帮我解决了,具体在这里
实现脚本
#!/bin/bash # author: yaronli (jidalyg_8711@163.com) # powered by yaronspace.cn set -x backup() { cd /var/www/ #打包代码 tar -czf /tmp/${1}_$(date +%F).tar.gz ${1} #导出数据 mysqldump -u${2} -p${3} ${1} > /tmp/${1}_$(date +%F).sql #以附件形式发送邮件 (uuencode /tmp/${1}_$(date +%F).tar.gz ${1}_$(date +%F).tar.gz; uuencode /tmp/${1}_$(date +%F).sql ${1}_$(date +%F).sql)\ | mail -s ${1}_$(date +%F) yangguangli19871124@gmail.com } #param1: 站点目录 param2: 数据库用户 param3: 密码 backup yaronspace **** **** backup xiaofangdeng **** ****
近期评论