A JIT implementation for Marshmallow to speed up dumping and loading objects.
Project description
*************************************************************
:fire:toastedmarshmallow:fire:: Makes Marshmallow Toasty Fast
*************************************************************
Toasted Marshmallow implements a JIT for marshmallow that speeds up dumping
objects 10-25X (depending on your schema). Toasted Marshmallow allows you to
have the great API that
`Marshmallow <https://github.com/marshmallow-code/marshmallow>`_ provides
without having to sacrifice performance!
::
Benchmark Result:
Original Time: 2682.61 usec/dump
Optimized Time: 176.38 usec/dump
Optimized (Cython) Time: 125.77 usec/dump
Speed up: 15.21x
Cython Speed up: 21.33x
Even ``PyPy`` benefits from ``toastedmarshmallow``!
::
Benchmark Result:
Original Time: 189.78 usec/dump
Optimized Time: 20.03 usec/dump
Speed up: 9.48x
Installing toastedmarshmallow
-----------------------------
.. code-block:: bash
pip install toastedmarshmallow
This will *also* install a slightly-forked ``marshmallow`` that includes some
hooks Toastedmarshmallow needs enable the JIT to run before falling back
to the original marshmallow code. These changes are minimal making it easier
to track upstream. You can find the changes
`Here <https://github.com/marshmallow-code/marshmallow/pull/629/files>`_.
This means you should **remove** ``marshmallow`` from your requirements and
replace it with ``toastedmarshmallow``. By default there is no
difference unless you explicitly enable Toasted Marshmallow.
Enabling Toasted Marshmallow
----------------------------
Enabling Toasted Marshmallow on an existing Schema is just one line of code,
set the ``jit`` property on any ``Schema`` instance to
``toastedmarshmallow.Jit``. For example:
.. code-block:: python
from datetime import date
import toastedmarshmallow
from marshmallow import Schema, fields, pprint
class ArtistSchema(Schema):
name = fields.Str()
class AlbumSchema(Schema):
title = fields.Str()
release_date = fields.Date()
artist = fields.Nested(ArtistSchema())
schema = AlbumSchema()
# Specify the jit method as toastedmarshmallow's jit
schema.jit = toastedmarshmallow.Jit
# And that's it! Your dump methods are 15x faster!
It's also possible to use the ``Meta`` class on the ``Marshmallow`` schema
to specify all instances of a given ``Schema`` should be optimized:
.. code-block:: python
import toastedmarshmallow
from marshmallow import Schema, fields, pprint
class ArtistSchema(Schema):
class Meta:
jit = toastedMarshmallow.Jit
name = fields.Str()
You can also enable Toasted Marshmallow globally by setting the environment
variable ``MARSHMALLOW_SCHEMA_DEFAULT_JIT`` to ``toastedmarshmallow.Jit`` .
Future versions of Toasted Marshmallow may make this the default.
How it works
------------
Toasted Marshmallow works by generating code at runtime to optimize dumping
objects without going through layers and layers of reflection. The generated
code optimistically assumes the objects being passed in are schematically valid,
falling back to the original marshmallow code on failure.
For example, taking ``AlbumSchema`` from above, Toastedmarshmallow will
generate the following 3 methods:
.. code-block:: python
def InstanceSerializer(obj):
res = {}
value = obj.release_date; value = value() if callable(value) else value; res["release_date"] = _field_release_date__serialize(value, "release_date", obj)
value = obj.artist; value = value() if callable(value) else value; res["artist"] = _field_artist__serialize(value, "artist", obj)
value = obj.title; value = value() if callable(value) else value; value = str(value) if value is not None else None; res["title"] = value
return res
def DictSerializer(obj):
res = {}
if "release_date" in obj:
value = obj["release_date"]; value = value() if callable(value) else value; res["release_date"] = _field_release_date__serialize(value, "release_date", obj)
if "artist" in obj:
value = obj["artist"]; value = value() if callable(value) else value; res["artist"] = _field_artist__serialize(value, "artist", obj)
if "title" in obj:
value = obj["title"]; value = value() if callable(value) else value; value = str(value) if value is not None else None; res["title"] = value
return res
def HybridSerializer(obj):
res = {}
try:
value = obj["release_date"]
except (KeyError, AttributeError, IndexError, TypeError):
value = obj.release_date
value = value; value = value() if callable(value) else value; res["release_date"] = _field_release_date__serialize(value, "release_date", obj)
try:
value = obj["artist"]
except (KeyError, AttributeError, IndexError, TypeError):
value = obj.artist
value = value; value = value() if callable(value) else value; res["artist"] = _field_artist__serialize(value, "artist", obj)
try:
value = obj["title"]
except (KeyError, AttributeError, IndexError, TypeError):
value = obj.title
value = value; value = value() if callable(value) else value; value = str(value) if value is not None else None; res["title"] = value
return res
Toastedmarshmallow will invoke the proper serializer based upon the input.
Since Toastedmarshmallow is generating code at runtime, it's critical you
re-use Schema objects. If you're creating a new Schema object every time you
serialize/deserialize an object you'll likely have much worse performance.
:zap::microscope: Experimental :microscope::zap:
--------------------------------------------------
Toastedmarshmallow also has an experimental Cython based jit. It takes the
generated code above and runs it through Cython first, getting another 1.5x
win. Generally the generated Python code is fast enough, but this is a useful
option when you've got to squeeze out every last bit of performance.
To use the Cython jit, replace `Jit` with `CythonJit`:
.. code-block:: python
schema.jit = toastedmarshmallow.CythonJit
:fire:toastedmarshmallow:fire:: Makes Marshmallow Toasty Fast
*************************************************************
Toasted Marshmallow implements a JIT for marshmallow that speeds up dumping
objects 10-25X (depending on your schema). Toasted Marshmallow allows you to
have the great API that
`Marshmallow <https://github.com/marshmallow-code/marshmallow>`_ provides
without having to sacrifice performance!
::
Benchmark Result:
Original Time: 2682.61 usec/dump
Optimized Time: 176.38 usec/dump
Optimized (Cython) Time: 125.77 usec/dump
Speed up: 15.21x
Cython Speed up: 21.33x
Even ``PyPy`` benefits from ``toastedmarshmallow``!
::
Benchmark Result:
Original Time: 189.78 usec/dump
Optimized Time: 20.03 usec/dump
Speed up: 9.48x
Installing toastedmarshmallow
-----------------------------
.. code-block:: bash
pip install toastedmarshmallow
This will *also* install a slightly-forked ``marshmallow`` that includes some
hooks Toastedmarshmallow needs enable the JIT to run before falling back
to the original marshmallow code. These changes are minimal making it easier
to track upstream. You can find the changes
`Here <https://github.com/marshmallow-code/marshmallow/pull/629/files>`_.
This means you should **remove** ``marshmallow`` from your requirements and
replace it with ``toastedmarshmallow``. By default there is no
difference unless you explicitly enable Toasted Marshmallow.
Enabling Toasted Marshmallow
----------------------------
Enabling Toasted Marshmallow on an existing Schema is just one line of code,
set the ``jit`` property on any ``Schema`` instance to
``toastedmarshmallow.Jit``. For example:
.. code-block:: python
from datetime import date
import toastedmarshmallow
from marshmallow import Schema, fields, pprint
class ArtistSchema(Schema):
name = fields.Str()
class AlbumSchema(Schema):
title = fields.Str()
release_date = fields.Date()
artist = fields.Nested(ArtistSchema())
schema = AlbumSchema()
# Specify the jit method as toastedmarshmallow's jit
schema.jit = toastedmarshmallow.Jit
# And that's it! Your dump methods are 15x faster!
It's also possible to use the ``Meta`` class on the ``Marshmallow`` schema
to specify all instances of a given ``Schema`` should be optimized:
.. code-block:: python
import toastedmarshmallow
from marshmallow import Schema, fields, pprint
class ArtistSchema(Schema):
class Meta:
jit = toastedMarshmallow.Jit
name = fields.Str()
You can also enable Toasted Marshmallow globally by setting the environment
variable ``MARSHMALLOW_SCHEMA_DEFAULT_JIT`` to ``toastedmarshmallow.Jit`` .
Future versions of Toasted Marshmallow may make this the default.
How it works
------------
Toasted Marshmallow works by generating code at runtime to optimize dumping
objects without going through layers and layers of reflection. The generated
code optimistically assumes the objects being passed in are schematically valid,
falling back to the original marshmallow code on failure.
For example, taking ``AlbumSchema`` from above, Toastedmarshmallow will
generate the following 3 methods:
.. code-block:: python
def InstanceSerializer(obj):
res = {}
value = obj.release_date; value = value() if callable(value) else value; res["release_date"] = _field_release_date__serialize(value, "release_date", obj)
value = obj.artist; value = value() if callable(value) else value; res["artist"] = _field_artist__serialize(value, "artist", obj)
value = obj.title; value = value() if callable(value) else value; value = str(value) if value is not None else None; res["title"] = value
return res
def DictSerializer(obj):
res = {}
if "release_date" in obj:
value = obj["release_date"]; value = value() if callable(value) else value; res["release_date"] = _field_release_date__serialize(value, "release_date", obj)
if "artist" in obj:
value = obj["artist"]; value = value() if callable(value) else value; res["artist"] = _field_artist__serialize(value, "artist", obj)
if "title" in obj:
value = obj["title"]; value = value() if callable(value) else value; value = str(value) if value is not None else None; res["title"] = value
return res
def HybridSerializer(obj):
res = {}
try:
value = obj["release_date"]
except (KeyError, AttributeError, IndexError, TypeError):
value = obj.release_date
value = value; value = value() if callable(value) else value; res["release_date"] = _field_release_date__serialize(value, "release_date", obj)
try:
value = obj["artist"]
except (KeyError, AttributeError, IndexError, TypeError):
value = obj.artist
value = value; value = value() if callable(value) else value; res["artist"] = _field_artist__serialize(value, "artist", obj)
try:
value = obj["title"]
except (KeyError, AttributeError, IndexError, TypeError):
value = obj.title
value = value; value = value() if callable(value) else value; value = str(value) if value is not None else None; res["title"] = value
return res
Toastedmarshmallow will invoke the proper serializer based upon the input.
Since Toastedmarshmallow is generating code at runtime, it's critical you
re-use Schema objects. If you're creating a new Schema object every time you
serialize/deserialize an object you'll likely have much worse performance.
:zap::microscope: Experimental :microscope::zap:
--------------------------------------------------
Toastedmarshmallow also has an experimental Cython based jit. It takes the
generated code above and runs it through Cython first, getting another 1.5x
win. Generally the generated Python code is fast enough, but this is a useful
option when you've got to squeeze out every last bit of performance.
To use the Cython jit, replace `Jit` with `CythonJit`:
.. code-block:: python
schema.jit = toastedmarshmallow.CythonJit
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
toastedmarshmallow-0.2.6.tar.gz
(60.4 kB
view details)
Built Distribution
File details
Details for the file toastedmarshmallow-0.2.6.tar.gz
.
File metadata
- Download URL: toastedmarshmallow-0.2.6.tar.gz
- Upload date:
- Size: 60.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 15dee79cac691c0a1dc9df694b6e014d00d465b588f49b893c9ece27d09856a0 |
|
MD5 | 3e180a26e3c89b77462be5e5d417e687 |
|
BLAKE2b-256 | d8c08d4bd4dec75d3afcd3227e59345b46645857db1eaa6346b3f177c82d5e95 |
File details
Details for the file toastedmarshmallow-0.2.6-py2.py3-none-any.whl
.
File metadata
- Download URL: toastedmarshmallow-0.2.6-py2.py3-none-any.whl
- Upload date:
- Size: 65.8 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6f8ecbf287e9745a9b6804a69f001804c98547be9425f06281162b742c8bfd68 |
|
MD5 | f34684871499d5c269c76e165780b36a |
|
BLAKE2b-256 | 4fe04cd56b14d6ef558688ed3ad696c92c612f3749aa4cdbfca5255a1b173591 |