Saya mencoba membagikan beberapa string di antara proses menggunakan bagian sharedctypes dari modul multiprosesor.

TL;DR: Saya ingin memasukkan string saya ke dalam array sharedctypes, seperti:

from multiprocessing.sharedctypes import Array

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

Informasi Lebih Lanjut:

dokumen memiliki catatan ini:

"Perhatikan bahwa array ctypes.c_char memiliki nilai dan atribut mentah yang memungkinkan seseorang menggunakannya untuk menyimpan dan mengambil string."

Menggunakan c_char saja:

from multiprocessing.sharedctypes import Array

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

Saya mendapatkan kesalahan tipe, yang masuk akal:

TypeError: one character bytes, bytearray or integer expected

Ini dapat (semacam) bekerja dengan membagi sengatan menjadi byte (yang juga masuk akal):

from multiprocessing.sharedctypes import Array

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

Tetapi ini sangat tidak nyaman untuk menyimpan daftar string yang besar.

Namun ketika saya mencoba menggunakan atribut value dan raw yang ditampilkan di dokumen di sini dan disebutkan dalam catatan itu masih belum ada keajaiban:

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

Memberikan kesalahan ini:

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

Dan raw memberikan ini:

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

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

Saya juga telah mencoba menggunakan tipe c_wchar_p yang ada dalam tabel tipe data primitif C yang kompatibel (ditemukan di dokumen) berhubungan langsung dengan string:

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

Python CRASHES ini, tidak ada kode kesalahan yang dilaporkan, prosesnya hanya keluar dengan kode 0.

Mengapa array sharedctypes tidak dapat menampung pointer seperti tipe c_wchar_p? solusi atau saran lain tentang cara menyimpan string dalam array sharedctype sangat diterima!

Pembaruan - Kode ini kadang-kadang berfungsi (sebagian besar waktu python berhenti bekerja tetapi kadang-kadang saya mendapatkan string kembali, meskipun sebagian besar omong kosong). tetapi komentar menyebutkan itu berfungsi dengan baik di windows.

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()

Perbarui 2

Ini omong kosong yang saya dapatkan:

