闲侃CPU(三)

CPU执行一条指令包含下面5个步骤,其中每个步骤都会由CPU的一个专门的功能单元(function unit)来完成:
(1)取指令;
(2)解码;
(3)执行指令;
(4)内存访问;
(5)写回寄存器。
最后两个步骤是可选的,因为很多指令只会访问寄存器,不会访问内存。上面的每个步骤至少要花费一个时钟周期(clock cycle)去完成。内存访问通常是最慢的,要占用多个时钟周期。 

指令流水线(Instruction Pipeline):是一种可以并行执行多条指令的CPU结构(architecture),也即同时执行不同指令的不同部分。假设上面提到的执行指令5个步骤每个步骤都占1个时钟周期,那么完成一个指令需要5个时钟周期(假设步骤45都要经历)。在执行这条指令的过程,每个步骤只有CPU的一个功能单元是工作的,其它的都在空闲中。采用指令流水线以后,多个功能单元可以同时活跃,举个例子:在解码一条指令时,可以同时取下一条指令。这样可以大大提高效率。理想情况下,执行每条指令仅需要1个时钟周期。

更进一步,如果CPU内执行特定功能的功能单元有多个的话,那么每个时钟周期可以完成更多的指令。这种CPU结构称之为“超标量(superscalar)”。指令宽度(Instruction Width)描述了可以并行处理的指令的数量。现代CPU一般是3-wide4-wide,即每个时钟周期可处理3~4条指令。

Cycles per instruction(CPI)是描述CPU在哪里耗费时钟周期和理解CPU利用率的一个重要度量参数。这个参数也可以表示为instructions per cycle(IPC)CPI表达了指令处理的效率,并不是指令本身的效率。

Bash shell进程问题浅析

bash shell中执行一个命令时,其实是由bash shell fork出一个子进程,然后在这个子进程中运行相应的命令,直至退出。在一个终端执行下列操作:

[root@localhost ~]# echo $$
19954
[root@localhost ~]# sleep 100

在另一个终端执行下列操作:

[root@localhost bin]# ps -ef | grep 19954
root     19954 19353  0 03:01 pts/3    00:00:00 /bin/bash
root     20265 19954  0 04:39 pts/3    00:00:00 sleep 100
root     20267 19354  0 04:39 pts/0    00:00:00 grep --color=auto 19954

