Table of Contents Previous Next
Logo
Deprecated AMI Mapping : K.2 Introduction
Copyright © 2003-2010 ZeroC, Inc.

K.2 Introduction

Modern middleware technologies attempt to ease the programmer’s transition to distributed application development by making remote invocations as easy to use as traditional method calls: a method is invoked on an object and, when the method completes, the results are returned or an exception is raised. Of course, in a distributed system the object’s implementation may reside on another host, and consequently there are some semantic differences that the programmer must be aware of, such as the overhead of remote invocations and the possibility of network-related errors. Despite those issues, the programmer’s experience with object-oriented programming is still relevant, and this synchronous programming model, in which the calling thread is blocked until the operation returns, is familiar and easily understood.
Ice is inherently an asynchronous middleware platform that simulates synchronous behavior for the benefit of applications (and their programmers). When an Ice application makes a synchronous twoway invocation on a proxy for a remote object, the operation’s in parameters are marshaled into a message that is written to a transport, and the calling thread is blocked in order to simulate a synchronous method call. Meanwhile, the Ice run time operates in the back­ground, processing messages until the desired reply is received and the calling thread can be unblocked to unmarshal the results.
There are many cases, however, in which the blocking nature of synchronous programming is too restrictive. For example, the application may have useful work it can do while it awaits the response to a remote invocation; using a synchronous invocation in this case forces the application to either postpone the work until the response is received, or perform this work in a separate thread. When neither of these alternatives are acceptable, the asynchronous facilities provided with Ice are an effective solution for improving performance and scal­ability, or simplifying complex application tasks.

Asynchronous Method Invocation

Asynchronous Method Invocation (AMI) is the term used to describe the client-side support for the asynchronous programming model. AMI supports both oneway and twoway requests, but unlike their synchronous counterparts, AMI requests never block the calling thread. When a client issues an AMI request, the Ice run time hands the message off to the local transport buffer or, if the buffer is currently full, queues the request for later delivery. The application can then continue its activities and, in the case of a twoway invocation, is notified when the reply eventually arrives. Notification occurs via a callback to an application-supplied programming-language object1.
AMI is described in detail in Section K.3.

Controlling Code Generation using Metadata

A programmer indicates a desire to use an asynchronous model (AMI, AMD, or both) by annotating Slice definitions with metadata (Section 4.17). The programmer can specify this metadata at two levels: for an interface or class, or for an individual operation. If specified for an interface or class, then asynchro­nous support is generated for all of its operations. Alternatively, if asynchronous support is needed only for certain operations, then the generated code can be mini­mized by specifying the metadata only for those operations that require it.
Synchronous invocation methods are always generated in a proxy; specifying AMI metadata merely adds asynchronous invocation methods. In contrast, speci­fying AMD metadata causes the synchronous dispatch methods to be replaced with their asynchronous counterparts. This semantic difference between AMI and AMD is ultimately practical: it is beneficial to provide a client with synchronous and asynchronous versions of an invocation method, but doing the equivalent in a server would require the programmer to implement both versions of the dispatch method, which has no tangible benefits and several potential pitfalls.
Consider the following Slice definitions:
["ami"] interface I {
  bool isValid();
  float computeRate();
};

interface J {
  ["amd"]        void startProcess();
  ["ami", "amd"] int endProcess();
};
In this example, all proxy methods of interface I are generated with support for synchronous and asynchronous invocations. In interface J, the startProcess operation uses asynchronous dispatch, and the endProcess operation supports asynchronous invocation and dispatch.
Specifying metadata at the operation level, rather than at the interface or class level, not only minimizes the amount of generated code, but more importantly, it minimizes complexity. Although the asynchronous model is more flexible, it is also more complicated to use. It is therefore in your best interest to limit the use of the asynchronous model to those operations for which it provides a particular advantage, while using the simpler synchronous model for the rest.

Transparency

The use of an asynchronous model does not affect what is sent “on the wire.” Specifically, the invocation model used by a client is transparent to the server, and the dispatch model used by a server is transparent to the client. Therefore, a server has no way to distinguish a client’s synchronous invocation from an asynchronous invocation, and a client has no way to distinguish a server’s synchronous reply from an asynchronous reply.

1
Polling for a response is not supported by the Ice run time, but it can be implemented easily by the application if desired.


Table of Contents Previous Next
Logo