মাল্টিপ্রসেসিং: ক্লাসে সংজ্ঞায়িত কোনও ফাংশনে পুল.ম্যাপ কীভাবে ব্যবহার করবেন?


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
"এটি একটি শ্রেণীর ফাংশন হিসাবে"? আপনি কি এমন কোড পোস্ট করতে পারেন যা প্রকৃত ত্রুটি পায় gets আসল কোড ব্যতীত আমরা কেবল অনুমান করতে পারি যে আপনি কী ভুল করছেন।
এস .লট

একটি সাধারণ মন্তব্য হিসাবে, পাইথনের স্ট্যান্ডার্ড আচার মডিউল ( এই উত্তরে উল্লিখিত পিকলাউড মডিউলটির মতো ) থেকে আরও শক্তিশালী পিকিং মডিউল রয়েছে ।
ক্লাউস

1
ক্লোজারে আমার একই রকম সমস্যা ছিল IPython.Parallel, তবে সেখানে আপনি বস্তুগুলিকে নোডে ঠেলা দিয়ে সমস্যাটি পেতে পারেন। মাল্টিপ্রসেসিংয়ের মাধ্যমে এই সমস্যাটি ঘুরে দেখতে বেশ বিরক্তিকর বলে মনে হচ্ছে।
অ্যালেক্স এস

এখানে calculateবাছাইযোগ্য, সুতরাং দেখে মনে হচ্ছে এটি 1) এর মাধ্যমে সমাধান করা যেতে পারে এমন কোনও কনস্ট্রাক্টরের সাথে একটি ফাংশন অবজেক্ট তৈরি করে যা কোনও calculateউদাহরণে অনুলিপি করে এবং তারপরে ২) এই ফাংশনটির কোনও উদাহরণকে Poolএর mapপদ্ধতিতে পাস করে । কোন?
rd11

1
@ তবুও আমি বিশ্বাস করি না পাইথনের "সাম্প্রতিক পরিবর্তনগুলি" কোনওরকম সহায়ক হবে। multiprocessingমডিউলটির কিছু সীমাবদ্ধতা ক্রস-প্ল্যাটফর্মের বাস্তবায়ন হওয়ার লক্ষ্য fork(2)এবং উইন্ডোজটিতে একটি- মত সিস্টেম কলের অভাবের কারণে । আপনি যদি উইন 32 সমর্থন সম্পর্কে চিন্তা না করেন তবে একটি সহজ প্রক্রিয়া-ভিত্তিক কর্মক্ষেত্র হতে পারে। অথবা আপনি কি প্রক্রিয়ার পরিবর্তে থ্রেড ব্যবহার করার জন্য প্রস্তুত করছি, আপনি প্রতিস্থাপন করতে পারেন 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
এটি আমার জন্য খুব ভাল কাজ করেছে, আপনাকে ধন্যবাদ। আমি একটি দুর্বলতা পেয়েছি: আমি কিছু ফাংশনগুলিতে পারম্প্যাপ ব্যবহার করার চেষ্টা করেছি যা একটি ডিফল্টডিক্টিক্টের কাছাকাছি পেরিয়ে যায় এবং আবার পিক্লিংএরর পেয়ে যায়। আমি এর কোনও সমাধান বের করতে পারিনি, আমি ডিফল্টডিক্টিক্টটি ব্যবহার না করার জন্য আমার কোডটি পুনরায় কাজ করেছি।
Sans

2
এটি পাইথন ২.7.২ এ কাজ করে না (ডিফল্ট, জুন 12 ২০১১, 15:08:59) [এমএসসি v.1500 32 বিট (ইন্টেল)] উইন 32
উবারশ্মিকেল

3
এটি পাইথন 2.7.3 আগস্ট 1,2012, 05:14:39 এ কাজ করে। এটি দৈত্য পুনরাবৃত্তকারীগুলিতে কাজ করে না -> এটি একটি ওএসআরারের কারণ ঘটায়: [ত্রুটিযুক্ত 24] পাইপগুলি খোলার সংখ্যার কারণে খুব বেশি ফাইল রয়েছে।
আইরিওওন ভন কাইফ

এই সমাধানটি প্রতিটি কাজের আইটেমের জন্য একটি প্রক্রিয়া তৈরি করে। নীচে "ক্লাউস সে" এর সমাধানটি আরও কার্যকর।
ypnos

85

আমি এখনও পর্যন্ত পোস্ট করা কোডগুলি ব্যবহার করতে পারিনি কারণ "মাল্টিপ্রসেসিং.পুল" ব্যবহার করে কোড ল্যাম্বডা এক্সপ্রেশন এবং "মাল্টিপ্রসেসিং.পুল" ব্যবহার করে না এমন কোডগুলির সাথে কাজ করে না যতগুলি কাজের আইটেম রয়েছে as