可以看到第一个终端的bash shell(进程ID19954fork产生了sleep 100这个进程。

当在bash shell中执行一个bash shell脚本时,其实先会fork出一个subshell子进程,再由这个子进程执行脚本中的命令。举个例子可能会解释的更清楚。

这是一个简单的bash shell脚本(test.sh):

#!/bin/bash
sleep 100

在一个终端执行这个脚本:

[root@localhost ~]# echo $$
19954
[root@localhost ~]# ./test.sh

在另一个终端执行下列操作:

[root@localhost bin]# ps -ef | grep test
root     20309 19954  0 05:01 pts/3    00:00:00 /bin/bash ./test.sh
root     20316 19354  0 05:02 pts/0    00:00:00 grep --color=auto test
[root@localhost bin]# ps -ef | grep 20309
root     20309 19954  0 05:01 pts/3    00:00:00 /bin/bash ./test.sh
root     20310 20309  0 05:01 pts/3    00:00:00 sleep 100
root     20318 19354  0 05:02 pts/0    00:00:00 grep --color=auto 20309

可以看到第一个终端的bash shell(进程ID19954fork产生了test.sh这个进程(进程ID20309),而test.sh这个进程又fork产生了sleep 100这个进程。

接下来要提一下source(“.”命令作用是一样的)这个bash shell内建命令。man source是这样解释的:

.  filename [arguments]
source filename [arguments]
      Read and execute commands from filename in the current shell environment and return the exit status of the last command executed from filename.  If filename does not contain a slash, file names in  PATH  are used to find the directory containing filename.  The file searched for in PATH need not be executable.  When bash is not in posix mode, the current directory is searched if no  file is  found in PATH.  If the sourcepath option to the shopt builtin command is turned off, the PATH is not searched.  If any arguments are supplied, they become the positional parameters when filename  is  executed.  Otherwise the positional parameters are unchanged.  The return status is the status of the last command exited within the script (0 if no commands are executed), and false if filename is not found or cannot be read.

可以看出,“source filename [arguments]”会在当前的shell环境执行文件中的命令,也就是不会产生一个subshell子进程。仍利用test.sh脚本演示一下:

在一个终端执行这个脚本:

[root@localhost ~]# echo $$
19954
[root@localhost ~]# source ./test.sh

在另一个终端执行下列操作:

[root@localhost bin]# ps -ef | grep test
root     20349 19354  0 05:24 pts/0    00:00:00 grep --color=auto test
[root@localhost bin]# ps -ef | grep 19954
root     19954 19353  0 03:01 pts/3    00:00:00 /bin/bash
root     20345 19954  0 05:24 pts/3    00:00:00 sleep 100
root     20347 19354  0 05:24 pts/0    00:00:00 grep --color=auto 19954

可以看到并没有test.sh这个进程,sleep 100这个进程是由bash shell(进程ID19954)进程直接fork产生的。

参考资料:
Shell十三问

推荐一篇介绍函数式编程(functional programming)的文章

说实话,对于函数式编程(functional programming),我一直云里雾里,不大明白。今天读到一篇文章:An introduction to functional programming,感觉写的不错,读完之后,至少觉得自己入门了。我把其中最核心的一段话摘录出来,并做了翻译:

When people talk about functional programming, they mention a dizzying number of “functional” characteristics. They mention immutable data, first class functions and tail call optimisation. These are language features that aid functional programming. They mention mapping, reducing, pipelining, recursing, currying and the use of higher order functions. These are programming techniques used to write functional code. They mention parallelization, lazy evaluation and determinism. These are advantageous properties of functional programs.  

Ignore all that. Functional code is characterised by one thing: the absence of side effects. It doesn’t rely on data outside the current function, and it doesn’t change data that exists outside the current function. Every other “functional” thing can be derived from this property. Use it as a guide rope as you learn.

译文:

当人们谈论起函数式编程,他们总会提到一堆令人眼花缭乱的“函数式”特性。他们提到“不可变数据”,“`first class functions`”和“尾调用优化”。这些是辅助函数式编程的语言特性。他们提到“`map/reduce`”,“流水线”,“递归”,“`currying`”和“高阶函数”。这些是写函数式代码的编程技术。他们提到“并行”,“惰性求值”和“确定性”。这些是函数式程序的优良特性。  

忽略上面提到的这些,函数式代码被一个特性所决定:没有副作用,即它不依赖于也不会改变当前函数以外的数据状态。其它所有“函数式特性”均由此特性衍生出来。  

使用screen命令产生并管理多个工作窗口

Unix/Linux下的screen命令一个很重要的功能就是可以在一个物理连接(SSH/telnet)终端(terminal)上创建并管理多个工作窗口(也称之为“virtual terminal”)。达到此目的可以有以下两种方式:

(1)启动screen命令进入一个工作窗口,进行一番操作后,使用ctrl-a d命令离开这个窗口,回到真实的终端。然后在真实终端再次启动screen命令,就可以启动下一个工作窗口。如下例所示:

[root@localhost ~]# screen
[detached from 5362.pts-0.localhost]
[root@localhost ~]# screen
[detached from 5378.pts-0.localhost]
[root@localhost ~]#
[root@localhost ~]# ps -ef | grep -i SCREEN
root      5362     1  0 06:19 ?        00:00:00 SCREEN
root      5378     1  0 06:20 ?        00:00:00 SCREEN
root      5394  5334  0 06:20 pts/0    00:00:00 grep --color=auto -i SCREEN
[root@localhost ~]# screen -ls
There are screens on:
        5378.pts-0.localhost    (Detached)
        5362.pts-0.localhost    (Detached)
2 Sockets in /var/run/screen/S-root.
[root@localhost ~]# ps -ef | grep 5378
root      5378     1  0 06:20 ?        00:00:00 SCREEN
root      5379  5378  0 06:20 pts/2    00:00:00 /bin/bash
root      5745  5722  0 21:45 pts/0    00:00:00 grep --color=auto 5378
[root@localhost ~]# ps -ef | grep 5362
root      5362     1  0 06:19 ?        00:00:00 SCREEN
root      5363  5362  0 06:19 pts/1    00:00:00 /bin/bash
root      5749  5722  0 21:50 pts/0    00:00:00 grep --color=auto 5362

可以看到会有两个SCREEN进程(进程号分别为53625378),同时每个进程都有一个/bin/bash的子进程,而这个/bin/bash子进程就是工作窗口(“virtual terminal”)。

(2)利用嵌套screen命令,也就是启动screen命令进入一个工作窗口以后,不会返回真正的终端,而是不断在当前的工作窗口中递归地调用screen命令。如下例所示:

[root@localhost ~]# screen
[detached from 5756.pts-0.localhost]
[root@localhost ~]# ps -ef | grep -i SCREEN
root      5756     1  0 21:52 ?        00:00:00 SCREEN
root      5817  5722  0 21:52 pts/0    00:00:00 grep --color=auto -i SCREEN
[root@localhost ~]# ps -ef | grep 5756
root      5756     1  0 21:52 ?        00:00:00 SCREEN
root      5757  5756  0 21:52 pts/1    00:00:00 /bin/bash
root      5772  5756  0 21:52 pts/2    00:00:00 /bin/bash
root      5787  5756  0 21:52 pts/3    00:00:00 /bin/bash
root      5802  5756  0 21:52 pts/4    00:00:00 /bin/bash
root      5819  5722  0 21:53 pts/0    00:00:00 grep --color=auto 5756

可以看到这种方式只会有一个SCREEN进程,所有的工作窗口(“virtual terminal”)都是由这一个进程产生的。

参考资料:
(1)Why is there only one SCREEN process in nested screen session?
(2)10 Screen Command Examples to Manage Linux Terminals

cd命令小技巧

(1)从任一目录回到用户的home目录:“cd”或“cd ~”。举例如下:

[root@localhost ~]# cd /home/iso/
[root@localhost iso]# pwd
/home/iso
[root@localhost iso]# cd
[root@localhost ~]# pwd
/root
[root@localhost ~]# cd /home/iso/
[root@localhost iso]# pwd
/home/iso
[root@localhost iso]# cd ~
[root@localhost ~]# pwd
/root

(2)回到之前的工作目录:“cd -”。举例如下:

[root@localhost ~]# pwd
/root
[root@localhost ~]# cd -
/home/iso
[root@localhost iso]# pwd
/home/iso

闲侃CPU(二)

时钟(clock)是驱动所有CPU处理器逻辑的数字信号。

CPU的速率可以用时钟周期(clock cycle)来衡量。举个例子,5 GHz CPU每秒可以产生50亿的时钟周期。每条CPU指令的执行都会占用一个或多个时钟周期。

CPU的速率是衡量CPU性能的一个重要参数。但是更快的CPU速率并不一定能带来性能的改善,而是要看这些CPU时钟周期都用在做什么。举个例子,如果都用在等待访问内存的结果,那么提高CPU的速率就不会带来真正性能的提升。

Bash shell内置wait命令简介

Bash shell内置了wait命令,官方文档对wait解释如下:

wait

     wait [-n] [jobspec or pid …]

Wait until the child process specified by each process ID pid or job specification jobspec exits and return the exit status of the last command waited for. If a job spec is given, all processes in the job are waited for. If no arguments are given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status. If neither jobspec nor pid specifies an active child process of the shell, the return status is 127.

wait命令可以使当前shell进程挂起,等待所指定的由当前shell产生的子进程退出后,wait命令才返回。wait命令的参数可以是进程ID或是job specification。举例如下:

root# sleep 10 &
[3] 876
root# wait 876
[3]+  Done                    sleep 10
root# sleep 20 &
[1] 877
root# wait %1
[1]+  Done                    sleep 20 

wait命令一个很重要用途就是在Bash shell的并行编程中,可以在Bash shell脚本中启动多个后台进程(使用&),然后调用wait命令,等待所有后台进程都运行完毕,Bash shell脚本再继续向下执行。像下面这样:

command1 &
command2 &
wait

Bash shell还有一个内置变量:$!,用来记录最后一个被创建的后台进程。

root# sleep 20 &
[1] 874
root# sleep 10 &
[2] 875
root# echo $!
875

echo $!输出结果是875,是第二个执行的sleep命令。

参考资料:
Does bash script wait for one process to finish before executing another?

什么是big data?

Big data”(大数据)的称呼已经火了很长一段时间了。今天我查阅了一些资料,记录一下自己的理解。“Big data”应该包含以下两个方面的含义:

(1)数据量本身很庞大。现在一款几亿人使用的社交软件可以聊天,上传图片,推送文章,发语音信息,等等。一个人可能一天就要产生几M到几十M的信息,那么几亿人一年会产生多少?真是一个非常大数量级的数据。

(2)伴随处理这些大数量级的数据所产生的技术。我们传统处理数据的方法已不再适合处理这些大规模数据了,所以要不断探索和解决这些技术难题。例如:如何存储这些数据,如何寻找特定的数据,如何从这些数据中挖掘出一些有用的信息,等等。

但是,每个问题都有两面性,“Big data”也不例外。一个显著的问题就是用户的隐私。你的社交软件知道了你的太多信息:你的手机号码,你的联系人,你喜欢看什么,等等。也许它比你还了解你。。。

参考资料:
(1)big data
(2)A (very) short history of big data
(3)Big Data

什么是sandbox?

stackoverflow上的一个帖子很好地解释了在计算机领域出现频率较高的“sandbox”的含义:

Sandbox的来源:国外的家庭在自家院子里圈出个地方,堆上沙子,让孩子在里面玩。由于这个小圈子和外界环境隔离开来,所以小孩子不会受到外界环境干扰,比较安全。这个环境就被称之为“sandbox”或“sandpit”。

在计算机领域,sandbox也是同样的含义。可以把sandbox看做计算机内部运行的一个独立环境,sandbox会对在其内部运行的程序(可以看做小孩子)做一个限制,这样即使程序会对计算机系统有破坏,它也跑不出sandbox这个环境。