मल्टीप्रोसेसिंग: किसी वर्ग में परिभाषित फ़ंक्शन पर पूल.मैप का उपयोग कैसे करें?


179

जब मैं कुछ चलाता हूं:

from multiprocessing import Pool

p = Pool(5)
def f(x):
     return x*x

p.map(f, [1,2,3])

यह बढ़िया काम करता है। हालाँकि, इसे एक वर्ग के कार्य के रूप में रखा जाता है:

class calculate(object):
    def run(self):
        def f(x):
            return x*x

        p = Pool()
        return p.map(f, [1,2,3])

cl = calculate()
print cl.run()

मुझे निम्नलिखित त्रुटि देता है:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/sw/lib/python2.6/threading.py", line 532, in __bootstrap_inner
    self.run()
  File "/sw/lib/python2.6/threading.py", line 484, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/sw/lib/python2.6/multiprocessing/pool.py", line 225, in _handle_tasks
    put(task)
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed

मैंने एलेक्स मार्टेली की एक पोस्ट को उसी तरह की समस्या से निपटने के लिए देखा है, लेकिन यह स्पष्ट रूप से पर्याप्त नहीं था।


1
"यह एक वर्ग के एक समारोह के रूप में"? क्या आप उस कोड को पोस्ट कर सकते हैं जो वास्तव में वास्तविक त्रुटि प्राप्त करता है। वास्तविक कोड के बिना हम केवल अनुमान लगा सकते हैं कि आप क्या गलत कर रहे हैं।
S.Lott

एक सामान्य टिप्पणी के रूप में, पायथन के अचार के मानक अचार की तुलना में अधिक शक्तिशाली अचार वाले मॉड्यूल मौजूद हैं (जैसे कि इस उत्तर में उल्लिखित पिकॉलॉड मॉड्यूल )।
klaus se

1
मुझे क्लोज़र में समान समस्या थी IPython.Parallel, लेकिन वहां आप ऑब्जेक्ट्स को नोड्स पर धकेलकर समस्या के आसपास पहुंच सकते हैं। मल्टीप्रोसेसिंग के साथ इस समस्या को प्राप्त करना बहुत कष्टप्रद लगता है।
एलेक्स एस

यहाँ calculate, picklable है, इसलिए यह) यह 1 से हल किया जा सकता की तरह लगता है एक निर्माता है कि एक से अधिक प्रतियों के साथ एक समारोह वस्तु बनाने calculateउदाहरण और उसके बाद 2) को यह समारोह वस्तु का एक उदाहरण से गुजर रहा Poolहै mapविधि। नहीं?
rd11

1
@ मुझे विश्वास नहीं है कि पायथन के "हाल के परिवर्तनों" में से कोई भी मदद करने जा रहा है। multiprocessingमॉड्यूल की कुछ सीमाएं क्रॉस-प्लेटफॉर्म कार्यान्वयन और fork(2)विंडोज में एक समान सिस्टम कॉल की कमी के अपने लक्ष्य के कारण हैं । यदि आप Win32 समर्थन की परवाह नहीं करते हैं, तो एक सरल प्रक्रिया-आधारित समाधान हो सकता है। या यदि आप प्रक्रियाओं के बजाय थ्रेड्स का उपयोग करने के लिए तैयार हैं, तो आप के from multiprocessing import Poolसाथ स्थानापन्न कर सकते हैं from multiprocessing.pool import ThreadPool as Pool
आया

जवाबों:


69

मैं इस बात से भी नाराज था कि पूल किस तरह का कार्य स्वीकार कर सकता है। मैंने इसे दरकिनार करने के लिए निम्नलिखित लिखा था। यह काम करने के लिए प्रकट होता है, यहां तक ​​कि पर्माप के पुनरावर्ती उपयोग के लिए भी।

from multiprocessing import Process, Pipe
from itertools import izip

def spawn(f):
    def fun(pipe, x):
        pipe.send(f(x))
        pipe.close()
    return fun

def parmap(f, X):
    pipe = [Pipe() for x in X]
    proc = [Process(target=spawn(f), args=(c, x)) for x, (p, c) in izip(X, pipe)]
    [p.start() for p in proc]
    [p.join() for p in proc]
    return [p.recv() for (p, c) in pipe]

if __name__ == '__main__':
    print parmap(lambda x: x**x, range(1, 5))

1
इसने मेरे लिए बहुत अच्छा काम किया है, धन्यवाद। मुझे एक कमजोरी मिली है: मैंने कुछ कार्यों पर पर्मप का उपयोग करने की कोशिश की जो कि एक डिफॉल्ट के आसपास से गुजरे और उन्हें फिर से पिकलिंग एअरर मिला। मैंने इसका हल नहीं निकाला, मैंने केवल डिफ़ॉल्ट कोड का उपयोग नहीं करने के लिए अपने कोड को फिर से काम किया।
बिना