['汣獵癩汥⁹景椠瑮搠祴数\u2e73ਊ††敓\u2065汁潳\u200a†ⴠⴭⴭⴭਭ††捳灩\u2e79灳捥慩\u2e6c癩\u202c捳灩\u2e79灳捥慩\u2e6c癩 \u0a65\u200a†丠瑯獥\u200a†ⴠⴭⴭ\u200a†圠\u2065獵\u2065桴\u2065污潧楲桴\u206d異汢獩敨\u2064祢䌠敬獮慨⁷ㅛ彝愠摮爠晥牥湥 \u2064祢\u200a†䄠牢浡睯瑩⁺湡\u2064瑓来湵嬠崲\u2c5f映牯眠楨档琠敨映湵瑣潩\u206e潤慭湩椠ੳ††慰瑲瑩潩敮\u2064 \u202c湡\u2064桃扥獹敨\u0a76††潰祬潮業污攠灸湡楳湯\u2073牡\u2065浥汰 \u206e慥档椠瑮牥慶\u2e6c删汥瑡癩\u2065牥潲\u2072湯\u200a†琠敨搠浯楡\u206eせ㌬崰甠楳杮䤠䕅⁅牡瑩浨瑥捩椠\ u2073潤畣敭瑮摥嬠崳\u205f獡栠癡湩\u2067\u0a61††数歡漠\u2066⸵攸ㄭ‶楷桴愠\u206e浲\u2073景ㄠ㐮ⵥ㘱⠠\u206e‽〳〰⤰ਮ \u200a†删晥牥湥散ੳ††ⴭⴭⴭⴭⴭ\u200a†⸠\u202eㅛ⁝\u2e43圠\u202e汃湥桳睡\u202c䌢敨祢桳癥猠牥敩\u2073潦\u2072慭桴浥瑡捩污 \u206c慌潢慲潴祲䴠瑡敨慭楴慣\u206c慔汢獥Ⱚ瘠汯\u202eⰵ䰠湯潤㩮\u200a \u2072慍敪瑳❹\u2073瑓瑡潩敮祲传晦捩ⱥㄠ㘹⸲\u200a†⸠\u202e㉛⁝\u2e4d䄠牢浡睯瑩⁺湡\u2064\u2e49䄠\u202e瑓 \u202c䠪湡扤潯\u206b景䴠瑡敨慭楴慣੬†††††䘠湵瑣潩獮Ⱚㄠ琰\u2068牰湩楴杮\u202c敎⁷潙歲›潄敶Ⱳㄠ㘹ⰴ \u2e70㌠㤷ਮ†††††栠瑴㩰⼯睷\u2e77慭桴献畦挮⽡捾浢愯湡獤瀯条彥㜳⸹瑨੭††⸮嬠崳栠瑴㩰⼯潫敢敳牡档 \u2e6e牯⽧瑨潤獣䴯瑡\u2d68敃桰獥䴯瑡⽨敃桰獥栮浴੬\u200a†䔠慸灭敬ੳ††ⴭⴭⴭⴭ\u200a†㸠㸾渠\u2e70ど嬨⸰⥝\u200a \u0a29††㸾‾灮椮⠰せⰮㄠ\u202e\u202b樲⥝\u200a†愠牲祡嬨ㄠ〮〰〰〰⬰⸰\u206a†††Ⱐ†⸰㠱㠷㌵㌷ ', ' \u2065汁潳\u200a†ⴠⴭⴭⴭਭ††捳灩\u2e79灳捥慩\u2e6c癩\u202c捳灩\u2e79灳捥慩\u2e6c癩\u0a65\u200a†丠瑯獥\u200a†ⴠⴭⴭ\u200a†圠\ u2065獵\u2065桴\u2065污潧楲桴\u206d異汢獩敨\u2064祢䌠敬獮慨⁷ㅛ彝愠摮爠晥牥湥散\u2064祢\u200a†䄠牢浡睯瑩⁺湡\u2064瑓 \u2c5f映牯眠楨档琠敨映湵瑣潩\u206e潤慭湩椠ੳ††慰瑲瑩潩敮\u2064湩潴琠敨琠潷椠瑮牥慶獬嬠ⰰ崸愠摮⠠ \u202c湡\u2064桃扥獹敨\u0a76††潰祬潮業污攠灸湡楳湯\u2073牡\u2065浥汰祯摥椠\u206e慥档椠瑮牥慶\u2e6c删汥瑡癩 \u2065牥潲\u2072湯\u200a†琠敨搠浯楡\u206eせ㌬崰甠楳杮䤠䕅⁅牡瑩浨瑥捩椠\u2073潤畣敭瑮摥嬠崳\u205f獡栠癡湩\u2067\ u0a61††数歡漠\u2066⸵攸ㄭ‶楷桴愠\u206e浲\u2073景ㄠ㐮ⵥ㘱⠠\u206e‽〳〰⤰ਮ\u200a†删晥牥湥散ੳ††ⴭⴭⴭⴭⴭ\u200a†⸠\ u202eㅛ⁝\u2e43圠\u202e汃湥桳睡\u202c䌢敨祢桳癥猠牥敩\u2073潦\u2072慭桴浥瑡捩污映湵瑣潩獮Ⱒ椠੮†††††⨠慎楴湯污 \u206c慌潢慲潴祲䴠瑡敨慭楴慣\u206c慔汢獥Ⱚ瘠汯\u202eⰵ䰠湯潤㩮\u200a†††††效\u2072慍敪瑳❹\u2073瑓瑡潩 \u200a†⸠\u202e㉛⁝\u2e4d䄠牢浡睯瑩⁺湡\u2064\u2e49䄠\u202e瑓来湵\u202c䠪湡扤潯\u206b景䴠瑡敨慭楴慣 \u2068牰湩楴杮\u202c敎⁷潙歲›潄敶Ⱳㄠ㘹ⰴ瀠\u2e70㌠㤷ਮ†††††栠瑴㩰⼯睷\ u2e77慭桴献畦挮⽡捾浢愯湡獤瀯条彥㜳⸹瑨੭††⸮嬠崳栠瑴㩰⼯潫敢敳牡档挮慰\u2e6e牯⽧瑨潤獣䴯瑡\u2d68敃桰獥䴯 \u200a†䔠慸灭敬ੳ††ⴭⴭⴭⴭ\u200a†㸠㸾渠\u2e70ど嬨⸰⥝\u200a†愠牲祡ㄨ〮\u0a29††㸾‾灮椮⠰せⰮ \u202e\u202b樲⥝\u200a†愠牲祡嬨ㄠ〮〰〰〰⬰⸰\u206a†††Ⱐ†⸰㠱㠷㌵㌷〫㘮㘴㘱㐹樴⥝ਊ††']

