objetos memoria manejo inmutables dinamica asignacion python buffer memoryview

inmutables - manejo de memoria en python



¿Cuál es exactamente el punto de la vista de memoria en Python? (3)

Aquí está el código python3.

#!/usr/bin/env python3 import time for n in (100000, 200000, 300000, 400000): data = ''x''*n start = time.time() b = data while b: b = b[1:] print (''bytes {:d} {:f}''.format(n,time.time()-start)) for n in (100000, 200000, 300000, 400000): data = b''x''*n start = time.time() b = memoryview(data) while b: b = b[1:] print (''memview {:d} {:f}''.format(n,time.time()-start))

Comprobando la documentation en memoryview:

Los objetos memoryview permiten que el código Python acceda a los datos internos de un objeto que admite el protocolo de búfer sin copiar.

clase memoryview (obj)

Crear una vista de memoria que haga referencia a obj. obj debe soportar el protocolo buffer. Los objetos incorporados que admiten el protocolo de búfer incluyen bytes y bytearray.

Entonces nos dan el código de muestra:

>>> v = memoryview(b''abcefg'') >>> v[1] 98 >>> v[-1] 103 >>> v[1:4] <memory at 0x7f3ddc9f4350> >>> bytes(v[1:4]) b''bce''

Una cita más, ahora vamos a echar un vistazo más de cerca:

>>> b = b''long bytes stream'' >>> b.startswith(b''long'') True >>> v = memoryview(b) >>> vsub = v[5:] >>> vsub.startswith(b''bytes'') Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: ''memoryview'' object has no attribute ''startswith'' >>> bytes(vsub).startswith(b''bytes'') True >>>

Así que lo que recojo de lo anterior:

Creamos un objeto de vista de memoria para exponer los datos internos de un objeto de búfer sin copiar, sin embargo, para hacer algo útil con el objeto (llamando a los métodos proporcionados por el objeto), ¡tenemos que crear una copia!

Por lo general, la memoria de memoria (o el objeto del búfer anterior) se necesitaría cuando tenemos un objeto grande, y los cortes también pueden ser grandes. La necesidad de una mayor eficiencia estaría presente si estuviéramos haciendo rebanadas grandes, o si hiciéramos rebanadas pequeñas pero muchas veces.

Con el esquema anterior, no veo cómo puede ser útil para cualquiera de las situaciones, a menos que alguien pueda explicarme lo que me estoy perdiendo aquí.

Edit1:

Tenemos una gran cantidad de datos, queremos procesarlos avanzando a través de ella de principio a fin, por ejemplo, extrayendo tokens desde el inicio de un búfer de cadena hasta que el búfer se consume. búfer, y el puntero se puede pasar a cualquier función que espere el tipo de búfer. ¿Cómo se puede hacer algo similar en python?

La gente sugiere soluciones alternativas, por ejemplo, muchas funciones de cadenas y expresiones regulares toman argumentos de posición que pueden usarse para emular el avance de un puntero. Hay dos problemas con esto: primero es una solución, se ve obligado a cambiar su estilo de codificación para superar las deficiencias, y segundo: no todas las funciones tienen argumentos de posición, por ejemplo, las funciones de startswith regulares y startswith do, encode() / decode() no

Otros pueden sugerir cargar los datos en trozos, o procesar el búfer en pequeños segmentos más grandes que el token máximo. Bien, estamos conscientes de estas posibles soluciones, pero se supone que trabajamos de una manera más natural en Python sin tratar de doblar el estilo de codificación para que se ajuste al idioma, ¿no es así?

Edit2:

Un ejemplo de código aclararía las cosas. Esto es lo que quiero hacer, y lo que asumí que la vista de memoria me permitiría hacer a primera vista. Permite usar pmview (vista de memoria adecuada) para la funcionalidad que estoy buscando:

tokens = [] xlarge_str = get_string() xlarge_str_view = pmview(xlarge_str) while True: token = get_token(xlarge_str_view) if token: xlarge_str_view = xlarge_str_view.vslice(len(token)) # vslice: view slice: default stop paramter at end of buffer tokens.append(token) else: break


Una razón por la que las memoryviews son útiles es porque se pueden memoryviews sin copiar los datos subyacentes, a diferencia de los bytes / str .

Por ejemplo, tomemos el siguiente ejemplo de juguete.

import time for n in (100000, 200000, 300000, 400000): data = ''x''*n start = time.time() b = data while b: b = b[1:] print ''bytes'', n, time.time()-start for n in (100000, 200000, 300000, 400000): data = ''x''*n start = time.time() b = memoryview(data) while b: b = b[1:] print ''memoryview'', n, time.time()-start

En mi computadora, me sale

bytes 100000 0.200068950653 bytes 200000 0.938908100128 bytes 300000 2.30898690224 bytes 400000 4.27718806267 memoryview 100000 0.0100269317627 memoryview 200000 0.0208270549774 memoryview 300000 0.0303030014038 memoryview 400000 0.0403470993042

Puede ver claramente la complejidad cuadrática del corte de cadena repetido. Incluso con solo 400000 iteraciones, ya es inmutable. Mientras tanto, la versión memoryview tiene una complejidad lineal y es muy rápida.

Edición: Tenga en cuenta que esto se hizo en CPython. Hubo un error en Pypy hasta 4.0.1 que hacía que las vistas de memoria tuvieran un rendimiento cuadrático.


memoryview objetos de vista de memoryview son excelentes cuando necesita subconjuntos de datos binarios que solo necesitan ser compatibles con la indexación. En lugar de tener que tomar porciones (y crear objetos nuevos, potencialmente grandes) para pasar a otra API , puede tomar un objeto de vista de memoryview .

Un ejemplo de API tal sería el módulo de struct . En lugar de pasar una porción del objeto de bytes grandes para analizar los valores C empaquetados, se pasa una memoryview de memoryview de la región de la que se deben extraer los valores.

memoryview objetos memoryview , de hecho, soportan la struct desempaquetando de forma nativa; puede apuntar a una región del objeto de bytes subyacente con una porción, luego usar .cast() para "interpretar" los bytes subyacentes como enteros largos, o valores de coma flotante, o listas de enteros de n dimensiones. Esto hace que para interpretaciones de formato de archivo binario muy eficientes, sin tener que crear más copias de los bytes.