আমি এই কোডটি মানিয়ে নিয়েছি এটি একটি পূর্বনির্ধারিত শ্রমিককে উত্সাহ দেয় এবং যদি কোনও নিষ্ক্রিয় কর্মী থাকে তবে কেবল ইনপুট তালিকার মাধ্যমে পুনরাবৃত্তি হয়। প্রত্যাশা অনুযায়ী সেন্ট সিটিআরএল-সি কর্মীদের জন্য আমি "ডিমন" মোডটি সক্ষম করেছিলাম।

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
@ ক্লাউস-সে জানি আমি মন্তব্যগুলিতে ধন্যবাদ জানাতে নিরুৎসাহিত হয়েছি, তবে আপনার উত্তর আমার পক্ষে খুব মূল্যবান, আমি প্রতিরোধ করতে পারিনি। আমি আশা করি আমি আপনাকে কেবল একটি খ্যাতির চেয়ে বেশি দিতে পারব ...
দেশ

2
(None, None)শেষ আইটেম হিসাবে @ গ্রেওল পাশ করা ইঙ্গিত দেয় funযে এটি প্রতিটি প্রক্রিয়াটির জন্য আইটেমগুলির ক্রম শেষে পৌঁছেছে।
aganders3

4
@deshtop: একটি খয়রাত সঙ্গে আপনি করতে পারেন, আপনার যদি যথেষ্ট খ্যাতি আছে নিজেকে :-)
মার্ক

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/ সমান্তরালতা- এবং- সামরিকীকরণ

এমনকি আপনি প্রাথমিকভাবে সংশোধন ছাড়াই এবং দোভাষীর কাছ থেকে কোড লিখেছেন। কেন আরও কিছু যে এর চেয়ে ভঙ্গুর এবং একক ক্ষেত্রে সুনির্দিষ্ট?

>>> 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
পথোস.মલ્ટিয়াপ্রসেসিংয়ে একটি অ্যাসিনক্রোনাস ম্যাপ ( amap) থাকে যা একটি অগ্রগতি বার এবং অন্যান্য অ্যাসিনক্রোনাস প্রোগ্রামিংয়ের ব্যবহারকে সক্ষম করে।
মাইক ম্যাকার্নস

আমি প্যাথোস.মল্টিপ্রসেসিং পছন্দ করি, যা মাল্টিপ্রসেসিং উপভোগ করার সময় অ সমান্তরাল মানচিত্রের প্রায় একটি ড্রপ-ইন প্রতিস্থাপন পরিবেশন করতে পারে। আমার কাছে প্যাথোস.মল্টিপ্রসেসিং.ম্যাপের একটি সহজ মোড়ক রয়েছে, যেমন একাধিক কোর জুড়ে কেবলমাত্র পঠনযোগ্য বড় ডেটা কাঠামো প্রক্রিয়াকরণ করার সময় এটি আরও মেমরি-দক্ষ হয়, এই গিট সংগ্রহস্থলটি দেখুন
ফ্যাস্যাণ্ডেজ

আকর্ষণীয় বলে মনে হচ্ছে তবে এটি ইনস্টল হয় না। এই বার্তাটি Could not find a version that satisfies the requirement pp==1.5.7-pathos (from pathos)
পাইপ

1
হ্যাঁ. আমি কার্যকারিতাটি পৃথক প্যাকেজগুলিতে বিভক্ত করে এবং 2/3 সামঞ্জস্যপূর্ণ কোডে রূপান্তর করায় আমি কিছুক্ষণের মধ্যে মুক্তি পাইনি। উপরের বেশিরভাগটি মোডুলারাইজ করা হয়েছে multiprocessযা 2/3 সামঞ্জস্যপূর্ণ। দেখুন stackoverflow.com/questions/27873093/... এবং pypi.python.org/pypi/multiprocess
মাইক ম্যাকার্নস

3
@ এক্স অ্যাপল: ঠিক ফলো-আপ হিসাবে, 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, যাতে পিইপি 8 অনুসরণ করা যায় । :)


18

মুরোল দ্বারা সমাধানটি সঠিক তবে এতে একটি ত্রুটি রয়েছে: যদি শিশুটি প্রচুর পরিমাণে ডেটা ফেরত পাঠায় তবে এটি পাইপের বাফারটি পূরণ করতে পারে, বাচ্চাকে আটকে দিতে পারে 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)  

আমার একই ক্লাসের মধ্য থেকে পুল.ম্যাপ () কলটিতে সেলফ.এফ ফাংশনটি ব্যবহার করা দরকার এবং সেলফ.এফ একটি আর্গুমেন্ট হিসাবে টুপল নেয় নি। যেহেতু এই ফাংশনটি কোনও শ্রেণিতে এম্বেড করা ছিল, তাই অন্যান্য উত্তরগুলির প্রস্তাবিত মোড়কের ধরণটি কীভাবে লিখবেন তা আমার কাছে পরিষ্কার ছিল না।

আমি একটি ভিন্ন র‍্যাপার ব্যবহার করে এই সমস্যার সমাধান করেছি যা একটি টুপল / তালিকা গ্রহণ করে, যেখানে প্রথম উপাদানটি ফাংশন হয় এবং বাকী উপাদানগুলি সেই ফাংশনের আর্গুমেন্ট, যাকে ইভাল_ফানস_টুপল (f_args) বলা হয়। এটি ব্যবহার করে, সমস্যাযুক্ত লাইনটি রিটার্ন পুল.ম্যাপ (ইভাল_ফানক_টুপল, আইটারটোউলস আইজিপ (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:])  

