পাইথন মাল্টিপ্রসেসিং পুলের ইমপাম_অনর্ডার্ড কলটির অগ্রগতি দেখান?


100

আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা imap_unordered()কল সহ সফলভাবে একটি মাল্টিপ্রসেসিং পুলের কাজগুলির সেট করে :

p = multiprocessing.Pool()
rs = p.imap_unordered(do_work, xrange(num_tasks))
p.close() # No more work
p.join() # Wait for completion

যাইহোক, আমার num_tasksপ্রায় 250,000, এবং তাই join()10 সেকেন্ড বা তার বেশি সময়ের জন্য মূল থ্রেডটি লক হয়ে যায় এবং আমি প্রধান প্রক্রিয়াটি লক না থাকা দেখানোর জন্য ক্রমবর্ধমানভাবে কমান্ড লাইনে প্রতিধ্বনিত করতে সক্ষম হতে চাই। কিছুটা এইরকম:

p = multiprocessing.Pool()
rs = p.imap_unordered(do_work, xrange(num_tasks))
p.close() # No more work
while (True):
  remaining = rs.tasks_remaining() # How many of the map call haven't been done yet?
  if (remaining == 0): break # Jump out of while loop
  print "Waiting for", remaining, "tasks to complete..."
  time.sleep(2)

ফলাফল অবজেক্টের জন্য বা পুলে নিজেই কোনও পদ্ধতি রয়েছে যা বাকি কাজগুলির সংখ্যা নির্দেশ করে? আমি কোনও multiprocessing.Valueঅবজেক্টকে কাউন্টার হিসাবে ব্যবহার করার চেষ্টা করেছি ( এর কাজটি করার পরে do_workএকটি counter.value += 1ক্রিয়া কল করে ), তবে কাউন্টারটি বাড়ানো বন্ধ করার আগে মোট মূল্যের ~ 85% হয়ে যায়।

উত্তর:


83

ফলাফল সেটটির ব্যক্তিগত বৈশিষ্ট্য অ্যাক্সেস করার দরকার নেই:

from __future__ import division
import sys

for i, _ in enumerate(p.imap_unordered(do_work, xrange(num_tasks)), 1):
    sys.stderr.write('\rdone {0:%}'.format(i/num_tasks))

7
আমি কোড প্রস্থান করার পরেই প্রিন্ট আউট দেখতে পাই (প্রতিটি পুনরাবৃত্তি নয়)। তোমার কি কোন পরামর্শ আছে?
হানান শিটইনার্ট

@ হানানশটইনার্ট: পাইথন 2 এবং 3 উভয়ের সাথে এটি আমার সিস্টেমে (উবুন্টু) ভাল কাজ করে I've আমি def do_word(*a): time.sleep(.1)উদাহরণ হিসাবে ব্যবহার করেছি । যদি এটি আপনার পক্ষে কাজ করে না তবে একটি সম্পূর্ণ ন্যূনতম কোড উদাহরণ তৈরি করুন যা আপনার সমস্যাটি দেখায়: আপনি কী প্রত্যাশা করবেন এবং তার পরিবর্তে কী ঘটবে সেগুলি ব্যবহার করে বর্ণনা করুন, কীভাবে আপনি আপনার পাইথন স্ক্রিপ্টটি চালাবেন, আপনার ওএস, পাইথন সংস্করণটি কী এবং এটি একটি নতুন প্রশ্ন হিসাবে পোস্ট করুন
jfs

15
আমার @ হানানশটইনার্টের মতো একই সমস্যা ছিল: এটি কারণ যে আমি ব্যবহার করার চেষ্টা করছিলাম Pool.map()। আমি বুঝতে পারি নি যে কেবলমাত্র imap() এবং imap_unordered()এইভাবে কাজ করে - ডকুমেন্টেশনটি কেবল "মানচিত্রের একটি অলস সংস্করণ ()" বলেছে তবে সত্যিকার অর্থে "অন্তর্নিহিত পুনরাবৃত্তকারীরা ফলাফল আসার সাথে সাথে ফলাফলগুলি ফিরে আসে"।
সিমোনমামুল্লুলেন

