पायथन में फॉर-लूप को समानांतर करना


35

क्या पायथन में ऐसे कोई उपकरण हैं जो मतलूब के समान हैं? मुझे यह धागा मिला , लेकिन यह चार साल पुराना है। मैंने सोचा कि शायद यहाँ किसी को और अधिक हाल का अनुभव हो सकता है।

यहाँ उस चीज़ के प्रकार का एक उदाहरण दिया गया है जिसे मैं समानांतर बनाना चाहता हूँ:

X = np.random.normal(size=(10, 3))
F = np.zeros((10, ))
for i in range(10):
    F[i] = my_function(X[i,:])

जहां my_functionएक ndarrayआकार लेता है (1,3)और एक स्केलर देता है।

कम से कम, मैं एक साथ कई कोर का उपयोग करना चाहूंगा --- जैसे parfor। दूसरे शब्दों में, 8-से-16 कोर के साथ एक साझा मेमोरी सिस्टम मान लें।


गूगल पर बहुत सारे परिणाम। ये बहुत सरल प्रतीत: blog.dominodatalab.com/simple-parallelization quora.com/What-is-the-Python-equivalent-of-MATLABs-parfor
डौग Lipinski

धन्यवाद, @ डौग-लिपिंस्की। उन उदाहरणों की तरह, जिन्हें मैंने googling के दौरान पाया है, इसमें कुछ तुच्छ संगणना हैं जो पुनरावृत्ति सूचकांक पर आधारित हैं। और वे हमेशा दावा करते हैं कि कोड "अविश्वसनीय रूप से आसान है।" मेरा उदाहरण फॉर-लूप के बाहर सरणियों (मेमोरी को आवंटित करता है) को परिभाषित करता है। मैं इसे किसी और तरह से कर रहा हूँ; मैं बस इसे मतलाब में कैसे करता हूं। पेचीदा हिस्सा जो उन उदाहरणों को बकने लगता है, लूप के अंदर फ़ंक्शन को दिए गए सरणी का हिस्सा मिल रहा है।
पॉल जी। कॉन्स्टेंटाइन

जवाबों:


19

जॉबलिब आप क्या चाहते हैं। मूल उपयोग पैटर्न है:

from joblib import Parallel, delayed

def myfun(arg):
     do_stuff
     return result

results = Parallel(n_jobs=-1, verbose=verbosity_level, backend="threading")(
             map(delayed(myfun), arg_instances))

जहां arg_instancesमूल्यों की सूची myfunसमानांतर में गणना की जाती है। मुख्य प्रतिबंध यह है कि myfunएक टॉपवेल फ़ंक्शन होना चाहिए। backendपैरामीटर या तो किया जा सकता है "threading"या "multiprocessing"

आप समानांतर फ़ंक्शन को अतिरिक्त सामान्य पैरामीटर पास कर सकते हैं। myfunप्रारंभिक निकाय वैश्विक वैरिएबल का भी उल्लेख कर सकता है, जो मूल्य बच्चों को उपलब्ध होंगे।

थ्रेड बैकएंड के साथ आर्ग्स और परिणाम बहुत कुछ हो सकते हैं, लेकिन परिणाम मल्टीप्रोसेसिंग बैकएंड के साथ क्रमबद्ध होने की आवश्यकता है।


Dask भी समान कार्यक्षमता प्रदान करता है। यह बेहतर हो सकता है यदि आप कोर डेटा से बाहर काम कर रहे हैं या आप अधिक जटिल संगणना को समानांतर बनाने की कोशिश कर रहे हैं।


मुझे मल्टीप्रोसेसिंग सहित बैटरी का उपयोग करने के लिए शून्य मान जोड़ा गया है। मैंने शर्त लगाई कि जॉबलीब हुड के नीचे इसका उपयोग कर रहा है।
जेवियर कॉम्बेल

1
यह उल्लेख किया जाना चाहिए कि जॉबलिब जादू नहीं है, threadingबैकेंड जीआईएल की अड़चन से ग्रस्त है और multiprocessingबैकेंड सभी मापदंडों और वापसी मूल्यों के क्रमांकन के कारण बड़े ओवरहेड लाता है। पायथन में समानांतर प्रसंस्करण के निम्न-स्तरीय विवरण के लिए यह उत्तर देखें ।
जैकब किलिकोवस्की