(ya itu ternyata semua berasal dari 'string', jangan tanya saya caranya)

0
Harry de winton 15 Agustus 2017, 16:33

2 jawaban

Jawaban Terbaik

Masalah yang Anda alami disebutkan dalam dokumentasi:

Catatan: Meskipun dimungkinkan untuk menyimpan pointer di memori bersama, ingat bahwa ini akan merujuk ke lokasi di ruang alamat dari proses tertentu. Namun, penunjuk kemungkinan besar tidak valid dalam konteks proses kedua dan mencoba untuk mereferensikan penunjuk dari proses kedua dapat menyebabkan crash.

Ini berarti bahwa menyimpan pointer (seperti string) tidak akan berfungsi, karena hanya alamat yang akan sampai ke proses anak, dan alamat itu tidak akan valid lagi di sana (karenanya kesalahan segmentasi). Pertimbangkan, misalnya, alternatif ini, di mana semua string digabungkan menjadi satu array dan array lain dengan panjang juga dilewatkan (Anda dapat mengubahnya untuk kenyamanan Anda):

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()

Keluaran:

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

Tentang alamat dalam subproses:

Ini agak keluar dari topik pertanyaan, tetapi terlalu lama untuk berkomentar. Sejujurnya ini mulai di luar jangkauan saya, lihat komentar eryksun di bawah ini untuk wawasan yang lebih terinformasi, tapi inilah pemahaman saya pula. Di Unix(-like) proses baru yang dibuat melalui fork memiliki memori dan alamat (virtual) yang sama dari proses induk, tetapi jika Anda kemudian exec< /a> beberapa program yang tidak lagi terjadi; Saya tidak tahu apakah multiprocessing Python menjalankan exec atau tidak di Unix (catatan: lihat komentar eryksun untuk lebih lanjut tentang ini dan set_start_method), tetapi bagaimanapun saya tidak akan menganggap ada jaminan bahwa alamat apa pun di kumpulan memori yang dikelola Python harus tetap sama . Di Windows, CreateProcess membuat proses baru dari executable yang pada prinsipnya tidak memiliki kesamaan dengan induknya. Saya tidak berpikir bahkan perpustakaan bersama yang digunakan oleh banyak proses (.so/.dll) harus berada di alamat yang sama di kedua platform. Saya tidak berpikir berbagi alamat (virtual) antar proses bahkan masuk akal ketika menggunakan memori bersama karena, jika saya ingat dengan benar (dan saya mungkin tidak), blok memori bersama dipetakan ke alamat virtual sewenang-wenang pada setiap proses. Jadi kesan saya adalah bahwa tidak ada alasan yang baik (atau "baik dan jelas", setidaknya) untuk berbagi alamat dengan subproses (tentu saja, tipe pointer di ctypes masih berguna untuk berbicara dengan perpustakaan asli dalam yang sama proses).

Seperti yang saya katakan, saya tidak 100% percaya diri dalam hal ini, tetapi saya pikir ide umumnya berjalan seperti itu.

2
jdehesa 15 Agustus 2017, 15:25

Contoh tambahan agar .raw dan .value berfungsi. Per dokumentasi ini hanya berfungsi untuk 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)

Output yang menunjukkan bahwa buffer bersama telah dimodifikasi:

b'string'
6
b'strinx'
1
Mark Tolonen 16 Agustus 2017, 01:28