异步编程

本节深入讨论异步编程将遇到的若干问题。建议多次阅读,以便吃透这一节的内容,这一节是对整个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. C#基础系列——异步编程初探:async和await

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

  2. 使用 boost.asio 简单实现 异步Socket 通信

     客户端: class IPCClient { public: IPCClient(); ~IPCClient(); bool run(); private: bool connect(); bool ...

  3. boost asio tcp 多线程异步读写,服务器与客户端。

    // server.cpp #if 0 多个线程对同一个io_service 对象处理 用到第三方库:log4cplus, google::protobuf 用到C++11的特性,Windows 需要 ...

  4. boost asio 学习(五) 错误处理

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

  5. Python Twisted系列教程2:异步编程初探与reactor模式

    作者:dave@http://krondo.com/slow-poetry-and-the-apocalypse/  译者:杨晓伟(采用意译) 这个系列是从这里开始的,欢迎你再次来到这里来.现在我们可 ...

  6. Boost.Asio基础(三)

    Socket控制 以下的函数进行处理一些高级的socket选项: get_io_service():返回io_service实例 get_option(option):返回socket option对 ...

  7. Boost.Asio基础

    http://www.voidcn.com/article/p-exkmmuyn-po.html http://www.voidcn.com/article/p-xnxiwkrf-po.html ht ...

  8. 温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法

    什么是异步编程(Async/Await) Async/Await本质上是通过编译器实现的语法糖,它让我们能够轻松的写出简洁.易懂.易维护的异步代码. Async/Await是C# 5引入的关键字,用以 ...

  9. [Boost基础]并发编程——asio网络库——异步socket处理

    异步服务器端 #include <conio.h> #include <iostream> using namespace std; #include <boost/as ...

随机推荐

  1. BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )

    建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接 ...

  2. C/C++中使用的正则表达式库

    正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑. 正则引擎主要可以分 ...

  3. windows下搭建python+selenium环境

    1.安装python https://www.python.org/ 2.安装setuptools(python的基础包工具) 下载地址:https://pypi.python.org/pypi/se ...

  4. Linux 下修改Tomcat使用的JVM内存大小

    我的服务器的配置: # OS specific support.  $var _must_ be set to either true or false. JAVA_OPTS="-Xms10 ...

  5. linux服务器在运行210天左右宕机

    减小字体 增大字体 作者:错新网  来源:www.cuoxin.com  发布时间:2014-2-25 19:21:32 错新网讯   最近几天,一批linux线上的服务器接连宕机,当时以为是硬件问题 ...

  6. 苹果iPhone不能判断红外发射管的好坏

    用手机来检测红外发射管好坏是目前比较常用的方法.实际操作比较简单,就是按照红外发射管的工作电压给发射管接上电源后,把手机的摄像头对着红外发射管就能看出好坏了.由于红外线是肉眼看不见的,如果不通过手机摄 ...

  7. Netty那点事: 概述, Netty中的buffer, Channel与Pipeline

    Netty那点事(一)概述 Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户ne ...

  8. linux中find批量删除空文件及空文件夹

    linux下批量删除空文件(大小等于0的文件)的方法  代码如下 复制代码 find . -name "*" -type f -size 0c | xargs -n 1 rm -f ...

  9. POJ 1721 CARDS(置换群)

    [题目链接] http://poj.org/problem?id=1721 [题目大意] 给出a[i]=a[a[i]]变换s次后的序列,求原序列 [题解] 置换存在循环节,因此我们先求出循环节长度,置 ...

  10. IE 中开发,兼容与性能测试工具汇总

    前言 对于开发者来说, IE的兼容性是最让人头疼的. 因为是微软的产品, 且绑定在操作系统上, 所以IE的占用率还是相当大, 对于开发者来说, 这部分的兼容的考虑就不可避免了. 对于IE 的各版本来说 ...