yaron's space
记录学习过程中的点点滴滴
记录学习过程中的点点滴滴
一 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
十 19th
最近在做性能优化时,遇到一个问题,系统中进程占用的内存没有那么多,但是通过TOP看到系统对实际物理内存接近满额,十分纳闷,后来问了同事
才知道原来是Cache Memory占用了大量内存,上网查阅了相关资料,整理记录下。
当进程对磁盘中的文件大量读写时,Linux内核为了提升读写性能,会将文件在内存中进行缓存,这部分内存就是Cache Memory(缓存内存)。即使你的程序运行结束后,Cache Memory也不会自动释放。这就会导致你在Linux系统中程序频繁读写文件后,你会发现可用物理内存会很少。
用下面的命令可以释放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
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
1. swapoff -a : 禁用swap空间
2. swapon -a : 开启swap空间
八 24th
今天学习了sort, uniq, cut, paste和split命令的用法,其中sort的选项比较多一些,其它的命令就比较简单了
关于sort,本站之前写过一篇关于sort的高级用法,请点击这里
sort [OPTION]… [FILE]…
对文件按指定的域进行排序
sort -o output.txt your_file.txt #对文件按第一域进行排序,将排序结果保存到output.txt sort -t: -r +2n your_file.txt #对文件按照第2个域进行逆向排序,第二个域为数字类型,同时分割符为: df | sort -b -r -k5 #按照磁盘的占用率从高到底进行排序输出
uniq [OPTION]… [INPUT [OUTPUT]]
从文件中去除或删除重复的行,在功能上和sort -u类似
uniq sort_file.txt #删除文件中重复的行 uinq -c sort_file.txt #显示每行出现的次数 uinq -d sort_file.txt #只显示出现次数>=2的行
join [OPTION]… FILE1 FILE2
将两个排序的文件合并为一个文件
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 OPTION… [FILE]…
从文件中获取指定域
cut -d: f3 file.txt #输出以:分割的第三个域 cut -d: f 1, 6 file.txt #输出以:分割的第一个和第六个域 ls -al | cut -c1-3 #显示ls输出每行的前三个字符
paste [OPTION]… [FILE]…
将文件的行进行merge
paste file1 file2 #将两个文件的每行合并 paste -d: file1 file2 #将两个文件的每行合并,分隔符为: paste -s file1 file2 #将file1的内容合并为一行,将file2的内容合并为一行
split [OPTION]… [INPUT [PREFIX]]
将文件按大小分为多份
split -20 file #将文件每20行进行一次分割
八 13th
最新在看《Linux And Unix shell Programing 》,避免看完之后忘记,以后每看一部分都记录下。今天主要记录下linux下
最常用的两个命令grep和find。
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
查找文件中包含某个关键词的行;
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 [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression]
在目录中查找文件
find . -name "*.txt" -print #在当前目录及其子目录中查找以.txt文件为后缀的文件 find . -type d -print #查到当前目录中的目录文件 find . -mtime +5 -name "*.log" -exec rm {} \; #删除5天前得日志 find . -mtime +5 -name "*.log" -ok rm {} \; #功能同上,但是删除前会确认
七 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. 如何生成对象工厂类呢? 这里首先不能将这个工作交给插件开发者,一方面开发量增大,另一方面也暴漏系统实现细节;但是也不能框架开发者手工实现,因为框架本身无法预知都有哪些插件需要开发。
所以可能的方法包括模板函数或者是宏定义了,本文使用宏定义进行实现,包括插件类型工厂和某个插件工厂。
七 14th
scoped_ptr, shared_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();
// 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的引用计数 };
六 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循环进行验证,以便能够容忍这种竞争。
六 16th
在shell脚本下,可以多种方式实现按行读取文件,如下:
for line in `cat ${input_filename}` do echo $line done
while read line do echo $line done < ${input_filename}
其中第二种方式是将文件重定向到标准输入中
那如何实现同时多个文件的读呢?
我们可以继续利用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
五 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即可
四 12th
鉴于国内网络环境的恶劣,本人的blog的托管在国外的vps,为了防范数据丢失,需要及时备份下网站的数据和代码,这样等哪天数据丢失即可及时恢复,数据最重要
自己就通过查找资料,简单地写了shell脚本
即可搞定
另外在使用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 **** ****
近期评论