Section 7.7. Synchronous Versus Asynchronous Processing


7.7. Synchronous Versus Asynchronous Processing

Although it's technically possible to call the same component synchronously and asynchronously, the likelihood that a component will be accessed both ways is low.

The reason is that using a set of components asynchronously requires drastic changes to the workflow of the client program, and as a result the client can't simply use the same execution sequence logic that it would for synchronous access. Consider, for example, an online store application. Let's suppose the client (a server-side object executing a customer request) accesses a Store object, where it places the customer's order details. The Store object uses three well-factored helper components to process the order: Order, Shipment, and Billing. In a synchronous scenario, the Store object calls the Order object to place the order. Only if the Order object succeeds in processing the order (i.e., if the item is available in the inventory) does the Store object call the Shipment object, and only if the Shipment object succeeds does the Store object access the Billing component to bill the customer. This sequence is shown in Figure 7-1.

Figure 7-1. Synchronous processing of a client order


The down side to the pattern shown in Figure 7-1 is that the store must process orders synchronously and serially. On the surface, it might seem that if the Store component invoked its helper objects asynchronously, it could increase its throughput because it could process incoming orders as fast as the client submitted them. The problem in doing so is that it's possible for the calls to the Order, Shipment, and Billing objects to fail independently. Because their methods would be invoked in a nondeterministic order, depending on thread availability in the thread pool, overall system load, and so on, things could go wrong in many ways. For example, the Order object might discover there were no items in the inventory matching the customer request after the Billing object had already billed the customer for it.

Using asynchronous calls on a set of interacting components requires that you change your code and your workflow. To call the helper components asynchronously, the Store component should call only the Order object, which in turn should call the Shipment object only if the order processing was successful (see Figure 7-2), to avoid the potential inconsistencies just mentioned. Similarly, only in the case of successful shipment should the Shipment object asynchronously call the Billing object.

Figure 7-2. Revised workflow for asynchronous processing of a client order


In general, if you have more than one component in your asynchronous workflow, you should have each component invoke the next one in the logical execution sequence. Needless to say, such a programming model introduces tight coupling between components (they have to know about each other) and changes to their interfaces (you have to pass in additional parameters, which are required for the desired invocation of components downstream).

The conclusion from this simple example is that using asynchronous instead of synchronous invocation introduces major changes to the component interfaces and the client workflow. Asynchronous invocation on a component that was built for synchronous execution works only in isolated cases. When you're dealing with a set of interacting components, it's better to simply spin off a worker thread to call them and use the worker thread to provide asynchronous execution. This will preserve the component interfaces and the original client execution sequence. Of course, to do that, you need to understand .NET concurrency management and multithreading, the subjects of the next chapter.



Programming. NET Components
Programming .NET Components, 2nd Edition
ISBN: 0596102070
EAN: 2147483647
Year: 2003
Pages: 145
Authors: Juval Lowy

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net