Saya memiliki 60GB SciPy Array (Matrix) yang harus saya bagikan antara 5+ multiprocessing
Process
objek. Saya telah melihat numpy-sharedmem dan membaca diskusi ini di daftar SciPy. Tampaknya ada dua pendekatan - numpy-sharedmem
dan menggunakan a multiprocessing.RawArray()
dan memetakan NumPy dtype
s ke ctype
s. Sekarang, numpy-sharedmem
sepertinya cara untuk pergi, tapi saya belum melihat contoh referensi yang bagus. Saya tidak memerlukan kunci apa pun, karena array (sebenarnya matriks) akan menjadi hanya-baca. Sekarang, karena ukurannya, saya ingin menghindari salinannya. Ini terdengar seperti metode yang benar adalah untuk menciptakan hanya salinan array sebagai sharedmem
array, dan kemudian menyebarkannya ke Process
objek? Beberapa pertanyaan khusus:
Apa cara terbaik untuk benar-benar meneruskan pegangan sharedmem ke sub-
Process()
es? Apakah saya memerlukan antrian hanya untuk melewatkan satu array? Apakah pipa lebih baik? Bisakah saya meneruskannya sebagai argumen keProcess()
subkelas init (di mana saya menganggap itu acar)?Dalam diskusi yang saya tautkan di atas, ada yang menyebutkan
numpy-sharedmem
tidak aman 64bit? Saya pasti menggunakan beberapa struktur yang tidak dapat dialamatkan 32-bit.Apakah ada tradeoff untuk
RawArray()
pendekatan ini? Lebih lambat, buggier?Apakah saya memerlukan pemetaan ctype-to-dtype untuk metode numpy-sharedmem?
Apakah ada yang punya contoh beberapa kode OpenSource melakukan ini? Saya sangat mahir belajar dan sulit untuk membuatnya bekerja tanpa contoh yang baik untuk dilihat.
Jika ada info tambahan yang dapat saya berikan untuk membantu mengklarifikasi ini untuk orang lain, silakan beri komentar dan saya akan menambahkan. Terima kasih!
Ini perlu dijalankan di Ubuntu Linux dan Mungkin Mac OS, tetapi portabilitas bukanlah masalah besar.
multiprocessing
untuk membuat salinan semuanya untuk setiap proses.target_function
). Sistem operasi akan menyalin bagian dari memori orang tua ke ruang memori anak hanya dengan modifikasi.Jawaban:
@Velimir Mlaker memberikan jawaban yang bagus. Saya pikir saya bisa menambahkan sedikit komentar dan contoh kecil.
(Saya tidak dapat menemukan banyak dokumentasi tentang sharedmem - ini adalah hasil dari eksperimen saya sendiri.)
target
danargs
untukProcess
. Ini berpotensi lebih baik daripada menggunakan variabel global.Contoh
#!/usr/bin/env python from multiprocessing import Process import sharedmem import numpy def do_work(data, start): data[start] = 0; def split_work(num): n = 20 width = n/num shared = sharedmem.empty(n) shared[:] = numpy.random.rand(1, n)[0] print "values are %s" % shared processes = [Process(target=do_work, args=(shared, i*width)) for i in xrange(num)] for p in processes: p.start() for p in processes: p.join() print "values are %s" % shared print "type is %s" % type(shared[0]) if __name__ == '__main__': split_work(4)
Keluaran
values are [ 0.81397784 0.59667692 0.10761908 0.6736734 0.46349645 0.98340718 0.44056863 0.10701816 0.67167752 0.29158274 0.22242552 0.14273156 0.34912309 0.43812636 0.58484507 0.81697513 0.57758441 0.4284959 0.7292129 0.06063283] values are [ 0. 0.59667692 0.10761908 0.6736734 0.46349645 0. 0.44056863 0.10701816 0.67167752 0.29158274 0. 0.14273156 0.34912309 0.43812636 0.58484507 0. 0.57758441 0.4284959 0.7292129 0.06063283] type is <type 'numpy.float64'>
Pertanyaan terkait ini mungkin berguna.
sumber
Jika Anda menggunakan Linux (atau sistem yang kompatibel dengan POSIX), Anda dapat mendefinisikan array ini sebagai variabel global.
multiprocessing
sedang digunakanfork()
di Linux saat memulai proses anak baru. Proses turunan yang baru muncul secara otomatis membagikan memori dengan induknya selama tidak diubah ( mekanisme salin-saat-tulis ).Karena Anda mengatakan "Saya tidak memerlukan kunci apa pun, karena array (sebenarnya matriks) akan menjadi hanya-baca", memanfaatkan perilaku ini akan menjadi pendekatan yang sangat sederhana namun sangat efisien: semua proses anak akan mengakses data yang sama dalam memori fisik saat membaca array numpy besar ini.
Jangan menyerahkan array Anda ke
Process()
konstruktor, ini akan menginstruksikanmultiprocessing
untukpickle
data kepada anak, yang akan sangat tidak efisien atau tidak mungkin dalam kasus Anda. Di Linux, tepat setelahfork()
anak adalah salinan persis dari induk yang menggunakan memori fisik yang sama, jadi yang perlu Anda lakukan adalah memastikan bahwa variabel Python 'yang berisi' matriks dapat diakses dari dalamtarget
fungsi yang Anda serahkanProcess()
. Ini biasanya dapat Anda capai dengan variabel 'global'.Kode contoh:
from multiprocessing import Process from numpy import random global_array = random.random(10**4) def child(): print sum(global_array) def main(): processes = [Process(target=child) for _ in xrange(10)] for p in processes: p.start() for p in processes: p.join() if __name__ == "__main__": main()
Pada Windows - yang tidak mendukung
fork()
-multiprocessing
menggunakan panggilan API win32CreateProcess
. Ini menciptakan proses yang sama sekali baru dari apa pun yang dapat dieksekusi. Itulah mengapa pada Windows seseorang diharuskan untuk mengambil data ke anak jika seseorang membutuhkan data yang telah dibuat selama runtime dari induknya.sumber
multiprocessing
atau proses turunan mungkin berakhir hang ( biasanya menggunakan 1 / n dari satu prosesor daripada n prosesor) saat melakukan operasi aljabar linier pada matriks / array global bersama. The multithreaded konflik yang dikenal dengan OpenBLAS tampaknya meluas ke Pythonmultiprocessing
fork
untuk meneruskan parameter yang diberikanProcess
, daripada serialisasi mereka? Artinya, tidak bisakahfork
diterapkan ke proses induk sebelumchild
dipanggil, sehingga nilai parameter masih tersedia dari OS? Apakah tampaknya lebih efisien daripada serialisasi itu?fork()
itu tidak tersedia di Windows, itu telah dinyatakan dalam jawaban saya dan beberapa kali di komentar. Saya tahu bahwa ini adalah pertanyaan awal Anda, dan saya menjawabnya dengan empat komentar di atas ini : "kompromi adalah menggunakan metode transfer parameter yang sama pada kedua platform secara default, untuk pemeliharaan yang lebih baik dan untuk memastikan perilaku yang sama.". Kedua cara memiliki kelebihan dan kekurangan, itulah sebabnya di Python 3 ada fleksibilitas yang lebih besar bagi pengguna untuk memilih metode. Diskusi ini tidak produktif tanpa membicarakan detail, yang seharusnya tidak kita lakukan di sini.Anda mungkin tertarik dengan sepotong kecil kode yang saya tulis: github.com/vmlaker/benchmark-sharedmem
Satu-satunya file yang menarik adalah
main.py
. Ini adalah tolok ukur dari numpy-sharedmem - kodenya hanya meneruskan array (baiknumpy
atausharedmem
) ke proses yang muncul, melalui Pipe. Para pekerja baru saja memanggilsum()
data. Saya hanya tertarik untuk membandingkan waktu komunikasi data antara dua implementasi.Saya juga menulis kode lain yang lebih kompleks: github.com/vmlaker/sherlock .
Di sini saya menggunakan modul numpy-sharedmem untuk pemrosesan gambar real-time dengan OpenCV - gambarnya adalah array NumPy, sesuai
cv2
API OpenCV yang lebih baru . Gambar, sebenarnya referensi darinya, dibagikan antara proses melalui objek kamus yang dibuat darimultiprocessing.Manager
(sebagai lawan menggunakan Antrian atau Pipa.) Saya mendapatkan peningkatan kinerja yang luar biasa jika dibandingkan dengan menggunakan array NumPy biasa.Pipa vs. Antrian :
Menurut pengalaman saya, IPC dengan Pipa lebih cepat daripada Antrian. Dan itu masuk akal, karena Antrian menambahkan penguncian untuk membuatnya aman bagi banyak produsen / konsumen. Pipa tidak. Tetapi jika Anda hanya memiliki dua proses yang berbicara bolak-balik, aman untuk menggunakan Pipe, atau, seperti yang dibaca dokumen:
sharedmem
keamanan :Masalah utama dengan
sharedmem
modul adalah kemungkinan kebocoran memori saat keluar dari program yang tidak terdeteksi. Ini dijelaskan dalam diskusi panjang di sini . Meskipun pada 10 Apr 2011 Sturla menyebutkan perbaikan untuk kebocoran memori, saya masih mengalami kebocoran sejak saat itu, menggunakan kedua repo, Sturla Molden sendiri di GitHub ( github.com/sturlamolden/sharedmem-numpy ) dan Chris Lee-Messer di Bitbucket ( bitbucket.org/cleemesser/numpy-sharedmem ).sumber
sharedmem
terdengar seperti masalah besar. Ada petunjuk untuk memecahkannya?sharedmem
modul open source , untuk referensi.Jika array Anda sebesar itu, Anda dapat menggunakan
numpy.memmap
. Misalnya, jika Anda memiliki larik yang disimpan dalam disk, katakanlah'test.array'
, Anda dapat menggunakan proses simultan untuk mengakses data di dalamnya bahkan dalam mode "menulis", tetapi kasus Anda lebih sederhana karena Anda hanya memerlukan mode "membaca".Membuat array:
a = np.memmap('test.array', dtype='float32', mode='w+', shape=(100000,1000))
Anda kemudian dapat mengisi larik ini dengan cara yang sama seperti yang Anda lakukan dengan larik biasa. Sebagai contoh:
a[:10,:100]=1. a[10:,100:]=2.
Data disimpan ke dalam disk saat Anda menghapus variabel
a
.Nanti Anda dapat menggunakan beberapa proses yang akan mengakses data di
test.array
:# read-only mode b = np.memmap('test.array', dtype='float32', mode='r', shape=(100000,1000)) # read and writing mode c = np.memmap('test.array', dtype='float32', mode='r+', shape=(100000,1000))
Jawaban terkait:
Bekerja dengan data besar dalam python dan numpy, tidak cukup ram, bagaimana cara menyimpan sebagian hasil pada disk?
Apakah mungkin untuk memetakan data diskonti pada disk ke array dengan python?
sumber
Anda mungkin juga merasa berguna untuk melihat dokumentasi untuk pyro seolah-olah Anda dapat mempartisi tugas Anda dengan tepat, Anda dapat menggunakannya untuk menjalankan bagian yang berbeda pada mesin yang berbeda serta pada inti yang berbeda di mesin yang sama.
sumber
Mengapa tidak menggunakan multithreading? Sumber daya proses utama dapat dibagikan oleh utasnya secara asli, sehingga multithreading jelas merupakan cara yang lebih baik untuk berbagi objek yang dimiliki oleh proses utama.
Jika Anda khawatir tentang mekanisme GIL python, mungkin Anda dapat menggunakan
nogil
darinumba
.sumber