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

异步方法调用——针对急迫的( 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的开发者指南中。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值