2
यह पायथन 2.7.2 में काम नहीं करता है (डिफ़ॉल्ट, जून 12 2011, 15:08:59) [MSC v.1500 32 बिट (इंटेल)] win32 पर
ubershmekel

3
यह पायथन 2.7.3 अगस्त 1,2012, 05:14:39 पर काम करता है। यह विशाल पुनरावृत्तियों पर काम नहीं करता है -> यह एक OSError का कारण बनता है: [Errno 24] पाइप की संख्या के कारण बहुत सारी खुली हुई फाइलें इसे खोलता है।
एरियोउर वॉन कौयफ

यह समाधान प्रत्येक कार्य आइटम के लिए एक प्रक्रिया पैदा करता है। नीचे "klaus se" का समाधान अधिक कुशल है।
य्पनोस

85

मैं अब तक पोस्ट किए गए कोड का उपयोग नहीं कर सका क्योंकि "मल्टीप्रोसेसिंग।पूल" का उपयोग करने वाले कोड लैम्ब्डा एक्सप्रेशन के साथ काम नहीं करते हैं और कोड "मल्टीप्रोसेसिंग।पूल" स्पॉन का उपयोग नहीं करते हैं क्योंकि कई प्रक्रियाएं हैं क्योंकि कार्य आइटम हैं।

मैंने कोड को अनुकूलित किया है कि यह श्रमिकों की पूर्वनिर्धारित राशि को जन्म देता है और केवल एक निष्क्रिय कार्यकर्ता मौजूद होने पर इनपुट सूची के माध्यम से पुनरावृत्त करता है। मैंने मजदूरों के लिए "डेमॉन" मोड को भी सक्षम किया ctrl-c काम करता है।

import multiprocessing


def fun(f, q_in, q_out):
    while True:
        i, x = q_in.get()
        if i is None:
            break
        q_out.put((i, f(x)))


def parmap(f, X, nprocs=multiprocessing.cpu_count()):
    q_in = multiprocessing.Queue(1)
    q_out = multiprocessing.Queue()

    proc = [multiprocessing.Process(target=fun, args=(f, q_in, q_out))
            for _ in range(nprocs)]
    for p in proc:
        p.daemon = True
        p.start()

    sent = [q_in.put((i, x)) for i, x in enumerate(X)]
    [q_in.put((None, None)) for _ in range(nprocs)]
    res = [q_out.get() for _ in range(len(sent))]

    [p.join() for p in proc]

    return [x for i, x in sorted(res)]


if __name__ == '__main__':
    print(parmap(lambda i: i * 2, [1, 2, 3, 4, 6, 7, 8]))

2
इस parmapफ़ंक्शन के साथ ठीक से काम करने के लिए आपको प्रगति पट्टी कैसे मिलेगी ?
झटकेदार

2
एक प्रश्न - मैंने इस समाधान का उपयोग किया लेकिन ध्यान दिया कि मैंने जो अजगर प्रक्रियाएँ शुरू कीं, वे स्मृति में सक्रिय रहीं। किसी भी त्वरित सोचा कि कैसे उन लोगों को मारने के लिए जब आपका परमपद बाहर निकलता है?
कॉम्पेंकॉन

1
@ klaus-se मुझे पता है कि हम टिप्पणियों में धन्यवाद कहने से हतोत्साहित हैं, लेकिन आपका जवाब मेरे लिए बहुत मूल्यवान है, मैं इसका विरोध नहीं कर सकता। काश मैं तुम्हें सिर्फ एक प्रतिष्ठा से अधिक दे सकता ...
deshtop

2
@greole (None, None)अंतिम आइटम के रूप में गुजरना इंगित करता है funकि यह प्रत्येक प्रक्रिया के लिए आइटम के अनुक्रम के अंत तक पहुंच गया है।
aganders3

4
@ डेशटॉप: यदि आप अपने आप में पर्याप्त प्रतिष्ठा रखते हैं, तो आप एक इनाम के साथ कर सकते हैं :-)
मार्क

57

मल्टीप्रोसेसिंग और अचार बनाना टूट गया है और सीमित है जब तक आप मानक पुस्तकालय के बाहर कूदते नहीं हैं।

यदि आप multiprocessingकहा जाता है की एक कांटा का उपयोग करें pathos.multiprocesssing, आप सीधे वर्गों और वर्ग विधियों का उपयोग मल्टीप्रोसेसिंग के mapकार्यों में कर सकते हैं। इसका कारण यह है है dillके बजाय प्रयोग किया जाता है pickleया cPickle, और dillअजगर में लगभग कुछ भी क्रमानुसार कर सकते हैं।