@ সিমোনমাম্যাকুলেন: প্রশ্ন এবং আমার উত্তর দুটি ব্যবহার imap_unordered()। হানানের সমস্যা সম্ভবত sys.stderr.write('\r..')(অগ্রগতি দেখানোর জন্য একই লাইনটি ওভাররাইট করা) এর কারণে is
jfs

4
সম্ভব! আমি মূলত আমি যে বোকামি অনুমানটি করেছি তা নথিভুক্ত করতে চেয়েছিলাম - অন্য কেউ এটি পড়ার ক্ষেত্রেও তা তৈরি করে দেয়।
সিমোনম সিএমুলুলেন

99

আমার ব্যক্তিগত প্রিয় - জিনিসগুলি সমান্তরালভাবে চালিত এবং প্রতিশ্রুতিবদ্ধ হওয়ার সময় আপনাকে একটি দুর্দান্ত সামান্য অগ্রগতি বার এবং সমাপ্তি ইটিএ দেয়।

from multiprocessing import Pool
import tqdm

pool = Pool(processes=8)
for _ in tqdm.tqdm(pool.imap_unordered(do_work, tasks), total=len(tasks)):
    pass

65
পুল যদি কোনও মূল্য ফেরত দেয়?
নিকপিক

11
আমি লুপের আগে রেজাল্ট নামে একটি খালি তালিকা তৈরি করেছি তারপরে লুপের ভিতরে কেবল রেজাল্ট.অ্যাপেন্ড (এক্স) করব। আমি এটি 2 টি প্রক্রিয়া দিয়ে চেষ্টা করেছি এবং মানচিত্রের পরিবর্তে ইমাম ব্যবহার করেছি এবং সবকিছু যেমন @Nickpick- এ চেয়েছিল তেমন কাজ করেছে
বিএস 7280

4
সুতরাং আমার অগ্রগতি বারটি জায়গায় উন্নতির পরিবর্তে নতুন লাইনে পুনরাবৃত্তি করছে, কেন এমন হতে পারে এমন কোনও ধারণা?
অস্টিন

4
ভুলে যাবেন নাpip install tqdm
মিঃ টি

4
@ বিএস 7280 ফলাফল অনুসারে.পেন্ড (এক্স) বলতে কি আপনার ফলাফল বোঝানো হয়েছে? অ্যাপেন্ড (_)? এক্স কি?
জেসন

27

আমি দেখেছি যে কাজটি ইতিমধ্যে এটির অগ্রগতি পরীক্ষা করার চেষ্টা করার আগেই কাজটি সম্পন্ন হয়েছিল। এটিই আমার জন্য টিকিডিএম ব্যবহার করে কাজ করেছিল

pip install tqdm

from multiprocessing import Pool
from tqdm import tqdm

tasks = range(5)
pool = Pool()
pbar = tqdm(total=len(tasks))

def do_work(x):
    # do something with x
    pbar.update(1)

pool.imap_unordered(do_work, tasks)
pool.close()
pool.join()
pbar.close()

এটি ব্লক করুক বা না করুক, মাল্টিপ্রসেসিংয়ের সমস্ত স্বাদের সাথে এটি কাজ করা উচিত।


5
আমার মনে হয় একগুচ্ছ থ্রেড তৈরি করে এবং প্রতিটি থ্রেড স্বতন্ত্রভাবে গণনা করছে
nburn42

4
আমার ফাংশনগুলির মধ্যে ফাংশন রয়েছে যার ফলে একটি পিকিং ত্রুটি হয়।
ওজুনক

22

আরো কিছু খনন সঙ্গে উত্তর খুঁজে পাওয়া যায়নি আমিঃ কটাক্ষপাত গ্রহণ __dict__এর imap_unorderedফলাফলের বস্তু, আমি দেখেছি এটা একটা হয়েছে _indexঅ্যাট্রিবিউট প্রতিটি কাজের সমাপ্তির সঙ্গে বাড়তি। সুতরাং এটি whileলুপে মোড়ানো লগিংয়ের জন্য কাজ করে :

p = multiprocessing.Pool()
rs = p.imap_unordered(do_work, xrange(num_tasks))
p.close() # No more work
while (True):
  completed = rs._index
  if (completed == num_tasks): break
  print "Waiting for", num_tasks-completed, "tasks to complete..."
  time.sleep(2)

