Overview
Callback subscriptions push frames to you. Async subscriptions let you pull them.subscribe() returns a subscription handle, await sub.recv_async() takes one frame at a time, and six streams each run their own coroutine driven concurrently by asyncio.gather.
Compared with callbacks, async gives you control over pacing: the code reads sequentially and can await other I/O directly. The cost is that the subscription queue fills up while you’re not reading, and silently drops frames once it’s full. This page measures exactly where that boundary sits.
Matching example: examples/python/wuji_glove/1.subscribe_async.py.
For field definitions of each stream, see SDK Reference. This page covers only how to run it and what the measurements show.
The C SDK glove examples offer callback subscriptions only, with no async counterpart. This page covers Python.
Prerequisites
Hardware
This example only reads. It writes no parameters.
Software
Before You Start
Read the callback page first. Frame structures for all six streams, the-1.0 invalid-channel marker, and how the numbers 744, 572, and 526 relate all live there, and this page doesn’t repeat them.
Data Flow
The queues live inside the SDK, filled by firmware pushes and decoupled from your consuming coroutines. That decoupling is where the frame-loss risk comes from.Queue Measurements
The Queue Holds 1024 Frames
The queue fills from the moment a subscription opens, even if you never read. Measured on thetactile stream at 132 Hz:
In the first two rows, the lag equals the production count, so nothing was lost. The third row stops at 1023, meaning everything beyond that was already discarded. The queue holds 1024 frames, matching the SDK’s internal broadcast channel setting.
Drops Take the Oldest Frames, Never a Sample Here and There
Across all three runs, reading 400 consecutive frames after the first one gives aheader.seq step set of exactly [1]. On overflow the queue discards the oldest batch at its head. What remains stays contiguous, with no holes punched in the middle.
Drops Raise No Exception, Only a WARN Log
After a 12-second backlog, reading resumes and the SDK prints:recv_async() returns the next frame normally, raises nothing, and carries no drop marker in its return value. Your application code has no visibility into those 549 lost frames. The log is the only signal.
For work that depends on data completeness, set the SDK log level to WARN or higher and route it into your own logging system rather than letting it scroll past in a terminal.
Fast Consumers Lose Nothing
Keep up and you lose nothing. Reading 200 frames with consecutiveawait recv_async() calls takes 1.52 seconds, an effective 131 Hz that matches the stream’s own rate, with every seq step equal to 1.
Runtime Handling
The example’s
while True loop has no exit condition and stops on KeyboardInterrupt. Its finally block only calls manager.disconnect_all(), leaving subscription handles to be reclaimed at process exit. A long-running service needs its own sub.close().
Integration Steps
subscribe() is a synchronous call, and the queue starts filling the moment it returns. The longer the gap between connecting and your first recv_async(), the older that first frame is. When you need data starting now, move subscribe() as close to the consuming loop as you can.
Running It
gather schedules fairly.
The palm=-0.1 on the Zones line comes from the example’s avg() including -1.0 invalid channels in its mean, not from the glove sensing a reversed force. The callback page explains the cause and the fix.
Adapting It
Callback or Async
Queue semantics are identical, and the 1024-frame boundary applies to callbacks too. Callbacks keep your event loop free. Async composes naturally with coroutines such as HTTP requests and database writes.
Don’t Block Inside a Coroutine
The event loop is single-threaded. Callingtime.sleep(), writing files synchronously, or making blocking HTTP requests inside a coroutine backs up all six streams at once. Hand blocking work to a thread pool:
Subscribe Only to What You Need
All six streams open means about 640recv_async() wakeups per second at rest. For tactile analysis, keep tactile or tactile_point_cloud alone and event-loop pressure drops immediately.
Lower the Stream Rate
130 Hz is higher than most applications need. Subscription handles support rate control, described in Adjusting Stream Rate. At a lower rate, those 1024 queued frames cover a longer window, which also buys more tolerance for jitter.Related
- Subscribing With Callbacks: frame structures for all six streams and invalid-channel handling
- Recording Data: write these streams to a replayable file
- Adjusting Stream Rate: bring 130 Hz down to what your application needs
- Data Subscription: subscription model and lifecycle
- Common Data Types:
FrameHeader,TactileFrame,HandSkeleton, and related structures