Strandify 内部协作对象以支持多线程

Strandify inter coorporating objects for multithread support

我当前的应用程序拥有多个“可激活”对象*。我的意图是“运行”所有这些对象在同一个 io_context 中并添加必要的保护以便从单线程切换到多线程(以使其可扩展)

如果这些对象彼此完全独立,则关联 io_context 的线程数 运行 可以平稳增长。但是由于这些对象需要协作,尽管每个对象中都有链,但应用程序在多线程中崩溃。

假设我们有类型 A 和类型 B 的对象,它们都由同一个 io_context 提供。这些类型中的每一种 运行 异步操作(计时器和套接字 - 它们的处理程序都被 bind_executor(strand, handler) 包围),并且可以基于通过套接字接收的信息和向它们发送的操作来构建缓存。类型 A 的对象需要从 B 的多个实例中获取缓存的信息才能执行自己的工作。

是否可以使用 strands(不添加显式互斥保护)来访问此信息?如果可以,如何访问?

如果不是,可以采用什么策略来实现可伸缩性?

我已经尝试过期货交易,但不出所料,这种策略会导致僵局。

谢谢

(*) 也许我的术语是错误的:对象获得对 io_context 的引用并拥有自己的链,所以我认为它们是可激活的,因为它们并不真正拥有 运行宁线程

你有点含糊不清。 “可激活”、“分层”、“相互合作”。它们都接近于有意义的概念,但是,勉强避免绑定到任何精确的含义。

解构

让我们使用更精确的概念来简化。

Let's say we have objects of type A and type B, all of them served by the same io_context

我认为说“类型 A 和 B 有关联的执行者”更有成效。当您确保 A 和 B 上的所有操作都从该执行程序 运行时,您确保执行程序序列化访问,然后您基本上得到 Active Object pattern.

[can build a cache based on information received via sockets] and posted operations to them

这很有趣。我认为这意味着您不直接调用 class 的成员,除非他们将实际执行推迟到 strand。同样,这将是活动对象。

但是,您的症状表明并非所有操作都“发布给他们”。这意味着它们 运行 在任意线程上,导致你的问题。

Would it be possible to access this information by using strands (without adding explicit mutex protection) and if yes how ?

你的问题的关键就在这里。数据依赖。 ;ole;y 也会限制缩放的有用性,当然除非从其他线程检索信息的生成是一项计算量大的操作。

但是,根据短语_“从 B 的多个实例中获取缓存的信息”,这表明实际上数据是即时的,您只需为跨线程访问支付同步成本。

问题

Q. Would it be possible to access this information by using strands (without adding explicit mutex protection) and if yes how ?

从技术上讲,是的。通过确保 所有 操作继续进行,并且对象成为真正的活动对象。

但是,有一个重要的警告:链不是零成本的。只有在某些上下文中它们才能被优化(例如,在立即延续或执行上下文没有并发时)。

但在所有其他上下文中,它们最终以与互斥量相似的成本进行同步。 strand 的目的不是消除锁争用。相反,它允许人们以声明方式指定任务的同步要求,以便无论异步完成的方法(使用回调、期货、协程、等待等)或选择的执行上下文如何,都可以正确同步相同的代码( s).

Example: I recently uncovered a vivid illustration of the cost of strand synchronization even in a simple context (where serial execution was already implicitly guaranteed) here:

sehe mar 15, 23:08 Oh cool. The strands were unnecessary. I add them for safety until I know it's safe to go without. In this case the async call chains form logical strands (there are no timers or full duplex sockets going on, so it's all linear). That... improves the situation :) Now it's 3.5gbps even with the 1024 byte server buffer

吞吐量增加了约 7 倍,仅仅移除了链。


Q. If not, what strategy could be adopted to achieve the scalability?

我怀疑您真的想要包含 shared_futures 的缓存。因此,第一次检索会将结果的未来放入缓存中,随后的检索会立即获得已经存在的共享未来。

如果您确保您的缓存查找数据结构是线程安全的,可能带有 reader/writer 锁 (shared_mutex),您将可以从 any 以最小的开销自由访问它 演员,而不是要求通过每个制作人的各个部分。

请记住等待期货是一个阻塞操作。因此,如果您从发布在执行上下文中的任务执行此操作,您可能很容易 运行 线程不足。在这种情况下,最好根据 boost::asio::async_resultboost::asio::async_completion 提供 async_get,这样您就可以以非阻塞方式等待。