docs/reference: Add strings vs bytes to speed optimisation tips.

Also add some additional context links, suggestions for alternative
classes, etc.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
This commit is contained in:
Angus Gratton
2025-02-04 12:20:38 +11:00
committed by Damien George
parent bab099826e
commit 0a55f1f40c
3 changed files with 40 additions and 1 deletions

View File

@@ -19,6 +19,10 @@ Classes
array are given by *iterable*. If it is not provided, an empty array are given by *iterable*. If it is not provided, an empty
array is created. array is created.
In addition to the methods below, array objects also implement the buffer
protocol. This means the contents of the entire array can be accessed as raw
bytes via a `memoryview` or other interfaces which use this protocol.
.. method:: append(val) .. method:: append(val)
Append new element *val* to the end of array, growing it. Append new element *val* to the end of array, growing it.

View File

@@ -19,6 +19,8 @@ Functions and types
.. class:: bytearray() .. class:: bytearray()
|see_cpython| `python:bytearray`.
.. class:: bytes() .. class:: bytes()
|see_cpython| `python:bytes`. |see_cpython| `python:bytes`.
@@ -104,6 +106,8 @@ Functions and types
.. class:: memoryview() .. class:: memoryview()
|see_cpython| `python:memoryview`.
.. function:: min() .. function:: min()
.. function:: next() .. function:: next()

View File

@@ -57,6 +57,8 @@ and used in various methods.
This is covered in further detail :ref:`Controlling garbage collection <controlling_gc>` below. This is covered in further detail :ref:`Controlling garbage collection <controlling_gc>` below.
.. _speed_buffers:
Buffers Buffers
~~~~~~~ ~~~~~~~
@@ -69,6 +71,13 @@ example, objects which support stream interface (e.g., file or UART) provide ``r
method which allocates new buffer for read data, but also a ``readinto()`` method method which allocates new buffer for read data, but also a ``readinto()`` method
to read data into an existing buffer. to read data into an existing buffer.
Some useful classes for creating reusable buffer objects:
- :class:`bytearray`
- :mod:`array` (:ref:`discussed below<speed_arrays>`)
- :class:`io.StringIO` and :class:`io.BytesIO`
- :class:`micropython.RingIO`
Floating point Floating point
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
@@ -80,15 +89,20 @@ point to sections of the code where performance is not paramount. For example,
capture ADC readings as integers values to an array in one quick go, and only then capture ADC readings as integers values to an array in one quick go, and only then
convert them to floating-point numbers for signal processing. convert them to floating-point numbers for signal processing.
.. _speed_arrays:
Arrays Arrays
~~~~~~ ~~~~~~
Consider the use of the various types of array classes as an alternative to lists. Consider the use of the various types of array classes as an alternative to lists.
The `array` module supports various element types with 8-bit elements supported The :mod:`array` module supports various element types with 8-bit elements supported
by Python's built in `bytes` and `bytearray` classes. These data structures all store by Python's built in `bytes` and `bytearray` classes. These data structures all store
elements in contiguous memory locations. Once again to avoid memory allocation in critical elements in contiguous memory locations. Once again to avoid memory allocation in critical
code these should be pre-allocated and passed as arguments or as bound objects. code these should be pre-allocated and passed as arguments or as bound objects.
Memoryviews
~~~~~~~~~~~
When passing slices of objects such as `bytearray` instances, Python creates When passing slices of objects such as `bytearray` instances, Python creates
a copy which involves allocation of the size proportional to the size of slice. a copy which involves allocation of the size proportional to the size of slice.
This can be alleviated using a `memoryview` object. The `memoryview` itself This can be alleviated using a `memoryview` object. The `memoryview` itself
@@ -118,6 +132,23 @@ of buffer and fills in entire buffer. What if you need to put data in the
middle of existing buffer? Just create a memoryview into the needed section middle of existing buffer? Just create a memoryview into the needed section
of buffer and pass it to ``readinto()``. of buffer and pass it to ``readinto()``.
Strings vs Bytes
~~~~~~~~~~~~~~~~
MicroPython uses :ref:`string interning <qstr>` to save space when there are
multiple identical strings. Each time a new string is allocated at runtime (for
example, when two other strings are concatenated), MicroPython checks whether
the new string can be interned to save RAM.
If you have code which performs performance-critical string operations then
consider using :class:`bytes` objects and literals (i.e. ``b"abc"``). This skips
the interning check, and can be several times faster than performing the same
operations with string objects.
.. note:: The fastest performance will always be achieved by avoiding new object
creation entirely, for example with a reusable :ref:`buffer as described
above<speed_buffers>`.
Identifying the slowest section of code Identifying the slowest section of code
--------------------------------------- ---------------------------------------