Skip to content

Latest commit

 

History

History
441 lines (314 loc) · 18.4 KB

py-recv.rst

File metadata and controls

441 lines (314 loc) · 18.4 KB

Receiving

The classes associated with receiving are in the :pyspead2.recv package. A stream represents a logical stream, in that packets with the same heap ID are assumed to belong to the same heap. A stream can have multiple physical transports.

Streams yield heaps, which are the basic units of data transfer and contain both item descriptors and item values. While it is possible to directly inspect heaps, this is not recommended or supported. Instead, heaps are normally passed to :pyspead2.ItemGroup.update.

Note

Malformed packets (such as an unsupported SPEAD version, or inconsistent heap lengths) are dropped, with a log message. However, errors in interpreting a fully assembled heap (such as invalid/unsupported formats, data of the wrong size and so on) are reported as :pyValueError exceptions. Robust code should thus be prepared to catch exceptions from heap processing.

Blocking receive

To do blocking receive, create a :pyspead2.recv.Stream, and add transports to it with :py~spead2.recv.Stream.add_buffer_reader, :py~spead2.recv.Stream.add_udp_reader, :py~spead2.recv.Stream.add_tcp_reader or :py~spead2.recv.Stream.add_udp_pcap_file_reader. Then either iterate over it, or repeatedly call :py~spead2.recv.Stream.get.

Asynchronous receive

Asynchronous I/O is supported through Python's :pyasyncio module. It can be combined with other asynchronous I/O frameworks like twisted and Tornado.

The stream is also asynchronously iterable, i.e., can be used in an async for loop to iterate over the heaps.

Memory allocators

To allow for performance tuning, it is possible to use an alternative memory allocator for heap payloads. A few allocator classes are provided; new classes must currently be written in C++. The default (which is also the base class for all allocators) is :pyspead2.MemoryAllocator, which has no constructor arguments or methods. An alternative is :pyspead2.MmapAllocator.

The most important custom allocator is :pyspead2.MemoryPool. It allocates from a pool, rather than directly from the system. This can lead to significant performance improvements when the allocations are large enough that the C library allocator does not recycle the memory itself, but instead requests memory from the kernel.

A memory pool has a range of sizes that it will handle from its pool, by allocating the upper bound size. Thus, setting too wide a range will waste memory, while setting too narrow a range will prevent the memory pool from being used at all. A memory pool is best suited for cases where the heaps are all roughly the same size.

A memory pool can optionally use a background task (scheduled onto a thread pool) to replenish the pool when it gets low. This is useful when heaps are being captured and stored indefinitely rather than processed and released.

Incomplete Heaps

By default, an incomplete heap (one for which some but not all of the packets were received) are simply dropped and a warning is printed. Advanced users might need finer control, such as recording metrics about the number of these heaps. To do so, set contiguous_only to False when constructing the stream. The stream will then yield instances of :pyIncompleteHeap.

Statistics

The :py~spead2.recv.Stream.stats property of a stream contains statistics about the stream. Note that while the fields below are expected to be stable except where otherwise noted, their exact interpretation in edge cases is subject to change as the implementation evolves. It is intended for instrumentation, rather than for driving application logic.

Each time the property is accessed, an internally consistent view of the statistics is returned. However, it is not synchronised with other aspects of the stream. For example, it's theoretically possible to retrieve 5 heaps from the stream iterator, then find that :py.StreamStats.heaps is (briefly) 4.

Some readers process packets in batches, and the statistics are only updated after a whole batch is added. This can be particularly noticeable if the ringbuffer fills up and blocks the reader, as this prevents the batch from completing and so heaps that have already been received by Python code might not be reflected in the statistics.

Additional statistics are available on the ringbuffer underlying the stream (~spead2.recv.Stream.ringbuffer property), with similar caveats about synchronisation.