मुझे फ़ंक्शन जटिलता और पुनरावृत्तियों की संख्या का संयोजन नहीं मिल रहा है, जिसके लिए जॉबलिब फॉर-लूप की तुलना में तेज़ होगा। मेरे लिए, यह एक ही गति है अगर n_jobs = 1, और अन्य सभी मामलों में बहुत धीमी है
UVs Fomins

@AleksejsFomins थ्रेड आधारित समानता उस कोड के लिए मदद नहीं करेगी जो GIL को जारी नहीं करता है लेकिन एक महत्वपूर्ण संख्या है, विशेष रूप से डेटा विज्ञान या संख्यात्मक पुस्तकालय। अन्यथा आपको म्यूट्रोप्राइसिंग की आवश्यकता है, जॉबली दोनों का समर्थन करता है। मल्टीप्रोसेसिंग मॉड्यूल में अब समानांतर भी है mapजिसे आप सीधे उपयोग कर सकते हैं। इसके अलावा अगर आप mkl संकलित संख्या का उपयोग करते हैं तो यह आपके द्वारा बिना कुछ किए स्वचालित रूप से सदिश परिचालनों को समानांतर कर देगा। Ananconda में स्थित खराबी डिफ़ॉल्ट रूप से सक्षम mkl है। हालांकि कोई सार्वभौमिक समाधान नहीं है। जॉबलिब बहुत कम उपद्रव है और 2015 में कम ओशन थे
डैनियल महलर

आपके सुझाव के लिए धन्यवाद। मुझे याद है कि मैंने पहले भी कुछ पोस्ट लिखने की कोशिश की थी, क्योंकि यह मेरी अपेक्षा के अनुरूप नहीं था। हो सकता है कि मैं इसे एक और रूप दे दूं
१२:४३


8

इस तरह के सरल छोरों को समानांतर बनाने के लिए एक अच्छा अनुमान my_functionचुनने के बिना कुछ भी संभालने के multiprocessing.Pool().map()लिए। joblib, dask, mpiसंगणना या numbaअन्य उत्तर में प्रस्तावित की तरह इस तरह के प्रयोग के मामलों के लिए किसी भी लाभ लाने और जोड़ नहीं लग बेकार निर्भरता (योग करने के लिए वे overkill हैं)। एक अन्य उत्तर में प्रस्तावित के रूप में थ्रेडिंग का उपयोग करना एक अच्छा समाधान होने की संभावना नहीं है, क्योंकि आपको अपने कोड के जीआईएल इंटरैक्शन के लिए अंतरंग होना होगा या आपके कोड को मुख्य रूप से इनपुट / आउटपुट करना चाहिए।

कहा कि numbaअनुक्रमिक शुद्ध अजगर कोड को गति देने के लिए एक अच्छा विचार हो सकता है, लेकिन मुझे लगता है कि यह सवाल के दायरे से बाहर है।

import multiprocessing
import numpy as np

if __name__ == "__main__":
   #the previous line is necessary under windows to not execute 
   # main module on each child under windows

   X = np.random.normal(size=(10, 3))
   F = np.zeros((10, ))

   pool = multiprocessing.Pool(processes=16)
   # if number of processes is not specified, it uses the number of core
   F[:] = pool.map(my_function, (X[i,:] for i in range(10)) )

