মাল্টিপ্রসেসিং ক্যু, পুল এবং লকিং ব্যবহারের মৃত সাধারণ উদাহরণ


92

আমি ডকুমেন্টেশনটি http://docs.python.org/dev/library/m মাল্টিপ্রসেসিং html এ পড়ার চেষ্টা করেছি তবে আমি এখনও মাল্টিপ্রসেসিং ক্যু, পুল এবং লকিং নিয়ে লড়াই করছি। এবং আপাতত আমি নীচের উদাহরণটি তৈরি করতে সক্ষম হয়েছি।

ক্যু এবং পুল সম্পর্কে, আমি ধারণাটি সঠিকভাবে বুঝতে পেরেছি কিনা তা আমি নিশ্চিত নই, তাই আমি ভুল হলে আমাকে সংশোধন করুন। আমি যেটি অর্জনের চেষ্টা করছি তা হ'ল সময়ে 2 টি অনুরোধগুলি প্রক্রিয়া করা হয় (ডেটা তালিকায় এই উদাহরণে 8 টি রয়েছে) তাই আমার কী ব্যবহার করা উচিত? 2 টি প্রক্রিয়া তৈরি করতে পুল যা দুটি পৃথক সারি (সর্বোচ্চ 2 টি) পরিচালনা করতে পারে বা প্রতিবার 2 ইনপুট প্রসেস করার জন্য আমার কি কিউ ব্যবহার করা উচিত? লকটি আউটপুটগুলি সঠিকভাবে মুদ্রণ করতে হবে।

import multiprocessing
import time

data = (['a', '2'], ['b', '4'], ['c', '6'], ['d', '8'],
        ['e', '1'], ['f', '3'], ['g', '5'], ['h', '7']
)


def mp_handler(var1):
    for indata in var1:
        p = multiprocessing.Process(target=mp_worker, args=(indata[0], indata[1]))
        p.start()


def mp_worker(inputs, the_time):
    print " Processs %s\tWaiting %s seconds" % (inputs, the_time)
    time.sleep(int(the_time))
    print " Process %s\tDONE" % inputs

if __name__ == '__main__':
    mp_handler(data)

উত্তর:


130

আপনার সমস্যার জন্য সবচেয়ে ভালো সমাধান একটি কাজে লাগাতে হয় PoolQueueগুলি ব্যবহার এবং পৃথক "সারি খাওয়ানো" কার্যকারিতা থাকা সম্ভবত ওভারকিল।

আপনার প্রোগ্রামটির সামান্য পুনরায় সাজানো সংস্করণটি এখানে, শুধুমাত্র একটিতে 2 টি প্রসেসের সাথে কোরালযুক্ত Pool। আমি বিশ্বাস করি যে আসল কোডটিতে নূন্যতম পরিবর্তন সহ এটি যাওয়ার সহজতম উপায়:

import multiprocessing
import time

data = (
    ['a', '2'], ['b', '4'], ['c', '6'], ['d', '8'],
    ['e', '1'], ['f', '3'], ['g', '5'], ['h', '7']
)

def mp_worker((inputs, the_time)):
    print " Processs %s\tWaiting %s seconds" % (inputs, the_time)
    time.sleep(int(the_time))
    print " Process %s\tDONE" % inputs

def mp_handler():
    p = multiprocessing.Pool(2)
    p.map(mp_worker, data)

if __name__ == '__main__':
    mp_handler()

নোট করুন যে mp_worker()ফাংশনটি এখন একটি একক যুক্তি (দুটি আগের আর্গুমেন্টের একটি টিপল) গ্রহণ করে কারণ map()ফাংশনটি আপনার ইনপুট ডেটাটিকে সাবলিস্টে বিভক্ত করে দেয়, প্রতিটি কর্মসূচি আপনার কর্মী ফাংশনকে একক যুক্তি হিসাবে দেওয়া হয়।

আউটপুট:

Processs a  Waiting 2 seconds
Processs b  Waiting 4 seconds
Process a   DONE
Processs c  Waiting 6 seconds
Process b   DONE
Processs d  Waiting 8 seconds
Process c   DONE
Processs e  Waiting 1 seconds
Process e   DONE
Processs f  Waiting 3 seconds
Process d   DONE
Processs g  Waiting 5 seconds
Process f   DONE
Processs h  Waiting 7 seconds
Process g   DONE
Process h   DONE

নীচে @ টেলস মন্তব্য অনুসারে সম্পাদনা করুন:

আপনি যদি "প্রতিটি পুলের সীমাবদ্ধতার জন্য একটি লক" চান যাতে আপনার প্রক্রিয়াগুলি টেন্ডেম জোড়িতে চলতে পারে, তবে:

