from multiprocessing.pool import ThreadPool
class ThreadedListSerializer(serializers.ListSerializer):
"""
Use `multiprocessing.ThreadPool` to run the child serializer's to_representation calls in parallel
control the thread pool size with `SERIALIZER_THREADS`
Most effectively used with `ModelSerializer`'s that have IO bound field level serialization (ie. computed properties that make db calls):
```
class User(ModelSerializer):
...
class Meta:
list_serializer_class = ThreadedListSerializer
```
"""
def worker(self, item):
representation = self.child.to_representation(item)
connection.close()
return representation
def to_representation(self, data):
"""
List of object instances -> List of dicts of primitive datatypes.
"""
# Dealing with nested relationships, data can be a Manager,
# so, first get a queryset from the Manager if needed
iterable = data.all() if isinstance(data, models.Manager) else data
pool = ThreadPool(processes=int(settings.SERIALIZER_THREADS))
list_representation = pool.map(self.worker, [item for item in iterable])
# avoid a memory leak :)
pool.close()
pool.join()
return list_representation