异步编程

本节深入讨论异步编程将遇到的若干问题。建议多次阅读,以便吃透这一节的内容,这一节是对整个boost.asio来说是非常重要的。

为什么须要异步

如前所述,通常同步编程要比异步编程更简单。同步编程下,我们非常easy线性地对问题进行考量。函数A调用完,继续运行B。B运行完,继续运行C。以此类推。相对照较直观。而对于异步编程,如果有5个事件,我们非常难知道它们详细的运行顺序,你甚至不知道,它究竟会不会被运行。
尽管编写异步的程序,非常难,可是依旧须要使用这样的方法。

由于server程序须要同一时候并行的处理大量的客户端。并行的客户端越多,异步编程的优势就越明显。
        如果有一个server程序,须要同一时候处理1000个并行的客户端,客户端和server之间的通信消息。以’\n’来结尾。
这是同步模式下的代码,使用1个线程:

using namespace boost::asio;
struct client{ip::tcp::socket sock;char buff[1024]; //每一个消息最大1024个字节int already_read; //已经读取了多少字节
};
std::vector<client> clients;
void handle_clients() {while(true) {for(int i=0; i<clients.size(); ++i) {if(clients[i].sock.available() ) on_read(clients[i]));}}
}void on_read(client& c) {int to_read = std::min(1024 - c.already_read, c.sock.available());c.sock.read_some(buffer(c.buff + c.already_read, to_read);c.already_read += to_read;if(std::find(c.buff, c.buff + c.already_read, '\n') < c.buff + c.already_read) {int pos = std::find(c.buff, c.buff + c.alread_read, '\n') - c.buff;std::string msg(c.buff, c.buff + pos);std::copy(c.buff + pos, c.buff + 1024, c.buff);c.already_read -= pos;on_read_msg(c, msg);}
}void on_read_msg(client & c, const std::string& msg) {if(msg == "request_login")c.sock.write("request_ok\n");else if ...
}

在任务server程序中,你都须要避免代码被堵塞。看上面的代码,我们希望handle_clients()这个函数尽可能的不被堵塞。

不论什么时候函数堵塞。从客户端发来的消息就会等待。直到函数不堵塞的时候才干来处理它们。为了避免程序被堵塞,我们仅仅在socket中确实有数据的时候才去读取,实现的代码是:

if(clients[i].sock.available() ) on_read(clients[i]));

在on_read函数中,我们仅仅读取socket确实有效的数据;调用read_util(c.sock, buffer(…),’\n’);是非常不好的选择。它会堵塞程序,直到完整的读取了所有的数据才返回。

我们永远不知道究竟什么时候才干读取完成。

程序的瓶颈是on_read_msg()这个函数。所有输入的数据都被卡在这里。on_read_msg()应该尽量避免出现这样的情况,但有时这又是全然没办法避免的。(比方,当socket的缓冲区满了以后,操作必将被堵塞)。
     以下是同步模式下的代码,使用10个线程:

using namespace boost::asio;//...这里的定义和前面一样bool set_reading() {boost::mutex::scope_lock lk(cs_);if(is_reading_) return false;else { if_reading_ = true; return true; }}void unset_reading() {boost::mutex::scoped_lock lk(cs_);is_reading_ = false;}private:boost::mutex cs_;bool is_reading_;
};
std::vector<client> clients;
void handle_clients() {for(int i=0; i<10; ++i) {boost::thread(handle_clients_thread);}
}void handle_clients_thread() {while(true) {for(int i=0; i<clients.size(); ++i) {if(clients[i].sock.available()) {if(clients[i].set_reading()) {on_read(clients[i]);clients[i].unset_reading();}}}}
}void on_read(client & c) {
...
}
void on_read_msg(client & c, const std::string& msg) {
...
}

为了使用多线程,我们须要同步机制,set_reading()和unset_reading()就是在做这个用的。set_reading()。非常重要。它測试当前是否有线程在做读取操作。
     能够看出来代码已经比較复杂了。
     另一种同步编程的方法,就是每一个client分配一个线程。可是随着并行的客户端数量的增长,这显然是不可行的。

如今我们来看看异步方法。当client请求数据的时候,on_read被调用,发送返回数据,之后又等待下一个请求(运行另一个异步的读操作)。

异步代码,10个线程:

using namespace boost::asio;
io_service service;
struct client {ip::tcp::socket sock;streambuf buff;
};
std::vector<client> clients;
void handle_clients() {for(int i=0; i<clients.size(); ++i) {async_read_util(clients[i].sock, clients[i].buff, '\n',boost::bind(on_read, clients[i], _1, _2));}for(int i=0; i<10; ++i)boost::thread(handle_clients_thread);
}
void handle_clients_thread() {service_run();
}void on_read(client& c, const error_code& err, size_t read_bytes) {std::istream in(&c.buff);std::string msg;std::getline(in, msg);if(msg == "request_login")c.sock.async_write("request_ok\n", on_write);else if ......//如今在同一个socket上等待下一个读取请求async_read_util(c.sock, c.buff, '\n',boost::bind(on_read, c, _1, _2));
}

