पायथन में मल्टीप्रोसेसिंग कतार का उपयोग कैसे करें?


94

मुझे यह समझने में बहुत परेशानी हो रही है कि अजगर पर मल्टीप्रोसेसिंग कतार कैसे काम करती है और इसे कैसे लागू किया जाए। आइए कहते हैं कि मेरे पास दो अजगर मॉड्यूल हैं जो एक साझा फ़ाइल से डेटा तक पहुंचते हैं, चलो इन दो मॉड्यूल को एक लेखक और एक पाठक कहते हैं। मेरी योजना पाठक और लेखक दोनों के अनुरोधों को दो अलग-अलग बहु-पंक्तिबद्ध कतारों में रखना है, और फिर एक तीसरी प्रक्रिया को इन अनुरोधों को लूप में रखना और इस तरह निष्पादित करना है।

मेरी मुख्य समस्या यह है कि मुझे वास्तव में पता नहीं है कि मल्टीप्रोसेसिंग को कैसे लागू किया जाए। सही तरीके से, आप वास्तव में प्रत्येक प्रक्रिया के लिए ऑब्जेक्ट को तुरंत नहीं कर सकते क्योंकि वे अलग-अलग कतार होंगे, आप यह कैसे सुनिश्चित करते हैं कि सभी प्रक्रियाएं एक साझा कतार से संबंधित हैं (या इस मामले में, कतारें)


4
जब आप मूल प्रक्रिया में उन्हें तत्काल करते हैं, तो प्रत्येक प्रक्रिया वर्ग को एक पैरामीटर के रूप में क्यू पास करें।
जोएल कॉर्नेट

जवाबों:


122

मेरी मुख्य समस्या यह है कि मुझे वास्तव में पता नहीं है कि मल्टीप्रोसेसिंग को कैसे लागू किया जाए। सही तरीके से, आप वास्तव में प्रत्येक प्रक्रिया के लिए ऑब्जेक्ट को तुरंत नहीं कर सकते क्योंकि वे अलग-अलग कतार होंगे, आप यह कैसे सुनिश्चित करते हैं कि सभी प्रक्रियाएं एक साझा कतार से संबंधित हैं (या इस मामले में, कतारें)

यह एक पाठक और लेखक की एक एकल कतार साझा करने का एक सरल उदाहरण है ... लेखक पाठक को पूर्णांक का एक गुच्छा भेजता है; जब लेखक संख्याओं से बाहर निकलता है, तो वह 'DONE' भेजता है, जो पाठक को रीड लूप से बाहर जाने देता है।

from multiprocessing import Process, Queue
import time
import sys

def reader_proc(queue):
    ## Read from the queue; this will be spawned as a separate Process
    while True:
        msg = queue.get()         # Read from the queue and do nothing
        if (msg == 'DONE'):
            break

def writer(count, queue):
    ## Write to the queue
    for ii in range(0, count):
        queue.put(ii)             # Write 'count' numbers into the queue
    queue.put('DONE')

if __name__=='__main__':
    pqueue = Queue() # writer() writes to pqueue from _this_ process
    for count in [10**4, 10**5, 10**6]:             
        ### reader_proc() reads from pqueue as a separate process
        reader_p = Process(target=reader_proc, args=((pqueue),))
        reader_p.daemon = True
        reader_p.start()        # Launch reader_proc() as a separate python process

        _start = time.time()
        writer(count, pqueue)    # Send a lot of stuff to reader()
        reader_p.join()         # Wait for the reader to finish
        print("Sending {0} numbers to Queue() took {1} seconds".format(count, 
            (time.time() - _start)))

13
महान उदाहरण है। ओपी के भ्रम को संबोधित करने के लिए बस एक अतिरिक्त जानकारी के रूप में ... यह उदाहरण दिखाता है कि एक साझा कतार को मास्टर प्रक्रिया से उत्पन्न होने की आवश्यकता है, जो तब इसके सभी उपप्रकारों में पारित हो जाती है। डेटा साझा करने के लिए दो पूरी तरह से असंबंधित प्रक्रियाओं के लिए, उन्हें कुछ केंद्रीय या संबंधित नेटवर्क डिवाइस (उदाहरण के लिए सॉकेट) पर संवाद करना होगा। कुछ को जानकारी को समन्वित करना है।
जीडी १

