asio 学习笔记

简述

Asio是一个用于网络和低级I/O编程的跨平台c++库,它使用现代c++方法为开发人员提供了一致的异步模型。Asio为c++网络、并发和其他类型的I/O提供了基本的构建块。
在这里插入图片描述

Proactor设计模式

IO设计模式:Reactor和Proactor对比

以主动写为例:
Reactor将handle放到select(),等待可写就绪,然后调用write()写入数据;写完处理后续逻辑。
Proactor调用aio_write后立刻返回,由内核负责写操作,写完后调用相应的回调函数处理后续逻辑。
可以看出,Reactor被动的等待指示事件的到来并做出反应;它有一个等待的过程,做什么都要先放入到监听事件集合中等待handler可用时再进行操作。
Proactor直接调用异步读写操作,调用完后立刻返回。

Proactor and Boost.Asio

在这里插入图片描述
——Asynchronous Operation
定义异步执行的操作,例如对套接字的异步读或写。
——Asynchronous Operation Processor
执行异步操作并在完成事件队列上排列事件。
——Completion Event Queue
缓冲完成事件,直到它们被异步事件解复用器出队列。
——Completion Handler
处理异步操作的结果。这些是函数对象,通常使用boost::bind创建。
——Asynchronous Event Demultiplexer
阻塞等待事件在完成事件队列上发生,并将完成的事件返回给其调用者。
——Proactor
调用asynchronous event demultiplexer来提取事件队列,并分派与事件相关的completion handler。
—— Initiator
应用程序特定的代码,用于启动异步操作。Initiator通过高级接口(如basic_stream_socket)与Asynchronous Operation Processor交互,该高级接口又委托给像reactive_socket_service这样的服务。

在许多平台上,Boost.Asio根据Reactor(如select、epoll或kqueue)实现了Proactor设计模式。实现方法如下:
—— Asynchronous Operation Processor
使用select、epoll或kqueue实现的Reactor。当Reactor指示资源已准备好执行操作时,处理器执行异步操作,并将相关的完成处理程序排入 completion event queue。

优势

——可以移植性
——解耦线程和并发
通过应用程序的实现,长时间的操作异步执行的。因此,应用程序不需要生成许多线程来增加并发性。
——性能及可延展性
由于上下文切换、同步和cpu间数据移动的增加,像一个连接对应一个线程(仅同步方法需要)这样的实现策略可能会降低系统性能。使用异步操作,可以通过最小化操作系统线程的数量来避免上下文切换的成本,并且只激活有事件要处理的控制的逻辑线程。
——简化应用程序同步
异步操作完成处理程序可以编写成它们存在于单线程环境中,因此可以在开发应用程序逻辑时很少或根本不考虑同步问题。
——函数组合
函数组合是指实现提供更高层次操作的函数,例如以特定格式发送消息。每个函数都是通过对低级读或写操作的多次调用来实现的。
函数组合是指实现提供更高层次操作的函数,例如以特定格式发送消息。每个函数都是通过对低级读或写操作的多次调用来实现的。要在异步模型中组合函数,可以将异步操作链接在一起。也就是说,一个操作的完成处理程序可以启动下一个操作。启动链中的第一个调用可以被封装,这样调用者就不需要知道高级操作是作为异步操作链实现的。以这种方式组合新操作的能力简化了在网络库之上更高级别抽象的开发,比如支持特定协议的函数。

劣势

——程序的复杂性
由于操作启动和完成之间在时间和空间上的分离,使用异步机制开发应用程序更加困难。由于控制的反向流,应用程序可能也更难调试。
——内存使用
在读取或写入操作期间,必须提交缓冲区空间,这可能会无限期地持续下去,并且每个并发操作都需要一个单独的缓冲区。另一方面,在套接字准备好读写之前,Reactor 模式不需要缓冲区空间。

Reactor-Style Operations

也支持。

ip::tcp::socket socket(my_io_context);
...
socket.non_blocking(true);
...
socket.async_wait(ip::tcp::socket::wait_read, read_handler);
...
void read_handler(asio::error_code ec)
{
  if (!ec)
  {
    std::vector<char> buf(socket.available());
    socket.read_some(buffer(buf));
  }
}

Threads and Asio

asio 有两种多线程模型,详解见链接
链接: https://www.cnblogs.com/fnlingnzb-learner/p/10402276.html.
所有注册到asio的回调函数调用都是在调用io_context::run()线程中的函数。
一个线程对应一个io_context,性能要好一些,且不会出现并发调用,不需要在回调函数中加锁。

Strands: Use Threads Without Explicit Locking

链被定义为事件处理程序的严格顺序调用(即没有并发调用)。使用链可以在多线程程序中执行代码,而不需要显式锁定。
详解见链接(解释了Strands的好处,并实现了一个demo用于讲解Strands)
链接: https://www.crazygaze.com/blog/2016/03/17/how-strands-work-and-why-you-should-use-them/.

Coroutines

协程运行在线程之上,一个线程包含多个协程。当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。
asio有两种协程,Stackless和Stackful。与无堆栈协程相比,堆栈协程可以从嵌套的堆栈框架内挂起。执行将在代码中之前挂起的完全相同的点上恢复。对于无堆栈协程,只有顶层例程可以挂起。由顶级例程调用的任何例程本身都不能挂起。这禁止在通用库中的例程中提供挂起/恢复操作。

Stackless Coroutines

coroutine类提供了对Stackless Coroutines的支持,Stackless Coroutines使程序以同步方式实现异步逻辑,以最小的开销,如下例所示:

struct session : asio::coroutine
{
  boost::shared_ptr<tcp::socket> socket_;
  boost::shared_ptr<std::vector<char> > buffer_;

  session(boost::shared_ptr<tcp::socket> socket)
    : socket_(socket),
      buffer_(new std::vector<char>(1024))
  {
  }

  void operator()(asio::error_code ec = asio::error_code(), std::size_t n = 0)
  {
    if (!ec) reenter (this)
    {
      for (;;)
      {
        yield socket_->async_read_some(asio::buffer(*buffer_), *this);
        yield asio::async_write(*socket_, asio::buffer(*buffer_, n), *this);
      }
    }
  }
};

协程类与伪关键字reenter、yield和fork一起使用。这些是预处理宏,使用类似于Duff’s Device的技术以switch语句的形式实现。

Stackful Coroutines

spawn()函数是用于运行Stackful协程的高级包装器。它基于 Boost.Coroutine协同程序库。spawn()函数使程序能够以同步方式实现异步逻辑,如下例所示:

boost::asio::spawn(my_strand, do_echo);

// ...

void do_echo(boost::asio::yield_context yield)
{
  try
  {
    char data[128];
    for (;;)
    {
      std::size_t length =
        my_socket.async_read_some(
          boost::asio::buffer(data), yield);

      boost::asio::async_write(my_socket,
          boost::asio::buffer(data, length), yield);
    }
  }
  catch (std::exception& e)
  {
    // ...
  }
}

Coroutines TS

TS代表了Technical Specification,直译的话是“技术规范”。TS是标准委员发出来鼓励各个厂家实现,以在提交标准之前发现问题的。即使在同一个领域,也可以有多个互相竞争的TS,不是每一个TS都会被最终作为标准提交。

先写到这里后续补充

参考

https://www.boost.org/doc/libs/1_76_0/
https://toutiao.io/posts/d2eeed/preview
https://stackoverflow.com/questions/28977302/how-do-stackless-coroutines-differ-from-stackful-coroutines

本博客是博主个人学习时的一些记录,不保证是为原创,如有侵权请与我联系。

留言即可,我会立即删除。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值