Rendimiento CoreData y RestKit al importar sets de datos muy grandes

Estoy usando RestKit para search datos JSON en varios puntos finales (en la plataforma iOS).

Hay varias preguntas en SO que apuntan a la misma dirección como esa:

Importar sets de datos grandes en iPhone utilizando CoreData

Pero mi pregunta sigue siendo diferente, porque sé, si el file JSON es demasiado grande, tengo que cortarlo en trozos. ¡Yo haré eso!

¿Cómo se realiza exactamente la import con CoreData en RestKit?
Parece que hay una configuration de contexts padre / hijo, que es muy ineficiente al importar sets de datos grandes en el menor time posible (tal vez de una vez al iniciar, ¡ sin importar por lotes / perezosos! ).

Vea aquí una publicación de Florian Kugler sobre la import de performant en CoreData (Stacks)

Mi pregunta es: ¿Puedo configurar un context diferente, aparte de la configuration de contexts padre / hijo que ya tiene RestKit y ejecutar una RKManagedObjectRequestOperation importando completamente asíncrona y en el otro context. Luego fusiona el context al mainContext para search …

Realmente quiero seguir con CoreData en lugar de cambiar a SQLite simple, obteniendo el mayor performance posible de la combinación CoreData y RestKit .

Estoy encantado con sus respuestas profesionales. Tal vez Blake pueda responderme directamente esta pregunta también.

Bueno, primero, si quieres un performance máximo, y si realmente lo necesitas , no uses RestKit, no uses AFNetworking y no uses NSJSONSerialization . Todos sufren de opciones de layout que no funcionan bien cuando se trata de grandes sets de datos y si su objective es mantener una printing de pie de memory moderadamente baja y un alto performance.

Debería tener un JSON individual muy grande (probablemente una matriz JSON cuyos elementos son objects JSON) como el cuerpo de una sola connection para get un performance superior. Alternativamente, puede tener un formatting de transporte personalizado que envíe múltiples JSON dentro de una connection (por ejemplo, una serie de objects JSON, separados por un "espacio en blanco").

Tener una gran cantidad de conexiones es definitivamente lento.

Cuando se esfuerza por lograr el performance más rápido, debe download simultáneamente , analizar el JSON, crear la representación y savelo en la tienda persistente.

Nota:

Al hacer esto en paralelo, eres especialmente vulnerable a los errores de connection y mantener un set de datos coherente y lógico puede convertirse en un desafío. Por lo tanto, si su connection sufre de mala calidad e interrupciones frecuentes, primero puede download y save el file JSON en un file temporal (también soporta encabezados de range HTTP para la oportunidad de suspender y reanudar una descarga). Claro, su desempeño disminuye, pero bajo estas condiciones, no puede hacerlo rápido de todos modos.

Por lo tanto, una vez más, cuando su meta es el máximo performance, debe utilizar todas las capacidades de las CPU, que se ejecutan tanto en paralelo como tiene sentido, y esto es especialmente cierto cuando la connection es rápida.

El analizador JSON también debería poder analizar "fragments", es decir, JSON parcial, contenidos en un object NSData , ya que esto es lo que obtenemos de la connection:didReceiveData:

Cuando reciba los datos de JSON, debe "mapear" esto en una representación adecuada. Por lo general, los analizadores JSON conocidos crean una "representación de Foundation". Sin embargo, el enfoque más rápido es crear directamente el tipo de objects deseados del JSON. Esto requiere una "API de estilo SAX", que básicamente es una versión simplificada de un analizador que envía "events de análisis" a un delegado o cliente; por ejemplo, "JSON-Array began" o "got JSON Boolean False", etc. y código personalizado que recibe estos events y construye el object deseado sobre la marcha.

Todo esto requiere un analizador JSON que tenga funciones que no encontrará en NSJSONSerialization : una API de estilo SAX, "análisis de bloque" o input de análisis que es una serie de documentos JSON.

