Partage
  • Partager sur Facebook
  • Partager sur Twitter

partager en mémoire une liste de datetime

7 avril 2016 à 10:41:07

Bonjour, je suis tombé sur un sujet ou pour partager une liste en mémoire, il fallait la convertir en array:

import test
	
maliste=[1.0,2,5.4,9,10.2]
shared_array_base = list_of_list_to_array(ctypes.c_float, maliste)

with Pool(processes=None, initializer=_initialize_subprocess, initargs=(shared_array_base,)) as pool:
	pool.starmap(StartProcess, [("process1")])
	
def _initialize_subprocess(shared_array_base):
    "Initialise notre subprocess avec la mémoire partagée."
    test.shared_array_base = shared_array_base
	
def StartProcess(name)
	print(name)
	print(test.shared_array_base)
	
def list_of_list_to_array(data_type, data):
	return Array(data_type, [elt for row in data for elt in row], lock=False)

Mais pour des datetime comment on fait ? car le type date n'existe pas dans c_types.

  • Partager sur Facebook
  • Partager sur Twitter
7 avril 2016 à 11:29:05

Il faut donc le sérialiser, le placer en mémoire et depuis l'autre processus le dé-sérialiser. (cf Pickle)

-
Edité par Dan737 7 avril 2016 à 11:29:17

  • Partager sur Facebook
  • Partager sur Twitter
7 avril 2016 à 11:47:30

donc c'est impossible de la partager en mémoire ?
  • Partager sur Facebook
  • Partager sur Twitter
7 avril 2016 à 12:24:48

Si, mais au risque de me répéter, tu vas sérialiser ces objets dans la zone mémoire à partager. L'autre processus peut donc lire ces données, mais pour les comprendre il devra les dé-sérialiser.

-
Edité par Dan737 7 avril 2016 à 12:25:12

  • Partager sur Facebook
  • Partager sur Twitter
7 avril 2016 à 13:33:28

si je le sérialise avec pickle, il vas être stocker sur le disque dur non ?, donc il n'est dans la mémoire ?
  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2016 à 9:10:42

tu veut que je fasse sa ?

with open("monfichier", 'wb') as f:
   pickle.dump(maliste, f)



  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2016 à 9:31:53

cog3cog3 a écrit:

si je le sérialise avec pickle, il vas être stocker sur le disque dur non ?, donc il n'est dans la mémoire ?

Non, pickle permet aussi de stocker le résultat dans une chaîne de bytes (pickle.dumps).

  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2016 à 9:45:34

Oui et ?