একটি অপেক্ষমান বি অপেক্ষা | একটি সম্পন্ন, বি সম্পন্ন | সি ওয়েটিং, ডি ওয়েটিং | সি সম্পন্ন, ডি সম্পন্ন | ...

তারপরে হ্যান্ডলার ফাংশনটি প্রতিটি জোড় ডেটার জন্য পুল (2 প্রসেসের) চালু করতে:

def mp_handler():
    subdata = zip(data[0::2], data[1::2])
    for task1, task2 in subdata:
        p = multiprocessing.Pool(2)
        p.map(mp_worker, (task1, task2))

এখন আপনার আউটপুট হল:

 Processs a Waiting 2 seconds
 Processs b Waiting 4 seconds
 Process a  DONE
 Process b  DONE
 Processs c Waiting 6 seconds
 Processs d Waiting 8 seconds
 Process c  DONE
 Process d  DONE
 Processs e Waiting 1 seconds
 Processs f Waiting 3 seconds
 Process e  DONE
 Process f  DONE
 Processs g Waiting 5 seconds
 Processs h Waiting 7 seconds
 Process g  DONE
 Process h  DONE

কীভাবে এটি করা যায় তার সহজ এবং প্রত্যক্ষ উদাহরণের জন্য ধন্যবাদ, তবে আমি কীভাবে প্রতিটি পুলের সীমাটির জন্য লকটি প্রয়োগ করতে পারি? আমি বোঝাতে চাইছি, আপনি যদি কোডটি সম্পাদন করেন তবে আমি "একটি ওয়েটিং বি ওয়েটিং | একটি সম্পন্ন, বি সম্পন্ন, সি ওয়েটিং, ডি ওয়েটিং, সি সম্পন্ন, ডি সম্পন্ন"
thclpr

4
অন্য কথায়, আপনি A এবং B উভয় সম্পন্ন না করা পর্যন্ত সি শুরু করতে চান না?
ভেলিমির ম্লেকার

ঠিক যেমন, আমি এটি মাল্টিপ্রসেসিং ব্যবহার করে করতে পারি
roপ্রসেস তবে

আপনাকে অনেক ধন্যবাদ, উদ্দেশ্য মতো কাজ করুন, তবে ফাংশনে এমপি_হ্যান্ডলার আপনি ভ্যারিয়েলের পরিবর্তে ভেরিয়েবল ডেটা উল্লেখ করছেন :)
thclpr

ঠিক আছে ধন্যবাদ, আমি var1সম্পূর্ণরূপে অপসারণ করেছি , dataপরিবর্তে বিশ্বব্যাপী উল্লেখ করে।
ভেলিমির ম্লেকার 19

8

এটি প্রশ্নের সাথে সম্পর্কিত 100% নাও হতে পারে, তবে আমার সন্ধানে একটি সারিতে মাল্টিপ্রসেসিং ব্যবহারের উদাহরণের জন্য এটি গুগলে প্রথমে প্রদর্শিত হবে।

এটি একটি প্রাথমিক উদাহরণ শ্রেণি যা আপনি ইনস্ট্যান্ট করতে এবং আইটেমগুলিকে একটি সারিতে স্থাপন করতে পারেন এবং সারি শেষ না হওয়া পর্যন্ত অপেক্ষা করতে পারেন। আমার এটাই দরকার।

from multiprocessing import JoinableQueue
from multiprocessing.context import Process


class Renderer:
    queue = None

    def __init__(self, nb_workers=2):
        self.queue = JoinableQueue()
        self.processes = [Process(target=self.upload) for i in range(nb_workers)]
        for p in self.processes:
            p.start()

    def render(self, item):
        self.queue.put(item)

    def upload(self):
        while True:
            item = self.queue.get()
            if item is None:
                break

            # process your item here

            self.queue.task_done()

    def terminate(self):
        """ wait until queue is empty and terminate processes """
        self.queue.join()
        for p in self.processes:
            p.terminate()

r = Renderer()
r.render(item1)
r.render(item2)
r.terminate()

4
কি item1এবং item2? তারা কি কোনও ধরণের টাস্ক বা ফাংশন, যা দুটি ভিন্ন প্রক্রিয়াতে কার্যকর করা হবে?
জেলফির কালটস্টল

4
হ্যাঁ এগুলি কার্য বা ইনপুট পরামিতি যা সমান্তরাল উপায়ে প্রক্রিয়াজাত হয়।
লিনক

8

এই বিষয়টির জন্য আমার ব্যক্তিগত গোটোটি এখানে:

এখানে সংক্ষিপ্তসার করুন, (অনুরোধগুলি স্বাগত করুন!): Https://gist.github.com/thorsummoner/b5b1dfcff7e7fdd334ec

import multiprocessing
import sys

THREADS = 3

