网站建设周志200字,网络营销定价的特点有,中企动力邮箱入口,wordpress自定义分类无法显示5.4.5 轮询和事件驱动处理模式
接下来#xff0c;我们探讨服务提供方同时支持事件驱动和轮询行为的情况。从服务实例#xff08;此处指骨架子类实例#xff09;的角度来看#xff0c;服务消费者的请求#xff08;包括服务方法或字段的 getter/setter 调用#xff09;可能…5.4.5 轮询和事件驱动处理模式
接下来我们探讨服务提供方同时支持事件驱动和轮询行为的情况。从服务实例此处指骨架子类实例的角度来看服务消费者的请求包括服务方法或字段的 getter/setter 调用可能在任意时间点到来。
在纯事件驱动的设置中通信管理会生成相应的调用事件并将这些事件转换为对服务实现提供的服务方法的具体方法调用。
这种设置的后果显而易见
对服务方法调用的响应通常会很快因为延迟仅受一般机器负载和内在 IPC 机制延迟的限制。包含服务实例的操作系统进程的上下文切换率可能会很高且不确定从而降低整体吞吐量。
正如您所见服务提供方的事件驱动处理模式既有优点也有缺点。然而我们确实通过 ara::com 支持这种处理模式。我们支持的另一种极端情况是纯轮询风格的方法。在这里服务提供方的应用程序开发人员明确调用 ara::com 提供的 API 来明确处理一个调用事件。
通过这种方式我们再次支持典型的 RT实时操作系统应用程序开发人员。他们的应用程序通常由于低抖动周期性警报而被激活。当应用程序处于活动状态时它以非阻塞方式检查事件队列并明确决定愿意处理自上次激活时间以来积累的哪些事件。再次强调应用程序进程的上下文切换 / 激活仅由特定的RT定时器接受异步通信事件不应导致应用程序进程激活。
那么ara::com 如何允许应用程序开发人员区分这些处理模式呢骨架实例的行为由其构造函数的第二个参数控制该参数的类型为 ara::com::MethodCallProcessingMode。
/*** 服务实现方骨架的请求处理模式。* * \note 平台供应商应完全按照此方式提供。*/
enum class MethodCallProcessingMode { kPoll, kEvent, kEventSingleThread };这意味着处理模式是为整个服务实例设置的即其所有提供的方法都将受到影响并且在骨架实例的整个生命周期内保持固定。构造函数中的默认值设置为 kEvent下面将对此进行解释。
5.4.5.1 轮询模式
如果将其设置为 kPollara::com 实现将不会异步调用任何提供的服务方法如果您想要处理下一个假设后台有一个队列用于存储传入的服务方法调用挂起的服务调用则必须在服务实例上调用以下方法
/*** 从通信管理中获取下一个调用并执行它。* * 仅在轮询模式下可用。*/
ara::core::Futurebool ProcessNextMethodCall();我们使用 ara::core::Future 的机制来返回一个在未来完成的结果。这个返回的 ara::core::Future 有什么作用呢它允许您在 “下一个请求” 被处理时得到通知。这有助于将服务方法调用一个接一个地连接起来可能会非常有帮助。一个典型的 RT 应用程序的简单用例可能是
RT 应用程序被调度。它调用 ProcessNextMethodCall 并使用 ara::core::Future::then() 注册一个回调。在与未完成请求相对应的中间件调用的服务方法完成后回调被调用。在回调中RT 应用程序决定是否有足够的时间来处理后续的服务方法。如果是这样它会调用另一个 ProcessNextMethodCall。
当然这个简单的例子假设 RT 应用程序知道其服务方法的最坏情况运行时间及其总体时间片但这并非不可能如果队列中确实存在未完成的请求并且已被分派则通信管理会将返回的 ara::core::Future 的 bool 值设置为 true否则将其设置为 false。
这对于应用程序开发人员来说是一个比较舒适的指示器即使请求队列为空也不会重复调用 ProcessNextMethodCall。因此在前一个调用返回的 ara::core::Future 的结果设置为 false 后直接调用 ProcessNextMethodCall 很可能不会执行任何操作除非在这个最小的时间框架内偶然有一个新的请求进来。
请注意对于基于典型操作系统的 AP 产品轮询模式会产生影响。除了排除由通信管理事件传入的服务方法调用导致的进程包含服务实现的上下文切换外队列的位置也存在限制它必须收集服务方法调用请求直到轮询服务实现消耗它们为止。
队列必须在服务提供应用程序的地址空间之外实现或者必须位于共享内存之类的位置以便发送方能够直接写入队列。与共享内存解决方案相比轮询服务提供程序对下面队列位置的访问可能会带来更高的成本 / 延迟。将队列放置在服务提供程序地址空间之外的典型解决方案是
内核空间如果绑定实现使用套接字或管道机制则写入调用的目标内核缓冲区类似于队列。在典型的操作系统中调整 / 配置这些缓冲区的最大大小可能意味着需要重新编译内核。不同绑定 / 通信管理守护应用程序的用户地址空间在用户空间内分配的队列的缓冲区空间分配通常可以更动态 / 灵活地完成。
5.4.5.2 事件驱动模式
如果将处理模式设置为 kEvent 或 kEventSingleThread当服务消费者的服务调用到来时ara::com 实现将异步将事件分派给服务方法实现。
与 kPoll 模式相反在这里服务消费者隐式地控制 / 触发服务提供程序进程的激活及其方法调用
那么 kEvent 和 kEventSingleThread 之间的区别是什么呢kEvent 意味着 ara::com 实现可以同时调用服务方法实现。
这意味着对于我们的示例如果 —— 在同一时间点 —— 来自不同服务消费者的一个对方法 Calibrate 的调用和两个对方法 Adjust 的调用到达ara::com 实现允许从其内部线程池中获取三个线程并同时为这两个服务方法执行这三个调用。
相反kEventSingleThread 模式确保在服务实例上ara::com 实现每次只调用一个服务方法。
这意味着 ara::com 实现必须为同一服务实例的传入服务方法调用事件排队并一个接一个地分派它们。
为什么我们提供这两个变体呢从功能的角度来看只有 kEvent 就足够了对于某些由于共享数据 / 一致性需求而无法同时运行的服务方法的服务实现它可以简单地自己进行同步例如通过 std::mutex
原因是 “效率”。如果您有一个服务实例实现它具有广泛的同步需求即无论如何几乎会同步所有服务方法调用那么如果通信管理从其线程池资源中 “花费”N 个线程而这些线程在直接获得硬同步后将 N - 1 个线程发送到睡眠状态这将是一种完全的资源浪费。