Search code examples
kdb

Always use neg[.z.w] to ensure that all messages are asynchronous?


Consider the following definition on server:

f:{show "Received ",string x; neg[.z.w] (`mycallback; x+1)}

on client side:

q)mycallback:{show "Returned ",string x;}
q)neg[h] (`f; 42)
q)"Returned 43"

In the q for motrtals, the tip says:

When performing asynchronous messaging, always use neg[.z.w] to ensure that all messages are asynchronous. Otherwise you will get a deadlock as each process waits for the other.

therefore I change the definition on the server as:

f:{show "Received ",string x; .z.w (`mycallback; x+1)}

everything goes fine, and I haven't seen any deadlocks.

Can anyone give me an example to show why I should always use neg[.z.w]?


Solution

  • If I understand you're question correctly I think your asking how sync and async messages work. The issue with the example you have provided is that x+1 is a very simple query that can be evaluated almost instantaneously. For a more illustrative example consider changing this to a sleep (or a more strenuous calculation, eg. a large database query).

    On your server side define:

    f:{show "Received ",string x;system "sleep 10"; neg[.z.w] (`mycallback; x+1)}
    

    Then on your client side you can send the synchronous query:

    h(`f; 42)
    

    multiple times. Doing this you will see there is no longer a q prompt on the client side as it must wait for a response. These requests can be queued and thus block both the client and server for a significant amount of time.

    Alternatively, if you were to call:

    (neg h)(`f; 42)
    

    on the client side. You will see the q prompt remain, as the client is not waiting for a response. This is an asynchronous call.

    Now, in your server side function you are looking at using either .z.w or neg .z.w. This follows the exact same principal however from a server perspective. If the response to query is large enough, the messaging can take a significant amount of time. Consequently, by using neg this response can be sent asynchronously so the server is not blocked during this process.

    NOTE: If you are working on a windows machine you will need to swap out sleep for timeout or perhaps a while loop if you are following my examples.

    Update: I suppose one way to cause such a deadlock would be to have two dependant processes, attempting to synchronously call each other. For example:

    q)\p 10002
    q)h:hopen 10003
    q)g:{h (`f1;`)}
    q)h (`f;`)' 
    

    on one side and

    q)\p 10003
    q)h:hopen 10002
    q)f:{h (`g;`)}
    q)f1:{show "test"}
    

    on the other. This would result in both processes being stuck and thus test never being shown.