首先,也许你需要看一看不借助框架,如何最简单有效的实现异步编程 [简约有理]。 这里描述了事件依赖的基础:流编程。
即Stream
。
如果你认为使用事件就是满页变量,那么就错误了。现在我们来聊聊封装事件流的接口。还是用上面的文章中的任务:
打开文件,获取操作符fd → 读取文件内容,写入缓冲区 → 缓冲区中追加1234567890 → 将缓冲区的新内容写回文件 → 关闭操作符fd
要编写为一个接口,很简单:把你需要变动的内容“参数化”,然后使用函数封装,并且提供`exports`,这样其他人或者其他程序就可以使用这个实现的接口。
现在我们来将这个任务流封装:
// my.js
var EventEmitter = require('events').EventEmitter,
fs = require('fs');
exports.read_write_file = function (filepath, buflen, callback) {
var myemitter = new EventEmitter(),
buffer = new Buffer(buflen);
myemitter
.on('open', function () {
fs.open(filepath, 'a+', function (err, fd) {
if (err)
myemitter.emit('error', err);
else
myemitter.emit('read', fd);
});
})
.on('read', function (fd) {
fs.read(fd, buffer, 0, buflen - 10, 0, function (err, bytesRead, buffer) {
if (err)
myemitter.emit('error', err);
else
myemitter.emit('write', fd);
});
})
.on('write', function (fd) {
buffer.write('1234567890', buflen - 10);
fs.write(fd, buffer, 0, buflen, 0, function (err, written, buffer) {
if (err)
myemitter.emit('error', err);
else
myemitter.emit('close', fd);
});
})
.on('close', function (fd) {
fs.close(fd, function (err) {
if (err)
myemitter.emit('error', err);
else
callback();
})
})
.on('error', function (err) {
callback(err);
})
.emit('open');
;
};
OK.
现在,我们拥有了一个封装的read_write_file(filepath, buflen, callback)
函数。输入文件路径、缓冲区字节长度,并且提供一个回调函数,那么read_write_file
将会运行一系列任务,并且在出错或者完成时,通过callback
投放出来。callback(err)
只有一个参数,就是可能出现的错误对象。
现在,可以方便的使用这个实现的接口:
var my = require('./my.js');
my.read_write_file('/home/xiaoming/log.txt', 100, function (err) {
if (err) {
console.log('O! NO! error: %j!', err);
} else {
console.log('Good work!');
}
});
更实际的内容
实际编码中,很少有如此一长串的异步处理,我们可以加点调味料,比如数据库操作。
// blog.js
var pool = require('mysql').createPool({/*config*/});
function auth_and_blog(username, callback) {
var myemitter = new EventEmitter(),
q_auth = 'select userid from users where username = ?',
q_blog = 'select blogId, text, title from blogs where userid = ?',
blog = null;
myemitter
.on('auth', function () {
pool.query(q_auth, [username], function (err, replies) {
if (err) {
myemitter.emit('err', err);
} else if (replies.length > 0) {
myemitter.emit('blog', replies[0].userid);
} else {
myemitter.emit('finish');
}
});
})
.on('blog', function (userid) {
pool.query(q_blog, [userid], function (err, replies) {
if (err) {
myemitter.emit('err', err);
} else {
blog = replies;
myemitter.emit('finish');
}
});
})
.on('finish', function () {
// Want do something ?
callback(null, blog);
})
.on('error', function (err) {
callback(err, null);
})
.emit('auth');
;
}
exports.auth_and_blog = auth_and_blog;
OK.
现在,来使用:
var blog = require('./blog.js');
blog.auth_and_blog(req.body.username, function (err, blog) {
if (err) {
res.send({err:err, state:0});
} else {
res.send({state:1, blog:blog});
}
})
作者最近打算聊聊关于学习nodejs和javascript的过程,所关注的不是一般教科书的大白科,而是够用即可,以及实用至上的理念。以C、Linux和TCP HTTP以及ISO七模型的角度,聊聊nodejs应该关联的内容,并且从javascript基础语法开始。
一个原则:够用即点到为止。
如果你感兴趣,可以关注作者的简书NodeJS in LNNM。
有可能会更新很慢很慢,但说不准有可能一天多篇文字。每次都是在路上走的时候文思泉涌,一旦坐下就大脑空空。可能是天天坐的时间有点长,乏了。如果打游戏无聊,排队等人的时候,找不到可以消遣的新闻,可以来此刷新一坐。
对于一些言论的man,我的意见是: 先让自己找到体面的工作,再在这里装B! 饭都吃不饱,装嘛B!自己写的程序不能让自己体面地生活,那就表明这个人也只能做些虚拟的装B,其写的代码狗P不是。
这世界上有很多黑客,从来不会结交那些天真幼稚的小朋友做伙伴,因为黑客的精神重在探索和发布,而不是跟你在网上过家家。
我看你确实看过很多代码,涉及面也很广。但我能看出你和代码的关系并不好,我的意思是,你并不能诚实地处理你和代码的关系。也影响你和人分享的氛围,如果你是在分享的话。 我看你写的代码很难受,我绝对是nodejs的菜鸟,但我居然能看出你的问题。比如你的这个帖子: 如何玩转闭包和柯里化: https://cnodejs.org/topic/55169b51e26684ed7ff21e1d 那个memorize函数的参数sets你改来改去还是留着了,就是不愿意放下身段,还有那个算法效率问题。你在那个帖子里,我必须要说,你有蒙混的嫌疑。我刚进坛子就遇到这个情况,强忍住才没有说难听的话,毕竟我真的是菜鸟。
算法效率,拜托你发个测试截图,再来跟我摆货。
你最大的问题就是连
$ node
>
ctrl + shift + v
都不会
- 那个代码现在没有任何问题
- 写个你的高效率算法代码给我看看
- 把你的测试截图给我看看
1、sets参数是多余的
谁跟你说sets参数是多余的
return x in cache
? cache[x]
: cache[x] = f(sets[x]);
2、缓存的作用非常有限
先学习函数式编程的基础课,再跟我谈缓存
自己把源代码复制到控制台,输出,仔细看看
@LongHorn-C 运算耗费的CPU周期远小于内存访问耗费的CPU周期,如果运算耗费周期大于内存访问周期,缓存就是有效果的,反之则没有效果。在某个运算量之后应该会有效果。
楼主啊,我以为就我一个人对你有意见呢,原来人还不少啊,分享是好事情,但要多矮下身段来多跟人交流。三人行,必有我师,这可不是什么客气话,这里可以为师的人太多了。
原生 Node 里的 events,util 都不错呀。简单写点代码,无须考虑大量callback。最近小试爬虫也是事件。楼主的代码我用 coffeescript 写来玩玩。
EventEmitter = require('events').EventEmitter
fs = require 'fs'
filepath = 'myread.txt'
buflen = 100
buffer = new Buffer buflen
show = console.log
class RunFile extends EventEmitter
constructor : (@filepath) ->
@init()
init : ->
@open @filepath
@on 'err',@handleErr
@on 'read',@read
@on 'write',@write
@on 'close',@close
@on 'done',@done
handleErr : (type,err) ->
show "Has some error. type: '%s', err: '%s'",type,err
open : (filepath)->
fs.open filepath,'a+',(err,fd) =>
if err then @emit 'err','open',err else @emit 'read',fd
read : (fd) ->
fs.read fd,buffer,0,buflen - 10,0,(err) =>
if err then @emit 'err','read',err else @emit 'write',fd
write : (fd) ->
buffer.write '1234567890',buflen - 10
fs.write fd,buffer,0,buflen,0,(err,written,buffer) =>
if err then @emit 'err','write',err else @emit 'close',fd
close : (fd) ->
fs.close fd,(err) =>
if err then @emit 'err','close',err else @emit 'done'
done : ->
show 'No error,well done!!'
run = new RunFile filepath
楼主啊,我以为就我一个人对你有意见呢,原来人还不少啊,分享是好事情,但要多矮下身段来多跟人交流。
可以,发个你比我高明的代码,我自然会放下身段向你学习。我在这的帖子,只不过是推广,我写了文字,在很多网站都发同样的帖子。 而且有时候是同事帮我在每个地方发布。你当我是什么社区忠实的会员?
然而现在,你要向我的https://cnodejs.org/topic/55169b51e26684ed7ff21e1d好好学习,直到你写出比这个代码高明的时候。
如果你写不出来,正如那句话:
Talk is cheap, show me the code
@coordcn 那个缓存问题,是很具体的问题。你进入那个帖子就知道了。代码都没几行。我抄出来的代码恰好解决我在一楼提出的两个问题,他的代码我运行过(sets参数他拐着弯非要把多余的东西变得不多余,结果拐弯的整个过程都显得多余),我给的代码我自己当然更加运行过了。
有些问题不吐不快。我看了你和楼主的讨论的那个socket问题,我也替你稍微感到郁闷,缓解了我当初所感到的困惑。
连自己的代码都不会编辑的你,说的话都不带打草稿的。 我到现在没见到你那code。
- 我的代码有什么问题?
- 你的代码在哪?
我觉得不知羞耻、空口白话很适合你。我们现在就可以从此楼辩个真章,上你的代码,我的代码已经摆在那了,要我再copy一次么。
@tulayang 以前写过一小段,楼主帮忙优化优化吧。
//fibonacci
var x = 0;
var fibo3 = [1, 1, 2];
console.time('first');
function fibonacci(n) {
x = 0;
if (n <= 0) return 0;
if (fibo3[n - 1]) {
return fibo3[n - 1];
} else {
var len = fibo3.length;
for (var i = 0; i < n - len; i++) {
calculateNext(fibo3, i + len);
}
}
return fibo3[n - 1];
}
function calculateNext(fibo3, index) {
x++;
fibo3.push(fibo3[index - 1] + fibo3[index - 2]);
}
var a = fibonacci(1000);
console.log('value is :' + a);
console.log('exec times is :' + x);
var a = fibonacci(1100);
console.log('value is :' + a);
console.log('exec times is :' + x);
var a = fibonacci(1200);
console.log('value is :' + a);
console.log('exec times is :' + x);
var a = fibonacci(1000000);
console.log('value is :' + a);
console.log('exec times is :' + x);
console.timeEnd('first');
@tulayang ES6 有 class 的方法了。封装成 api 的话,我只会用构造器 + 原型。不用 ES6 ,类之间继承,也可用 node 原生的 util.inherits(constructor, superConstructor) 。原生 node 还是提供不少方法的,只不过用库,框架多了,忘记原生的好处。
fibonacci的算法如下:
f(0) : 0 f(1) : 1 f(2) : f(1) + f(0) 1 f(3) : f(2) + f(1) 2 f(4) : f(3) + f(2) 3 f(5) : f(4) + f(3) 5 …
知道了这个规律,可以编码如下:
function fibonacci(n) {
if (n === 0) {
return 0;
}
if (n === 1) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
实际运行,你会发现:
fibonacci(1000):
调用fibonacci(999):
调用fibonacci(998):
调用fibonacci(997):
调用fibonacci(996):
...
调用fibonacci(995):
...
调用fibonacci(996):
...
调用fibonacci(997):
...
调用fibonacci(998):
调用fibonacci(997):
...
调用fibonacci(996):
...
其中的很多是被重复调用,这就造成计算浪费,可以使用存储的方式:
- 0, 1是已知的,所以不计算了,直接放入缓存.
- 计算的时候,先从缓存取值. 如果是数字,那么表明n的计算已经被缓存过,直接返回.
- 如果不是数字,那么表明还没有缓存过n的计算,做一次fibonacci. 记住,这时候n一定是大于1的,所以放心的做
fibonacci(n - 1) + fibonacci(n - 2)
这样的计算. - 计算完,把新的值保存进缓存.
function fibonacci() {
var cache = [0, 1]; // 0, 1的值是固定值
return function walk(n) {
var result = cache[n]; // 先从缓存中取值
if (typeof result !== 'number') { // 是否是有效值?
result = walk(n - 1) + walk(n - 2); // 不是,做一次fibonacci
cache[n] = result; // 把值加入缓存
}
return result; // 返回计算结果
};
}
var f = fibonacci();
f(0); // 0
f(1); // 1
f(2); // 1
f(3); // 2
f(4); // 3
f(5); // 5
f(6); // 8
f(7); // 13
f(8); // 21
...
这个代码写完,其实我也很满意,这是我经常发帖的一个原因:可以经常巧遇,写些工作中遇不到的算法解题。 这个代码我觉得还算不错吧。
@tulayang 说: “这个代码我觉得还算不错吧。”
搞半天,写出个这么个代码。 @dayuoba 提出的这个问题暴露出楼主对自己所讲的memorize和cache的理解不行。漂亮的代码如下,请学着点,show u the code:
fibonacci =memorize(function(n) {
if (n === 0) {
return 0;
}
if (n === 1) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
});
这才叫简洁,通用,函数式编程。楼主的代码,和上面这段代码比较起来,难看。 memorize函数请见:https://cnodejs.org/topic/55169b51e26684ed7ff21e1d#551898c3687c387d2f5b2939 ,10楼
把你爹的代码和《javascript权威指南》复制过来的代码拼凑在一起,表示你懂了函数式编程? 谁告诉你函数式编程memorize是一个固定的写法???
1. 如果没有给你memorize,你还不会写了? 2. 每次写代码,你都先写好一个memorize才能写别的代码? 3. 你拼凑的代码行数计算效率提高多少?
也不看看你爹的代码行数和你自己的代码行数。 谈函数式编程,你还早十年呢。写出自己的代码才是真的懂,孩子,别在这里脑残了。
我以前是基于事件机制写node服务端代码的推荐者,但是经过近两年的实践,也产出过一些应用,但事后总结下来,发现服务端功能逻辑代码使用这种事件机制写出来的代码是反人性的,或者说不符合一般习惯于服务端编程的开发者。相信楼主目前写起来很方便,很自然,很简单,但是一年后再回来看,就会有不一样的想法了。我们两年前还在力推eventproxy,就是完全基于事件解决node异步编程的。但是在nodejs发展到今天,一个应用的业务服务端逻辑代码还使用这种方式来写,我只认为当下可以玩玩,真的还在实际的团队协作项目中使用,那就算了。 自豪地采用 CNodeJS ionic
让我给你做个速度测试,孩子!!!
计算100
- 你的花费了14ms
- 哥的好像才1ms
计算1000
- 你的花费了38ms
- 哥的好像也是才1ms
计算10000
- 你的堆栈溢出了,宝贝!RangeError: Maximum call stack size exceeded
- 哥的好像也是才3ms
function memorize(f) {
var cache = {};
return function(){
var key = arguments.length + Array.prototype.join.call(arguments,',');
if (key in cache) {console.log('retrieve from cache'); return cache[key];}
else return cache[key]=f.apply(this,arguments);
}
}
fibonacci =memorize(function(n) {
if (n === 0) {
return 0;
}
if (n === 1) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
});
var start = new Date();
fibonacci(1000);
var end = new Date();
console.log('Time: %dms.', end.getTime() - start.getTime());
// 38ms
function fibonacci() {
var cache = [0, 1]; // 0, 1的值是固定值
return function walk(n) {
var result = cache[n]; // 先从缓存中取值
if (typeof result !== 'number') { // 是否是有效值?
result = walk(n - 1) + walk(n - 2); // 不是,做一次fibonacci
cache[n] = result; // 把值加入缓存
}
return result; // 返回计算结果
};
}
var start = new Date();
var f = fibonacci();
f(1000);
var end = new Date();
console.log('Time: %dms.', end.getTime() - start.getTime());
// 3ms
@tulayang 你这个可怜虫。 我的速度慢,因为我debug了。console.log速度慢,懂?递归总有堆栈溢出的问题。
那个memorize函数非常通用,一次写成,到处用。这恰是函数式编程的好处。写好的东西,memorize一下就有了新的函数,自动有缓存功能。
你爱自称爹,你给你爹丢脸。
逗比,你的代码到3697就堆栈溢出,还有脸贴,我呸!!!
(我当然知道你的console, 自己去掉console试试谁的速度慢,我的要比你慢,我是你孙子!反之,你是我孙子!)
(去掉console, 哥的速度是你的3倍!年轻人,copy来的代码不要那么狂妄!)
var start = new Date();
fibonacci(3697);
var end = new Date();
console.log('Time: %dms.', end.getTime() - start.getTime());
king@king-pc:~$ node test
(null):0
(null)
RangeError: Maximum call stack size exceeded
你比速度用C好了。代码的简洁性,函数式编程,就是应该那个样子,我前面没有说比快,我说简洁通用。 速度问题,因为我缓冲的Key是长字符串(这样更通用),存储的是实参值,而不是整数,多占空间(导致堆栈早溢出),缓存查找慢。
可怜虫,听懂了?
@fengmk2 楼主不会认为这些会是问题的,他现在的阶段是手里拿着锤子看什么都是钉子。异步回调也好,事件也好,都有其适用的特定范围。而是事实上这些模式也增加了编码的难度,同时也增加了理解的难度和协作的难度,说到底,很多东西都不是那么直观了。
楼主那些个算法,自己都没搞清楚适用范围,以为缓存那么廉价么?内存访问耗费的CPU周期是CPU计算周期的将近200倍,你计算量没有超过内存访问耗费的CPU周期,缓存毫无意义。
要讲算法,百度上比楼主牛的算法海去了,小学生水平的东西拿来炫耀不可耻么?三人行必有我师,不是说说而已,摆正自己的态度才是正途。
@tulayang 我什么时候和你说比速度了。你每个缓存方案重写代码,函数式编程有什么用?你自己把memorize里的key换成整数(这会大大降低这个高阶函数的通用性),看看还有没有堆栈早溢和速度问题?
我想你早已知道你在memorize函数那贴中的问题,你这个可怜虫可怜到不敢承认。
@tulayang 谢谢楼主花时间编码回复。 思路上可能有一些差异,可能我倾向于未来是否需要对缓存做持久化。 這樣對於以前計算過的值是不需要再計算的。用空間換時間,比較笨,比較有效的方法 fibonacci還有一個數學公式計算法,太難了我看見公式都不知道怎麼推出來的
- 速度你不行
- 稳定性你不行,3697就完蛋
- 代码行数你不行,哥的目测11行
- 使用? var f = fibonacci(); f(1); f(2);
- 你抄袭了《javascript权威指南》和我的源码
先想想怎么解决你的堆栈吧,菜鸟,就这么点,还真跟你相配!
还是要提醒你一点,javascript在没有尾递归优化前提下,递归深度过大总会出现堆栈溢出。 这个fibonacci因为每次要调用两个前面的项,我现在认为无法使用尾递归。
我的版本的堆栈极限是:13962。 到13963就该溢出了。当然速度必然胜过某个抄袭书本和我的源码的家伙。
@LongHorn-C 我讲的缓存是个普遍性问题,一般的程序员都天然的认为内存很快,但是跟CPU的运算速度比起来,内存的访问速度太慢了。所有最终的优化都将集中在片上缓存的优化上,我不是太清楚脚本语言是否拥有这样的能力,但一个结论是可以肯定的,内存缓存的结果只在耗费CPU时间大于内存访问的时间时才会起作用。
昨天由于达到回复上限,所以没有回复。
从楼主发言来看,楼主的知识结构是很奇怪的,我不清楚,他的公司是怎样一个公司。也许他们公司他就是最牛的,奇淫技巧太过,基本功不足。那个node架构的讨论可以看出他连一些最基础的东西都没搞懂,这样的人还口口声声说自己在读linux源代码,这雄心壮志是好的,但也得埋下头来才行啊。先把node和libuv的源码读通了成不?
一般的程序员都天然的认为内存很快,但是跟CPU的运算速度比起来,内存的访问速度太慢了。所有最终的优化都将集中在片上缓存的优化上
笑喷了,内存只是寄存和传输数据的,还跟cpu比运算速度。而且要跑到cpu的缓存上了?
- 你知道cpu的缓存是干吗的吗?
- 编程所使用的缓存就是内存的一块
@coordcn 缓存有时候可以解决算法复杂度问题。
比如一个算法是O(n^2),甚至O(n^n),它会随n增大呈指数增长, 它用了缓存后,在n 很大时,改进的速度绝不止几十倍。对于一般的O(n)或者更小的复杂度算法而言,缓存没有多少提高,因为缓存本身的查找算法复杂度就是O(n)了,所以甚至会降低速度。
如果你不能适应函数式这种封装变量的方式,可以完全使用C风格编码:
var cache = [0, 1];
function fibonacci(n) {
var result = cache[n]; // 先从缓存中取值
if (typeof result !== 'number') { // 是否是有效值?
result = fibonacci(n - 1) + fibonacci(n - 2); // 不是,做一次fibonacci
cache[n] = result; // 把值加入缓存
}
return result; // 返回计算结果
}
exports.fibonacci = fibonacci;
或者面向对象风格:
function Fibonacci() {
if (!(this instanceof Fibonacci)) {
return new Fibonacci();
}
this._cache = [0, 1];
}
Fibonacci.prototype.todo = function (n) {
var result = this._cache[n];
if (typeof result !== 'number') {
result = this.todo(n - 1) + this.todo(n - 2);
this._cache[n] = result;
}
return result;
};
Fibonacci().todo(6);
闭包是穷人的对象,对象是穷人的闭包
@tulayang 可怜虫
你连续算10个斐波那契看看。 f(1900),f(1910),f(1150), f(1800),f(999) ,f(1901),f(1919),f(1152), f(1804),f(996) 按总时间最少为高效。
你会跪下喊爷爷的,如果你诚实的话。
逗比!!!叫爷爷!!!
function memorize(f) {
var cache = {};
return function(){
var key = arguments.length + Array.prototype.join.call(arguments,',');
if (key in cache) {return cache[key];}
else return cache[key]=f.apply(this,arguments);
}
}
fibonacci =memorize(function(n) {
if (n === 0) {
return 0;
}
if (n === 1) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
});
var start = new Date();
fibonacci(1900);
fibonacci(1910);
fibonacci(1150);
fibonacci(1800);
fibonacci(999);
var end = new Date();
console.log('Time: %dms.', end.getTime() - start.getTime());
// Time: 5ms.
function fibonacci() {
var cache = [0, 1]; // 0, 1的值是固定值
return function walk(n) {
var result = cache[n]; // 先从缓存中取值
if (typeof result !== 'number') { // 是否是有效值?
result = walk(n - 1) + walk(n - 2); // 不是,做一次fibonacci
cache[n] = result; // 把值加入缓存
}
return result; // 返回计算结果
};
}
var start = new Date();
var f = fibonacci();
f(1900);
f(1910);
f(1150);
f(1800);
f(999);
var end = new Date();
console.log('Time: %dms.', end.getTime() - start.getTime());
// Time: 1ms.
@LongHorn-C 恩,就是这个道理,算法要讨论,但最主要的是要考虑适用范围,楼主这种内存缓存包打天下的做法是不可取的,要以实际情况来权衡。如果我直接计算就行的,就没必要用缓存,因为计算速度和内存访问的速度差距是巨大的,小计算结果没必要缓存。
@fengmk2 其实我认为eventproxy是一个混杂不清的实现。它把MessageQueue(借用ZeroMQ的图,cnode上传图片太慢了),Promise,AOP,全混到一起,而且起了一个误导人的名字:Event proxy(哎~event)。如果只是想要异步并行,不需要任何多余的步骤,要吗?如果是想要一个依赖关系,比如 A必须等待B和C都完成,那么就应该用Promise,EventEmitter不是作这个用的,也实现不了。eventproxy完成是个混合的东西,比如那个all方法,完全就是Promise.all的翻版。举例Jscex里也谈到了:http://blog.zhaojie.me/2012/02/jscexify-nodeclub-3-home-page-implementation.html 。后面的step就是手工实现了Promise all done的语义么。
看下EventProxy的API:bind、subscribe、all、fail。Promise、MQ、AspectOrientProgramming 齐活了。另外还有not,连逻辑操作都整合进去了,最后就成了work flow manager,我不是说work flow manager不好,但为毛用event proxy这词。这概念混杂可见
function fibonacci(n) {
if (n === 0) {
return 0;
}
if (n === 1) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
var start = new Date();
fibonacci(40);
var end = new Date();
console.log('Time: %dms.', end.getTime() - start.getTime());
// Time: 1687ms.
function fibonacci() {
var cache = [0, 1];
return function walk(n) {
var result = cache[n];
if (typeof result !== 'number') {
result = walk(n - 1) + walk(n - 2);
cache[n] = result;
}
return result;
};
}
var start = new Date();
var f = fibonacci();
f(40);
var end = new Date();
console.log('Time: %dms.', end.getTime() - start.getTime());
// Time: 0ms.
http://blog.csdn.net/dadoneo/article/details/6776272
参考下吧,跟楼主这种动不动叫人小孩,叫爷爷的会掉智商的,比他聪明的人海去了。这个问题最好的办法当然是有数学功底,其次也可以用简单的循环,根本不需要所谓的缓存。楼主就是手里有锤子,看什么都是钉子的典型。
楼主本来要show函数式的,被你一搅和,现在人家又追求速度和效率去了,矛盾啊,就是这样,人家的算法还比他的好上很多,这你叫楼主怎么活,走偏锋,比速度也比不过人家啊。
http://blog.csdn.net/dadoneo/article/details/6776272
不要说我用C欺负他,以楼主的能力,转换成javascript是秒秒钟的事情。所以人还是那句话,做人要谦虚,动不动叫人小孩,叫爷爷的是不成熟的表现,没准过个几年,楼主回过头来看这些,自己都会觉得可笑了。人都是从不知天高地厚,老子天下第一那会过来的,但越是静下心来学,就越觉得自己不入流,要学的东西太多了,服务端编程太难,现在我都觉得javascript的进入是不是一个错误,不是node本身不好,而是门槛低了,人也浮躁了。
node的火爆是不是也映射了互联网的浮躁呢?我现在越来越有这种感觉了,资本都希望短平快,产品原型一出就想上市圈钱,这真的健康么?我们或许忘记了,node不过是一个工具罢了,他承载不起太多的东西,把底层搞透了,才是正途。最近看到一个朋友想重拾C++,我认为这是好现象,大家一起加油吧。
我现在的方向是C和Lua,我自觉自己的能力有限,无法把握C++,更无法搞懂V8,当时大家讨论fibjs,我读了@响马的代码,大至了解了fibjs的运作原理,但说实在的,我无法把握那些复杂的代码。所以我选择简单精炼的C和Lua。
我是来乱入的。 斐波那契数列各种计算方式的时间复杂度
- 递归 O(1.618 ^ n)
- 递推 O(n)
- 记忆化递归 O(n) 不过算过n之后小于n的结果由于有记忆可以 O(1)得出
- 矩阵 O(logn) 也可以加记忆化,不过没什么必要的样子。log已经是光速了。
顺路说一句,根据个人经验,越快的算法,理解和阅读起来就越难。可读性什么的都去死吧。
@coordcn 错误其实在他们觉得老子有FP功底就天下无敌。这种程序员其实我见得多了,特征都是:JS出生、看不起Java、老子懂FP天下无敌。可惜他们才刚见了个S-expression就以为那个就是FP?不知道APL的脸要往哪搁,更别提其实人家Lisp本来开始是M-expression。Y/U/W combinator估计也不会写,才看到curring就手舞足蹈,还有奇葩的把callback当成FP,不知道Haskell do notation心里怎么想了。 估计continuation什么的他们还没学到,不知道学到了又会如何BS yield了,可惜他们又不知道SSA是什么。。。。总之,我本来觉得自己是FP还没入门的半吊子,就不敢在博客上随便发表对Haskell、Racket有什么看法,结果估计由于我会PHP,就被这些FP神棍们碾压了很多遍了,就算我拿C++模板来侃,都无法阻挡连strong type和weak type都分不清的FP神棍们秀他们的优雅的四则运算:
add(multiply(250,250),multiply(250,250))
对了,strong type和week type这样区分最简单的,阮大神的博客又误导了一把: 《Programming Language:Application and Interpretation》
So what is “strong typing”? This appears to be a meaningless phrase, and people often use it in a non- sensical fashion. To some it seems to mean “The language has a type checker”. To others it means “The language is sound” (that is, the type checker and run-time system are related). To most, it seems to just mean, “A language like Pascal, C or Java, related in a way I can’t quite make precise”. If someone uses this phrase, be sure to ask them to define it for you. (For amusement, watch them squirm.)
@coordcn 错误其实在他们觉得老子有FP功底就天下无敌。这种程序员其实我见得多了,特征都是:JS出生、看不起Java、老子懂FP天下无敌。可惜他们才刚见了个S-expression就以为那个就是FP?不知道APL的脸要往哪搁,更别提其实人家Lisp本来开始是M-expression。Y/U/W combinator估计也不会写,才看到curring就手舞足蹈,还有奇葩的把callback当成FP,不知道Haskell do notation心里怎么想了。 估计continuation什么的他们还没学到,不知道学到了又会如何BS yield了,可惜他们又不知道SSA是什么。。。。总之,我本来觉得自己是FP还没入门的半吊子,就不敢在博客上随便发表对Haskell、Racket有什么看法,结果估计由于我会PHP,就被这些FP神棍们碾压了很多遍了,就算我拿C++模板来侃,都无法阻挡连strong type和weak type都分不清的FP神棍们秀他们的优雅的四则运算:
add(multiply(250,250),multiply(250,250))
对了,strong type和week type这样区分最简单的,阮大神的博客又误导了一把: 《Programming Language:Application and Interpretation》
So what is “strong typing”? This appears to be a meaningless phrase, and people often use it in a non- sensical fashion. To some it seems to mean “The language has a type checker”. To others it means “The language is sound” (that is, the type checker and run-time system are related). To most, it seems to just mean, “A language like Pascal, C or Java, related in a way I can’t quite make precise”. If someone uses this phrase, be sure to ask them to define it for you. (For amusement, watch them squirm.)