pathos.multiprocessingएक अतुल्यकालिक मानचित्र फ़ंक्शन भी प्रदान करता है ... और यह mapकई तर्कों (जैसे map(math.pow, [1,2,3], [4,5,6])) के साथ कार्य कर सकता है

चर्चा देखें: बहुक्रिया और डिल एक साथ क्या कर सकते हैं?

और: http://matthewrocklin.com/blog/work/2013/12/05/Parallelism-and-Serialization

यहां तक ​​कि यह आपके द्वारा शुरू किए गए कोड को भी संशोधित किए बिना और दुभाषिया से संभालता है। किसी भी मामले में और अधिक नाजुक और विशिष्ट क्यों है?

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> class calculate(object):
...  def run(self):
...   def f(x):
...    return x*x
...   p = Pool()
...   return p.map(f, [1,2,3])
... 
>>> cl = calculate()
>>> print cl.run()
[1, 4, 9]

यहां कोड प्राप्त करें: https://github.com/uqfoundation/pathos

और, बस यह दिखाने के लिए कि वह क्या कर सकता है:

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> 
>>> p = Pool(4)
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> x = [0,1,2,3]
>>> y = [4,5,6,7]
>>> 
>>> p.map(add, x, y)
[4, 6, 8, 10]
>>> 
>>> class Test(object):
...   def plus(self, x, y): 
...     return x+y
... 
>>> t = Test()
>>> 
>>> p.map(Test.plus, [t]*4, x, y)
[4, 6, 8, 10]
>>> 
>>> res = p.amap(t.plus, x, y)
>>> res.get()
[4, 6, 8, 10]

1
pathos.multiprocessing में एक एसिंक्रोनस मैप ( amap) भी है जो एक प्रगति बार और अन्य एसिंक्रोनस प्रोग्रामिंग के उपयोग को सक्षम करता है।
माइक मैककर्न्स

मुझे pathos.multiprocessing पसंद है, जो मल्टीप्रोसेसिंग का आनंद लेते हुए गैर-समानांतर मानचित्र के लगभग एक ड्रॉप-इन प्रतिस्थापन की सेवा कर सकता है। मेरे पास pathos.multiprocessing.map का एक सरल आवरण है, जैसे कि यह अधिक स्मृति-कुशल है जब कई कोर में एक रीड-ओनली बड़े डेटा संरचना को संसाधित करते हुए, यह गिट रिपॉजिटरी देखें
फस्चेंज

दिलचस्प लगता है, लेकिन यह स्थापित नहीं करता है। यह संदेश पाइप देता है:Could not find a version that satisfies the requirement pp==1.5.7-pathos (from pathos)
xApple

1
हाँ। मैंने थोड़ी देर में जारी नहीं किया है क्योंकि मैं कार्यक्षमता को अलग-अलग पैकेजों में विभाजित कर रहा हूं, और 2/3 संगत कोड में भी परिवर्तित कर रहा हूं। उपर्युक्त में से अधिकांश को संशोधित किया गया है multiprocessजिसमें 2/3 संगत है। देखें stackoverflow.com/questions/27873093/... और pypi.python.org/pypi/multiprocess
माइक मैककर्न्स

3
@xApple: बस एक अनुवर्ती के रूप में, pathosएक नया स्थिर रिलीज हुआ है और यह भी 2.x और 3.x संगत है।
माइक मैकार्न्स

40

वर्तमान में आपकी समस्या का कोई हल नहीं है, जहां तक ​​मुझे पता है: आपके द्वारा दिया जाने वाला फ़ंक्शन map()आपके मॉड्यूल के आयात के माध्यम से सुलभ होना चाहिए। यही कारण है कि रॉबर्ट का कोड काम करता है: f()निम्नलिखित कोड आयात करके फ़ंक्शन प्राप्त किया जा सकता है:

def f(x):
    return x*x

class Calculate(object):
    def run(self):
        p = Pool()
        return p.map(f, [1,2,3])

if __name__ == '__main__':
    cl = Calculate()
    print cl.run()

मैंने वास्तव में एक "मुख्य" खंड जोड़ा है, क्योंकि यह विंडोज प्लेटफॉर्म के लिए सिफारिशों का पालन ​​करता है ("सुनिश्चित करें कि मुख्य मॉड्यूल को अनपेक्षित साइड इफेक्ट्स के बिना एक नए पायथन दुभाषिया द्वारा सुरक्षित रूप से आयात किया जा सकता है")।

