2017-08-15 3 views
1

J'essaie de partager certaines chaînes entre les processus en utilisant la partie sharedctypes du module multitraitement.Stockage des chaînes dans un multi-traitement sharedctypes Array

TL; DR: Je souhaite mettre mes cordes dans un tableau de sharedctypes, comme ceci:

from multiprocessing.sharedctypes import Array 

Array(ctypes.c_char, ['a string', 'another string']) 

Plus d'informations:

Les docs ont cette note:

"Notez qu'un tableau de ctypes.c_char a une valeur et des attributs bruts qui permettent de l'utiliser pour stocker et récupérer des chaînes. "

En utilisant c_char seul:

from multiprocessing.sharedctypes import Array 

Array(ctypes.c_char, ['a string', 'another string']) 

Je reçois une erreur de type, ce qui est logique:

TypeError: one character bytes, bytearray or integer expected 

Cela peut (un peu) le travail par splittingthe aiguillon pour octets (ce qui rend aussi sens):

from multiprocessing.sharedctypes import Array 

multiproccessing.sharedctypes.Array(ctypes.c_char, [b's', b't', b'r', b'i', b'n', b'g']) 

Mais ce n'est pas très pratique f ou stocker de grandes listes de chaînes.

Cependant quand j'ai essayé d'utiliser les value et raw attributs figurant dans la documentation here et mentionnés dans cette note il n'y a toujours pas de magie:

Array(ctypes.c_char.value, ['string']) 

donne cette erreur:

TypeError: unsupported operand type(s) for *: 'getset_descriptor' and 'int' 

et raw donne ceci:

Array(ctypes.c_char.raw, ['string']) 

AttributeError: type object 'c_char' has no attribute 'raw' 

I ont également essayé d'utiliser le type c_wchar_p qui, dans la table de primitives des types de données compatible C (qui se trouve dans le docs) correspond directement à une chaîne:

Array(ctypes.c_wchar_p, ['string']) 

Ce CRASHES python, aucun code d'erreur est signalé, le processus se termine simplement par le code 0.

Pourquoi les tableaux sharedctypes ne peuvent-ils pas contenir de pointeurs comme le type c_wchar_p? toute autre solution ou conseil sur la façon de stocker des chaînes dans une grappe de type sharedctype est la bienvenue!