5
अच्छा उदाहरण .. मैं इस विषय के लिए भी नया हूं .. अगर मेरे पास एक ही लक्ष्य फ़ंक्शन (विभिन्न तर्कों के साथ) चलाने वाली कई प्रक्रियाएं हैं, तो यह कैसे सुनिश्चित करें कि वे डेटा को कतार में डालते समय न टकराएं .. ताला आवश्यक है ?
WYSIWYG

@bharat_iyengar मल्टीप्रोसेसिंग मॉड्यूल डॉक्यूमेंटेशन से, यह कहता है कि क्यू को कुछ तालों / फासफोरस का उपयोग करके लागू किया गया है। इसलिए जब आप प्राप्त () और पुट (ऑब्जेक्ट) कतार विधियों का उपयोग करते हैं, तो कतार अवरुद्ध हो जाएगी यदि कुछ अन्य प्रक्रिया / धागा कतार में कुछ पाने या डालने की कोशिश कर रहा है। इसलिए आपको इसे मैन्युअल रूप से लॉक करने के बारे में चिंता करने की आवश्यकता नहीं है।
almel

1
स्पष्ट रोक की स्थिति निहित रोक की स्थिति से बेहतर है
माइक पेनिंगटन

2
क्यूज़ शून्य शून्य तक जा सकता है यदि कतार पाठक कतार लेखक की दर से अधिक हो
माइक पेनिंगटन

8

" from queue import Queue" में कोई मॉड्यूल नहीं है queue, इसके बजाय multiprocessingइसका उपयोग किया जाना चाहिए। इसलिए, इसे " from multiprocessing import Queue" जैसा दिखना चाहिए


11
जबकि साल के अंत में, का उपयोग multiprocessing.Queueकरना सही है। Queue.Queueअजगर धागे के लिए सामान्य का उपयोग किया जाता है । जब आप Queue.Queueमल्टीप्रोसेसिंग के साथ उपयोग करने का प्रयास करते हैं , तो प्रत्येक बच्चे की प्रक्रिया में क्यू ऑब्जेक्ट की प्रतियां बनाई जाएंगी और बच्चे की प्रक्रियाओं को कभी भी अपडेट नहीं किया जाएगा। मूल रूप से, Queue.Queueएक वैश्विक साझा किए गए ऑब्जेक्ट multiprocessing.Queueका उपयोग करके काम करता है , और आईपीसी का उपयोग करके काम करता है। देखें: stackoverflow.com/questions/925100/…
माइकल गुफ्रे

5

यहां एक मृत सरल उपयोग है multiprocessing.Queueऔर multiprocessing.Processजो कॉल करने वालों को "ईवेंट" प्लस तर्कों को एक अलग प्रक्रिया में भेजने की अनुमति देता है जो प्रक्रिया पर ईवेंट को एक "do_" विधि में भेजता है। (पायथन 3.4+)

import multiprocessing as mp
import collections

Msg = collections.namedtuple('Msg', ['event', 'args'])