Boost.Asio基础(五) 异步编程初探相关推荐

  1. boost.asio基础篇 小白入门注解

    参考资料:https://blog.csdn.net/caoshangpa/article/details/79231740 一个基础的同步客户端 //使用asio的所有程序都需要至少有一个io_co ...

  2. boost.asio无锁异步并发

    简介 给出一个不安全的情况,假设我们有一个socket用于和用户通信,用户会发送多个请求,我们处理请求需要一定的时间,同时使用异步并发的模型来处理对应的请求,即一个io_context::run会有多 ...

  3. 异步编程初探:async和await

    前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友就说到了async, await等新语法.确实,没有异步的多线程是单调的.乏味的,async和await是出现在C#5.0之后,它的出现给了 ...

  4. dart基础之异步编程

    在java中,有Thread来代表一个线程,但是在dart中是没有线程概念的,只有类似于多线程的isolate.除此之外,还针对读文件.数组操作专门制定了一个异步Stream类,使用起来很方便.本次主 ...

  5. 对Boost.Asio中异步事件循环的理解

    Boost.Asio是一个异步编程的网络框架, 核心的优势在于IO操作的异步调用. 异步调用时, 会用到boost::asio::io_context::run()函数, 这个函数表示启动一个IO的异 ...

  6. Boost.Asio使用实例

    1.概述: Boost.Asio是一个跨平台的C++库,用于网络和底层I/O编程,可以在I/O对象(如socket)上执行同步和异步操作. 2.简略的过程分析.以socket的连接操作为例: 你的程序 ...

  7. VScode CMake 编写 Boost Asio Chat程序----记录6

    目录 一 前言 二  参考 三 程序 四 解读 五  注意事项 一 前言 实现了如下功能: 1 留言室(原功能). 2 两个client可以相互交谈 但是需要离开room, 要想留言,需要重新进入, ...

  8. Boost.Asio初步(一)

    [注]本翻译来自https://theboostcpplibraries.com/boost.asio.boost.asio从v1.66起io_service变成了io_context,二者有一定差异 ...

  9. asio boost 异步错误处理_boost asio 学习(五) 错误处理

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=6 5. Erro ...

最新文章

  1. c语言xml序列化,C# XML和实体类之间相互转换(序列化和反序列化)
  2. python自学网站 知乎-知乎千赞回答 | 为什么自学python看不进去?
  3. 数据库access和mysql_数据库access和MYSQL有什么区别?
  4. 乾坤 微前端_前端优秀资源整理(持续更新~)
  5. BZOJ-3171-循环格-TJOI2013-费用流
  6. ssh(Spring+Spring mvc+hibernate)——Dept.hbm.xml
  7. mysql导入竖杠分割的数据_MYSQL :逗号分隔串表,分解成竖表
  8. 互联网日报 | 4月20日 星期二 | 华为正式宣布卖车;携程在港交所挂牌上市;广州期货交易所正式揭牌...
  9. PNChart,简洁高效有动画效果的iOS图表库
  10. Python案例:通过方向键移动屏幕上的图像
  11. python多重继承super父类参数_多重继承如何处理super()和不同的参数?
  12. 图解TCPIP-DNS
  13. 事情隐瞒或者公开,对你没有任何意义
  14. 高性能stun服务器搭建,STUN/TURN服务器搭建
  15. android内存卡测试,安卓sd卡真假检测工具_内存卡检测扩容卡软件_sd insight
  16. 联想微型计算机m73拆机,联想M73更换处理器 | 更换i3 4330t处理器_什么值得买
  17. 台式机鼠标失灵打开计算机,台式电脑鼠标不动怎么办
  18. Java算法:牛客网哔哩哔哩bilibili笔试真题算法Java版1-14题
  19. flea-jersey使用之文件上传接入
  20. AARRR模型——留存:始于价值,合于套路,久于习惯(中)

热门文章

  1. [29期] 打仗、打球、打游戏、打代码。。。
  2. Windows Server 2008部署***服务器
  3. 立即更新 Chrome 浏览器!这个 0day 已遭在野利用
  4. 为避免攻击,研究员把严重的比特币漏洞详情焐了两年
  5. 年薪30W前端程序员,需要吃透的前端书籍推荐
  6. docker machine介绍和使用
  7. python学习路程1
  8. 用python写一个简单的web服务器
  9. 查看linux服务器内存使用情况,不够时创建Swap、手动 cached
  10. OpenStack_Swift源代码分析——Ring基本原理及一致性Hash算法