मैंने सामने एक बड़े अक्षर को भी जोड़ा Calculate, ताकि PEP 8 का अनुसरण किया जा सके । :)


18

Mrule द्वारा समाधान सही है, लेकिन इसमें एक बग है: यदि बच्चा बड़ी मात्रा में डेटा वापस भेजता है, तो यह पाइप के बफर को भर सकता है, जिससे बच्चे पर अवरुद्ध हो जाता है pipe.send(), जबकि माता-पिता बच्चे के बाहर निकलने का इंतजार कर रहे हैं pipe.join()। इसका उपाय है कि बच्चे के join()आईएनजी से पहले बच्चे के डेटा को पढ़ें । इसके अलावा बच्चे को गतिरोध को रोकने के लिए पाइप के माता-पिता के अंत को बंद करना चाहिए। नीचे दिए गए कोड को ठीक करता है। यह भी ध्यान रखें कि यह parmapप्रति तत्व में एक प्रक्रिया बनाता है X। एक और अधिक उन्नत समाधान कई संख्याओं में multiprocessing.cpu_count()विभाजित करने के लिए उपयोग करना Xहै, और फिर लौटने से पहले परिणामों को मर्ज करना है। मैं पाठक के लिए एक अभ्यास के रूप में छोड़ देता हूं ताकि मूसल द्वारा अच्छे उत्तर की संक्षिप्तता को खराब न करें। ;)

from multiprocessing import Process, Pipe
from itertools import izip

def spawn(f):
    def fun(ppipe, cpipe,x):
        ppipe.close()
        cpipe.send(f(x))
        cpipe.close()
    return fun

def parmap(f,X):
    pipe=[Pipe() for x in X]
    proc=[Process(target=spawn(f),args=(p,c,x)) for x,(p,c) in izip(X,pipe)]
    [p.start() for p in proc]
    ret = [p.recv() for (p,c) in pipe]
    [p.join() for p in proc]
    return ret

if __name__ == '__main__':
    print parmap(lambda x:x**x,range(1,5))

आप प्रक्रियाओं की संख्या कैसे चुनते हैं?
patapouf_ai

हालांकि यह त्रुटि के कारण बहुत जल्दी मर जाता है OSError: [Errno 24] Too many open files। मुझे लगता है कि इसे ठीक से काम करने के लिए प्रक्रियाओं की संख्या पर कुछ प्रकार की सीमाएं होनी चाहिए ...
patapouf_ai

13

मैंने भी इससे संघर्ष किया है। मेरे पास एक सरल उदाहरण के रूप में एक वर्ग के डेटा सदस्यों के रूप में कार्य थे:

from multiprocessing import Pool
import itertools
pool = Pool()
class Example(object):
    def __init__(self, my_add): 
        self.f = my_add  
    def add_lists(self, list1, list2):
        # Needed to do something like this (the following line won't work)
        return pool.map(self.f,list1,list2)  

मुझे एक ही वर्ग के भीतर से एक पूल.मैप () कॉल में फंक्शन self.f का उपयोग करने की आवश्यकता थी और self.f ने एक तर्क के रूप में एक ट्यूपल नहीं लिया। चूंकि यह फ़ंक्शन एक वर्ग में एम्बेडेड था, इसलिए यह मेरे लिए स्पष्ट नहीं था कि कैसे सुझाए गए अन्य उत्तरों के प्रकार के आवरण को लिखना है।

मैंने एक अलग आवरण का उपयोग करके इस समस्या को हल किया, जो एक टपल / सूची लेता है, जहां पहला तत्व फ़ंक्शन है, और शेष तत्व उस फ़ंक्शन के तर्क हैं, जिन्हें eval_func_tuple (f_args) कहा जाता है। इसका उपयोग करके, समस्याग्रस्त लाइन को रिटर्न पूल.मैप (eval_func_tuple, itertools.izip (itertools.repeat) (self.f), list1, list2) से बदला जा सकता है। यहाँ पूर्ण कोड है:

फ़ाइल: उपयोग

def add(a, b): return a+b

def eval_func_tuple(f_args):
    """Takes a tuple of a function and args, evaluates and returns result"""
    return f_args[0](*f_args[1:])  

फ़ाइल: मेनहोम

from multiprocessing import Pool
import itertools
import util  

pool = Pool()
class Example(object):
    def __init__(self, my_add): 
        self.f = my_add  
    def add_lists(self, list1, list2):
        # The following line will now work
        return pool.map(util.eval_func_tuple, 
            itertools.izip(itertools.repeat(self.f), list1, list2)) 