हालांकि कुछ कैविएट (लेकिन जो अधिकांश अनुप्रयोगों को प्रभावित नहीं करना चाहिए):

  • खिड़कियों के नीचे कोई कांटा समर्थन नहीं है, इसलिए प्रत्येक बच्चे के स्टार्टअप पर मुख्य मॉड्यूल के साथ एक दुभाषिया लॉन्च किया गया है, इसलिए इसमें एक ओवरहेड हो सकता है (विज्ञापन इसका कारण है if __name__ == "__main__"
  • दलीलें और my_function के परिणाम अचंभित और अचंभित हैं, यह बहुत बड़ा ओवरहेड हो सकता है, इसे कम करने के लिए इस उत्तर को देखें https://stackoverflow.com/a/37072511/128629 । यह नॉन पिकेबल ऑब्जेक्ट्स को भी अनुपयोगी बनाता है
  • my_functionवैश्विक चर के साथ संचार जैसे साझा राज्यों पर निर्भर नहीं होना चाहिए क्योंकि राज्यों को प्रक्रिया के बीच साझा नहीं किया जाता है। शुद्ध कार्य (गणितीय इंद्रियों में कार्य) उन कार्यों का उदाहरण हैं जो राज्यों को साझा नहीं करते हैं

6

Parfor की मेरी धारणा यह है कि MATLAB कार्यान्वयन विवरण संलग्न कर रहा है, इसलिए यह दोनों साझा मेमोरी समानता (जो आप चाहते हैं) का उपयोग कर सकता है और मेमोरी समानतावाद वितरित कर सकता है (यदि आप MATLAB वितरित कंप्यूटिंग सर्वर चला रहे हैं )।

यदि आप साझा मेमोरी समानतावाद चाहते हैं, और आप किसी प्रकार के कार्य समानांतर लूप को निष्पादित कर रहे हैं, तो मल्टीगॉर्सिंग मानक लाइब्रेरी पैकेज संभवतः वही है, जो आप चाहते हैं, जॉब की तरह एक अच्छा फ्रंट-एंड , जैसा कि डग के पोस्ट में उल्लेख किया गया है। मानक पुस्तकालय दूर नहीं जा रहा है, और इसे बनाए रखा गया है, इसलिए यह कम जोखिम वाला है।

वहाँ अन्य विकल्प भी हैं, जैसे कि समानांतर पायथन और आईपीथॉन की समानांतर क्षमताएं । पैरेलल पायथन में एक त्वरित झलक मुझे लगता है कि यह पैरेफोर की भावना के करीब है, इसमें पुस्तकालय वितरित मामले के लिए विवरण संलग्न करता है, लेकिन ऐसा करने की लागत यह है कि आपको उनके पारिस्थितिकी तंत्र को अपनाना होगा। IPython का उपयोग करने की लागत समान है; आपको चीजों को करने के आईपीथॉन तरीके को अपनाना होगा, जो आपके लिए लायक हो भी सकता है और नहीं भी।

यदि आप वितरित मेमोरी की परवाह करते हैं, तो मैं mpi4py की सलाह देता हूं । लिस्संद्रो डालसिन महान काम करता है, और mpi4py को PETSc पायथन रैपर में उपयोग किया जाता है, इसलिए मुझे नहीं लगता कि यह जल्द ही कभी भी दूर हो जाएगा। मल्टीप्रोसेसिंग की तरह, यह एक कम (एर) -लेवल इंटरफ़ेस है समांतर की तुलना में समानता है, लेकिन एक है जो थोड़ी देर तक चलने की संभावना है।


धन्यवाद, @Geoff क्या आपके पास इन पुस्तकालयों के साथ काम करने का कोई अनुभव है? शायद मैं साझा मेमोरी मशीन / मल्टीकोर प्रोसेसर पर mpi4py का उपयोग करने की कोशिश करूंगा।
पॉल जी। कॉन्सटेंटाइन

@PaulGConstantine मैंने mpi4py का सफलतापूर्वक उपयोग किया है; यदि आप MPI से परिचित हैं, तो यह बहुत दर्दनाक है। मैंने मल्टीप्रोसेसिंग का उपयोग नहीं किया है, लेकिन मैंने इसे सहयोगियों के लिए अनुशंसित किया है, जिन्होंने कहा कि यह उनके लिए अच्छा काम करता है। मैंने IPython का भी उपयोग किया है, लेकिन समानता की विशेषताएं नहीं हैं, इसलिए मैं यह नहीं बोल सकता कि यह कितनी अच्छी तरह काम करता है।
ज्योफ ऑक्सबेरी

1
: एरन एक अच्छा mpi4py ट्यूटोरियल वह पाठ्यक्रम सुपरकंप्यूटिंग में PyHPC के लिए तैयार है github.com/pyHPC/pyhpc-tutorial
मैट Knepley

4

एक "ब्लैक बॉक्स" टूल की तलाश में, जिसका उपयोग समानांतर "जेनेरिक" पायथन कार्यों में निष्पादित करने के लिए किया जा सकता है, मैं यह विश्लेषण करने का सुझाव my_function()दूंगा कि हाथ से कैसे समानांतर किया जा सकता है।

सबसे पहले, my_function(v)अजगर forलूप ओवरहेड के निष्पादन समय की तुलना करें : [सी] पायथन forलूप बहुत धीमी हैं, इसलिए समय my_function()को नगण्य में खर्च किया जा सकता है।

>>> timeit.timeit('pass', number=1000000)
0.01692986488342285
>>> timeit.timeit('for i in range(10): pass', number=1000000)
0.47521495819091797
>>> timeit.timeit('for i in xrange(10): pass', number=1000000)
0.42337894439697266

दूसरी जाँच करें कि क्या कोई सरल वेक्टर कार्यान्वयन है my_function(v)जिसके लिए छोरों की आवश्यकता नहीं है:F[:] = my_vector_function(X)

(ये दो पहले बिंदु बहुत तुच्छ हैं, मुझे माफ कर दो अगर मैंने उन्हें यहां पूर्णता के लिए उल्लेख किया है।)

तीसरा और सबसे महत्वपूर्ण बात, CPython कार्यान्वयन के लिए कम से कम, कि क्या जांच करने के लिए है my_functionयह समय के सबसे अधिक खर्च करता है के अंदर या बाहर वैश्विक दुभाषिया ताला , या जीआईएल । यदि जीआईएल के बाहर समय बिताया जाता है, तो threadingमानक पुस्तकालय मॉड्यूल का उपयोग किया जाना चाहिए। ( यहाँ एक उदाहरण है)। बीटीडब्ल्यू, कोई भी जी my_function()एक्सटेंशन जारी करने के लिए सी एक्सटेंशन के रूप में लिखने के बारे में सोच सकता है ।

अंत में, यदि my_function()जीआईएल जारी नहीं करता है , तो कोई multiprocessingमॉड्यूल का उपयोग कर सकता है ।

संदर्भ: समवर्ती निष्पादन पर अजगर डॉक्स और समानांतर प्रसंस्करण पर सुन्न / डरावना इंट्रो


2

आप जूलिया को आजमा सकते हैं। यह पायथन के बहुत करीब है, और बहुत सारे MATLAB निर्माण हैं। यहाँ अनुवाद है:

F = @parallel (vcat) for i in 1:10
    my_function(randn(3))
end

यह यादृच्छिक संख्याओं को समानांतर में भी बनाता है, और कमी के दौरान परिणामों को अंत में संक्षिप्त करता है। यह मल्टीप्रोसेसिंग का उपयोग करता है (इसलिए आपको उपयोग करने से addprocs(N)पहले प्रक्रियाओं को जोड़ने की आवश्यकता है , और यह एचपीसी पर कई नोड्स पर भी काम करता है जैसा कि इस ब्लॉग पोस्ट में दिखाया गया है )।

आप pmapइसके बजाय उपयोग कर सकते हैं :

F = pmap((i)->my_function(randn(3)),1:10)

यदि आप थ्रेड समानता चाहते हैं, तो आप उपयोग कर सकते हैं Threads.@threads(हालांकि सुनिश्चित करें कि आप एल्गोरिथ्म थ्रेड-सुरक्षित बनाते हैं)। जूलिया खोलने से पहले, पर्यावरण चर JULIA_NUM_THREADS सेट करें, फिर यह है:

Ftmp = [Float64[] for i in Threads.nthreads()]
Threads.@threads for i in 1:10
    push!(Ftmp[Threads.threadid()],my_function(randn(3)))
end
F = vcat(Ftmp...)

यहां मैं प्रत्येक थ्रेड के लिए एक अलग सरणी बनाता हूं, इस तरह वे सरणी में जोड़ते समय टकराते नहीं हैं, फिर बाद में सरणियों को संक्षिप्त करें। थ्रेडिंग बहुत नया है इसलिए अभी थ्रेड्स का सीधा उपयोग है, लेकिन मुझे यकीन है कि थ्रेडेड कटौती और मैप्स को उसी तरह जोड़ा जाएगा जैसे यह मल्टीप्रोसेसिंग के लिए था।


0

मैं जॉबलिब लाइब्रेरी के समानांतर और विलंबित कार्यों का उपयोग करने की सलाह देता हूं, विशाल सरणियों के लिए अस्थायी साझा मेमोरी बनाने के लिए "टेम्पोफाइल" मॉड्यूल का उपयोग करें, उदाहरण और उपयोग यहां देखे जा सकते हैं https://pythonhosted.org/joblib/parth.html

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.