Mise à jour - Ce code parfois œuvres (la plupart des arrêts mais python travail de temps de temps en temps j'obtenir des chaînes en arrière, même si elles sont la plupart du temps charabia). mais les commentaires mentionnent qu'il fonctionne bien sur les fenêtres.

from multiprocessing import Process, Lock 
from multiprocessing.sharedctypes import Value, Array 
import ctypes 


def print_strings(S): 
    """Print strings in the C array""" 
    print([a for a in S]) 

if __name__ == '__main__': 
    lock = Lock() 
    string_array = Array(ctypes.c_wchar_p, ['string']) 
    q = Process(target=print_strings, args=(string_array,)) 
    q.start() 
    q.join() 

Mise à jour 2

C'est le charabia je reçois:

[vue « de la lèpre Jiu de chasse Ji Qian Li numéro poignardé Gai \ u2e73 ਊ †† Duo \ u2065 jus Tu \ u200a † ჰⴭⴭⴭ ਭ †† Yue Yan \ u2e79 Hui Wan Lian \ u2e6c scabies \ u202c Yue Yan \ u2e79 Hui Wan Lian \ u2e6c scabies \ u0a65 \ u200a † Qiu Lang Jiao \ u200a † ჰⴭⴭ \ u200a † Ya \ u2065 chasse \ u2065 arbalétrier \ u2065 Wuzhenweifu \ u206d Yituhuitou \ u2064 te 䌠 roi traquant généreux ⁷ ㅛ Yiyunqiaoju Hanfangtusan \ Mi \ u200a † 䄠 Laobohunying ⁺ Yu \ u2064 Lianlaiyoucan Huang \ u2c5f Ying Gumianzhendang Tian Yi Touyingyousuo \ u206e Runyintongqian ੳ † Weiqiangyingyi Xia \ de Tongzhutiantou décanté Tian Qian Li Fangqingxiecan de ressentiment ⰸ ⠠ Qiao Tong Yang \ le u202c Yu \ u2064 Taodenlutou \ u0a76 †† Kuizhichaoye Mei Tang Wumojiuyu \ u2073 Mu \ Qian de Yitaizhentang \ u206e Zaodangqianli Fang Qing \ u2e6c Shanzhishilai \ Fang pigwash \ u2072 soupe \ u200a † Tiantoushuowu Yu \ u206e se ㌬ Ziqingmeifei 䤠 䕅 ⁅ Mu Ying Lanwenlieqian \ u2073 Rundayangli Tangcan 崳 \ u205f Querenchitong \ u2067 \ u0a61 numéro †† Huan désert \ u2066⸵ « ressentiment kai arbalétrier Yau ㄭ \ u206e Hong \ u2073 roi ㄠ 㐮 ⵥ 㘱 ⠠ \ u206e‽ 〳〰⤰ਮ \ u200a † Shanhanfangtu San ੳ †† ⴭⴭⴭⴭⴭ \ u200a † ⸠ \ u202e ㅛ ⁝ \ u2e43 Ya \ u202e Patubenshui \ u202c 䌢 Toumibenzheng Ceonfang Xiao \ u2073 inondé \ u2072 arbalétrier illicite Yashiliewu reflètent Yousuoyixian Ⱒ Qian 8 ††††† ⨠ Shenshitangwu Suipiaomeiguan \ u206c panique Huangmanzhujin 䴠 Shi Touyinshiguan \ u206c Mutu Jiao Ⱚ stérile Hong \ u202e ⰵ 䰠 soupe exécutez 㩮 \ u200a ††††† effet \ u2072 éclat indigné Duo de pierres précieuses ❹ \ u2073 Lianshiyixia Jinzhuanhuilie ⱥ ㄠ 㘹 ⸲ \ u200a † ⸠ \ u202e㉛⁝ \ u2e4d 䄠 Laobohunying ⁺ Yu \ u2064 \ u2e49䄠 \ u202e Lian à vous \ u202c 䠪 balancer Yu Xun \ u206b roi 䴠 Shi Touyintiguan 6 ††††† 䘠 Yousuoyixian Ⱚ ㄠ Yan \ Choutongshibei de \ u202c enseignement avec ⁷ ans Wei> Shu Zhen ⱳ ㄠ 㘹 ⰴ Ying \ u2e70㌠ 㤷 ਮ ††††† Renjue 㩰 ⼯ Jian \ u2e77 Yinfuxianqi Ti ⽡ Wodousongyu Dunyingtiaoyan 㜳 ⸹ Jin 7 †† ⸮ peut 崳 Renjue 㩰 ⼯ Wan Ai oser Mudangtiwei \ u2e6e Jin Yun tourne ⽧ vétérinaire 䴯 Shi \ u2d68 Min Kuojiao 䴯 Shi Min Kuojiaoeryu 6 \ u200a † 䔠 Di détruire le roi ੳ †† ⴭⴭⴭⴭ \ u200a † exécution 㸾 canal \ u2e70 Ci-do ⸰⥝ \ u200a † offres fades Chai ㄨ 〮 \ u0a29 †† 㸾 - Guangshen ⠰ se Ⱞ ㄠ \ u20 2e \ u202b Diffusion Section ⥝ \ u200a † offres fades Chai Ci ㄠ 〮〰〰〰⬰⸰ \ u206a ††† Ⱐ † ⸰ 㠱 㠷 ㌵㌷〫 㘮 㘴 㘱 㐹 piquet ⥝ਊ †† '' ਊ †† Duo \ u2065 jus Tu \ u200a † ჰⴭⴭⴭ ਭ †† Yue Yan \ u2e79 Hui Wan Lian \ u2e6c scabies \ u202c Yue Yan \ u2e79 Hui Wan Lian \ u2e6c scabies \ u0a65 \ u200a † Qiu Lang Jiao \ u200a † ჰⴭⴭ \ u200a † Ya \ chasse u2065 \ u2065 arbalétrier \ u2065 Wuzhenweifu \ u206d Yituhuitou \ u2064 te 䌠 roi traquant généreux ⁷ ㅛ Yiyunqiaoju Hanfangtusan \ Mi \ u200a † 䄠 Laobohunying ⁺ Yu \ u2064 Lianlaiyoucan Huang \ u2c5f Yinggumianzhen Dangtiantouying Vous Suo Yi \ u206e Runyintongqian ੳ †† Weiqiangyingyi Xia \ de Dongzhutiantou décanté le ressentiment de Tian Li Qian Yang Dong Qiao Fangqingxiecan ⥦ ⠠ ⰸ \ u202c Yu \ u2064 Taodenlutou \ u0a76 †† Kuizhichaoye Wumojiuyu Mei Tang \ Mu \ u2065 Yataizhentang Qian \ u206e Zaodangqianli Fang Qing \ u2e6c Shanzhishilai \ u2065 Fang pigwash \ u2072 soupe \ u200a † Tiantoushuowu Yu \ u206e se ㌬ Ziqingmeibei 䤠 䕅 ⁅ Mu Ying Lanwenlieqian \ u2073 Rundayangli Tangcan 崳 \ u205f Xirenchidong \ u2067 \ u0a61 †† nombre de joie désert \ u2066⸵ « ressentiment kai arbalétrier Yau ㄭ \ u206e Hong \ u2073 roi ㄠ 㐮 ⵥ 㘱 ⠠ \ u206e‽ 〳〰⤰ਮ \ u200a † Shanhanfangtu San ੳ †† ⴭⴭⴭⴭⴭ \ u200a † ⸠ \ u202e ㅛ ⁝ \ u2e43 Ya \ u202e Patubenshui \ u202c 䌢 Toumibenzheng Ceonfang Xiao \ u2073 inondé \ u2072 arbalétrier illicite Yashiliewu reflètent Yousuoyixian Ⱒ Qian 8 ††††† ⨠ Shenshitangwu Suipiaomeiguan \ u206c panique Huangmanzhujin 䴠 Shi Touyinshiguan \ u206c Mutu Jiao Ⱚ stérile Hong \ u202e ⰵ 䰠 soupe exécutez 㩮 \ u200a ††††† effet \ u2072 éclat indigné Duo de pierres précieuses ❹ \ u2073 Lianshiyixia Jinzhuanhuilie ⱥ ㄠ 㘹 ⸲ \ u200a † ⸠ \ u202e㉛⁝ \ u2e4d 䄠 Laobohunying ⁺ Yu \ u2064 \ u2e49䄠 \ u202e Lian à vous \ u202c 䠪 balancer Yu Xun \ u206b roi 䴠 Shi Touyintiguan 6 ††††† 䘠 Yousuoyixian Ⱚ ㄠ Yan \ Choutongshibei de \ u202c enseignement avec ⁷ ans Wei> Shu Zhen ⱳ ㄠ 㘹 ⰴ Ying \ u2e70㌠ 㤷 ਮ ††††† Renjue 㩰 ⼯ Jian \ u2e77 Yinfuxianqi Ti ⽡ Wodousongyu Dunyingtiaoyan 㜳 ⸹ Jin 7 †† ⸮ peut 崳 Renjue 㩰 ⼯ Wan Ai oser Mudangtiwei \ u2e6e Jin Yun tourne ⽧ vétérinaire 䴯 Shi \ u2d68 Min Kuojiao 䴯 Shi Min Kuojiaoeryu 6 \ u200a † 䔠 Di détruire le roi ੳ †† ⴭⴭⴭⴭ \ u200a † exécution 㸾 canal \ u2e70 Ci-do ⸰⥝ \ u200a † offres fades Chai ㄨ 〮 \ u0a29 †† 㸾 - Guangshen ⠰ se Ⱞ ㄠ \ u20 2e \ u202b Diffusion Section ⥝ \ u200a † offres fades Chai Ci ㄠ 〮〰〰〰⬰⸰ \ u206a ††† Ⱐ † ⸰ 㠱 㠷 ㌵㌷〫 㘮 㘴 㘱 㐹 piquet ⥝ਊ †† « ]

(oui que apparemment tout est venu de « string », ne me demandez pas comment)

+1

J'ai juste essayé 'Array (ctypes.c_wchar_p, [ 'string'])' et semble fonctionner avec Python 3.5.3 sur Windows ... – jdehesa

+0

@jdehesa ouais j'étais sur le point de mettre à jour quelque chose à ce sujet, ma sortie n'est PAS cohérente - de temps en temps je récupère des chaînes (mais elles sont du charabia) mais la plupart du temps je obtenir une fenêtre indiquant que Windows a planté –

+0

@jdehesa J'ai ajouté une mise à jour d'un programme complet, cela fonctionne-t-il pour vous? (Je suis aussi sur Windows) –

Répondre

2

Le problème que vous rencontrez est mentionné dans the documentation:

Note: Although it is possible to store a pointer in shared memory remember that this will refer to a location in the address space of a specific process. However, the pointer is quite likely to be invalid in the context of a second process and trying to dereference the pointer from the second process may cause a crash.

Cela signifie que le stockage des pointeurs (comme les chaînes) ne va pas travailler, parce que l'adresse obtiendra au processus de l'enfant, et cette adresse ne sera pas valide plus là (d'où le défaut de segmentation). Considérons, par exemple, cette alternative, où toutes les chaînes sont concaténer dans un tableau et un autre tableau avec les longueurs est passé trop (vous pouvez modifier à votre convenance):

from multiprocessing import Process, Lock 
from multiprocessing.sharedctypes import Value, Array 
import ctypes 

def print_strings(S, S_len): 
    """Print strings in the C array""" 
    received_strings = [] 
    start = 0 
    for length in S_len: 
     received_strings.append(S[start:start + length]) 
     start += length 
    print("received strings:", received_strings) 

if __name__ == '__main__': 
    lock = Lock() 
    my_strings = ['string1', 'str2'] 
    my_strings_len = [len(s) for s in my_strings] 
    string_array = Array(ctypes.c_wchar, ''.join(my_strings)) 
    string_len_array = Array(ctypes.c_uint, my_strings_len) 
    q = Process(target=print_strings, args=(string_array, string_len_array)) 
    q.start() 
    q.join() 

Sortie:

received strings: ['string1', 'str2'] 

À propos des adresses dans le sous-processus:

Ceci est un peu hors sujet de la question, mais il était temps de mettre dans un commentaire. Honnêtement cela commence à être hors de ma profondeur, jetez un oeil à des commentaires de eryksun ci-dessous pour un aperçu plus éclairées, mais voici mon u . Omprendre de toute façon sur Unix (-comme) un nouveau processus créé par fork a la même mémoire et les adresses (virtuelles) que le processus parent, mais si vous alors exec un programme qui est plus le cas, je ne sais pas si Python multiprocessing un court exec ou non sur Unix (NDLR: voir eryksun's comment pour plus de détails et set_start_method), mais en tout cas je ne suppose qu'il ya aucune garantie que toute adresse dans le pool de mémoire gérés Python doit rester le même.Sous Windows, CreateProcess crée un nouveau processus à partir d'un exécutable qui n'a en principe rien en commun avec le parent. Je ne pense pas que même les bibliothèques partagées utilisées par plusieurs processus (.so/.dll) devraient être à la même adresse dans chaque plate-forme. Je ne pense pas que partager des adresses (virtuelles) entre processus ait même du sens quand on utilise la mémoire partagée puisque, si je me souviens bien (et je ne le pense pas), les blocs de mémoire partagés sont mappés à des adresses virtuelles arbitraires sur chaque processus. Donc mon impression est qu'il n'y a pas de bonne raison (ou "bonne et évidente", au moins) pour partager des adresses avec un sous-processus (bien sûr, les types de pointeurs dans ctypes sont toujours utiles pour parler aux bibliothèques natives dans le même processus). Comme je l'ai dit, je ne suis pas sûr à 100% de cela, mais je pense que l'idée générale est la même.

+0

Bonne réponse, j'aurais imaginé que la mémoire partagée entre les processus aurait signifié que les pointeurs étaient valides. Si l'adresse de mémoire est passée directement ou pointée à ne devrait pas faire une grande différence? tant que la mémoire est toujours accessible. Ou les adresses mémoire diffèrent-elles entre les processus? (clairement il y a quelque chose qui me manque) –

+0

@Harrydewinton J'allais écrire un commentaire mais j'allais devenir long, j'ai étendu la réponse. – jdehesa

+2

À partir de Python 3.4, la méthode de démarrage du multitraitement (définie par 'set_start_method') est par défaut de« forker »sur les systèmes POSIX, ce qui est problématique lorsqu'il est combiné avec le threading. Vous pouvez changer la méthode start pour "spawn" pour obtenir un comportement semblable à Windows, et il y a une troisième option "forkserver" qui essaie de fournir le meilleur des deux mondes. – eryksun

1

Autre exemple obtenant .raw et .value pour fonctionner. Par documentation, il ne fonctionne que pour Array(ctypes.c_char,...):

from multiprocessing import Process 
from multiprocessing.sharedctypes import Value, Array 
import ctypes 

def print_strings(s): 
    """Print strings in the C array""" 
    print(s.value) 
    print(len(s)) 
    s[len(s)-1]=b'x' 

if __name__ == '__main__': 
    string_array = Array(ctypes.c_char, b'string') 
    q = Process(target=print_strings, args=(string_array,)) 
    q.start() 
    q.join() 
    print(string_array.raw) 

montrant que le tampon de sortie a été partagé modifié:

b'string' 
6 
b'strinx' 
+0

donc 'c_char' ne fonctionne que pour une chaîne * simple * qui est stockée comme un tableau d'octets? (donc plus pratique que de diviser la chaîne en octets manuellement mais pas capable de stocker plusieurs chaînes?) (aussi, belle réponse) –