मल्टीप्रोसेसिंग क्यू, पूल और लॉकिंग का उपयोग करने का मृत सरल उदाहरण


91

मैंने http://docs.python.org/dev/library/multiprocessing.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)

जवाबों:


129

आपकी समस्या का सबसे अच्छा समाधान एक का उपयोग करना है 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

नीचे दिए गए @ टिप्पणी के अनुसार संपादित करें:

यदि आप "प्रत्येक पूल सीमा के लिए एक ताला" चाहते हैं, ताकि आपकी प्रक्रियाएं अग्रानुक्रम जोड़े में चलें, तो:

A वेटिंग B वेटिंग | ए किया, बी किया | सी वेटिंग, डी वेटिंग | सी किया, डी किया | ...

फिर प्रत्येक जोड़ी डेटा के लिए पूल (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

2
दूसरे शब्दों में, आप नहीं चाहते कि C तब तक शुरू हो जब तक A और B दोनों नहीं हो जाते?
वेलिमेर म्लेकर 18

वास्तव में, मैं इसे मल्टीप्रोसेसिंग का उपयोग करके कर सकता हूँ।
फ़िर भी

बहुत बहुत धन्यवाद, इरादा के अनुसार काम करें, लेकिन फ़ंक्शन mp_handler पर आप var1 के बजाय चर डेटा का संदर्भ दे रहे हैं :)
thclpr

ठीक है धन्यवाद, मैंने var1पूरी तरह से हटा दिया, dataइसके बजाय वैश्विक का जिक्र किया ।
वेलिमिर म्लेकर 19

8

यह प्रश्न से संबंधित 100% नहीं हो सकता है, लेकिन मेरी खोज पर एक कतार के साथ बहुप्रयोग का उपयोग करने के उदाहरण के लिए यह Google पर सबसे पहले दिखाई देता है।

यह एक बुनियादी उदाहरण वर्ग है जिसे आप एक पंक्ति में आइटम को तुरंत लिख सकते हैं और रख सकते हैं और कतार समाप्त होने तक प्रतीक्षा कर सकते हैं। बस इतना ही चाहिए।

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()

2
क्या हैं item1और item2? क्या वे कुछ प्रकार के कार्य या कार्य हैं, जिन्हें दो अलग-अलग प्रक्रियाओं में निष्पादित किया जाएगा?
ज़ेल्फ़िर कलस्टहल 16

2
हां वे कार्य या इनपुट पैरामीटर हैं जो समानांतर तरीके से संसाधित होते हैं।
linqu

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()

1
मुझे बिल्कुल यकीन नहीं है कि .map_async () किसी भी तरह से .map () से बेहतर है।
थोरसुमोनर

3
तर्क get()एक समयबाह्य है, शुरू की गई नौकरियों की संख्या से कोई लेना-देना नहीं है।
माता

@ ममता है, तो इसका मतलब है कि मतदान में उपयोग किया जाना है? .get(timeout=1)? और क्या .get()पूरी की गई सूची प्राप्त करना ठीक है ?
थोरसुमोनर

हां, .get()सभी परिणाम उपलब्ध होने तक अनिश्चित काल तक प्रतीक्षा करता है और परिणामों की सूची लौटाता है। आप मौसम के परिणाम उपलब्ध होने की जांच करने के लिए एक मतदान लूप का उपयोग कर सकते हैं, या आप map_async()कॉल में एक कॉलबैक फ़ंक्शन पास कर सकते हैं जो उपलब्ध होने के बाद हर परिणाम के लिए आमंत्रित किया जाएगा।
माता

2

कोमोडो एडिट (win10) जैसे संपादकों का उपयोग करने वाले सभी के 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 तब तक इंतजार किया जाता है जब तक कि सभी कार्य पूरा नहीं हो जाते।

2
ध्यान दें कि आप उपयोग कर रहे हैं concurrent.futures, लेकिन ओपी multiprocessingऔर पायथन 2.7 के बारे में पूछ रहा है ।
टिम पीटर्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.