和优秀的人一起玩
和智商底下,要求 底下,没有上进心的人一起真是太郁闷了
I'd rather be in outer space 🛸

Andulka
NASA
"I'm Dorothy Gale from Kansas"
d e v o n
PUT YOUR BEARD IN MY MOUTH
$LAYYYTER
Xuebing Du

Origami Around
Claire Keane
Alisa U Zemlji Chuda
Sade Olutola
No title available

@theartofmadeline
Jules of Nature

JBB: An Artblog!
art blog(derogatory)
ojovivo

tannertan36

No title available

seen from United States

seen from Singapore
seen from United States

seen from United States

seen from United States
seen from United States

seen from United States
seen from United States

seen from Malaysia

seen from United States
seen from United States

seen from United States

seen from Malaysia
seen from Malaysia

seen from Germany
seen from United States
seen from United States
seen from United Arab Emirates
seen from United States

seen from Türkiye
@xcaptainjoey
和优秀的人一起玩
和智商底下,要求 底下,没有上进心的人一起真是太郁闷了
This is what I see when I see the dog sleeping picture.
It’s a person.
Have a calm and relaxing weekend, Tumblr.
LoL
Videogame Marathons, Then and Now
For more comics, go to Dorkly.com!
小时候真美好,长大后就不行了。
Big Boss Snake
Created by Terry Huddleston || FB
I love this, pretty awesome
最好不再加班
加班没意义,以后还是该下班下班吧!
又是折腾
昨晚在公司折腾到9点才回,回来后又折腾到2点才睡觉,程序员真是没有生活。
今天又加了一天班
从三号上班开始,每天晚上9点之前没有下过班,每天都忙得要死烦得要死,事情一大堆,这些事情怎么就交接给我了。
如何连接路由器
昨天住的地方断网了,房东来联网的时候弄到了路由器的登录帐号密码以及拨号的帐号密码。被这网络虐了一个多月今天终于可以上后台看看了,内心真是激动啊。 先在浏览器中打开192.168.1.1,登录进去查看没有几台机器在线,这时候网速也还可以,没想太多。到了晚上突然网速很卡,妹的,肯定是对面几个屌丝在p2p下载或者是隔壁几个妹子在看视频。这时候再去浏览器中打开192.168.1.1已经打不开了,总是无法请求到路由器。 突然想到在公司都用ssh来登录服务器后台,路由器用这种方法能登录吗?试了一下ssh 192.168.1.1 但是连接被拒,看来路由器里面没有启动sshd啊,换种方法试一下,telnet 192.168.1.1 telnet也是一种远程登录的方法,但是因为连接没有加密不安全已经逐渐不怎么流行了,但是竟然被我用telnet登上了路由器。 看到熟悉的shell命令行内心那叫一个激动啊。
截图显示了路由器的名称,版本,内建终端是busybox,shell是msh。 内建的shell不是bash还是有点小失望的,上网搜了一下msh发现这东西还不算小众,是微软开发的一款脚本语言,虽然现在还不懂msh编程,不过有文档慢慢学也可以。 查看了一下基本的命令,竟然大部分都能用,ifconfig显示了路由器的网卡接口,包括br0, eth0, eth1, lo, ppp0, wlan0 br0长这样:
wlan0和eth0是同一块网卡,但是为什么显示通过这2块网卡的流量不同呢?
还有一个eth1网卡,发送和接收的流量都很大
最后就是拨号用到的ppp0了
这样就能大致分析出这个路由器的工作原理了,因为我们可以用有线和无线2种方式连接路由器,所以推测出当我们连上路由器的时候首先连上的是wlan0和eth0,如果用无线方式连的是wlan0,如果多此一举用了有线那么连上的就是eth0了。从上图可以看到eth0接收到0字节的流量,所以没有人有线连着路由器。 向wlan0发送数据后,数据会立刻被发送到一个桥接网卡br0上,这个网卡扮演的就是分组转发过滤的功能了。 从br0出来就到了eth1了,但是这个网卡没有ip地址,所以真正负责对外通信的还是它上面虚拟出来的ppp0,一切都是如此的顺其自然。 研究完路由器的网卡信息,又切换进/proc目录去瞧了瞧,里面运行这蛮多进程的,不过我对他们没兴趣,查看下路由器用的cpu如何, cat cpuinfo
信息很简单,我不太懂硬件,只知道有1个cpu,cpu型号是R3000 v0.0 在proc目录下的另外一个收获就是发现了pptp和l2tp,看来以后要是想配置vpn可以直接在路由器上配置,然后所有的设备翻墙了。 切换进/bin下看看,一堆可执行的文件,不过不敢轻易执行,再过2个礼拜搬家的时候再试试里面这些命令到底是干嘛的。 netcore路由器还是挺好玩的,不知道别的牌子的路由器内部的操作系统怎样。
SICP习题:找零钱的方法
上了一个多月班了,都是弄些无聊的框架,接口,查数据,取数据,简直要无聊死了,趁着清明节的三天假期宅在宿舍又重温了一下SICP,不得不说每一次看这本书都有新的体会。 看了一下一道关于找零钱的方法数的题目: 有5种零钱,分别是1美分,5美分,10美分,25美分,50美分,给定一张大面额的纸币,问有几种方法来找开这张钱。 书上说的是用递归的方法来解决这个问题,假设要找的钱总数是a,有n种零钱来找,那么这个找钱的过程可以分为2部分: 1. 某种零钱没有用到。 2. 这种零钱至少出现一次。 用伪代码来表示就是: cc(a, n) = cc(a, n-1) + cc(a-d, n),其中d是被排除的那种零钱的币值,在这里我们假设被排除的顺序是从大到小来排除的,因为找零钱的时候都是先找大的,然后在往小的找。 书中的代码写的特别美观,复制一份来放到这里:
(define (count-change amount) (cc amount 5)) (define (cc amount kinds-of-coins) (cond ((= amount 0) 1) ((or (< amount 0) (= kinds-of-coins 0)) 0) (else (+ (cc amount (- kinds-of-coins 1)) (cc (- amount (first-denomination kinds-of-coins)) kinds-of-coins))))) (define (first-denomination kinds-of-coins) (cond ((= kinds-of-coins 1) 1) ((= kinds-of-coins 2) 5) ((= kinds-of-coins 3) 10) ((= kinds-of-coins 4) 25) ((= kinds-of-coins 5) 50)))
好久没看到这么优雅的括号了。思路清晰,看起来很轻松。顺便吐槽一句,现在看php代码真是不开心,从一个入口文件开始看,本来一路下来就行了,但是继承太厉害了,看到一个函数,得往里扒3、4层才能找到它的定义,一个简简单单的方法直接实现就好了,但是php非得层层封装,让我这种用vim来看代码的人情何以堪,而且服务器上的vim还没有安装任何插件,要找一个函数的定义得手动找打那个父类的定义,然后查找到那个函数。找类的时候有时候还得用find命令来找。而include, require功能还能执行代码,更加加重了找函数的复杂度。 看到书上用scheme实现的算法,自己用python重新写了一遍,因为这个问题我也还没有想到好的别的算法,所以加点语法糖进去:
#!/usr/bin/env python def cc(amount , types_of_coins): d = rest(types_of_coins) if amount == 0: return 1 elif amount < 0 or types_of_coins == 0: return 0 else: return cc(amount, types_of_coins-1) + cc(amount-d, types_of_coins) def rest(types_of_coins): if types_of_coins == 1: return 1 elif types_of_coins == 2: return 5 elif types_of_coins == 3: return 10 elif types_of_coins == 4: return 25 elif types_of_coins == 5: return 50 if __name__ == '__main__': print cc(100, 5)
功能是一样的,但是python的代码感觉没有scheme的美观,如果用php来实现的话估计更难看。
一次惨痛的教训
今天下午快下班的时候有个同事和我说测试服挂了,一看果然502错误,真是自从开始上班以来第一次遇到这么棘手的问题。 先试着重启了一下nginx,但是没反应,还是那个错误,而且同一台服务器下另一个网站还是完好的,应该不是nginx的错误。 既然不是服务器错误肯定是网站内部出错了,用svn查看了一下代码,发现有2个文件有改动,当时没及细想就把这2个文件revert了,在打开浏览器访问一下发现还是502,好心慌。赶紧找潇哥也就是带我的学长汇报情况。 潇哥果然是大牛,直接就排除nginx服务器的错误可能,开始找php-fpm的日志,打开浏览器访问发现没有出现新的日志。原来是这个日志被关闭了,又找php.ini来打开日志记录功能,开始查看日志。 这时候有日志了,但是出现一堆执行被访问到的函数,以及它们所在的文件。潇哥这时候又逐个文件逐个函数下断点,php没有太好的调试工具,而且服务器上也没有办法安装图形界面软件,结果得echo和exit逐行检测。真是个漫长的过程,中间有好多怀疑,比如说框架损坏了,或者是mysql连接错误, 或者是redis无法访问,或者是php的2个版本之间有冲突,查了1个多小时发现是一个配置文件里面连接mysql的帐号密码错误了。这时候已经7点多了,潇哥说他要赶15分那趟班车回家,就让我自己把剩下的问题解决了。 虽然把数据库的配置改过来了,但是新的问题又出现了,因为之前没怎么细想就用svn回滚了这个文件,但是现在发现这个文件上一次提交是去年,后面的改动都没有提交,所以我一revert就直接回到去年的版本了。没办法,手动加入新版网站的配置进去,加了几行看看,但是发现这时候出现500错误,这是说明网站内部有逻辑问题。简直想爆粗口了。 没办法给志新哥打电话,他是我的老领导,但是上个月跑到广州去开疆拓土了,在电话里说了几句,觉得是我写的配置文件有错误,得找一个相近的来替换了,结果开始找配置文件,又花了一段时间竟然还真找到了一个差不多的配置文件,赶紧换上去。 因为我们网站改版过好多次,里面有3个版本的网站,而配置文件里也包含了这3个网站的信息,我得小心翼翼地把最新的那个版本相关的配置文件找出来,把无关的配置注释掉,这时候又发现了问题,最早的经典版是可以访问的,但是界面太丑了,而去年年底上线的新版也能访问但是界面也显得很丑陋,我把最新的扁平设计版本找出来,本以为会和前2个版本一样正常运行,可是在测试的时候竟然发现又是500错误。 简直要暴走了,旁边还有2个人等着我的服务器呢,一个是我的产品经理,另一个是一个前端工程师,因为今天要上线一个新皮肤,为公司一款很火的游戏打打广告,所以他们2个都等着我的机器测试,要是在本地测试过了就能让运维推送到线上服务器去。这时候已经8点多了,但是还是没搞定。 这时候急也没用,按照潇哥调试时的步骤一个一个看吧,从最初的入口文件开始下断点,检查各个函数是否运行正常,查来查去终于发现在控制器向视图渲染的地方出问题了。因为这个网站是用mvc模式开发的,这种交叉的地方又难判断了,因为不知道是c还是v出问题了。 这时候是8点40多,前端和产品经理都先走了,他们要赶班车回家,再晚的话就没有地铁了。 走之前产品经理让我给运维说声先把那个皮肤上线了,这可是没有在本地测试过的东西啊,直接上线太危险了,但是需求太急不能不上,那就上吧,万一没问题呢?然后就找了运维的同事让把皮肤推送到线上。 这个时候运维同学刚好到家,赶紧连上服务器推送,还好这活对他们来说很简单,2分钟搞定,搞定后我拜托他帮我从线上下个视图文件,因为我本地服务器可能就是因为这个视图文件导致崩溃的。下下来了替换上去,谢天谢地,终于正常了。这时候看一下时间,9点10分。 突然发现公司线上的网站出现问题了,新上线的那个皮肤无法点击,我的天,这就是没有经过测试的代码,我都可以引咎辞职了,因为我的失误影响了公司业务,赶紧向产品经理汇报,他让我找前端看看,给前端发qq,他还没有回复我。 纠结到9点40才决定从公司走,因为再待下去也没用,我改不了前端代码,而且运维睡觉了再去麻烦他也不好。这是我工作以来遇到的最严重的一场事故,总结一下主要问题有以下几点:1. 不该一看到错误就回滚代码。 2. 回滚代码前没有仔细看上一次提交代码的时间。 3. 不善于调试,下手太慢了,调了半天才找到出错的地方。 4. 没有备份的习惯,服务器崩溃后竟然找不到备份的代码。
json和xml
最近一直在处理一些数据格式的问题,怎么把数据从mysql中取出,怎么保存到redis缓存中,网页如何从redis中取出数据,技术含量不高,但是就是很麻烦,各种格式切换。 数据在mysql中是按照字段存入表中的,通过sql语句可以很方便查询数据,redis是一种键值对应的数据库,怎么在这2个数据库之间存取数据呢?json是一个好帮手。 首先我们要知道redis有5种数据类型,字符串,列表,集合,有序集合,哈希表。假如我有一个数据表game包含4个字段: category_id, game_id, game_url, game_desc 分别表示游戏分类,游戏id,游戏外部url,游戏描述。一个category_id下可以有很多个game_id,game_id算作主码吧。现在我要把game_id为123的那条记录找出来存入redis中,怎么实现呢? 先用php+PDO来连接数据库吧。 $pdo = new PDO($dsn, $username, $passwd); $sql = "select * from game where game_id=123;"; $sth = $pdo->prepare($sql); $sth->execute(); $row = $sth->fetch(); 这样就通过php把这一条记录存入变量$row中了,row这时候是一个数组,如何把它存入redis呢? 虽然redis提供了很多种数据结构,但是我们公司的代码大部分都是用字符串来存数据的,哈希都很少用,剩下的就根本不用。当然这里的字符串是一个json字符串,为什么要用json呢?因为它的结构很清晰,而且消耗内存少,不会像xml那样到处都是标签。 要把一个数组{'category_id'=>1, 'game_id'=>123, 'game_url'=>'www.hisdhig.com/abc.png', 'game_desc'=>'很好玩的游戏'}存入redis也是用php $redis->set("game123", json_encode($row)); 这里把row编码为json格式存入redis 现在连上redis服务器,get game123看看有没有数据,当然这时候的数据是很难读的json字符串,如果我们要把它以人类可读的方式打印出来就要解码 print_r json_decode($redis->get("game123"))就好了。 现在知道我的工作有多无聊了吧!!! 前几天还写过一个简单的游戏接口,因为我们公司库存了很多游戏的数据,这可是多年来公司的珍藏啊,有很多别的公司不想自己找游戏就会叫我们提供游戏信息给他,这些信息保存在一个xml文件里面,合作公司拿到这个接口后就可以把里面的数据保存到它的数据库中,这就显得他的网站信息很丰富了。 xml文件是有一大堆标签组成的,每个标签都有一个名字加上0个或多个属性,这样一个标签叫作一个元素,一个元素下面还有很多子元素。比如我们的接口最上层的一个元素名是然后在这个元素下有一大堆子元素,都叫作但是每个game又有很多属性,比如说id啦,图片啦,游戏介绍等,写那个接口的时候就是用php提供的xml方法来把属性元素加进去的。 $dom = new DOMDocument('1.0', 'UTF-8'); 来生成一个xml对象 $g = $dom->createElement('games');来生成一个根元素 $g->setAttribute(...)给这个元素g设置属性 然后就是循环生成子元素,然后循环插入子元素的属性了 然后$g.appendChild($subgame)就把每一个子元素都加入到父元素下了。 $dom->saveXml()保存这个xml文件
我的近况
到公司实习快一周了,大致熟悉了一下公司的基本项目,与开发流程,发现以前学校学的东西和实际要用的真是很大不同。 我比较拿手的语言算是C和python,结果来了公司让我搞php开发,而且是为了维护公司主页,看了一下主页的代码,我的任务就是看懂公司目前用的php框架,然后基于现有框架开发。看了一下yii这个框架,发现有了框架真是省去了很多编码的功夫。数据库用的是mysql,前几年这个数据库很火,可是在最近几年已经不那么流行了,但是公司还坚持用,真是令人佩服。由于数据库有些数据是经常要存取的,所以还要用到redis缓存。而这些软件单独使用效果又不大,还得学习php和mysql的接口,php和redis的接口。前几天遇到一个实际问题,说的是公司有大概10万款小游戏,每个游戏都有一个标签,问题是打开一个游戏网页,在旁边列出9个推荐的游戏出来,看了公司原来用的那个php脚本,大概160行,但是要运行2个多小时才能从数据库中读出所有游戏以及它们的标签并存入redis缓存。本来算法倒是很清晰,就是不熟悉那些接口,过几天好好看看能不能优化一下算法,这样我就大功一件了。 剩下那些一起来的同事大部分是搞C++的,看他们写的那么底层的代码真是触目惊心,我们整个网站后台也写不了一个C++文件那么多行代码,还是写脚本好。 现在来总结一下:以前在学校老师说会编程就够了,因为编程是最基本的,但是到了公司发现几乎不要多精通一门语言,现在的面向对象和敏捷开发导致自己写的代码越来越少,都是调用接口或重用以前的代码;以前觉得算法很重要,但是现在用到的不多,好不容易碰到一个与效率很相关的问题,结果还不好优化算法,主要是优化程序结构和数据库查询过程;在学校认真学了一下C,结果发现现在C只能拿来当一下业余爱好了,因为几乎没有哪家公司纯粹拿C来开发;以前学了计算机网络,可是现在碰到的网络问题也就是虚拟机连连服务器,配置一个nginx而已,网站的问题都是由框架来解决的;目前还有2个爱好没有受到影响,scheme和ml,这2个语言当初学的时候就是拿来玩的,至少现在还有一点小众的乐趣。数学知识几乎没用上,不过我还是很感谢数学给我带来的思维,mathematica和matlab还是一直给我带来很大的快乐。
关于未来的一点小想法
今天回老家拜年了,吃完中午饭给一个以前玩得很好的初中同学打电话约出来玩。到了他家之后又给另外几个同学打电话,大家一起坐下来聊天,真是感触良多。小学5年加初中前2年都是在乡下度过的,认识了一大群可爱的好朋友,但是从初三开始搬家到城里来了,然后高中三年加大学三年半都没有怎么找过以前的那些同学。 第一个同学A:初中时和我关系算是最好的,当年他对我说他要考上中国农业大学做一个新世纪的农民,当时听见这话的时候我内心是很鄙视他的,觉得他胸无大志,但是可惜高考他没有考好结果跑去深圳打工去了,现在已经工作三年了。现在他的感触就是不管做什么工作都要注意存钱,每月至少存一半工资,这样才能有钱回家娶老婆。和他的交谈发现社会真是可以磨平人的性格,从胸怀大志的热血青年到后来的锋芒尽去。 第二个同学B: 这是一个女同学,和我从小学开始就是同学,当时2个人家里住得也不远。从小就是一个美女,初中时班上好多男生向她表白过,现在却在准备结婚的事了,新郎不是我们的同学而是一个我闻所未闻的外地人,真是闪婚啊。听她现在的谈吐完全不像当年那个说句话都会不好意思的小女孩了,成熟老练,总是能够挑出各种八卦来和众人分享。 第三个同学C: 也是一个女同学,人长得还行,但是现在孩子都一岁多了,每天操心的事就是给孩子喂奶、做家务等,完全一个家庭主妇,和同学B很聊得来,有说不完的八卦。 听他们介绍当年我们的同学现在混得好的只有一个,不过就是在城里买了房子而已,而且还是家里帮了大忙。剩下的同学现在有的在做厨师,但是饭店生意不怎么好。有的在做销售,工资时高时低。有的带着老婆小孩在外面打工。有的结婚之后夫妻关系不好...... 未来我的方向在哪里呢?搞技术一条路走下去?在家里想看点书可是已经不像以前一样收父母待见了,在电脑前稍微待久点就被叫着干这干那或者直接叫出去找人玩。技术对于我们大学理工科学生来说似乎是一条确定的道路了,但是这样走下去成就总是有限。在进我们村的10分钟山路中看到了很多豪车,代表着主人成功的事业,这些人都是我的老乡。有做稀土的,有在广东开厂的,有在浙江做生意的,有在本地搞房地产的。搞技术搞10年也不一定能买得起保时捷。 又想起了上个月去东莞的5天,豪华的消费场所,如果没有自己的事业一晚上就能花光一年的工资。 以前还在读书的时候也算是家庭的骄傲吧,回到老家大家都说这家有个本科生,但是现在要毕业了却受到歧视,不是公务员,工资不高,和家里那些土豪没法比,我真是郁闷啊,很期待大学毕业,这样就能在广阔的舞台上施展自己的才华了,可是现在发现毕业不过是进入了有一个围城,我该如何才能跳出这座城呢?
QQ号被盗经历记录
一直以来都很崇拜黑客, Linus Torvalds,Richard Matthew Stallman,Ken Thompson, Dennis Ritchie,Kevin David Mitnick等,但是总感觉他们离我太远,但是今天却让我见识了一下身边的骇客,真是涨见识了。 本月2号晚上接到一个朋友QQ上发来的一条信息,包含了一个链接,信息内容是让我点开链接,没怎么迟疑就打开了那个链接,看起来像是一个人的QQ空间,但是打开网页之后有一个窗口让我登陆QQ,因为以前也有过登陆QQ看别人空间的经历,所以没怎么迟疑就输入我的帐号和密码了,但是点提交却发现没反应,那时候准备睡觉了,所以没有多想就下线睡觉了。 3号一整天没有上QQ,今天中午登陆了一下QQ发现很多好友给我发信息,空间所有好友都被删除了,这时候我才意识到QQ被盗了。赶紧上QQ安全中心查看了一下登录记录,发现在3好晚上有异常登录
可恶的广西黑客,昨天那时候我正在家里看电视呢。 检查了一下发现昨天那家伙给我QQ里面很多好友都发了那个诈骗信息,而且还把我的好友都删除了。希望朋友们不要像我一样上当,不然我真是没脸见你们了。由于QQ绑定了手机还设定了密保问题,所以密码没有被改,但是我后来还是把密码换了。 那家伙给我发的是这个网址,用whois工具查了一下网站的域名,hbj.metabolicbalance.net.au指向的是北京息壤公司,查了一下发现这家公司是做服务器托管业务的,
估计是柳州那个黑客在息壤注册了一个云服务器,然后上传了一个恶意的网页上去。metabolicbalance.net.au指向的是美国一家公司。
从这里可以看出北京这家公司有多水了,自己是做云服务的但是实际上确是把美国人的服务器转租一下,鄙视这样的公司。 不知道黑客在租服务器的时候有没有提供详细的个人信息,就我所知亚马逊,谷歌的云服务器要租用的话必须提供详细的个人信息,包括信用卡号,要是息壤的管理也和他们一样严格就好了,可以联系他们公司让他们把那个网站关闭掉。 心血来潮查看了一下恶意网页源代码, 发现我看到的貌似一个人空间的网页其实是黑客放的一张图 <img src="/attached/image/新的QQ空间模块/11.jpg" style="z-index:20" /> 登录界面是用javascript写的,
<script> function checkform () { if (document.getElementById('u').value=='' || document.getElementById('u').value.length<6) { alert('您还没有输入帐号'); return false; } if(document.getElementById('p').value=='' || document.getElementById('p').value.length<6){ alert('您还没有输入密码'); return false; } return true; } </script>
提交部分是由一个asp脚本来完成的,
<form action="saveinfo.asp" method="post" target="_top" onsubmit="return checkform();"> <input type="hidden" name="uid" value="91"> <input type="text" id="u" name="u" /> <input type="password" id="p" name="p" maxlength="16" /> <input type="submit" id="s" name="s" value="" /> </form>
点击之后又返回checkform这个函数了,所以提交是没有任何效果的。 到现在为止黑客只需要在服务器的数据库上直接查询就能得到各个上当受骗人的帐号和密码了,真是等于双手把自己的个人信息送给黑客,他们不必要费一点功夫。 总结一下这次受骗的原因: 1. 太轻信QQ上朋友发来的信息了,没有深思这话的真假。 2. 安全意识薄弱,一前从没有遇到过黑客,病毒,木马什么的,所以懈怠了。 3. 自认为自己的防范措施很严格,使用更为安全的linux操作系统,定期给系统打补丁,从不下载未经认证的文件,从不在网络上泄露个人信息。但是这些都不够,安全意识才是最重要的。 经历过这次风波之后希望自己以后能吸取教训,也希望我的朋友们没有受到困扰,因为我的失误给你们造成这么大的麻烦真是对不起。QQ密码要常换,而且发现异常要上qq安全中心检查登录情况,密保问题和手机绑定也是很重要的。
第一次尝试zram
昨天在家里的老电脑上安装了一个lubuntu,这电脑真是太老了,09年买的华硕F5z,CPU是AMD Athlon x2 QL64的,一般家用上上网什么的足够了,主要是内存不行,只有740M,运行windows xp sp3开个网页登个QQ内存就超800M了,这时候想起了Lubuntu,值得一试。 安装过程都是很简单的,然后使用发现资源占用真是低,开机之后190M内存使用,然后开firefox,abiword,transmission,pdf,听歌都只用了500+的内存,其中firefox占用的内存挺多的,200M。不过这样的性能够用了。 为什么windows如此消耗内存但是linx占用资源就相对少呢? 我觉得原因有几点: 1. 家里的windows装了360,360真是流氓软件,退出了安全卫士之后开一下浏览器又打开了,总是在后台运行吃我的资源,让老电脑情何以堪啊。 2. lubuntu默认启用了zram,就是说系统会自动把ram中不常用的内容压缩,减少ram使用量。上wiki查了一下发现zram是linux3.2以后才加入内核中的,估计windows暂时还无法跟进吧。 3. 记得以前看CSAPP的时候书中写道windows系统的内存对齐机制比linux严格,也许因为这点导致windows又多浪费了点内存吧。 如果要在ubuntu上面启用zram也很简单,sudo apt-get install zram-config 就行了,这个配置脚本会自动启用内核中的zram。然后在磁盘工具中会看到多了几个ramdisk。/dev 目录下有zram0~zram3,因为我有4G的ram,所以zram盘比较多。然后free -m发现swap分区容量也增大了2G。在我现在的电脑上运行没有发现什么更快的,因为平时内存只用2G,不过在老电脑上面效果还是很明显的。
关于斐波那契数的一些有趣事实
Fibonacci数有很简单的递归形式,Fib(n) = Fib(n-1) + Fib(n-2), n>=3,Fib(0) = 1, Fib(1) = 1。要算第n个斐波那契数真是太简单了,编程初学者都会,但是计算方法很多,都很典型,今天来复习一下。 1. 用C语言迭代实现。
int fib(int n) { int a, b, z, i; a = b = 1; for (i = 3; i <= n; i++) { z = a + b; a = b; b = z; } return z; }
2. 用C语言递归实现。
int fib2(int n) { if (n == 1 || n == 2) { return 1; } else { return fib2(n-1) + fib2(n-2); } }
这是树形递归,如果对于大的n效率是很慢的,左分支和右分支会重复计算相同的内容,而且这也是自顶向下的递归,也要做2^n次递归计算。 3. 尾递归的scheme实现。
(define (fib n) (define (iter a b count) (if (or (= count 1) (= count 2)) a (iter (+ a b) a (- count 1)))) (iter 1 1 n))
这个递归实现已经类似与第一个C版本的迭代过程了,但是在方法1中要定义一个额外的变量z来保存a,b的状态,而scheme不用,这就是没有变量没有副作用的好处。 尾递归的C实现。
int fib4(int n, int a, int b) { if (n <= 2) return a; return fib4(n-1, a+b, a); }
尾递归就是用额外的变量把线性的空间复杂度降为常量空间复杂度。 4. 借用一个数组来保存状态。这是一种自底向上的方法,没有重复计算,也没有多余的函数调用开销,在形式上也是递归的,时间和空间复杂度都是theta(n),以后遇到递归问题都要想想能不能自己建数组来保存状态。
int fib3(int n) { int a[n], i; a[0] = a[1] = 1; for (i = 2; i < n; i++) { a[i] = a[i-1] + a[i-2]; } return a[n-1]; }
这种方法是从动态规划里面学来的,如果用递归计算太慢的话就用数组来保存状态。 5. 从SICP上学来的新算法,不是直接用递归公式编程,而是跳跃式的计算,因为规模减半了,所以这种算法时间复杂度只有theta(log n)。下面来看看scheme代码吧。
(define (fib5 n) (define (even? n) (= (remainder n 2) 0)) (define (fib-iter a b p q count) (cond ((= count 0) b) ((even? count) (fib-iter a b (+ (* p p) (* q q)) (+ (* q q) (* 2 p q)) (/ count 2))) (else (fib-iter (+ (* b q) (* a q) (* a p)) (+ (* b p) (* a q)) p q (- count 1))))) (fib-iter 1 0 0 1 n))
详细的算法说明得看SICP练习1.19。这种算法一般人真是不容易想到。
Project Euler上一些有趣的题(二)
还有一个挺有意思的题目是Problem 21这个题的重点就是要找出一个数的所有约数。比如输入6就输出1,2,3。最简单的暴力算法就是从1到n-1反复试除看看能否整除,如果能就把这个数添加到一个列表中。 如果用python的话实在是太简单了,一个列表解析就搞定 [x for x in range(1, n) if n % x == 0] 这样就能得到一个n的所有约数组成的列表了。 当然还可以通过循环判断来逐步把符合要求的数append到列表中,不过这种方法和列表解析之间似乎没有显著的效率差异。 这个问题当然也能用C来实现了,但是具体操作的时候让我郁闷了,C的数组没有边界,要添加一个数字进数组中还得手动realloc动态分配内存,然后得到了数组指针的同时还得知道数组的大小,不然没法输出,写到一半就不想写了。 因为正在学习函数式编程的缘故我又用scheme写了一个类似功能的程序
(define (f-list n) (define (f-list-help i n) (cond [(>= i n) '()] [(zero? (modulo n i)) (cons i (f-list-help (+ 1 i) n))] [else (f-list-help (+ 1 i) n)])) (f-list-help 1 n))
刚开始想的时候总是不知道如何下手,因为没有赋值没有循环,只有值绑定和函数调用,然后去scheme社群里问才弄到这个程序,结构很简单,也很一般,额外构造一个f-list-help函数来帮助迭代,有了这样的帮助程序就能把递归函数写得像循环一样了。