Para maximizar la utilización de la CPU, el disco y la networking, divide sus "tareas" en operaciones vinculadas a la CPU, enlazadas a E / S respectivamente enlazadas a la networking y cree tantas y corra tantas en paralelo como sea sano para el sistema . Estas tareas básicamente se ejecutan de forma asíncrona, toman una input, procesan la input y producen una salida que es la input de la próxima tarea asíncrona. Las primeras tareas notifican la siguiente tarea cuando está terminada, por ejemplo, a través de manejadores de finalización (bloques), y pasa su salida a través de parameters.

El procesamiento de los "trozos" entrantes de datos JSON, es decir, el análisis y la creación de la representación , es una operación vinculada a la CPU. Sin embargo, esto suele ser bastante rápido y no creo que valga la pena el esfuerzo de enviar estas tareas enlazadas a la CPU en todas las CPU disponibles mediante una queue simultánea.

El procesamiento de "trozos" entrantes de datos JSON puede implementarse básicamente en dos enfoques, nuevamente con ventajas y desventajas:

Procesamiento de datos JSON parciales de forma asincrónica

Cuando obtiene un "chunk" en connection:didReceiveData: puede progtwigr asíncronamente esto en una queue diferente para el procesamiento (es decir, el análisis y la creación de la representación) ejecutándose en un subprocess diferente al delegado.

Pros: el delegado regresa inmediatamente, por lo tanto NO bloquea el hilo del delegado, lo que a su vez da como resultado una lectura más rápida de los datos de la networking entrante y tampones de networking moderadamente pequeños. La connection finaliza en la duración más breve posible.

Contras: si el procesamiento es lento en comparación con la recepción de los datos, puede NSData en queue una gran cantidad de objects NSData en el bloque que se espera que se ejecute en una queue de envío en serie. Eso mantendrá la memory asignada para cada object NSData , y la RAM del sistema puede eventualmente agotarse y puede recibir advertencias o lockings de la memory a less que tome las acciones apropiadas.

Procesamiento de datos JSON parciales de manera síncrona

Al recibir un fragment del JSON, el analizador se invocará sincrónicamente con respecto al hilo del delegado.

Pros: Esto evita el problema de la memory cuando el procesamiento de datos es lento en comparación con la recepción de los datos. Sin embargo, esto puede detener la lectura de datos de la networking (una vez que el buffer de recepción interno está lleno).

Contras: Si el procesamiento es lento y los búferes internos de la networking se llenan, esto boostá el time de connection y, por lo tanto, boostá la probabilidad de que la connection se desconecte.

Ambos enfoques se benefician de un analizador rápido / generador de representación y requieren un analizador que puede procesar "fragments" de JSON como un object NSData y notificar de forma asíncrona a un cliente cuando finaliza con la representación. Opcionalmente, también debería tener una API de "estilo SAX". Hay dos analizadores JSON de terceros que conozco cumplen con estos requisitos:

jsonlite y esto

JPJson

Ambos son muy rápidos (más rápido que JSONKit y NSJSONSerialization), admiten el análisis de estilo SAX y pueden procesar JSON en fragments como objects NSData . JPJson también puede procesar un file que contiene varios JSON.

(Divulgación: Soy el autor de JPJson)

Cuando se crea una representación, el siguiente paso es crear e inicializar el object gestionado (a less que el analizador genere gestionar directamente los objects) y save el object en el almacén persistente. Esta es una operación de E / S y CPU enlazada, pero es probable que haya más CPU enlazada cuando se usan los almacenes SSD. Progtwigré este process en una queue separada y examinaré cómo funciona esto junto con las otras operaciones vinculadas a la CPU. Dependiendo de la velocidad de la networking, la networking se vuelve más vinculada a la CPU con mayor ancho de banda.

Un enfoque escalable que toma en count conexiones malas y buenas, se esfuerza por mantener el bajo nivel de memory y maximiza el performance, es bastante difícil de lograr, sin embargo, y una tarea de progtwigción desafiante. ¡Que te diviertas! 😉