QforMortals3/Example Asynchronous Callbacks

From Kx Wiki
Jump to: navigation, search

1.20 Example: Asynchronous Callbacks

The IPC mechanism of q does not have callbacks built in but it is powerful enough that we can create callbacks ourselves. We assume that you have started separate client and server q sessions and have opened the connection from the client to the server, as in the previous section.

Heretofore, calls to the server were synchronous, meaning that at the point of the remote call, the client blocks until the requested work on the server completes and the result is returned. It is also possible to make the remote call asynchronous. In this case, the client does ‘’’not’’’ block: the application of the open handle returns immediately.

In order to demonstrate this, we have to come clean about what is really in the open handle h. See for yourself by displaying the h from an open connection.

q)h:hopen `:localhost:5042
q)h
3i

Your result will probably not match this but it will be an integer. Yes, an open handle is just a positive 32-bit integer. When this (positive) integer is applied as a function, the call is synchronous. To make an asynchronous call, negate the value in h—i.e., neg h—and use this with function application syntax. Seriously.

Since nothing will be displayed in the client session, it helps to display progress on the server as the request is performed. Create the function echo in the server session.

q)echo:{show x}		 	/ on server

Now make an asynchronous remote call to echo from the client.

q)(neg h) (`echo; 42)		/ on client
_

Observe on your q consoles that the client application returns immediately with no result and that the server displays the progress message.

Now to callbacks. We begin by instrumenting a function rsvp on the server that, when invoked remotely, will call back to the client. It will receive two parameters: its own argument and the symbolic name of the client function to call.

q)rsvp:{[arg;cb] ..}		 / on server

We initially invoke the server’s (show) with the passed arg to indicate that we are hard at work on the transmitted data.

q)rsvp:{[arg;cb] show arg;}

Now for the big moment. To make the return call from the server to the client, we need the open handle of the connection for the remote call we are processing. This is conveniently placed in the q system variable .z.w (“who” called) for the duration of each remote call. We use it to make an ‘’’asynchronous’’’ remote call (hence the neg) over the caller’s handle, passing the provided callback name and our arduously computed result 43.

q)rsvp:{[arg;cb] show arg; (neg .z.w) (cb; 43);}

In the final step, we display another progress message on the server console indicating the remote call has completed. Since this function returns its actual result remotely, we end its body with ‘;’ to ensure that it returns nothing locally.

q)rsvp:{[arg;cb] show arg; (neg .z.w) (cb; 43); show `done;}

We turn to the client side and create echo to serve as the function called back for this demonstration.

q)echo:{show x}		 / on client

It remains to fire off the remote asynchronous call from the client. We pass the client open handle a list containing: the name of the remote function; the argument for the remote function; and the name of our own function to be called back during the remote computation. Be sure to do it asynchronously else you will get deadlocks.

q)(neg h) (`rsvp; 42; `echo)		/ on client

Provided all went well, the server console will display:

q)42
`done

The client console should display:

q)(neg h) (`rsvp; 42; `echo)
q)43

And there you have it. Callbacks built from scratch in q using a few lines of code.



Prev: Interprocess Communication 101, Next: Websockets 101

Reprinted with the author's permission from: q for Mortals Version 3, An Introduction to Q Programming by Jeffry A. Borror.

The book is available on Amazon. In the United Kingdom, it is available at Amazon UK.

©2015 Jeffry A. Borror/ q4m LLC

Personal tools
Namespaces
Variants
Actions
Navigation
Print/export
Toolbox