if __name__ == '__main__':
    myExample = Example(util.add)
    list1 = [1, 2, 3]
    list2 = [10, 20, 30]
    print myExample.add_lists(list1, list2)  

रनिंग मेनफ्रेम [11, 22, 33] देगा। इसे सुधारने के लिए स्वतंत्र महसूस करें, उदाहरण के लिए eval_func_tuple को खोजशब्द तर्क लेने के लिए संशोधित किया जा सकता है।

एक अन्य नोट पर, एक अन्य जवाब में, फ़ंक्शन "पर्माप" सीपीयू की संख्या से अधिक प्रक्रियाओं के मामले के लिए अधिक कुशल बनाया जा सकता है। मैं नीचे एक संपादित संस्करण कॉपी कर रहा हूँ। यह मेरी पहली पोस्ट है और मुझे यकीन नहीं था कि मुझे मूल उत्तर को सीधे संपादित करना चाहिए। मैंने कुछ चरों का नाम भी बदला।

from multiprocessing import Process, Pipe  
from itertools import izip  

def spawn(f):  
    def fun(pipe,x):  
        pipe.send(f(x))  
        pipe.close()  
    return fun  

def parmap(f,X):  
    pipe=[Pipe() for x in X]  
    processes=[Process(target=spawn(f),args=(c,x)) for x,(p,c) in izip(X,pipe)]  
    numProcesses = len(processes)  
    processNum = 0  
    outputList = []  
    while processNum < numProcesses:  
        endProcessNum = min(processNum+multiprocessing.cpu_count(), numProcesses)  
        for proc in processes[processNum:endProcessNum]:  
            proc.start()  
        for proc in processes[processNum:endProcessNum]:  
            proc.join()  
        for proc,c in pipe[processNum:endProcessNum]:  
            outputList.append(proc.recv())  
        processNum = endProcessNum  
    return outputList    

if __name__ == '__main__':  
    print parmap(lambda x:x**x,range(1,5))         

8

मैंने klaus se और aganders3 का उत्तर लिया, और एक दस्तावेज मॉड्यूल बनाया जो अधिक पठनीय है और एक फ़ाइल में है। आप इसे अपने प्रोजेक्ट में जोड़ सकते हैं। यह भी एक वैकल्पिक प्रगति पट्टी है!

"""
The ``processes`` module provides some convenience functions
for using parallel processes in python.

Adapted from http://stackoverflow.com/a/16071616/287297

Example usage:

    print prll_map(lambda i: i * 2, [1, 2, 3, 4, 6, 7, 8], 32, verbose=True)

Comments:

"It spawns a predefined amount of workers and only iterates through the input list
 if there exists an idle worker. I also enabled the "daemon" mode for the workers so
 that KeyboardInterupt works as expected."

Pitfalls: all the stdouts are sent back to the parent stdout, intertwined.

Alternatively, use this fork of multiprocessing: 
https://github.com/uqfoundation/multiprocess
"""

# Modules #
import multiprocessing
from tqdm import tqdm

################################################################################
def apply_function(func_to_apply, queue_in, queue_out):
    while not queue_in.empty():
        num, obj = queue_in.get()
        queue_out.put((num, func_to_apply(obj)))

################################################################################
def prll_map(func_to_apply, items, cpus=None, verbose=False):
    # Number of processes to use #
    if cpus is None: cpus = min(multiprocessing.cpu_count(), 32)
    # Create queues #
    q_in  = multiprocessing.Queue()
    q_out = multiprocessing.Queue()
    # Process list #
    new_proc  = lambda t,a: multiprocessing.Process(target=t, args=a)
    processes = [new_proc(apply_function, (func_to_apply, q_in, q_out)) for x in range(cpus)]
    # Put all the items (objects) in the queue #
    sent = [q_in.put((i, x)) for i, x in enumerate(items)]
    # Start them all #
    for proc in processes:
        proc.daemon = True
        proc.start()
    # Display progress bar or not #
    if verbose:
        results = [q_out.get() for x in tqdm(range(len(sent)))]
    else:
        results = [q_out.get() for x in range(len(sent))]
    # Wait for them to finish #
    for proc in processes: proc.join()
    # Return results #
    return [x for i, x in sorted(results)]

################################################################################
def test():
    def slow_square(x):
        import time
        time.sleep(2)
        return x**2
    objs    = range(20)
    squares = prll_map(slow_square, objs, 4, verbose=True)
    print "Result: %s" % squares

संपादित करें : @ अलेक्जेंडर- mcfarlane सुझाव और एक परीक्षण समारोह जोड़ा गया


