您的位置:首页 > 其它

TAO教程之七:异步方法调用——针对急迫的( impatient )客户端的CORBA解决方案

2008-09-11 09:38 357 查看
异步方法调用——针对急迫的( impatient )客户端的CORBA解决方案 我们的简单服务详细阐述了如何通过传统CORBA同步方向调用来查询股票的价格的。假定,举例来说,一个复杂的市场分析工具的初始化时,我们必须对数百支股票进行价格查询。在这种情况下按顺序发送请求会严重影响性能;由于在发送后一条查询请求之前我们需要等待上一条查询的返回,所以我们不能利用分布式的系统本身的并行性。针对这个问题传统的解决方法是使用oneway调用或者使用多线程。这两种方式都是可行的,但都有缺点:多线程编程非常困难并且容易出错,oneway不可靠并且需要回调接口返回股票的值。最近,OMG核准了CORBA Messaging规范来扩展基本的调用模型以支持异步调用。这以之前的同步调用模型不同,新的模型使用IDL编译器和SII来达到类型安全和提高的性能,并且应用程序不会在等待影响时阻塞。该模型提供的ORB的一个引用来返回处理器,这个处理器将异步的接收响应。该规范还定义了投递(polling)接口,由于TAO未实现此接口,所以这里不作讨论。
为了解决上面的问题我们扩展IDL接口来包含新的操作:
interface Single_Query_Stock : Stock {
    double get_price_and_names (out string symbol,
                               out string full_name);
  };


这将使一些示例得以简化。

第一步是生成支持回调AMI的stubs和skeletions。我们使用-GC标记:

$ $ACE_ROOT/TAO/TAO_IDL/tao_idl -GC Quoter.idl


您或许想简单的查看生成的客户端的接口。IDL编译器添加新的方法到
Quoter::Stock
接口。请特别注意下面的方法:

virtual void sendc_get_price_and_names (
      AMI_Single_Query_StockHandler_ptr ami_handler
    );


这就是用于发送异步请求的操作。处理器对象用于接收响应。下面是一个正规的CORBA对象,此对象带有下面的IDL接口:

interface AMI_Single_Query_StockHandler {
  void get_price_and_names (in double ami_return_val,
                           in string symbol,
                           in string full_name);
};


你无须编写IDL接口。该接口由IDL编译器自动从原始的IDL中生成,所以也称它为隐式IDL。请注意参数是如何生成的,第一个参数是简单的返回值,后面是输出参数,由于处理器必须接收返回,所以设为input。

实现返回处理器

我们必须为新的IDL接口实现伺服代码(servant),以便于我们可以接收到返回值,这正如我们的服务端:

class Single_Query_Stock_Handler_i : public POA_Quoter::AMI_Single_Query_StockHandler
{
public:
  Single_Query_Stock_Handler_i (int *response_count)
    : response_count_ (response_count) {}

  void get_price_and_names (CORBA::Double ami_return_val,
                           const char *symbol,
                           const char *full_name)
  {
    std::cout << "The price of one stock in /""
              << full_name << "/" (" << symbol << ") is "
              << ami_return_val << std::endl;
    *this->response_count_++;
  }

private:
  int *response_count_;
};


response_count_
字段用来当所有的应答都收到之后中止客户端。

发送异步方向调用

和其它CORBA对象一样激活处理器伺服器(servant):

int response_count = 0;
    Single_Query_Stock_Handler_i handler_i (&response_count);
    Quoter::AMI_Single_Query_StockHandler_var handler =
      handler_i._this ();


然后我们修改循环用来立即发送所有的请求:

int request_count = 0;
    for (int i = 2; i != argc; ++i) {
      try {
        // Get the stock object
        Quoter::Stock_var tmp =
          factory->get_stock (argv[i]);
        Quoter::Single_Query_Stock_var stock =
          Quoter::Single_Query_Stock::_narrow (tmp.in ());

        stock->sendc_get_price_and_names (handler.in ());
        request_count++;
      }


在循环结束后我们一直等待,直到收回所有的响应:

while (response_count < request_count
           && orb->work_pending ()) {
      orb->perform_work ();
    }


练习1

完成
client.cpp
文件。这个客户端是否扮演服务端的角色?如果不是,该角色涉及到处理器伺服的什么?如果您认为这也是服务端,那么关于POA您做了些什么?

您可以使用下面的文件完成您的实现:Quoter.idl, Handler_i.h, Handler_i.cpp. 记住简单客户端的主函数(here))是一个不错的开端。

解决方案

查看 client.cpp 文件。这与您的应该不会有太大的差异。

测试

在基于在介绍一节简单服务端之上提供了简单服务器。和以前一样,您需要下面的文件 Stock_i.h, Stock_i.cpp, Stock_Factory_i.h Stock_Factory_i.cppserver.cpp.

配置

迄今为止我们在TAO中使用的是默认的配置,但是通过好的调整能让AMI可以工作得更好。例如,默认的TAO为每个显示的请求使用单独的连接。这对于同步方向调用(SMI)来说是一个好的策略,因为用单独的线程发送并发的请求不需要用到共享的资源,但这个方法对于异步方法调用(AMI)来说缺少可伸缩性,这是因为它需要创建过多的连接。本解决方案改变策略用于使连接可被共享。为了达到这个目的,我们需要创建一个下面内容的svc.conf文件:

static Client_Strategy_Factory "-ORBTransportMuxStrategy MUXED"


还有许多其它的配置选项,这些都描述在文档 Options.htmlconfigurations.html 和来自OCI的开发者指南中。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