যাইহোক, আমি খুঁজে পেয়েছি যে এর imap_unorderedজন্য অদলবদলের map_asyncফলে খুব দ্রুত কার্যকর কার্যকর হয়, যদিও ফলাফল অবজেক্টটি কিছুটা আলাদা। পরিবর্তে, ফলাফল অবজেক্টের map_asyncএকটি _number_leftবৈশিষ্ট্য এবং একটি ready()পদ্ধতি রয়েছে:

p = multiprocessing.Pool()
rs = p.map_async(do_work, xrange(num_tasks))
p.close() # No more work
while (True):
  if (rs.ready()): break
  remaining = rs._number_left
  print "Waiting for", remaining, "tasks to complete..."
  time.sleep(0.5)

4
আমি পাইথন ২.7..6 এর জন্য এটি পরীক্ষা করেছি এবং আরএসএস_ নাম্বার-বামে খণ্ডের বাকী অংশ বলে মনে হচ্ছে। সুতরাং যদি RSS._chunksize 1 না হয় তবে RSS._number_left বাকী তালিকা আইটেমের সংখ্যা হবে না।
অ্যালেন

আমি এই কোডটি কোথায় রাখব? আমি বোঝাতে চাইছি rsযে এগুলি কার্যকর করা হয় না যতক্ষণ না সামগ্রীটি জানা যায় এবং এটি কিছুটা দেরি হয় বা না?
ওয়াকান টানকা

@ ওয়াকানট্যাঙ্কা: অতিরিক্ত থ্রেড ছড়িয়ে দেওয়ার পরে এটি মূল স্ক্রিপ্টে যায়। আমার মূল উদাহরণে, এটি "যখন" লুপে যায়, যেখানে rsইতিমধ্যে অন্যান্য থ্রেড চালু হয়েছে।
মিডনাইটলাইটিং

4
আপনি দয়া করে আপনার প্রশ্ন এবং / অথবা উত্তরটি ন্যূনতম কাজের উদাহরণ দেখানোর জন্য সম্পাদনা করতে পারেন? আমি rsকোনও লুপে দেখতে পাচ্ছি না, আমি নবাগত একাধিক প্রসেস করছি এবং এটি সাহায্য করবে। আপনাকে অনেক ধন্যবাদ.
ওয়াকান টানকা

4
কমপক্ষে python 3.5, সমাধানটি ব্যবহার _number_leftকরে কাজ করে না। _number_leftপ্রক্রিয়া করা বাকি অংশগুলি প্রতিনিধিত্ব করে। উদাহরণস্বরূপ, আমি যদি 50 টি উপাদান সমান্তরালভাবে আমার ফাংশনে প্রেরণ করতে চাই, তবে 3 টি প্রক্রিয়াযুক্ত একটি থ্রেড পুলের জন্য _map_async()প্রতিটি 5 টি উপাদান সহ 10 টি খণ্ড তৈরি করে। _number_leftতারপরে এই অংশগুলির মধ্যে কতগুলি সম্পন্ন হয়েছে তা উপস্থাপন করে।
এমএসএসএম

9

আমি জানি যে এটি একটি পুরানো প্রশ্ন, তবে আমি পাইথন-এ পাইথন-এর কাজগুলির পুলের অগ্রগতি ট্র্যাক করতে চাইলে আমি এখানে যা করছি।

from progressbar import ProgressBar, SimpleProgress
import multiprocessing as mp
from time import sleep

def my_function(letter):
    sleep(2)
    return letter+letter

dummy_args = ["A", "B", "C", "D"]
pool = mp.Pool(processes=2)

results = []

pbar = ProgressBar(widgets=[SimpleProgress()], maxval=len(dummy_args)).start()

r = [pool.apply_async(my_function, (x,), callback=results.append) for x in dummy_args]

while len(results) != len(dummy_args):
    pbar.update(len(results))
    sleep(0.5)
pbar.finish()

print results

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

আউটপুট:

4 of 4                                                                         
['AA', 'BB', 'CC', 'DD']

আশা করি এটা সাহায্য করবে.


পরিবর্তন হতে হবে: এর [pool.apply_async(my_function, (x,), callback=results.append) for x in dummy_args]জন্য(pool.apply_async(my_function, (x,), callback=results.append) for x in dummy_args)
ডেভিড প্রিজবিলা