आपकी प्रगति बार के साथ एक मुद्दा ... बार केवल मापता है कि कैसे कार्यकुशलता को प्रोसेसर के बीच विभाजित किया गया था। यदि कार्यभार पूरी तरह से विभाजित है, तो सभी प्रोसेसर join()एक ही समय में होंगे और आपको डिस्प्ले 100%में बस पूरा फ्लैश मिलेगा tqdm। केवल तभी उपयोगी होगा जब प्रत्येक प्रोसेसर में एक पक्षपाती कार्यभार हो
अलेक्जेंडर मैकफर्लेन

1
tqdm()लाइन को लपेटने के लिए कदम : result = [q_out.get() for _ in tqdm(sent)]और यह एक बहुत बेहतर काम करता है - महान प्रयास हालांकि वास्तव में इस की सराहना करते हैं +1
अलेक्जेंडर मैकफर्लेन

उस सलाह के लिए धन्यवाद, मैं इसे आज़माऊंगा और फिर उत्तर को अपडेट करूंगा!
xApple

उत्तर अपडेट किया गया है, और प्रगति बार बहुत बेहतर काम करता है!
xApple

8

मुझे पता है कि यह अब से 6 साल पहले पूछा गया था, लेकिन मैं अपना समाधान जोड़ना चाहता था, जैसा कि ऊपर दिए गए सुझावों में से कुछ बहुत ही जटिल हैं, लेकिन मेरा समाधान वास्तव में बहुत सरल था।

मुझे बस इतना करना था कि एक हेल्पर फंक्शन में पूल.मैप () कॉल लपेटें। टगले के रूप में विधि के लिए आर्ग्स के साथ क्लास ऑब्जेक्ट को पास करना, जो इस तरह से थोड़ा सा दिखता था।

def run_in_parallel(args):
    return args[0].method(args[1])

myclass = MyClass()
method_args = [1,2,3,4,5,6]
args_map = [ (myclass, arg) for arg in method_args ]
pool = Pool()
pool.map(run_in_parallel, args_map)

7

कक्षाओं में परिभाषित कार्य (कक्षाओं के भीतर भी कार्य) वास्तव में अचार नहीं करते हैं। हालाँकि, यह काम करता है:

def f(x):
    return x*x

class calculate(object):
    def run(self):
        p = Pool()
    return p.map(f, [1,2,3])

cl = calculate()
print cl.run()

15
धन्यवाद, लेकिन मुझे यह वर्ग के बाहर फ़ंक्शन को परिभाषित करने के लिए थोड़ा गंदा लगता है। कक्षा को किसी दिए गए कार्य को प्राप्त करने के लिए सभी को बंडल करना चाहिए।
मर्मोज़ जूल

3
@ मिमोज़: "क्लास को अपनी ज़रूरत के हिसाब से बंडल करना चाहिए" रियली? मुझे इसके कई उदाहरण नहीं मिल रहे हैं। अधिकांश कक्षाएं अन्य वर्गों या कार्यों पर निर्भर करती हैं। एक वर्ग की निर्भरता को "गंदा" क्यों कहते हैं? एक निर्भरता के साथ क्या गलत है?
S.Lott

खैर, फ़ंक्शन को मौजूदा वर्ग डेटा को संशोधित नहीं करना चाहिए - क्योंकि यह अन्य प्रक्रिया में संस्करण को संशोधित करेगा - इसलिए यह एक स्थिर विधि हो सकती है। आप अचार को एक स्थिर विधि से बना सकते हैं: stackoverflow.com/questions/1914261/… या, इस तुच्छ चीज़ के लिए, आप एक लैम्ब्डा का उपयोग कर सकते हैं।
रॉबर्ट

6

मुझे पता है कि यह सवाल 8 साल और 10 महीने पहले पूछा गया था, लेकिन मैं आपको अपना समाधान पेश करना चाहता हूं:

from multiprocessing import Pool

class Test:

    def __init__(self):
        self.main()

    @staticmethod
    def methodForMultiprocessing(x):
        print(x*x)

    def main(self):
        if __name__ == "__main__":
            p = Pool()
            p.map(Test.methodForMultiprocessing, list(range(1, 11)))
            p.close()

TestObject = Test()

आपको बस अपने क्लास फंक्शन को स्टैटिक मेथड बनाने की जरूरत है। लेकिन यह एक वर्ग विधि के साथ भी संभव है:

from multiprocessing import Pool

class Test:

    def __init__(self):
        self.main()

    @classmethod
    def methodForMultiprocessing(cls, x):
        print(x*x)

    def main(self):
        if __name__ == "__main__":
            p = Pool()
            p.map(Test.methodForMultiprocessing, list(range(1, 11)))
            p.close()

TestObject = Test()

पायथन 3.7.3 में परीक्षण किया गया


