admin

该用户没有分享资料


admin

Latency Numbers Every Programmer Should Know

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的介绍

最近在做性能优化时,遇到一个问题,系统中进程占用的内存没有那么多,但是通过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用法详解

今天学习了sort, uniq, cut, paste和split命令的用法,其中sort的选项比较多一些,其它的命令就比较简单了

关于sort,本站之前写过一篇关于sort的高级用法,请点击这里

一、Sort命令

sort [OPTION]… [FILE]…

对文件按指定的域进行排序

常用选项:
  1. -c: 检测文件是否已经排序
  2. -m: 将两个已经排序的文件进行合并
  3. -u: 在排序过程中,删除重复的行
  4. -o: 保存排序后的文件
  5. -t: 域分隔符,默认为空格和tab
  6. -n: 指定待排序的域为数字类型
  7. -r: 逆序排序,默认为正向排序
  8. -b: 按域排序时忽略第一个空格
  9. +n: 按照第n个域进行排序,域从第0个开始计数
  10. +m.n: 按照第m个域的第n个字符开始开始排序
  11. -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类似

常用选项:
  1. -u: 只显示不重复的行
  2. -d: 只显示重复的行
  3. -c: 打印每一行出现的次数
  4. -fn: 忽略前n个域
常用的用法例子:

uniq sort_file.txt #删除文件中重复的行

uinq -c sort_file.txt  #显示每行出现的次数

uinq -d sort_file.txt  #只显示出现次数>=2的行

三、join命令

join [OPTION]… FILE1 FILE2

将两个排序的文件合并为一个文件

常用选项:
  1. -j n  m: 选择连接的域,n为文件号,m为域号
  2. -o n.m : 指定显示的域,n为文件号,m为域号
  3. -an: 显示文件n中不匹配的文件行
  4. -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]…

从文件中获取指定域

常用选项:
  1. -d: 分割符
  2. -f: 输出域的编号
  3. -c: 输出字符的编号
常见的用法:

cut -d: f3 file.txt #输出以:分割的第三个域

cut  -d: f 1, 6 file.txt #输出以:分割的第一个和第六个域

ls -al | cut -c1-3  #显示ls输出每行的前三个字符

五、paste命令

paste [OPTION]… [FILE]…

将文件的行进行merge

常用选项:
  1. -d:  指定两个文件的行合并后的分割符
  2. -s: 将每个文件合并为一行,而不是按行进行合并
常见用法:

paste file1 file2 #将两个文件的每行合并

paste -d: file1 file2 #将两个文件的每行合并,分隔符为:

paste -s file1 file2 #将file1的内容合并为一行,将file2的内容合并为一行

六、split命令

split [OPTION]… [INPUT [PREFIX]]

将文件按大小分为多份

常用选项:
  1. -output_file-size: 指定文件被分割的行数
  2. prefix: 输出文件的前缀
常见用法:

split -20 file #将文件每20行进行一次分割

    [shell学习笔记]grep和find命令详解

    最新在看《Linux And Unix shell Programing 》,避免看完之后忘记,以后每看一部分都记录下。今天主要记录下linux下

    最常用的两个命令grep和find。

    一、Grep命令

    grep [OPTIONS] PATTERN [FILE...]

    grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]

    查找文件中包含某个关键词的行;

    常用选项:
    1. -c : 只输出匹配的行数
    2. -i : 查找不区分大小写
    3. -n: 显示匹配的行号
    4. -v: 显示不包含关键词的行
    5. -A Num: 显示匹配的行及其后面num行
    6. -B Num: 显示匹配的行及其前面的num行
    7. -r:  如果遇到目录递归查询
    8. -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]

    在目录中查找文件

    常用选项:
    1. -name: 按照文件名来查找
    2. -type: 按照文件类型查找(b: block  d: directory  )
    3. -perm: 按照权限来查找
    4. -user: 按照文件属主来查找
    5. -group: 按照组来查找
    6. -mtime +n -n: 按照修改时间来查找,-n代表n天以内的修改的文件,+n代表n天以前的修改的文件
    7. -newer fil1 !file2 : 查找比file1新的文件,但是比file2旧的文件
    8. -size n c: 按照文件大小查找,带c表示以字节计算
    9. -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 {} \; #功能同上,但是删除前会确认
    
    register

    C++插件机制的一种实现方法(对象工厂)

    背景

    在我们的实际开发过程中,经常会开发一些插件,比较常见的例子如:给你 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用法和实现方法

    scoped_ptr, shared_ptr和weak_ptr的都称为智能指针,但是各个的用法都不太一样,

    本文就就详细介绍其具体用法以及具体实现方法。

    • 用法介绍

    1. scoped_ptr: “scoped”即作用域的含义,主要用于指针在某个作用域中有效,当离开作用域时,该指针自动释放,这就避免了出现忘记回收内存的情形,同时scoped_ptr的复制构造函数和赋值函数为私有,这样就避免了指针的传递, 示例如下:
    2. 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.
      }
      
    3. shared_ptr: 共享所有权的智能指针,当某个对象需要在多个地方使用时,被多个指针引用,此时程序可能就无法确定在何时释放该对象,因此就需要使用“引用计数”的方法,当对象被引用的次数为0时,自动释放该对象,示例代码如下:
    4. 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();
      
    5. weak_ptr: shared_ptr是强引用,而weak_ptr是弱引用;当使用shared_ptr出现循环引用时,造成内存无法释放,如果 你能预料到此种情况发生,你就应该使用weak_ptr类型;另外weak_ptr不会增加所指对象的引用计数,但是会增加计数器的对象引用计数,这点可以后面的实现中看到这点,详细请点击这里
    • 实现原理

    1. scoped_ptr的实现:其主要是在其析构函数中delete对象,同时将copy constructure 和 assign operator设置为私有,避免了指针的传递,这点比auto_ptr安全的多;另外scoped_array是针对new[]和delete[]的只能指针,具体实现请见附件。
    2. shared_ptr的实现:其主要用到了引用计数,每个指向同一对象shared_ptr都指向同一个计数器,其中计数器的定义如下,当shared_ptr对象复制时,对象引用计数加1,当shared_ptr对象释放时,引用计数减1,当引用计数减为0时,delete所指的对象。具体实现请看附件。
    3. 
      // 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的引用计数
      };
      
    4. weak_ptr的实现:需要注意的一点weak_ptr需要使用shared_ptr构造,不能直接使用原始指针进行构造,它主要操作的是weak_count_计数器,具体实现请看附件。

    更多 >

    关于pthread_cond_wait使用while循环判断的理解

    在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下同时读取多个文件的方法

    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地址方法

    通过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工具

    需求

    鉴于国内网络环境的恶劣,本人的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 **** ****