এটা সত্যি না. একটি জেনারেটর অবজেক্ট এখানে কাজ করবে না। চেক করা হয়েছে।
সোয়াগাতাম

9

টিমের পরামর্শ অনুসারে, আপনি এই সমস্যাটি সমাধান করতে tqdmএবং ব্যবহার করতে পারেন imap। আমি এই সমস্যাটির জন্য কেবল হোঁচট খেয়েছি এবং imap_unorderedসমাধানটি টুইঙ্ক করেছি , যাতে আমি ম্যাপিংয়ের ফলাফলগুলি অ্যাক্সেস করতে পারি। এখানে কিভাবে এটা কাজ করে:

from multiprocessing import Pool
import tqdm

pool = multiprocessing.Pool(processes=4)
mapped_values = list(tqdm.tqdm(pool.imap_unordered(do_work, range(num_tasks)), total=len(values)))

আপনি যদি আপনার কাজ থেকে ফিরে আসা মূল্যগুলি সম্পর্কে চিন্তা না করেন তবে আপনার তালিকাটি কোনও ভেরিয়েবলের কাছে অর্পণ করার দরকার নেই।


5

কারও সাথে কাজ করার জন্য একটি সহজ সমাধান সন্ধানের জন্য Pool.apply_async():

from multiprocessing import Pool
from tqdm import tqdm
from time import sleep


def work(x):
    sleep(0.5)
    return x**2

n = 10

p = Pool(4)
pbar = tqdm(total=n)
res = [p.apply_async(work, args=(
    i,), callback=lambda _: pbar.update(1)) for i in range(n)]
results = [p.get() for p in res]

3

অগ্রগতি মুদ্রণ তৈরি করতে আমি একটি কাস্টম ক্লাস তৈরি করেছি। এই সাহায্য করে:

from multiprocessing import Pool, cpu_count


class ParallelSim(object):
    def __init__(self, processes=cpu_count()):
        self.pool = Pool(processes=processes)
        self.total_processes = 0
        self.completed_processes = 0
        self.results = []

    def add(self, func, args):
        self.pool.apply_async(func=func, args=args, callback=self.complete)
        self.total_processes += 1

    def complete(self, result):
        self.results.extend(result)
        self.completed_processes += 1
        print('Progress: {:.2f}%'.format((self.completed_processes/self.total_processes)*100))

    def run(self):
        self.pool.close()
        self.pool.join()

    def get_results(self):
        return self.results

1

এই সহজ ক্যু ভিত্তিক পদ্ধতির চেষ্টা করুন, যা পুলিংয়ের সাথেও ব্যবহার করা যেতে পারে। সচেতন হোন যে অগ্রগতি বারের সূচনার পরে কোনও কিছু মুদ্রণ করা এটিকে স্থানান্তরিত করবে, কমপক্ষে এই নির্দিষ্ট অগ্রগতির বারের জন্য। (পিপিআইআই এর অগ্রগতি 1.5)

import time
from progress.bar import Bar

def status_bar( queue_stat, n_groups, n ):

    bar = Bar('progress', max = n)  

    finished = 0
    while finished < n_groups:

        while queue_stat.empty():
            time.sleep(0.01)

        gotten = queue_stat.get()
        if gotten == 'finished':
            finished += 1
        else:
            bar.next()
    bar.finish()


def process_data( queue_data, queue_stat, group):

    for i in group:

        ... do stuff resulting in new_data

        queue_stat.put(1)

    queue_stat.put('finished')  
    queue_data.put(new_data)

def multiprocess():

    new_data = []

    groups = [[1,2,3],[4,5,6],[7,8,9]]
    combined = sum(groups,[])

    queue_data = multiprocessing.Queue()
    queue_stat = multiprocessing.Queue()

    for i, group in enumerate(groups): 

        if i == 0:

            p = multiprocessing.Process(target = status_bar,
                args=(queue_stat,len(groups),len(combined)))
                processes.append(p)
                p.start()

        p = multiprocessing.Process(target = process_data,
        args=(queue_data, queue_stat, group))
        processes.append(p)
        p.start()

    for i in range(len(groups)):
        data = queue_data.get() 
        new_data += data

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