- 论坛徽章:
- 44
|
本帖最后由 windoze 于 2014-11-06 11:08 编辑
回复 21# yulihua49
当然是阻塞到条件满足为止啊,比如说你要读26个字节,那么tcp_stream::read(buf, 26)会一直阻塞到26个字节都被读出来为止,至于数据,对调用者来说当然是放在调用者提供的缓冲区里,(虽然tcp_stream内部其实有一个自己的缓冲区,多copy一次确实会影响效率,但程序简单了)。
例子中那个s << s.rdbuf()其实是偷了个懒,意思是说,程序一直阻塞,直到读到随便多少(但不超过stream内部缓冲区,目前是1500字节)数据,然后就把这些数据(阻塞)写出去。
你描述的问题,程序写出来大概就这样:
- void connection_handler(tcp_stream &s) {
- char buf[26];
- s.read(buf, 26); // 这里会阻塞直到读到了26个字节,
- // ...
- char cmd[68];
- fill_some_data(cmd, 68); // 你自己的函数,生成68个字节的数据准备发送
- s.write(cmd, 68); // 这里会阻塞直到68个字节都发送完
- // ...
- }
复制代码 每个阻塞点都会导致内部的scheduler切换到其它fiber继续执行,对于这个fiber来说所有的I/O都是最普通的同步阻塞操作,并且没有short read/write问题,但对于线程池来说内部进行的都是异步的非阻塞I/O。
简单说,这个库可以让你像早年间每连接一线程那样写程序,唯一的区别就是同样的程序结构可以处理更多的并发连接,一个进程中创建几百上千个线程就会很慢了,绝大多数时间都会花在线程切换上,但fiber或者说green thread创建和切换的成本都很低(目前的测试创建成本对比thread大约是100:1,切换成本大约相当于5次函数调用),所以创建几万个毫无压力,(压力测试中创建过2M个,程序还能跑)。
但由于是线程池结构,所以对于并发少但CPU密集的任务,这种结构就没有优势了,不过对于绝大多数网络服务端,coroutine+async I/O的结构都能极大的简化程序结构,同时保持高并发能力。
PS. C++的stream/streambuf框架一定要有个内部缓冲区,如果你觉得多一次copy很不爽,也可以用Fiberized.IO的Boost.ASIO集成功能,比如:
- void connection_handler(tcp_stream &s)
- char buf[123];
- boost::system::error_code ec;
- size_t byte_read=boost::asio::async_read(s,
- boost::asio::buffer(buf, sizeof[buf]),
- boost::asio::transfer_at_least(123),
- fibio::asio::yield[ec]); // 用fibio::asio::yield当作ASIO中的completion handler,所有的boost::asio::async_xxx都可以变成fiber内的同步阻塞调用
- // 这里byte_read应该等于123,否则ec.value()就不为0
- }
复制代码 |
|