No se puede pasar un objeto lxml etree a un proceso separado

Estoy trabajando en un proyecto para analizar varios archivos xml simultáneamente en Python usando lxml. Cuando inicializo el proceso, quiero que mi clase principal realice un trabajo en el XML antes de que pase el objeto etree al proceso, pero encuentro que cuando el objeto etree llega al nuevo proceso, la clase sobrevive pero el XML ha desaparecido. dentro del objeto y getroot () devuelve Ninguno.

Sé que solo puedo pasar datos seleccionables usando la cola, pero ¿esto también es el caso con lo que paso al proceso dentro del campo ‘args’?

Aquí está mi código:

import multiprocessing, multiprocessing.pool, time from lxml import etree def compute(tree): print("Start Process") print(type(tree)) # Returns  print(id(tree)) # Returns new ID 44637320 as expected print(tree.getroot()) # Returns None def pool_init(queue): # see http://stackoverflow.com/a/3843313/852994 compute.queue = queue class Main(): def __init__(self): pass def main(self): tree = etree.parse('test.xml') print(id(tree)) # Returns object ID 43998536 print(tree.getroot()) #Returns  self.queue = multiprocessing.Queue() self.pool = multiprocessing.Pool(processes=1, initializer=pool_init, initargs=(self.queue,)) self.pool.apply_async(func=compute, args=(tree,)) time.sleep(10) if __name__ == '__main__': Main().main() 

Cualquier y toda ayuda muy apreciada.

ACTUALIZACIÓN / RESPUESTA

Basándome en la respuesta en la siguiente publicación, la modifiqué un poco y logré que funcionara con una huella de memoria mucho menor sin utilizar String IO. El método etree.tostring devuelve una matriz de bytes, que puede decaparse, luego, para descomprimirla, la matriz de bytes se puede analizar con etree.

 import multiprocessing, multiprocessing.pool, time, copyreg from lxml import etree def compute(tree): print("Start Process") print(type(tree)) # Returns  print(tree.getroot()) # Returns . Success! def pool_init(queue): # see http://stackoverflow.com/a/3843313/852994 compute.queue = queue def elementtree_unpickler(data): return etree.parse(BytesIO(data)) def elementtree_pickler(tree): return elementtree_unpickler, (etree.tostring(tree),) copyreg.pickle(etree._ElementTree, elementtree_pickler, elementtree_unpickler) class Main(): def __init__(self): pass def main(self): tree = etree.parse('test.xml') print(tree.getroot()) #Returns  self.queue = multiprocessing.Queue() self.pool = multiprocessing.Pool(processes=1, initializer=pool_init, initargs=(self.queue,)) self.pool.apply_async(func=compute, args=(tree,)) time.sleep(10) if __name__ == '__main__': Main().main() 

ACTUALIZACIÓN 2

Después de realizar algunas evaluaciones comparativas con la memoria, descubrí que pasar objetos grandes hace que los objetos no puedan ser eliminados por la recolección de basura en el proceso principal. Probablemente esto no sea un problema a pequeña escala, pero, por otro lado, los objetos estaban en el orden de varios cientos de MB en la memoria. Tan pronto como se haya llamado a una tarea asíncrona con un objeto XML en la statement, ese objeto no se puede borrar de la memoria si se elimina del proceso principal, incluso invocando manualmente la recolección de basura. Así que como resultado he vuelto a cerrar el XML en el proceso principal y pasar el nombre del archivo al subproceso.

Use el siguiente código para registrar picklers / unpicklers simples para objetos lxml Element / ElementTree. Usé eso en el pasado con lxml y zmq.

 import copy_reg try: from cStringIO import StringIO except ImportError: from StringIO import StringIO from lxml import etree def element_unpickler(data): return etree.fromstring(data) def element_pickler(element): data = etree.tostring(element) return element_unpickler, (data,) copy_reg.pickle(etree._Element, element_pickler, element_unpickler) def elementtree_unpickler(data): data = StringIO(data) return etree.parse(data) def elementtree_pickler(tree): data = StringIO() tree.write(data) return elementtree_unpickler, (data.getvalue(),) copy_reg.pickle(etree._ElementTree, elementtree_pickler, elementtree_unpickler)