最近一直忙着写垃圾代码了,好久没静下心来思考点东西了。期间用node.js写了点小玩意练了下手,回来看看自己写的那篇关于异步的一些思考,感觉有点东西当时想的不是很准确,有必要再写篇文章,下面的代码纯属手写,懒得开VS调了...
1.lambda
有了lambda,就有了闭包,有了lambda也就可以很容易的实现bind的各种功能。比如说吧,有一个函数,声明是这样的:
int foo(int a,double b);
用bind的话,可以给他直接绑定变量,比如:
//前面有两个变量x和y分别为int和double,略去不写
std::function<int(void)> func = std::bind(foo, x, y);
用lambda的话:
std::function<int(void)> func = [x,y]()->int{return foo(x, y);};
如果要求奇葩点,要调换两个参数的位置,用bind这么写:
std::function<int(double,int)> func = std::bind(foo, std::placeholders::_2, std::placeholders::_1);
这样返回的函数对象的参数就是两个参数的位置调换了。如果用lambda:
std::function<int(double,int)> func = [](double b, int a)->int{return foo(a, b);};
或者只绑定一个参数:
std::function<int(double)> func = std::bind(foo, x, std::placeholders::_1);
lambda:
std::function<int(double)> func = [x](double b)->int{return foo(x,b);};
所以仔细想下,有了lambda,bind真的意义不大了,C++11里面加了bind或许有啥特殊用处我还没了解,或者只是为了兼容吧,比如asio的placeholder,应该就只能用bind吧...
2.CPS变换
一开始以为CPS跟异步只是有点关系,后来发现如果不用啥coroutine库或者async.js这样的库,代码里面的cps变换简直多到让人蛋碎...而且这玩意有传染性..只要一个操作是异步的,需要一个回调来处理结果,那得到结果之后的代码只能在回调里面,然后里面再接着来一个异步操作...于是就这么一层层的嵌套下去了。比如说:
app.get('/',function()
{
//do something..
//要到数据库查点东西..
db.get(function(docs)
{
//遍历结果
docs.forEach(function(doc)
{
//....
});
});
});
这种代码能看???用bind也是一个样,只是把回调函数单独抽出去了而已,本质上跟这个一个样..如果循环里面再嵌套一个异步操作..简直无法可想,很多异步还不能同时发起多个读取或写入操作,必须等前一个完成,比如asio(nodejs能不能我还真不太清楚),这是你只能把循环拆分开来放到各个回调里面。比如说吧,我要把一个vector里面的东西循环发送出去(下面代码只是表达意思):
// 前面有个vec为std::vector<int>类型,handle_write为回调函数,没代码
foreach(auto x in vec)
{
boost::asio::async_write(sock, boost::asio::buffer(&x,sizeof(int)), handle_write);
}
这是严重错误的,你在发起了一次async_write之后,没有等返回(handle_write被调用)就可能循环回来发第二次了,之前的asio学习笔记就说过了。所以你只能改成这样:
void handle_write(std::vector<int>::iterator it) //省略了错误判断
{
++it;
if (it == vec.end())
{
//循环完了处理后事
return;
}
boost::asio::async_write(sock, boost::asio::buffer(&(*it),sizeof(int)), std::bind(handle_write,it));
}
// 在xx函数中..
....
std::vector<int>::iterator it = vec.begin();
boost::asio::async_write(sock, boost::asio::buffer(&(*it),sizeof(int)), std::bind(handle_write,it));
.....
就特么一个循环都要写成这样,你让我如何不蛋疼..你如果把上面的std::bind和handle_write换成lambda的表示方式,就能看出来他跟nodejs的那个一模一样。当然你可以用coroutine把他搞得像看起来同步的那样..不过C++的coroutine(也就是boost.coroutine和asio的那个coroutine了)也是各种蛋疼。
先写这些了,以后想到啥再补充..话说直接在blog里面敲代码真是恶心啊,终于知道了那些用记事本写代码的...真的是在用绳命装X啊。