2011-08-08 10 views
14

Empecé a utilizar la biblioteca de búferes de protocolo, pero noté que usaba grandes cantidades de memoria. ¡wmpler.asizeof muestra que uno de mis objetos es aproximadamente 76k! Básicamente, contiene algunas cadenas, algunos números y algunas enumeraciones, y algunas listas opcionales de los mismos. Si estuviera escribiendo lo mismo que una C-struct, esperaría que fuera de unos cientos de bytes, y de hecho el método ByteSize devuelve 121 (el tamaño de la cadena serializada).Buffers de protocolo de Google enormes en python

¿Es lo que espera de la biblioteca? Había oído que era lento, pero esto no se puede usar y me hace sentir más inclinado a creer que lo estoy usando mal.

Editar

Aquí es un ejemplo I construido. Este es un archivo pb similar, pero más simple que lo que he estado usando

package pb; 

message A { 
    required double a  = 1; 
} 

message B { 
    required double b  = 1; 
} 

message C { 
    required double c  = 1; 
    optional string s  = 2; 
} 

message D { 
    required string d  = 1; 
    optional string e  = 2; 
    required A a   = 3; 
    optional B b   = 4; 
    repeated C c   = 5; 
} 

Y aquí lo estoy usando

>>> import pb_pb2 
>>> a = pb_pb2.D() 
>>> a.d = "a" 
>>> a.e = "e" 
>>> a.a.a = 1 
>>> a.b.b = 2 
>>> c = a.c.add() 
>>> c.c = 5 
>>> c.s = "s" 
>>> import pympler.asizeof 
>>> pympler.asizeof.asizeof(a) 
21440 
>>> a.ByteSize() 
42 

Tengo la versión 2.2.0 de protobuf (un poco viejo en este punto) y python 2.6.4.

+1

Parte del código de demostración que reproduce el comportamiento estaría bien. – phihag

+1

@phihag Aquí hay algo similar reproduciendo el comportamiento. –

Respuesta

5

Las instancias de objetos tienen una huella de memoria mayor en python que en los lenguajes compilados. Por ejemplo, el siguiente código, que crea clases muy simples que imitan sus proto pantallas 1440:

class A: 
    def __init__(self): 
    self.a = 0.0 

class B: 
    def __init__(self): 
    self.b = 0.0 

class C: 
    def __init__(self): 
    self.c = 0.0 
    self.s = "" 

class D: 
    def __init__(self): 
    self.d = "" 
    self.e = "" 
    self.e_isset = 1 
    self.a = A() 
    self.b = B() 
    self.b_isset = 1 
    self.c = [C()] 

d = D() 
print asizeof(d) 

No me sorprende que se genera protobuf clases tienen 20 veces más memoria, ya que añadir una gran cantidad de placa de la caldera.

La versión C++ seguramente no sufre de esto.

+0

No esperaba que fuera pequeño, pero como puede ver en este ejemplo, ¡un objeto realmente básico es 20k! Eso es un aumento de 500 veces sobre el tamaño necesario para contener la información necesaria. Un factor de 10 es tal vez correcto, pero 500 significa que no puede retener más de un (relativamente) pequeño número de estos objetos en la memoria. Por contrato, el generador de impulsos sugiere que el tamaño de un int es 24, que es tal vez un aumento de 6 veces en el tamaño que va desde C++ a python. –

+1

si esto es importante, puede intentar reducir el tamaño utilizando el atributo de clase '__slots__'. –

+0

No conozco ninguna razón fundamental por la cual 'pb_pb2.D' necesite almacenar objetos reales de Python. Si no lo hace, esta lógica no necesariamente se sostiene. Si no necesita y lo hace, parece que podría escribirse mal. –

0

Editar: Probablemente este no sea su problema real aquí, pero acabamos de experimentar un mensaje de 45MB protobuf que toma> 4GB de RAM al decodificar. Parece ser esta: https://github.com/google/protobuf/issues/156

que se sabe acerca de protobuf 2,6 y una solución sólo se fusionaron en maestro de marzo de 7 este año: https://github.com/google/protobuf/commit/f6d8c833845b90f61b95234cd090ec6e70058d06

+0

Resulta que la pérdida de memoria no solucionó nuestro problema. –

Cuestiones relacionadas