ফাইল: main.py

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 কীওয়ার্ড আর্গুমেন্টগুলি গ্রহণের জন্যও পরিবর্তন করা যেতে পারে।

অন্য একটি নোটে, অন্য উত্তরে, "পারম্প্যাপ" ফাংশনটি উপলব্ধ সিপিইউর সংখ্যার চেয়ে বেশি প্রসেসির ক্ষেত্রে আরও দক্ষ করা যায়। আমি নীচে সম্পাদিত সংস্করণটি অনুলিপি করছি। এটি আমার প্রথম পোস্ট এবং আমি নিশ্চিত না যে আমার সরাসরি উত্তরটি সম্পাদনা করতে হবে কিনা I আমি কিছু ভেরিয়েবলের নামও দিয়েছি।

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

আমি ক্লাউস সে এবং অ্যাগান্ডার 3 এর উত্তর নিয়েছি এবং একটি ডকুমেন্টেড মডিউল তৈরি করেছি যা আরও পঠনযোগ্য এবং একটি ফাইলে ধারণ করে। আপনি এটি কেবল আপনার প্রকল্পে যুক্ত করতে পারেন। এমনকি এটি একটি alচ্ছিক অগ্রগতি বার আছে!

"""
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

সম্পাদনা : যোগ করা @ আলেকজান্ডার-এমসিফার্লেন পরামর্শ এবং একটি পরীক্ষা ফাংশন


আপনার অগ্রগতি বারের সাথে একটি সমস্যা ... বারটি কেবলমাত্র কার্যক্ষমতার প্রসেসরের মধ্যে কীভাবে অবিচ্ছিন্নভাবে ওয়ার্ক লোড বিভক্ত হয়েছিল তা পরিমাপ করে। যদি কাজের চাপটি পুরোপুরি বিভক্ত হয় তবে সমস্ত প্রসেসর join()একই সাথে আসবে এবং আপনি কেবল ডিসপ্লেতে 100%সম্পূর্ণ ফ্ল্যাশ পাবেন tqdm। কেবলমাত্র এটি কার্যকর হবে যদি প্রতিটি প্রসেসরের একটি পক্ষপাতদুষ্ট কাজের চাপ থাকে
আলেকজান্ডার ম্যাকফারলেন

1
tqdm()লাইনটি মোড়ানোর জন্য সরানো : result = [q_out.get() for _ in tqdm(sent)]এবং এটি অনেক বেশি ভাল কাজ করে - দুর্দান্ত প্রচেষ্টা যদিও সত্যই এটির এত প্রশংসা করে +1
আলেকজান্ডার ম্যাকফারলেন

সেই পরামর্শের জন্য ধন্যবাদ, আমি এটি চেষ্টা করব এবং তারপরে উত্তরটি আপডেট করব!
x অ্যাপল

উত্তর আপডেট হয়েছে, এবং অগ্রগতি বার আরও ভাল কাজ করে!
এক্সপ্লেল

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
@ মেমোজ: "ক্লাসটির প্রয়োজনীয় সমস্ত বান্ডিল করা উচিত" সত্যিই? এর অনেক উদাহরণ আমি পাই না। বেশিরভাগ ক্লাস অন্যান্য ক্লাস বা ফাংশনের উপর নির্ভর করে। কোনও শ্রেণি নির্ভরতা "নোংরা" কেন? নির্ভরতা নিয়ে কী ভুল?
এস .লট

ঠিক আছে, ফাংশনটি বিদ্যমান বর্গের ডেটা সংশোধন করা উচিত নয় - কারণ এটি অন্যান্য প্রক্রিয়াতে সংস্করণটি সংশোধন করবে - সুতরাং এটি একটি স্থির পদ্ধতি হতে পারে। আপনি একটি স্ট্যাটিক পদ্ধতিতে আচার বাছাই করতে পারেন: 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()

পাইথন ৩.7.৩ এ পরীক্ষিত


3

আমি ক্লাউস সে এর পদ্ধতিটি সংশোধন করেছি কারণ এটি যখন ছোট তালিকা দিয়ে আমার জন্য কাজ করছিল তখন আইটেমের সংখ্যা ~ 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]

আমি উপরের কোডটি পাইথন ৩.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

পাইথন 3-তে মাল্টিপ্রসেসিং পুলটি ব্যবহার করার জন্য আমি এখানে লিখেছিলাম এমন একটি বয়লারপ্লেট রয়েছে, বিশেষত পরীক্ষাগুলি চালাতে পাইথন ৩..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আসলে আমার জন্য সবচেয়ে খারাপ কাজ করা বলে মনে হচ্ছে। আপনার কেসটি চেষ্টা করে দেখুন এবং আপনি যে মেশিনটি চালানোর পরিকল্পনা করছেন তাতে এটি বেঞ্চমার্ক করুন। এছাড়াও উপর পড়তে প্রক্রিয়া পুল । চিয়ার্স!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.