我开发了一个基于 Beancount 的账本托管服务 HostedBeans,欢迎大家来了解纯文本复式记账并试用我的服务。

笔记: 循环, 递归, 迭代, 遍历

本文首发于SegmentFault, http://segmentfault.com/q/1010000000199577#a-1020000000199630

表示”重复”这个含义的词有很多, 比如循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate).

循环

循环算是最基础的概念, 凡是重复执行一段代码, 都可以称之为循环. 大部分的递归, 遍历, 迭代, 都是循环.

递归

递归的定义是, 根据一种(几种)基本情况定义的算法, 其他复杂情况都可以被逐步还原为基本情况.

在编程中的特征就是, 在函数定义内重复调用该函数.

例如斐波那契数列, 定义F(0)=1, F(1)=1, 所有其他情况: F(x)=F(x-1)+F(x-2).

所有大于1的整数经过有限次的反推之后都可以转换到两种基本情况. 而在编程中, 算法则是这样的:

int F(x)
{
    if(x==0 || x==1)
        return 1;    //这里是退出递归的条件, 以保证在有限次递归后能够得到结果
    return F(x-1)+F(x-2);    //转化为更为基本的情况, 重复调用自身进行计算
}

迭代(数学)

迭代在数学和编程中有不同的含义.

数学方面是指在循环的基础上, 每一次循环, 都比上一次更为接近结果.

例如下面是一个迭代的例子.

int result = 0;
for(int i=0; i>10; i++)
    result += i;    //每一次循环之后, result都更加接近结果45

有很多数学问题, 都是迭代算法, 如牛顿迭代法(求平方根).

迭代(编程)

按顺序访问一个列表中的每一项, 这在很多编程语言中表现为foreach语句:

$arr = [1, 2, 3, 4];
foreach($arr as $i)
    echo $i;

遍历

按一定规则访问一个非线性的结构中的每一项, 强调非线性结构(树, 图). 而迭代一般适用于线性结构(数组, 队列).

结论

  • 循环(loop) – 最基础的概念, 所有重复的行为
  • 递归(recursion) – 在函数内调用自身, 将复杂情况逐步转化成基本情况
  • (数学)迭代(iterate) – 在多次循环中逐步接近结果
  • (编程)迭代(iterate) – 按顺序访问线性结构中的每一项
  • 遍历(traversal) – 按规则访问非线性结构中的每一项

这些概念都表示“重复”的含义, 彼此互相交叉, 在上下文清晰的情况下, 不必做过于细致的区分.

参考

RP主机如何进行权限控制

折腾虚拟主机一年多了, 除去编写面板,研究的更多的就是权限控制了. 在此我分享一下我在Linux虚拟主机权限控制方面的经验.

阅读本文需要一定的Linux服务器维护基础.

《应用密码学》的前言中讲到:

如果我把一封信锁在保险柜中, 把保险柜藏在纽约的某个地方, 然后告诉你去读这封信, 这并不是安全, 而是隐藏.

相反,如果我把一封信锁在保险柜中, 然后把保险柜及其设计规范和许多同样的保险柜给你, 以便你和世界上最好的开保险柜的专家能够研究锁的装置.

而你还是无法打开保险柜去读这封信, 这才是安全.

我不是说我的安全措施无懈可击, 我只是认为隐藏起来也于事无补, 不如分享出来, 在此我也提示RP主机的用户, 请不要在服务器上做尝试突破限制的操作, 根据协议你可能被封停帐号, 你可以自行架设环境来测试, 或与我交流. 啊, 题外话说了这么多.

我很懒, 我在尽可能地借助Linux本身的功能来进行权限控制, 而且这也是RP主机的宗旨——提供完整的Linux环境.

文件

文件方面, Linux本身已经提供了一套文件权限系统, 我只需要提示用户应当将文件权限设置为770即可: chmod -R 770 ~

为了防止疏忽,我们还可以在.bashrc中加入umask 007这样创建出来的文件默认就是660(注1), 不过这对PHP等脚本生成的文件并不起作用, 因为他们没有通过bash环境.

注1: Linux不允许一个文件创建时就有执行权限, 所以默认是660, 对于目录则是770.

我没有使用单独的FTP软件, 比如有名的vsftp, 因为我觉得配置起来很麻烦, 容易产生新漏洞. sshd自带的SFTP功能完全可以满足文件管理的需求, 这是自带的功能, 方便.

我还使用了quota-tools来限制用户的磁盘占用, 因为磁盘这东西, 占了多少就是多少, 总不能随便删人的文件啊, 所以一定要限制死.

Web

Web部分可谓是重中之重, 因为按照Linux的规则, 端口是被一个进程独占的, 但是大家都需要用80端口来开设Web服务, 这就需要以root运行一个Web服务器, 然后根据用户的在面板中的配置, 分发, 执行Web请求. 其实, 只需要一个反向代理来分发请求就够了, 但是为了降低建站的门槛, 毕竟相当大一部分用户购买RP主机就是为了建站, 所以还要提供公共的常见脚本(PHP)运行环境.

