3.3异步完成标记(Asynchronous Completion Token, ACT)
1.问题
当一个客户机应用程序异步地调用对一个或几个服务的操作请求时,每个服务通过一个完成事件将其响应返回给应用程序。然后应用程序必须向相应的处理程序多路分解该事件。处理程序可以是一个函数或对象,用于处理包含在完成事件中的异步操作响应。要有效地解决这个问题,需要考虑以下3个强制条件:
·一个服务可能不知道客户机应用程序异步地调用其操作时所处的语境。因此,客户机应用程序而不是服务器必须负责确定如何将完成事件多路分解给被指派去处理它的处理程序。
·要确定在异步操作完成执行后客户机如何多路分解和处理完成事件,需要客户机应用程序和服务之间的通信,这种通信开销应尽可能地小。
·当服务响应到达了一个客户机应用程序时。应用程序应在尽可能少的时间内向处理异步操作响应的处理程序多路分解完成事件。
2.解决方案
将表示启动程序(initiator)如果处理服务响应的信息和客户机启动程序对一个服务调用的每个异步操作一起传送。操作完成后将这些信息返回给启动程序,使用这些信息可以高效地多路分解该响应,使启动程序能相应地处理它。
具体地说,就是为每个客户机启动程序对一个服务调用的每个异步操作建立一个异步完成标记。异步完成标记包括能唯一标识完成处理程序的信息。服务保存异步完成标识,但不修改它。服务对启动程序做出响应时,响应中包括原先传送的异步完成标记。这样启动程序可以使用异步完成标记来识别用于处理来自原先的异步操作的响应的完成处理程序。
3.结构
服务提供一些能被异步访问的功能。
客户机启动程序异步调用服务的操作。它还将这些操作所返回的响应多路分解给指定的完成处理程序。完成处理程序是应用程序中的一个函数或对象,它负责处理服务响应。
一个异步完成标记(ACT)中包含了标识某启动程序的完成处理程序的信息。当启动程序调用一个操作时,它将异步完成标记传递给服务,当异步操作完成时,服务将未改变的异步完成标记返回给启动程序。然后,该完成处理程序处理来自原来的异步操作的响应。服务中保存有一组异步完成标记,用于处理由启动程序同时调用的多个异步操作。
4.实现
1)定义异步完成标记的表示法。异步完成标记的表示对启动程序和完成处理程序应该是有意义的,但对服务是不透明的。
·指针异步完成标记。通常用指向程序设计语言中的结构的指针表示异步完成标记。
·对象引用异步完成标记。为了简化在异构系统中对异步完成标记的使用,可以将异步完成标记表示为在分布式对象计算中间件(如CORBA)中定义的对象引用。
·索引异步完成标记。将异步完成标记表示为对启动程序可以访问的完成处理程序表的索引。
2)选择在启动程序中保存异步完成标记和策略。
·隐含异步完成标记。将异步完成标记定义为启动程序的完成处理程序对象的地址,从而可以被“隐含地”保存。通常在指针或对象引用异步完成标记中使用这种策略。隐含异步完成标记的时间和空间效率很高,但健壮性和安全性不好。
·显式异步完成标记。启动程序在一个明确的数据结构中保存异步完成标记,这种策略适用于索引异步完成标记。在启动程序中使用显式数据结构保存异步完成标记的好处是能提高健壮性和可靠性。
3)确定如何将异步完成标记从启动程序传递给服务。
·隐含参数通常被透明地存储在传递给服务的语境或环境中。
·显式参数定义在异步操作中。
4)确定在服务中保存异步完成标记的策略。
·如果服务是同步执行的,那么当服务处理操作时,可以简单地将异步完成标记驻留在服务的运行时栈中,如果服务和启动程序运行在不同的线程或进程中,可以同步执行服务操作,但仍向启动程序提供一种异步程序设计模型。
·如果服务异步地处理启动程序操作,它可能需要同时处理多个请求。在这种情况下必须在数据结构中维持一个异步完成标记,该数据结构驻留于任何服务的运行时栈范围之外。
5)确定异步完成标记可用的次数。
·启动程序为每个异步调用传递一个单独的异步完成标记。然而启动程序可以对一个服务多次调用某个异步操作。对于每次调用,它可以指派同一个完成处理程序来处理操作的响应,从而使创建和销毁异步完成标记的开销最少。
·服务只返回一次异步完成标记和来自异步操作的响应。不过一旦发生了一个特定事件,服务也可使用同一个异步完成标记发出一系统的响应。在这种情况下,来自一个异步操作调用的异步完成标记可以被多次返回给启动程序。
6)确定启动程序将异步完成标记多路分解给完成处理程序钩子方法的策略。
·排队的完成事件。由一个服务,或者当服务在远程时由一个本地服务代理将异步完成标记置于一个完成事件队列中。启动程序从完成事件队列中删除该异步完成标记,并能用封装在异步完成标记中的信息控制其后续的处理。
·回调。启动程序向服务传递一个回调函数或对象。当异步操作完成时,服务或者本地服务代理可以调用回调函数。可以将异步完成标记作为参数返回给回调函数或对象,并进行向下类型转换,以找出进行后续高效处理的完成处理程序。
5.结论
优点:
1)简化启动程序的数据结构。启动程序不需要复杂的数据结构来将服务响应与完成处理程序结合起来。服务返回的异步完成标记可以被向下类型转换或重新解释,使之带有启动程序将其多路分解给相应的完成活动所需要的信息。
2)高效的状态查询。异步完成标记的时间性能很好,因为不需要对与服务响应一起返回的数据进行复杂的分析。将响应和先前的请求结合起来所需的相关信息可以存储在异步完成标记中或者在由异步完成标记所引用的对象中。另一方面,异步完成标记可作为对访问状态的指针或索引,用于高效访问,从而消除了昂贵的表搜索。
3)空间效率高。异步完成标记可以在消费最小的数据空间的情况下向应用程序提供足够的信息,将大量的状态结合起来,以处理异步操作完成动作。
4)灵活性。要利用服务的异步完成标记,用户自定义的异步完成标记不必非要继承一个接口。这样应用程序可以将不可预见其类型转换或者不可能进行类型转换的对象作为异步完成标记传递。异步完成标记的通用特性可以用于将任何类型的对象与一个异步操作联系起来。
5)非独裁的并发策略。因为可以从异步完成标记中有效地恢复耗时长的操作状态,所以可以异步地执行这样的操作。因此启动程序可以是单线程的,也可以是多线程的,这依赖于应用需求。
不足:
1)内存泄漏。如果启动程序使用指向动态分配的内存区域的指针作为异步完成标记,当服务不能返回异步完成标记时(如服务崩溃时)会产生内存泄漏。考虑这种可能性的启动程序应维持一个单独的异步完成标记存储池或表,这样可以在服务失败或服务破坏了异步完成标记时,进行显式的垃圾收集。
2)认证。当异步事件完成时,异步完成标记返回给启动程序,启动程序在使用之前需要进行认证。如果服务器不能将异步完成标记看成是非透明的而有可能改变异步完成标记的值,这种认证是必需的。
3)应用程序重映射。如果异步完成标记是直接指向内存的指针,将应用程序的某一部分直接映射到虚拟存储器中时就会发生错误。在崩溃后重新启动的持久应用程序中,以及对于从内存映射地址空间中分配的对象可能会出现这种情况。为了防止这些错误,可以将存储池的索引作为异步完成标记。由“索引异步完成标记”提供的这种间接方式可以防止重映射,因为在重映射过程中,索引能保持有效,而指向内存的指针则不行。