Readers of this website may have noticed that I have recently added an IQML section to the website’s top menu bar. IQML is a software connector that connects Matlab to DTN’s IQFeed, a financial data-feed of live and historic market data. IQFeed, like most other data-feed providers, sends its data in asynchronous messages, which need to be processed one at a time by the receiving client program (Matlab in this case). I wanted IQML to provide users with two complementary modes of operation:
- Streaming (asynchronous, non-blocking) – incoming server data is processed by internal callback functions in the background, and is made available for the user to query at any later time.
- Blocking (synchronously waiting for data) – in this case, the main Matlab processing flows waits until the data arrives, or until the specified timeout period has passed – whichever comes first.
Implementing streaming mode is relatively simple in general – all we need to do is ensure that the underlying connector object passes the incoming server messages to the relevant Matlab function for processing, and ensure that the user has some external way to access this processed data in Matlab memory (in practice making the connector object pass incoming data messages as Matlab callback events may be non-trivial, but that’s a separate matter – read here for details).
In today’s article I’ll explain how we can implement a blocking mode in Matlab. It may sound difficult but it turns out to be relatively simple.
I had several requirements/criteria for my blocked-wait implementation:
- Compatibility – It had to work on all Matlab platforms, and all Matlab releases in the past decade (which rules out using Microsoft Dot-NET objects)
- Ease-of-use – It had to work out-of-the-box, with no additional installation/configuration (which ruled out using Perl/Python objects), and had to use a simple interface function
- Timeout – It had to implement a timed-wait, and had to be able to tell whether the program proceeded due to a timeout, or because the expected event has arrived
- Performance – It had to have minimal performance overhead
The basic idea
The basic idea is to use Matlab’s builtin waitfor, as I explained in another post back in 2012. If our underlying connector object has some settable boolean property (e.g.,
Done) then we can set this property in our event callback, and then
waitfor(object,'Done'). The timeout mechanism is implemented using a dedicated timer object, as follows:
% Wait for data updates to complete (isDone = false if timeout, true if event has arrived) function isDone = waitForDone(object, timeout) % Initialize: timeout flag = false object.setDone(false); % Create and start the separate timeout timer thread hTimer = timer('TimerFcn',@(h,e)object.setDone(true), 'StartDelay',timeout); start(hTimer); % Wait for the object property to change or for timeout, whichever comes first waitfor(object,'Done'); % waitfor is over - either because of timeout or because the data changed % To determine which, check whether the timer callback was activated isDone = isvalid(hTimer) && hTimer.TasksExecuted == 0; % Delete the timer object try stop(hTimer); catch, end try delete(hTimer); catch, end % Return the flag indicating whether or not timeout was reached end % waitForDone
where the event callback is responsible for invoking
object.setDone(true) when the server data arrives. The usage would then be similar to this:
requestDataFromServer(); if isBlockingMode % Blocking mode - wait for data or timeout (whichever comes first) isDone = waitForDone(object, 10.0); % wait up to 10 secs for data to arrive if ~isDone % indicates a timeout fprintf(2, 'No server data has arrived within the specified timeout period!\n') end else % Non-blocking (streaming) mode - continue with regular processing end
Using a stand-alone generic signaling object
But what can we do if we don’t have such a
Done property in our underlying object, or if we do not have programmatic access to it?
We could create a new non-visible figure and then waitfor one of its properties (e.g.
Resize). The property would be initialized to
'off', and within both the event and timer callbacks we would set it to
'on', and then
waitfor(hFigure,'Resize','on'). However, figures, even if non-visible, are quite heavy objects in terms of both memory, UI resources, and performance.
It would be preferable to use a much lighter-weight object, as long as it abides by the other criteria above. Luckily, there are numerous such objects in Java, which is bundled in every Matlab since 2000, on every Matlab platform. As long as we choose a small Java object that has existed forever, we should be fine. For example, we could use a simple
javax.swing.JButton and its boolean property
hSemaphore = handle(javax.swing.JButton); % waitfor() expects a handle() object, not a "naked" Java reference % Wait for data updates to complete (isDone = false if timeout, true if event has arrived) function isDone = waitForDone(hSemaphore, timeout) % Initialize: timeout flag = false hSemaphore.setEnabled(false); % Create and start the separate timeout timer thread hTimer = timer('TimerFcn',@(h,e)hSemaphore.setEnabled(true), 'StartDelay',timeout); start(hTimer); % Wait for the object property to change or for timeout, whichever comes first waitfor(hSemaphore,'Enabled'); % waitfor is over - either because of timeout or because the data changed % To determine which, check whether the timer callback was activated isDone = isvalid(hTimer) && hTimer.TasksExecuted == 0; % Delete the timer object try stop(hTimer); catch, end try delete(hTimer); catch, end % Return the flag indicating whether or not timeout was reached end % waitForDone
In this implementation, we would need to pass the
hSemaphore object handle to the event callback, so that it would be able to invoke
hSemaphore.setEnabled(true) when the server data has arrived.
Under the hood, note that
Enabled is not a true “property” of
javax.swing.JButton, but rather exposes two simple public getter/setter methods (setEnabled() and isEnabled()), which Matlab interprets as a “property”. For all intents and purposes, in our Matlab code we can treat
Enabled as a property of
javax.swing.JButton, including its use by Matlab’s builtin waitfor function.
There is a light overhead to this: on my laptop the waitfor function returns ~20 mSecs after the invocation of
hSemaphore.setEnabled(true) in the timer or event callback – in many cases this overhead is negligible compared to the networking latencies for the blocked data request. When event reactivity is of utmost importance, users can always use streaming (non-blocking) mode, and process the incoming data events immediately in a callback.
Of course, it would have been best if MathWorks would add a timeout option and return value to Matlab’s builtin waitfor function, similar to my
waitForDone function – this would significantly simplify the code above. But until this happens, you can use
waitForDone pretty-much as-is. I have used similar combinations of blocking and streaming modes with multiple other connectors that I implemented over the years (Interactive Brokers, CQG, Bloomberg and Reuters for example), and the bottom line is that it actually works well in practice.
Let me know if you’d like me to assist with your own Matlab project or data connector, either developing it from scratch or improving your existing code. I will be visiting Boston and New York in early June and would be happy to meet you in person to discuss your specific needs.