3

मैंने klaus se की विधि को संशोधित किया क्योंकि यह मेरे लिए छोटी सूचियों के साथ काम कर रहा था, यह तब लटका होगा जब वस्तुओं की संख्या ~ 1000 या उससे अधिक थी। Noneरुकने की स्थिति के साथ एक समय में नौकरियों को धकेलने के बजाय , मैं इनपुट कतार को एक ही बार में लोड करता हूं और बस खाली होने तक प्रक्रियाओं को उस पर कुतरने देता हूं।

from multiprocessing import cpu_count, Queue, Process

def apply_func(f, q_in, q_out):
    while not q_in.empty():
        i, x = q_in.get()
        q_out.put((i, f(x)))

# map a function using a pool of processes
def parmap(f, X, nprocs = cpu_count()):
    q_in, q_out   = Queue(), Queue()
    proc = [Process(target=apply_func, args=(f, q_in, q_out)) for _ in range(nprocs)]
    sent = [q_in.put((i, x)) for i, x in enumerate(X)]
    [p.start() for p in proc]
    res = [q_out.get() for _ in sent]
    [p.join() for p in proc]

    return [x for i,x in sorted(res)]

संपादित करें: दुर्भाग्य से अब मैं अपने सिस्टम पर इस त्रुटि में चल रहा हूं: मल्टीप्रोसेसिंग कतार अधिकतम सीमा 32767 है , उम्मीद है कि वहां काम करने वाले कर्मचारी मदद करेंगे।


1

आप किसी भी मुद्दे के बिना अपना कोड चला सकते हैं यदि आप किसी भी तरह से Poolऑब्जेक्ट को क्लास में ऑब्जेक्ट की सूची से मैन्युअल रूप से अनदेखा करते हैं क्योंकि यह pickleसक्षम नहीं है जैसा कि त्रुटि कहती है। आप इसे फॉलो के साथ __getstate__फंक्शन ( यहां भी देखें) के साथ कर सकते हैं । Poolवस्तु की तलाश करेगा __getstate__और __setstate__कार्य करता है और अगर यह यह पाता है जब आप चलाने के लिए उन्हें अमल map, map_asyncआदि:

class calculate(object):
    def __init__(self):
        self.p = Pool()
    def __getstate__(self):
        self_dict = self.__dict__.copy()
        del self_dict['p']
        return self_dict
    def __setstate__(self, state):
        self.__dict__.update(state)

    def f(self, x):
        return x*x
    def run(self):
        return self.p.map(self.f, [1,2,3])

फिर करो:

cl = calculate()
cl.run()

आप उत्पादन देंगे:

[1, 4, 9]

मैंने पायथन 3.x में उपरोक्त कोड का परीक्षण किया है और यह काम करता है।


0

मुझे यकीन नहीं है कि अगर यह दृष्टिकोण लिया गया है, लेकिन मैं एक काम कर रहा हूं जिसका उपयोग कर रहा हूं:

from multiprocessing import Pool

t = None

def run(n):
    return t.f(n)

class Test(object):
    def __init__(self, number):
        self.number = number

    def f(self, x):
        print x * self.number

    def pool(self):
        pool = Pool(2)
        pool.map(run, range(10))

if __name__ == '__main__':
    t = Test(9)
    t.pool()
    pool = Pool(2)
    pool.map(run, range(10))

आउटपुट होना चाहिए:

0
9
18
27
36
45
54
63
72
81
0
9
18
27
36
45
54
63
72
81

0
class Calculate(object):
  # Your instance method to be executed
  def f(self, x, y):
    return x*y

if __name__ == '__main__':
  inp_list = [1,2,3]
  y = 2
  cal_obj = Calculate()
  pool = Pool(2)
  results = pool.map(lambda x: cal_obj.f(x, y), inp_list)

एक संभावना है कि आप इस फ़ंक्शन को कक्षा के प्रत्येक भिन्न उदाहरण के लिए लागू करना चाहेंगे। फिर यहाँ भी उस के लिए समाधान है

class Calculate(object):
  # Your instance method to be executed
  def __init__(self, x):
    self.x = x

  def f(self, y):
    return self.x*y

if __name__ == '__main__':
  inp_list = [Calculate(i) for i in range(3)]
  y = 2
  pool = Pool(2)
  results = pool.map(lambda x: x.f(y), inp_list)

0

यहां मेरा समाधान है, जो मुझे लगता है कि यहां अन्य लोगों की तुलना में थोड़ा कम हैकिश है। यह रात्रिभोज के उत्तर के समान है।

someclasses = [MyClass(), MyClass(), MyClass()]

