How do I execute a q function call with parameters over IPC? Tuesday, October 9, 2012 at 8:03PM
Short answer: q)phandle: hopen `:serverhost:5012 q)phandle (function; arg1; arg2 ..) .. q)hclose phandle q) To invoke a function in another q process (i.e., a function that already exists in that q process), you need the following:
Then all you need to do is to apply the process handle to a list whose first element is the function name (as a symbol) and whose remaining elements are the arguments. For example, let's start one q process, which will be our server, listening on TCP port 5012. In our server, we'll define a function square (we'll make the background color different for the server to make it easier to distinguish from the client): $ q -p 5012 // server .. q)\p // display the listening port 5012 q)square: {x * x} q)square 3 9 q) Next, we'll start up another q process (the client), create a process handle connected to the first q process (the server), and request the first process to compute square 5: $ q // client .. q)phandle: hopen `:localhost:5012 q)phandle (`square; 5) // remote execution 25 q) To call a function with more parameters, simply add them to the end of the list. We'll demonstrate by defining a 2-argument function on the server that calculates the length of a right triangle's hypotenuse: q)hypotenuse: {sqrt sum square x,y} q)hypotenuse[3;4] 5f q) q)phandle (`hypotenuse; 5; 12) 13f q) What if the function you're calling doesn't take any parameters? For example, we'll define a function in the server called serverTime that returns the local time according to the server: q)serverTime: {[] .z.T} q)serverTime[] 11:51:34.762 q) You can't pass zero parameters over IPC: q)phandle enlist `serverTime // a list with just 'length // the function name q) // is not allowed However, you can pass whatever you like, and it won't matter: q)phandle `serverTime`ignored 11:52:28.537 q)phandle (`serverTime; ()) // () is often used 11:52:40.923 q)phandle (`serverTime; ::) // so is :: 11:52:47.338 q) See :: (generic null). So far, all of our examples involved a client invoking a predefined function on the server. You can also pass a function defined on the client to be executed on the server. To see this, let's define a global variable on the server: q)SERVERGLOBAL: 47 q) Now, on the client, we'll define a function called getSERVERGLOBAL to retrieve the value of SERVERGLOBAL on the server. Instead of passing the name of the function (i.e., `getSERVERGLOBAL), we pass the function's value: q)getSERVERGLOBAL: {[] SERVERGLOBAL} q)getSERVERGLOBAL[] 'SERVERGLOBAL // not defined here q)phandle (getSERVERGLOBAL; ::) // note the missing ` 47 q) Notice that this operation does not cause getSERVERGLOBAL to become defined on the server: q)getSERVERGLOBAL 'getSERVERGLOBAL q) This technique can be used to run built-in functions and anonymous functions (aka lambdas) on the server as well: q)phandle (+; 2; 4) 6 q)phandle ({til SERVERGLOBAL - x}; 42) 0 1 2 3 4 q) There is one more way to convey code to the server to run: you can pass the code in a string. q)phandle "SERVERGLOBAL + 4" 51 q) We prefer passing a function over a string, because - especially as the expression to be passed gets more complex - it's easier to read. |
|