Merci pour vos réponses, mais je comprend absolument pas ce que vous me demander de faire :(

o

  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2016 à 14:27:17

"Non, pickle permet aussi de stocker le résultat dans une chaîne de bytes "


Je doute que se soit une bonne idée, il vas falloir convertir la liste en chaine, et ensuite partager en mémoire cette chaine, sauf que ctype ne permet pas à ma connaissance de partager des bytes ?

Et ensuite, pour accéder a un élément de sa liste il devra nécessairement la reconvertir en liste, donc au final niveau consommation mémoire sa revient au même, et niveau temps d’accès c'est pire.


Je débute en python, je me trompe peut être.

-
Edité par slitaz 12 avril 2016 à 14:28:37

  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2016 à 14:41:09

j'ai crois avoir enfin compris cette histoire de chaîne de caractère, mais par contre, j'ai une erreur d'aces en lecture sur ma variable !?

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
  
from multiprocessing import Pool, Array
from functools import partial
import ctypes
import numpy as np
from time import sleep
import pickle
  
import test
  
  
def heavy_duty_function(line):
    shared_array = pickle.Unpickler(test.shared_array_base)
    print(shared_array)
  
def _initialize_subprocess(shared_array_base):
    test.shared_array_base = shared_array_base
     
def list_to_pickle(data):
    return pickle.dumps(data)
  
  
if __name__=='__main__':
    data = [0,1,2,3,4,5,6]
    shared_array_base = list_to_pickle(data)
    del data
  
    with Pool(processes=4, initializer=_initialize_subprocess, initargs=(shared_array_base,)) as pool:
        pool.map(heavy_duty_function, range(2))

dans la doc que j'ai trouvé c'est pourtant bien écrit qu'il faut utiliser la commande unpickle, j'ai essayé avec load, mais j'ai la meme erreur.

je me pose par contre la question de la synchronisation, comme la dit Slitaz, peut on lire/modifier un élément de la liste pickler sans la reconvertir en liste ?

-
Edité par cog3cog3 12 avril 2016 à 14:42:57

  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2016 à 17:32:07

effectivement c'est ce que je disait, tu pourrais pas lire la variable directement... ce qui enlève tout intérêt à partager en mémoire cette variable.

Pour ton bug, par contre je sais pas pourquoi tu l'as.

  • Partager sur Facebook
  • Partager sur Twitter
14 avril 2016 à 17:32:51

Il faut réaliser que pour partager de la mémoire entre plusieurs processus avec Array, on abandonne le concept de la représentation d'un objet Python en mémoire pour quelque chose de beaucoup plus basique. Pour une liste d'int par exemple, on convertit les objets Python int en une représentation en mémoire, en utilisant le type ctypes.c_intpar exemple que l'on place les uns derrière les autres. Il faut donc manipuler des données plus basiques.

Pour un objet datetime, il n'y a pas en effet un équivalent ctypes. Il faut lui trouver une représentation. Et je te propose par exemple d'utiliser pickle pour transformer de manière unique cet objet python en une série d'octets (bytes). Je n'ai pas dit qu'il fallait sérialiser avec pickle l'entièreté de la liste ! Maintenant le problème est que tu dois t'assurer que chaque représentation de datetime prend le même espace mémoire, car sinon comment prendre un élément en particulier ?

En faisant un petit test chez moi, je trouve qu'avec le protocol par défaut de pickle, un objet datetime prend 44 octets. Donc si tu as 1000 objets, te voilà avec un espace mémoire de 44 000 octets. Tu peux accéder à n'importe quel élément avec des offsets de 44 octets. Tu prends ton objets de 44 octets, tu le reconvertit en objet datetime dans le nouveau processus avec pickle.loads(data) et tu manipules cet objets. Si tu as besoin de le ré-écrire, tu le dump de nouveau et tu le replaces dans l'espace alloué.

Donc c'est une conversion on-the-fly. Si tu ne lis qu'une valeur à la fois, ça ne prendra pas beaucoup de mémoire en plus. Par contre ce sera nécessairement un peu plus lent que si tu avais partager un type natif de c_type.

Mais une chose est certaine, c'est loin d'être trivial !

Tu trouveras peut-être aussi ce post intéressant : http://stackoverflow.com/questions/1268252/python-possible-to-share-in-memory-data-between-2-separate-processes En particulier la réponse de M Martelli.

EDIT: si tu peux utiliser numpy, tu pourrais utiliser le type numpy.datetime64 qui prend 8 octets en mémoire et ne te demanderas donc pas toutes ces sérialisations.

-
Edité par Dan737 14 avril 2016 à 17:48:40

  • Partager sur Facebook
  • Partager sur Twitter
21 avril 2016 à 11:54:10

j'ai préférer utiliser pickle du ocup qui est plus simple.

J'ai une derniere question, es t'il possible de séparer l'étape de partage en mémoire et celle de la création du processus ?

dans le code y'a ceci:

with Pool(processes=None, initializer=_initialize_subprocess, initargs=(shared_array_base,)) as pool:
    pool.starmap(StartProcess, [("process1")])


peut on crée shared_array_base en dehors et avant la condition with ?

  • Partager sur Facebook
  • Partager sur Twitter
21 avril 2016 à 16:59:42

non tu peut il est lié a pool
  • Partager sur Facebook
  • Partager sur Twitter
21 avril 2016 à 17:58:19

C'est a dire, faut crée un 2eme pool avant ?
  • Partager sur Facebook
  • Partager sur Twitter
21 avril 2016 à 22:46:54

non je voulais dire que c'était impossible, quand tu partage ta variable, tu ne peut le faire que au moment ou tu crée ton processus, tu pourra pas le faire avant.

shared_array_base doit obligatoirement être crée pendant la création de ton processus.

  • Partager sur Facebook
  • Partager sur Twitter
22 avril 2016 à 10:20:04

a mince, tant pis merci quand même pour ton aide.
  • Partager sur Facebook
  • Partager sur Twitter
22 avril 2016 à 15:49:00

Moi je pense que c'est possible de séparer le pool et ton array, mais je n'ai pas les connaissance pour t'aider, peut être que quelqu'un d'autre pourra t'aider :(

  • Partager sur Facebook
  • Partager sur Twitter
22 avril 2016 à 20:40:06

merci pour ton aide. Personne d'autre pour m'aider ?
  • Partager sur Facebook
  • Partager sur Twitter
23 avril 2016 à 14:05:24

Je ne pense pas que quelqu'un t'aideras, c'est un forum pour débutant, ton problème est assez complexe, tu ferais mieu de poster ton problème sur developpez.com ou stackoverflow. Tu auras des personnes plus compétente que nous ici.
  • Partager sur Facebook
  • Partager sur Twitter
23 avril 2016 à 15:10:11

Tu devrais peut-être nous expliquer quelles sont tes contraintes. De toute évidence il n'est pas possible de lancer un nouveau processus qui doit partager une zone mémoire sans lui indiquer qu'elle est cette zone... Par contre il n'est pas nécessaire que la zone contienne déjà des données. On pourrait imaginer que les sub-processes aient pour objectif de remplir cette zone mémoire, par exemple.

-
Edité par Dan737 23 avril 2016 à 15:11:05

  • Partager sur Facebook
  • Partager sur Twitter
23 avril 2016 à 21:08:56

je voudrais partager mon array en mémoire mais sans crée de processus juste apres
  • Partager sur Facebook
  • Partager sur Twitter
24 avril 2016 à 8:30:35

Tu veux partager ton array avec ... personne ?? C'est dur de partager quand on est tout seul.

Quand tu définis ta liste et que tu crées ton Array tu as une zone mémoire prête à être partagée. Tu peux appeler le bloc with que bien plus tard dans le code si nécessaire.

  • Partager sur Facebook
  • Partager sur Twitter
24 avril 2016 à 11:39:31

je voudrais juste séparer le partage de la variable, et la création du processus.

Au départ mon array sera partagé avec juste 1 processus, puis par la suite, d'autre processus pourrons l'utiliser.

  • Partager sur Facebook
  • Partager sur Twitter
25 avril 2016 à 15:25:33

J'ai répondu à ça dans le 2ème paragraphe. Donc tu créés ton Array et par la suite quand tu créeras un nouveau processus avec with tu partageras ton Array.

  • Partager sur Facebook
  • Partager sur Twitter