def method_caller(some_object, some_method='the method'):
    return getattr(some_object, some_method)()

othermethod = partial(method_caller, some_method='othermethod')

with Pool(6) as pool:
    result = pool.map(othermethod, someclasses)

0

से http://www.rueckstiess.net/research/snippets/show/ca1d7d90 और http://qingkaikong.blogspot.com/2016/12/python-parallel-method-in-class.html

हम एक बाहरी कार्य कर सकते हैं और इसे कक्षा स्व ऑब्जेक्ट के साथ बीज कर सकते हैं:

from joblib import Parallel, delayed
def unwrap_self(arg, **kwarg):
    return square_class.square_int(*arg, **kwarg)

class square_class:
    def square_int(self, i):
        return i * i

    def run(self, num):
        results = []
        results = Parallel(n_jobs= -1, backend="threading")\
            (delayed(unwrap_self)(i) for i in zip([self]*len(num), num))
        print(results)

या जॉबलीब के बिना:

from multiprocessing import Pool
import time

def unwrap_self_f(arg, **kwarg):
    return C.f(*arg, **kwarg)

class C:
    def f(self, name):
        print 'hello %s,'%name
        time.sleep(5)
        print 'nice to meet you.'

    def run(self):
        pool = Pool(processes=2)
        names = ('frank', 'justin', 'osi', 'thomas')
        pool.map(unwrap_self_f, zip([self]*len(names), names))

if __name__ == '__main__':
    c = C()
    c.run()

0

यह एक बहुत अच्छा समाधान नहीं हो सकता है लेकिन मेरे मामले में, मैं इसे इस तरह से हल करता हूं।

from multiprocessing import Pool

def foo1(data):
    self = data.get('slf')
    lst = data.get('lst')
    return sum(lst) + self.foo2()

class Foo(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def foo2(self):
        return self.a**self.b   

    def foo(self):
        p = Pool(5)
        lst = [1, 2, 3]
        result = p.map(foo1, (dict(slf=self, lst=lst),))
        return result

if __name__ == '__main__':
    print(Foo(2, 4).foo())

मुझे selfअपने फंक्शन में पास होना था क्योंकि मुझे उस फंक्शन के माध्यम से अपनी क्लास की विशेषताओं और कार्यों को एक्सेस करना है। यह मेरे लिए काम कर रहा है। सुधार और सुझावों का हमेशा स्वागत है।


0

यहाँ एक बॉयलरप्लेट है जिसे मैंने python3 में मल्टीप्रोसेसिंग पूल का उपयोग करने के लिए लिखा था, विशेष रूप से python3.7.7 का उपयोग परीक्षणों को चलाने के लिए किया गया था। मैंने अपने सबसे तेज़ रन का उपयोग किया imap_unordered। बस अपने परिदृश्य में प्लग करें और इसे आज़माएं। आप उपयोग कर सकते हैं timeitया केवल time.time()यह पता लगाने के लिए कि आपके लिए सबसे अच्छा कौन सा काम करता है।

import multiprocessing
import time

NUMBER_OF_PROCESSES = multiprocessing.cpu_count()
MP_FUNCTION = 'starmap'  # 'imap_unordered' or 'starmap' or 'apply_async'

def process_chunk(a_chunk):
    print(f"processig mp chunk {a_chunk}")
    return a_chunk


map_jobs = [1, 2, 3, 4]

result_sum = 0

s = time.time()
if MP_FUNCTION == 'imap_unordered':
    pool = multiprocessing.Pool(processes=NUMBER_OF_PROCESSES)
    for i in pool.imap_unordered(process_chunk, map_jobs):
        result_sum += i
elif MP_FUNCTION == 'starmap':
    pool = multiprocessing.Pool(processes=NUMBER_OF_PROCESSES)
    try:
        map_jobs = [(i, ) for i in map_jobs]
        result_sum = pool.starmap(process_chunk, map_jobs)
        result_sum = sum(result_sum)
    finally:
        pool.close()
        pool.join()
elif MP_FUNCTION == 'apply_async':
    with multiprocessing.Pool(processes=NUMBER_OF_PROCESSES) as pool:
        result_sum = [pool.apply_async(process_chunk, [i, ]).get() for i in map_jobs]
    result_sum = sum(result_sum)
print(f"result_sum is {result_sum}, took {time.time() - s}s")

उपरोक्त परिदृश्य में imap_unorderedवास्तव में मेरे लिए सबसे खराब प्रदर्शन होता है। अपने मामले को आज़माएं और उस मशीन पर बेंचमार्क करें जिसे आप इसे चलाने की योजना बनाते हैं। प्रोसेस पूल पर भी पढ़ें । चीयर्स!

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