Apache负责运行各种网页脚本, 如PHP, Python, CGI等等. 为了保证自由度, 我没有对PHP加任何的限制, 我希望借助Linux本身的进程安全模型——让脚本以对应的Linux用户来运行.

于是我找到了 mpm_itk_module, 这种工作模式, 可以为每个Virtual Host指定实际运行的用户. 当收到请求时, Apache的工作进程会setuid为相应用户, 然后再执行相应的脚本完成请求.

借助于Linux本身的功能, PHP进程可以按照权限访问文件, 创建新进程(以实际的用户), 而不会干扰到其他用户.

但和标准的 mpm_perfork_module 相比, 因为要频繁地setuid, 创建和销毁进程, 性能相差了几十上百倍之多. 但为了权限控制的灵活性, 只能牺牲性能了. 在新版本中, 我正在把性能低下的Apache边缘化.

目前, 事实上是Nginx在监听80端口, 负责处理静态文件请求, 并把其他请求反向代理到Apache. 为了提供静态文件, Nginx需要能偶访问所有用户的文件.

我选择了以www-data用户来运行Nginx, 同时将www-data加入到每个用户的组当中, 所以需要用户将文件设置为770, 给予同组的Nginx权限.

新版本的Web

新版本中将使用PHP-FPM代替Apache处理PHP脚本, PHP-FPM的功能很强大, 可以建立不同的进程池, 在新版本中, 每个用户都会有一个单独的进程池.

每个进程池表现为一个UNIX socket文件, 用户也可以编译自己的PHP和PHP-FPM来代替默认的PHP-FPM.

新版本中使用了 uWSGI 代替Aapche的 mod_wsgi 来处理Python脚本, 用户需要自行运行uWSGI守护进程, 监听一个UNIX socket, 并配置Nginx的反向代理即可.

事实上这种方式适用于所有的fcgi服务器.

MySQL

MySQL再简单不过了, 装一个phpmyadmin, 默认的安全策略已经相当完善, 每个用户对以自己的用户名为前缀的数据库具有全部权限, 可以随意建立数据库.

流量统计

说实话直到目前我还没找到较可行的方案, 我希望依然以Linux中的用户为单位进行统计. 目前我正在调研iptables的相关功能.

目前还有两个部分的用户相关进程没有以实际用户运行: PPTP, Nginx的worker.

不知不觉写了这么多, 不过好像没啥实际的啊.

石头剪子布

(写于半个月前)

闲来无聊看了一部同名微电影,25分钟,翻拍自在QQ空间和微博流传了很久的一个段子。

一个变态杀人狂绑架一对情侣,让他们玩石头剪子布,赢的人活下来,平局一起死。

电影本身,画面还是相当精致的,而剧情在原有的不足140字的段子的基础上真的没有什么突破。影片展现了三对情侣的选择,他们无一例外地都事先约定好了一起死,但却又都没能如愿,有的是因为自私,有的是想保护对方,还有的不得而知。

对我这个情商为零的死理性谈爱情和生命的取舍实在不好玩。生命的唯一意义就是繁衍后代,爱情不过是附属品。从前有一群人不这么认为,后来就没有后来了,因为他们都死光了。更何况两个人活一个比一起死要划算的多,就算是为了惩处凶手,避免更多人受害,也要留个活口啊。再加上石头剪子布这个十分不靠谱的游戏方式,如果不是因为有情侣这个元素,我丝毫不认为这个段子会火。

我想如果是我,我不会事先约定的,随运气吧。

来看另一个更经典也更简洁的博弈问题(囚徒困境).

两个同案犯,因证据不足,必须要互相指认对方的罪行才能定罪,于是警察将他们分开审问。

若两人都不指认对方,则均无罪释放;若一人指认另一人不指认,则前者从轻后者从重,分别判一年和十年;若两人都指认对方,则各判一年。

本来从两个罪犯组成的团体来讲,两人都不指认是最好的结果。

但一旦从个人的角度来考虑,那么指认则是最佳选择:若对方不指认,我指认,那么我能获得更少的刑期;如果对方指认,那我同样必须指认才能获得更少的刑期。

可以看出囚徒困境是对个人利益和团体利益的一个博弈,在无法沟通的情况下,因为出卖同伙会为自己带来短期的利益,所以彼此出卖虽然违反团体的最佳利益,但却是个人的最佳选择。

我想电影中的杀人狂想要通过游戏验证的也是情侣之间是否真正地信任对方,能否通过这种信任换取两个人的最佳利益。不得不说,电影中这个游戏规则,设计得很失败。

精子生于 1995 年,英文 ID jysperm.

订阅推送

通过 Telegram Channel 订阅我的博客日志、产品和项目的动态:

王子亭的博客 @ Telegram


通过邮件订阅订阅我的博客日志、产品和项目的动态(历史邮件):

该博客使用基于  Hexo  的  simpleblock  主题。博客内容使用  CC BY-NC-ND  授权发布。最后生成于 2025-02-10.