# Used to prevent multiple threads from mixing thier output
GLOBALLOCK = multiprocessing.Lock()


def func_worker(args):
    """This function will be called by each thread.
    This function can not be a class method.
    """
    # Expand list of args into named args.
    str1, str2 = args
    del args

    # Work
    # ...



    # Serial-only Portion
    GLOBALLOCK.acquire()
    print(str1)
    print(str2)
    GLOBALLOCK.release()


def main(argp=None):
    """Multiprocessing Spawn Example
    """
    # Create the number of threads you want
    pool = multiprocessing.Pool(THREADS)

    # Define two jobs, each with two args.
    func_args = [
        ('Hello', 'World',), 
        ('Goodbye', 'World',), 
    ]


    try:
        # Spawn up to 9999999 jobs, I think this is the maximum possible.
        # I do not know what happens if you exceed this.
        pool.map_async(func_worker, func_args).get(9999999)
    except KeyboardInterrupt:
        # Allow ^C to interrupt from any thread.
        sys.stdout.write('\033[0m')
        sys.stdout.write('User Interupt\n')
    pool.close()

if __name__ == '__main__':
    main()

4
আমি ঠিক নিশ্চিত নই যে .map_async () কোনওভাবেই .map () এর চেয়ে ভাল।
থারস্মমনার

4
যুক্তি get()একটি সময়সীমা, যে কাজ শুরু হয়েছে তার সাথে কিছুই করার নেই।
মাতা

@ মতা তাই, পোলিং লুপে ব্যবহার করার অর্থ কি? .get(timeout=1)? এবং .get()সম্পূর্ণ তালিকাটি অর্জনের জন্য কেবল কি বলা ঠিক আছে ?
থারস্মমনার

হ্যাঁ, .get()সমস্ত ফলাফল উপলব্ধ না হওয়া পর্যন্ত অনির্দিষ্টকালের জন্য অপেক্ষা করে এবং ফলাফলের তালিকাটি প্রত্যাবর্তন করে। আবহাওয়ার ফলাফলগুলি উপলব্ধ কিনা তা পরীক্ষা করতে আপনি একটি পোলিং লুপ ব্যবহার করতে পারেন, বা আপনি map_async()কলটিতে কলব্যাক ফাংশনটি পাস করতে পারেন যা একবার এটি উপলব্ধ হয়ে ওঠার পরে প্রতিটি ফলাফলের জন্য অনুরোধ করা হবে।
মাতা

2

কমোডো এডিট (উইন 10) এর মতো সম্পাদক ব্যবহার করে সবার জন্য যুক্ত sys.stdout.flush()করুন:

def mp_worker((inputs, the_time)):
    print " Process %s\tWaiting %s seconds" % (inputs, the_time)
    time.sleep(int(the_time))
    print " Process %s\tDONE" % inputs
    sys.stdout.flush()

বা প্রথম লাইন হিসাবে:

    if __name__ == '__main__':
       sys.stdout.flush()

এটি স্ক্রিপ্ট চলাকালীন কী ঘটে তা দেখতে সহায়তা করে; ব্ল্যাক কমান্ড লাইন বক্সের দিকে তাকানোর পরে।


1

এখানে আমার কোডের একটি উদাহরণ রয়েছে (থ্রেডেড পুলের জন্য, তবে কেবল শ্রেণীর নাম পরিবর্তন করুন এবং আপনার কাছে প্রক্রিয়া পুল থাকবে):

def execute_run(rp): 
   ... do something 

pool = ThreadPoolExecutor(6)
for mat in TESTED_MATERIAL:
    for en in TESTED_ENERGIES:
        for ecut in TESTED_E_CUT:
            rp = RunParams(
                simulations, DEST_DIR,
                PARTICLE, mat, 960, 0.125, ecut, en
            )
            pool.submit(execute_run, rp)
pool.join()

মূলত:

  • pool = ThreadPoolExecutor(6) 6 টি থ্রেডের জন্য একটি পুল তৈরি করে
  • তারপরে আপনার কাছে গুচ্ছ রয়েছে যা পুলটিতে কাজগুলি যুক্ত করে
  • pool.submit(execute_run, rp) পুলটিতে একটি টাস্ক যুক্ত করে, প্রথম অ্যারগমেন্ট একটি থ্রেড / প্রক্রিয়াতে ডাকা একটি ফাংশন, বাকী আর্গুমেন্টগুলি ডাকা ফাংশনে পাস করা হয়।
  • pool.join সমস্ত কাজ শেষ হওয়া পর্যন্ত অপেক্ষা করে।

4
মনে রাখবেন যে আপনি ব্যবহার করছেন concurrent.futuresতবে ওপি multiprocessingএবং পাইথন ২.7 সম্পর্কে জিজ্ঞাসা করছে ।
টিম পিটারস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.