class BaseProcess(mp.Process):
    """A process backed by an internal queue for simple one-way message passing.
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.queue = mp.Queue()

    def send(self, event, *args):
        """Puts the event and args as a `Msg` on the queue
        """
       msg = Msg(event, args)
       self.queue.put(msg)

    def dispatch(self, msg):
        event, args = msg

        handler = getattr(self, "do_%s" % event, None)
        if not handler:
            raise NotImplementedError("Process has no handler for [%s]" % event)

        handler(*args)

    def run(self):
        while True:
            msg = self.queue.get()
            self.dispatch(msg)

उपयोग:

class MyProcess(BaseProcess):
    def do_helloworld(self, arg1, arg2):
        print(arg1, arg2)

if __name__ == "__main__":
    process = MyProcess()
    process.start()
    process.send('helloworld', 'hello', 'world')

sendमाता-पिता की प्रक्रिया में होता है, do_*बच्चे की प्रक्रिया में होता है।

मैंने कोई भी अपवाद संभालना छोड़ दिया जो जाहिर तौर पर रन लूप को बाधित करेगा और बच्चे की प्रक्रिया से बाहर निकलेगा। आप runअवरुद्ध या अन्य जो कुछ भी नियंत्रित करने के लिए ओवरराइड करके इसे कस्टमाइज़ कर सकते हैं ।

यह वास्तव में केवल उन परिस्थितियों में उपयोगी है जहां आपके पास एक एकल कार्यकर्ता प्रक्रिया है, लेकिन मुझे लगता है कि इस सवाल का एक प्रासंगिक उत्तर थोड़ा और वस्तु-उन्मुखीकरण के साथ एक सामान्य परिदृश्य का प्रदर्शन करना है।


1
बकाया जवाब! धन्यवाद। +50 :)
किमीकिले

3

स्टैक ओवरफ्लो और वेब पर कई उत्तरों पर मेरी नज़र थी, जबकि बड़े पांडा पांडा के चारों ओर से गुजरने के लिए कतारों का उपयोग करके मल्टीप्रोसेसिंग करने का एक तरीका स्थापित करने की कोशिश की जा रही थी। मुझे ऐसा लग रहा था कि हर जवाब एक ही तरह के समाधानों की पुनरावृति कर रहा था, बिना किसी किनारे के मामलों की भीड़ पर विचार किए बिना, निश्चित रूप से इस तरह की गणना करते समय सामने आएगा। समस्या यह है कि एक ही समय में कई चीजें होती हैं। कार्यों की संख्या, श्रमिकों की संख्या, प्रत्येक कार्य की अवधि और कार्य निष्पादन के दौरान संभावित अपवाद। ये सभी सिंक्रोनाइज़ेशन को मुश्किल बनाते हैं और अधिकांश उत्तर यह नहीं बताते हैं कि आप इसके बारे में कैसे जा सकते हैं। इसलिए कुछ घंटों के लिए चक्कर लगाने के बाद यह मेरा काम है, उम्मीद है कि यह ज्यादातर लोगों के लिए उपयोगी होगा।

किसी भी कोडिंग उदाहरण से पहले कुछ विचार। चूंकि queue.Emptyया queue.qsize()कोई अन्य समान विधि प्रवाह नियंत्रण के लिए अविश्वसनीय है, जैसे कोई भी कोड

while True:
    try:
        task = pending_queue.get_nowait()
    except queue.Empty:
        break

फर्जी है। यह कार्यकर्ता को मार देगा भले ही मिलीसेकंड बाद में एक और कार्य कतार में खड़ा हो जाए। कार्यकर्ता ठीक नहीं होगा और थोड़ी देर बाद सभी कर्मचारी गायब हो जाएंगे क्योंकि वे अनियमित रूप से कतार को क्षण भर खाली पाते हैं। अंतिम परिणाम यह होगा कि मुख्य मल्टीप्रोसेसिंग फ़ंक्शन (प्रक्रियाओं में शामिल होने के साथ) सभी पूर्ण किए गए कार्यों के बिना वापस आ जाएगा। अच्छा लगा। सौभाग्य सौभाग्य है कि यदि आपके पास हजारों कार्य हैं और कुछ गायब हैं।

अन्य मुद्दा प्रहरी मूल्यों का उपयोग है। कई लोगों ने कतार के अंत को ध्वजांकित करने के लिए कतार में एक प्रहरी मूल्य जोड़ने का सुझाव दिया है। लेकिन इसे किसके पास फहराना है? यदि एन श्रमिक है, तो मान लें कि एन कोर की संख्या है जो उपलब्ध है या लेना है, तो एक एकल प्रहरी मूल्य केवल एक कार्यकर्ता को कतार के अंत में ध्वजांकित करेगा। अन्य सभी कार्यकर्ता अधिक काम के इंतजार में बैठेंगे जब कोई नहीं होगा। मैंने देखा है विशिष्ट उदाहरण हैं

while True:
    task = pending_queue.get()
    if task == SOME_SENTINEL_VALUE:
        break

एक कार्यकर्ता को प्रहरी मूल्य मिलेगा जबकि शेष अनिश्चित काल तक प्रतीक्षा करेगा। कोई पोस्ट नहीं आई जिसका मैंने उल्लेख किया है कि आपको कतार में लेटिन मूल्य को AT LEAST में जमा करने की आवश्यकता है क्योंकि आपके पास कार्यकर्ता हैं ताकि सभी को मिल जाए।

अन्य मुद्दा कार्य निष्पादन के दौरान अपवादों से निपटने का है। फिर से इन्हें पकड़ा जाना चाहिए और प्रबंधित किया जाना चाहिए। इसके अलावा, यदि आपके पास एक completed_tasksकतार है , तो आपको स्वतंत्र रूप से एक निर्धारक तरीके से गिनना चाहिए कि आपके द्वारा तय किए गए काम को पूरा करने से पहले कितने आइटम कतार में हैं। फिर से कतार के आकार पर भरोसा करना विफल हो जाता है और अप्रत्याशित परिणाम देता है।

नीचे दिए गए उदाहरण में, par_proc()फ़ंक्शन को उन कार्यों सहित कार्यों की एक सूची प्राप्त होगी , जिनके साथ इन कार्यों को किसी भी नामित तर्क और मूल्यों के साथ निष्पादित किया जाना चाहिए।

import multiprocessing as mp
import dill as pickle
import queue
import time
import psutil

SENTINEL = None


def do_work(tasks_pending, tasks_completed):
    # Get the current worker's name
    worker_name = mp.current_process().name

    while True:
        try:
            task = tasks_pending.get_nowait()
        except queue.Empty:
            print(worker_name + ' found an empty queue. Sleeping for a while before checking again...')
            time.sleep(0.01)
        else:
            try:
                if task == SENTINEL:
                    print(worker_name + ' no more work left to be done. Exiting...')
                    break

                print(worker_name + ' received some work... ')
                time_start = time.perf_counter()
                work_func = pickle.loads(task['func'])
                result = work_func(**task['task'])
                tasks_completed.put({work_func.__name__: result})
                time_end = time.perf_counter() - time_start
                print(worker_name + ' done in {} seconds'.format(round(time_end, 5)))
            except Exception as e:
                print(worker_name + ' task failed. ' + str(e))
                tasks_completed.put({work_func.__name__: None})


def par_proc(job_list, num_cpus=None):

    # Get the number of cores
    if not num_cpus:
        num_cpus = psutil.cpu_count(logical=False)

    print('* Parallel processing')
    print('* Running on {} cores'.format(num_cpus))

    # Set-up the queues for sending and receiving data to/from the workers
    tasks_pending = mp.Queue()
    tasks_completed = mp.Queue()

    # Gather processes and results here
    processes = []
    results = []

    # Count tasks
    num_tasks = 0

    # Add the tasks to the queue
    for job in job_list:
        for task in job['tasks']:
            expanded_job = {}
            num_tasks = num_tasks + 1
            expanded_job.update({'func': pickle.dumps(job['func'])})
            expanded_job.update({'task': task})
            tasks_pending.put(expanded_job)

    # Use as many workers as there are cores (usually chokes the system so better use less)
    num_workers = num_cpus

    # We need as many sentinels as there are worker processes so that ALL processes exit when there is no more
    # work left to be done.
    for c in range(num_workers):
        tasks_pending.put(SENTINEL)

    print('* Number of tasks: {}'.format(num_tasks))

    # Set-up and start the workers
    for c in range(num_workers):
        p = mp.Process(target=do_work, args=(tasks_pending, tasks_completed))
        p.name = 'worker' + str(c)
        processes.append(p)
        p.start()

    # Gather the results
    completed_tasks_counter = 0
    while completed_tasks_counter < num_tasks:
        results.append(tasks_completed.get())
        completed_tasks_counter = completed_tasks_counter + 1

    for p in processes:
        p.join()

    return results

और यहाँ उपरोक्त कोड को चलाने के लिए एक परीक्षण है

def test_parallel_processing():
    def heavy_duty1(arg1, arg2, arg3):
        return arg1 + arg2 + arg3

    def heavy_duty2(arg1, arg2, arg3):
        return arg1 * arg2 * arg3

    task_list = [
        {'func': heavy_duty1, 'tasks': [{'arg1': 1, 'arg2': 2, 'arg3': 3}, {'arg1': 1, 'arg2': 3, 'arg3': 5}]},
        {'func': heavy_duty2, 'tasks': [{'arg1': 1, 'arg2': 2, 'arg3': 3}, {'arg1': 1, 'arg2': 3, 'arg3': 5}]},
    ]

    results = par_proc(task_list)

    job1 = sum([y for x in results if 'heavy_duty1' in x.keys() for y in list(x.values())])
    job2 = sum([y for x in results if 'heavy_duty2' in x.keys() for y in list(x.values())])

    assert job1 == 15
    assert job2 == 21

कुछ अपवादों के साथ एक और एक

def test_parallel_processing_exceptions():
    def heavy_duty1_raises(arg1, arg2, arg3):
        raise ValueError('Exception raised')
        return arg1 + arg2 + arg3

    def heavy_duty2(arg1, arg2, arg3):
        return arg1 * arg2 * arg3

    task_list = [
        {'func': heavy_duty1_raises, 'tasks': [{'arg1': 1, 'arg2': 2, 'arg3': 3}, {'arg1': 1, 'arg2': 3, 'arg3': 5}]},
        {'func': heavy_duty2, 'tasks': [{'arg1': 1, 'arg2': 2, 'arg3': 3}, {'arg1': 1, 'arg2': 3, 'arg3': 5}]},
    ]

    results = par_proc(task_list)

    job1 = sum([y for x in results if 'heavy_duty1' in x.keys() for y in list(x.values())])
    job2 = sum([y for x in results if 'heavy_duty2' in x.keys() for y in list(x.values())])

    assert not job1
    assert job2 == 21

आशा है कि सहायक है।


2

हमने इसके दो संस्करणों को लागू किया, एक साधारण मल्टी थ्रेड पूल जो कई तरह के कॉलबल्स को निष्पादित कर सकता है, जिससे हमारा जीवन बहुत आसान हो जाता है और दूसरा संस्करण प्रक्रियाओं का उपयोग करता है , जो कि कॉलबेल के लिए कम लचीला होता है और आवश्यकता होती है और अतिरिक्त कॉल करने के लिए।

जमे हुए_पूल को सही पर सेट करना तब तक निष्पादन को समाप्त कर देगा जब तक कि फिनिश_पुल_क्यू को वर्ग में नहीं बुलाया जाता।

थ्रेड संस्करण:

'''
Created on Nov 4, 2019

@author: Kevin
'''
from threading import Lock, Thread
from Queue import Queue
import traceback
from helium.loaders.loader_retailers import print_info
from time import sleep
import signal
import os

class ThreadPool(object):
    def __init__(self, queue_threads, *args, **kwargs):
        self.frozen_pool = kwargs.get('frozen_pool', False)
        self.print_queue = kwargs.get('print_queue', True)
        self.pool_results = []
        self.lock = Lock()
        self.queue_threads = queue_threads
        self.queue = Queue()
        self.threads = []

        for i in range(self.queue_threads):
            t = Thread(target=self.make_pool_call)
            t.daemon = True
            t.start()
            self.threads.append(t)

    def make_pool_call(self):
        while True:
            if self.frozen_pool:
                #print '--> Queue is frozen'
                sleep(1)
                continue

            item = self.queue.get()
            if item is None:
                break

            call = item.get('call', None)
            args = item.get('args', [])
            kwargs = item.get('kwargs', {})
            keep_results = item.get('keep_results', False)

            try:
                result = call(*args, **kwargs)

                if keep_results:
                    self.lock.acquire()
                    self.pool_results.append((item, result))
                    self.lock.release()

            except Exception as e:
                self.lock.acquire()
                print e
                traceback.print_exc()
                self.lock.release()
                os.kill(os.getpid(), signal.SIGUSR1)

            self.queue.task_done()

    def finish_pool_queue(self):
        self.frozen_pool = False

        while self.queue.unfinished_tasks > 0:
            if self.print_queue:
                print_info('--> Thread pool... %s' % self.queue.unfinished_tasks)
            sleep(5)

        self.queue.join()

        for i in range(self.queue_threads):
            self.queue.put(None)

        for t in self.threads:
            t.join()

        del self.threads[:]

    def get_pool_results(self):
        return self.pool_results

    def clear_pool_results(self):
        del self.pool_results[:]

प्रक्रिया संस्करण:

  '''
Created on Nov 4, 2019

@author: Kevin
'''
import traceback
from helium.loaders.loader_retailers import print_info
from time import sleep
import signal
import os
from multiprocessing import Queue, Process, Value, Array, JoinableQueue, Lock,\
    RawArray, Manager
from dill import dill
import ctypes
from helium.misc.utils import ignore_exception
from mem_top import mem_top
import gc

class ProcessPool(object):
    def __init__(self, queue_processes, *args, **kwargs):
        self.frozen_pool = Value(ctypes.c_bool, kwargs.get('frozen_pool', False))
        self.print_queue = kwargs.get('print_queue', True)
        self.manager = Manager()
        self.pool_results = self.manager.list()
        self.queue_processes = queue_processes
        self.queue = JoinableQueue()
        self.processes = []

        for i in range(self.queue_processes):
            p = Process(target=self.make_pool_call)
            p.start()
            self.processes.append(p)

        print 'Processes', self.queue_processes

    def make_pool_call(self):
        while True:
            if self.frozen_pool.value:
                sleep(1)
                continue

            item_pickled = self.queue.get()

            if item_pickled is None:
                #print '--> Ending'
                self.queue.task_done()
                break

            item = dill.loads(item_pickled)

            call = item.get('call', None)
            args = item.get('args', [])
            kwargs = item.get('kwargs', {})
            keep_results = item.get('keep_results', False)

            try:
                result = call(*args, **kwargs)

                if keep_results:
                    self.pool_results.append(dill.dumps((item, result)))
                else:
                    del call, args, kwargs, keep_results, item, result

            except Exception as e:
                print e
                traceback.print_exc()
                os.kill(os.getpid(), signal.SIGUSR1)

            self.queue.task_done()

    def finish_pool_queue(self, callable=None):
        self.frozen_pool.value = False

        while self.queue._unfinished_tasks.get_value() > 0:
            if self.print_queue:
                print_info('--> Process pool... %s' % (self.queue._unfinished_tasks.get_value()))

            if callable:
                callable()

            sleep(5)

        for i in range(self.queue_processes):
            self.queue.put(None)

        self.queue.join()
        self.queue.close()

        for p in self.processes:
            with ignore_exception: p.join(10)
            with ignore_exception: p.terminate()

        with ignore_exception: del self.processes[:]

    def get_pool_results(self):
        return self.pool_results

    def clear_pool_results(self):
        del self.pool_results[:]
def test(eg):
        print 'EG', eg

दोनों के साथ कॉल करें:

tp = ThreadPool(queue_threads=2)
tp.queue.put({'call': test, 'args': [random.randint(0, 100)]})
tp.finish_pool_queue()

या

pp = ProcessPool(queue_processes=2)
pp.queue.put(dill.dumps({'call': test, 'args': [random.randint(0, 100)]}))
pp.queue.put(dill.dumps({'call': test, 'args': [random.randint(0, 100)]}))
pp.finish_pool_queue()

0

बस 2 स्टैंडअलोन कार्यक्रमों के बीच एक कतार पर एक संदेश पारित करने के प्रदर्शन के लिए एक सरल और सामान्य उदाहरण बनाया। यह सीधे ओपी के सवाल का जवाब नहीं देता है, लेकिन अवधारणा को इंगित करने के लिए पर्याप्त स्पष्ट होना चाहिए।

सर्वर:

multiprocessing-queue-manager-server.py

import asyncio
import concurrent.futures
import multiprocessing
import multiprocessing.managers
import queue
import sys
import threading
from typing import Any, AnyStr, Dict, Union


class QueueManager(multiprocessing.managers.BaseManager):

    def get_queue(self, ident: Union[AnyStr, int, type(None)] = None) -> multiprocessing.Queue:
        pass


def get_queue(ident: Union[AnyStr, int, type(None)] = None) -> multiprocessing.Queue:
    global q

    if not ident in q:
        q[ident] = multiprocessing.Queue()

    return q[ident]


q: Dict[Union[AnyStr, int, type(None)], multiprocessing.Queue] = dict()
delattr(QueueManager, 'get_queue')


def init_queue_manager_server():
    if not hasattr(QueueManager, 'get_queue'):
        QueueManager.register('get_queue', get_queue)


def serve(no: int, term_ev: threading.Event):
    manager: QueueManager
    with QueueManager(authkey=QueueManager.__name__.encode()) as manager:
        print(f"Server address {no}: {manager.address}")

        while not term_ev.is_set():
            try:
                item: Any = manager.get_queue().get(timeout=0.1)
                print(f"Client {no}: {item} from {manager.address}")
            except queue.Empty:
                continue


async def main(n: int):
    init_queue_manager_server()
    term_ev: threading.Event = threading.Event()
    executor: concurrent.futures.ThreadPoolExecutor = concurrent.futures.ThreadPoolExecutor()

    i: int
    for i in range(n):
        asyncio.ensure_future(asyncio.get_running_loop().run_in_executor(executor, serve, i, term_ev))

    # Gracefully shut down
    try:
        await asyncio.get_running_loop().create_future()
    except asyncio.CancelledError:
        term_ev.set()
        executor.shutdown()
        raise


if __name__ == '__main__':
    asyncio.run(main(int(sys.argv[1])))

ग्राहक:

multiprocessing-queue-manager-client.py

import multiprocessing
import multiprocessing.managers
import os
import sys
from typing import AnyStr, Union


class QueueManager(multiprocessing.managers.BaseManager):

    def get_queue(self, ident: Union[AnyStr, int, type(None)] = None) -> multiprocessing.Queue:
        pass


delattr(QueueManager, 'get_queue')


def init_queue_manager_client():
    if not hasattr(QueueManager, 'get_queue'):
        QueueManager.register('get_queue')


def main():
    init_queue_manager_client()

    manager: QueueManager = QueueManager(sys.argv[1], authkey=QueueManager.__name__.encode())
    manager.connect()

    message = f"A message from {os.getpid()}"
    print(f"Message to send: {message}")
    manager.get_queue().put(message)


if __name__ == '__main__':
    main()

प्रयोग

सर्वर:

$ python3 multiprocessing-queue-manager-server.py N

Nएक पूर्णांक है जो यह दर्शाता है कि कितने सर्वर बनाने चाहिए। <server-address-N>सर्वर द्वारा आउटपुट में से एक को कॉपी करें और इसे प्रत्येक का पहला तर्क दें multiprocessing-queue-manager-client.py

ग्राहक:

python3 multiprocessing-queue-manager-client.py <server-address-1>

परिणाम

सर्वर:

Client 1: <item> from <server-address-1>

Gist: https://gist.github.com/89062d639e40110c61c2f88018a8b0e5


UPD : यहाँ एक पैकेज बनाया गया ।

सर्वर:

import ipcq


with ipcq.QueueManagerServer(address=ipcq.Address.DEFAULT, authkey=ipcq.AuthKey.DEFAULT) as server:
    server.get_queue().get()

ग्राहक:

import ipcq


client = ipcq.QueueManagerClient(address=ipcq.Address.DEFAULT, authkey=ipcq.AuthKey.DEFAULT)
client.get_queue().put('a message')

यहां छवि विवरण दर्ज करें

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