मल्टीप्रोसेसिंग: मैं कई प्रक्रियाओं के बीच एक तानाशाह को कैसे साझा करूं?


113

एक प्रोग्राम जो कई प्रक्रियाओं को बनाता है जो एक सम्मिलित-योग्य कतार पर काम करते हैं Q, और अंततः Dपरिणामों को संग्रहीत करने के लिए एक वैश्विक शब्दकोश में हेरफेर कर सकते हैं । (इसलिए प्रत्येक बच्चे की प्रक्रिया Dअपने परिणाम को स्टोर करने के लिए उपयोग कर सकती है और यह भी देख सकती है कि अन्य बच्चे प्रक्रियाएं क्या परिणाम दे रहे हैं)

अगर मैं डिक्शनरी डी को एक बच्चे की प्रक्रिया में प्रिंट करता हूं, तो मैं उन संशोधनों को देखता हूं जो उस पर किया गया है (यानी डी पर)। लेकिन मुख्य प्रक्रिया क्यू में शामिल होने के बाद, अगर मैं डी प्रिंट करता हूं, तो यह एक खाली तानाशाही है!

मैं समझता हूं कि यह एक सिंक्रनाइज़ेशन / लॉक मुद्दा है। क्या कोई मुझे बता सकता है कि यहां क्या हो रहा है, और मैं डी तक पहुंच को कैसे सिंक्रनाइज़ कर सकता हूं?


1
यह कम से कम उम्मीद के मुताबिक काम नहीं करता है। OSX 10.14.4 डिक्ट का उपयोग करते हुए अजगर 3.7.2 पर है, यह सिंक्रनाइज़ नहीं है और इसकी सामग्री अन्य प्रक्रियाओं द्वारा फिर से लिखी गई है। हालाँकि, <code> multiprocessing.Manager ()। List () </ code> अपेक्षा के अनुसार काम करता है।
एंड्रयू ड्रुकेंको

जवाबों:


162

एक सामान्य उत्तर में एक Managerवस्तु का उपयोग करना शामिल है । डॉक्स से अनुकूलित:

from multiprocessing import Process, Manager

def f(d):
    d[1] += '1'
    d['2'] += 2

if __name__ == '__main__':
    manager = Manager()

    d = manager.dict()
    d[1] = '1'
    d['2'] = 2

    p1 = Process(target=f, args=(d,))
    p2 = Process(target=f, args=(d,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

    print d

आउटपुट:

$ python mul.py 
{1: '111', '2': 6}

4
धन्यवाद प्रेषक। वास्तव में, डी = मल्टीप्रोसेसिंग। मानेगर ()। तानाशाही () मेरी समस्या को हल करता है। मैं डी = तानाशाही () का उपयोग कर रहा था।
डोप

3
@ लॉरेंज़बेल्ली, यदि आप पूछ रहे हैं कि क्या प्रबंधक तक पहुंच सिंक्रनाइज़ है, तो मेरा मानना ​​है कि उत्तर हां है। multiprocessing.Manager()का एक उदाहरणSyncManager देता है , जिसके नाम से उतना ही पता चलता है!
प्रेषक

@ मैं एक बच्चे की प्रक्रिया के साथ एक माता पिता की प्रक्रिया के सुन्न यादृच्छिक साझा करना चाहते हैं। मैं का उपयोग करने की कोशिश की है, Managerलेकिन अभी भी भाग्य नहीं है। क्या आप कृपया यहाँ मेरे प्रश्न पर एक नज़र डाल सकते हैं और देख सकते हैं कि क्या आप कोई समाधान प्रस्तुत कर सकते हैं? यदि मैं np.random.seed(None)हर बार मैं एक यादृच्छिक संख्या उत्पन्न करता हूं, तो मैं अलग-अलग यादृच्छिक संख्या प्राप्त कर सकता हूं , लेकिन यह मुझे मूल प्रक्रिया की यादृच्छिक स्थिति का उपयोग करने की अनुमति नहीं देता है, जो कि मैं नहीं चाहता। कोई भी मदद बहुत ही सराहनीय होगी।
अमीर

1
@RadioControlled एक अद्यतन लिखने के लिए खुश है, लेकिन संक्षेप में, जबकि मुझे नहीं लगता कि आप इसे सीधे कर सकते हैं, आप आसानी से एक ही कुंजी और मूल्यों के साथ एक नया प्रबंधित तानाशाह बना सकते हैं, और मूल के बजाय इसका उपयोग कर सकते हैं। क्या यह आपके मामले के लिए पर्याप्त है?
प्रेषित

1
@ लिंग, मैं यही कर रहा हूं। तो जवाब होगा कि आपको बस यही करना होगा।
रेडियो ने

25

मल्टीप्रोसेसिंग थ्रेडिंग की तरह नहीं है। प्रत्येक बच्चे की प्रक्रिया को मुख्य प्रक्रिया की मेमोरी की एक प्रति मिलेगी। आम तौर पर राज्य को संचार (पाइप / सॉकेट), सिग्नल या साझा मेमोरी के माध्यम से साझा किया जाता है।

मल्टीप्रोसेसिंग आपके उपयोग के मामले के लिए कुछ सार उपलब्ध करता है - साझा स्थिति जिसे परदे के पीछे से साझा किया जाता है या साझा किया जाता है: http://docs.python.org/library/multiprocessing.html#sharing-state-between-processes

प्रासंगिक अनुभाग:


1
बहुत बहुत धन्यवाद। आपने मुझे / एक समाधान के लिए नेतृत्व किया: बहुसंकेतन। मैनाजर ()। तानाशाही ()।
DOP

क्या कोई इस बात पर विस्तार से बता सकता है कि "प्रत्येक बच्चे की प्रक्रिया को मुख्य प्रक्रिया की स्मृति की एक प्रति मिलेगी" का अर्थ क्या है।
इसकाme2003

@ Itsme2003 डिफ़ॉल्ट रूप से एक स्पॉन्डेड प्रक्रिया की मूल प्रक्रिया की मेमोरी तक कोई पहुँच नहीं है (यह थ्रेड्स के लिए आइस अंतर में से एक है)। इसलिए जब किसी प्रक्रिया को मूल प्रक्रिया की एक वस्तु की आवश्यकता होती है, तो उसे इसकी एक प्रति (वास्तविक वस्तु का संदर्भ प्राप्त करने के बजाय) बनानी होगी। प्रक्रियाओं के बीच वस्तुओं को साझा करने के तरीके के बारे में विस्तार से बताया गया है।
निकोलस मर्कट

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

16

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

from mmap import mmap
import struct
from timeit import default_timer
from multiprocessing import Manager
from pyshmht import HashTable


class shared_immutable_dict:
    def __init__(self, a):
        self.hs = 1 << (len(a) * 3).bit_length()
        kvp = self.hs * 4
        ht = [0xffffffff] * self.hs
        kvl = []
        for k, v in a.iteritems():
            h = self.hash(k)
            while ht[h] != 0xffffffff:
                h = (h + 1) & (self.hs - 1)
            ht[h] = kvp
            kvp += self.kvlen(k) + self.kvlen(v)
            kvl.append(k)
            kvl.append(v)

        self.m = mmap(-1, kvp)
        for p in ht:
            self.m.write(uint_format.pack(p))
        for x in kvl:
            if len(x) <= 0x7f:
                self.m.write_byte(chr(len(x)))
            else:
                self.m.write(uint_format.pack(0x80000000 + len(x)))
            self.m.write(x)

    def hash(self, k):
        h = hash(k)
        h = (h + (h >> 3) + (h >> 13) + (h >> 23)) * 1749375391 & (self.hs - 1)
        return h

    def get(self, k, d=None):
        h = self.hash(k)
        while True:
            x = uint_format.unpack(self.m[h * 4:h * 4 + 4])[0]
            if x == 0xffffffff:
                return d
            self.m.seek(x)
            if k == self.read_kv():
                return self.read_kv()
            h = (h + 1) & (self.hs - 1)

    def read_kv(self):
        sz = ord(self.m.read_byte())
        if sz & 0x80:
            sz = uint_format.unpack(chr(sz) + self.m.read(3))[0] - 0x80000000
        return self.m.read(sz)

    def kvlen(self, k):
        return len(k) + (1 if len(k) <= 0x7f else 4)

    def __contains__(self, k):
        return self.get(k, None) is not None

    def close(self):
        self.m.close()

uint_format = struct.Struct('>I')


def uget(a, k, d=None):
    return to_unicode(a.get(to_str(k), d))


def uin(a, k):
    return to_str(k) in a


def to_unicode(s):
    return s.decode('utf-8') if isinstance(s, str) else s


def to_str(s):
    return s.encode('utf-8') if isinstance(s, unicode) else s


def mmap_test():
    n = 1000000
    d = shared_immutable_dict({str(i * 2): '1' for i in xrange(n)})
    start_time = default_timer()
    for i in xrange(n):
        if bool(d.get(str(i))) != (i % 2 == 0):
            raise Exception(i)
    print 'mmap speed: %d gets per sec' % (n / (default_timer() - start_time))


def manager_test():
    n = 100000
    d = Manager().dict({str(i * 2): '1' for i in xrange(n)})
    start_time = default_timer()
    for i in xrange(n):
        if bool(d.get(str(i))) != (i % 2 == 0):
            raise Exception(i)
    print 'manager speed: %d gets per sec' % (n / (default_timer() - start_time))


def shm_test():
    n = 1000000
    d = HashTable('tmp', n)
    d.update({str(i * 2): '1' for i in xrange(n)})
    start_time = default_timer()
    for i in xrange(n):
        if bool(d.get(str(i))) != (i % 2 == 0):
            raise Exception(i)
    print 'shm speed: %d gets per sec' % (n / (default_timer() - start_time))


if __name__ == '__main__':
    mmap_test()
    manager_test()
    shm_test()

मेरे लैपटॉप के प्रदर्शन के परिणाम हैं:

mmap speed: 247288 gets per sec
manager speed: 33792 gets per sec
shm speed: 691332 gets per sec

सरल उपयोग उदाहरण:

ht = shared_immutable_dict({'a': '1', 'b': '2'})
print ht.get('a')

14
Github? प्रलेखन? हम इस उपकरण का उपयोग कैसे कर सकते हैं?
पावलोस पैंतेलियादिस

10

@ प्रेषक के यहाँ के अलावा, कुछ यह भी सोच रहे होंगे कि कैसे कार्यक्षमता का उपयोग करें multiprocessing.Pool

अच्छी बात यह है कि उदाहरण .Pool()के managerलिए एक तरीका है जो शीर्ष स्तर के सभी परिचित एपीआई की नकल करता है multiprocessing

from itertools import repeat
import multiprocessing as mp
import os
import pprint

def f(d: dict) -> None:
    pid = os.getpid()
    d[pid] = "Hi, I was written by process %d" % pid

if __name__ == '__main__':
    with mp.Manager() as manager:
        d = manager.dict()
        with manager.Pool() as pool:
            pool.map(f, repeat(d, 10))
        # `d` is a DictProxy object that can be converted to dict
        pprint.pprint(dict(d))

आउटपुट:

$ python3 mul.py 
{22562: 'Hi, I was written by process 22562',
 22563: 'Hi, I was written by process 22563',
 22564: 'Hi, I was written by process 22564',
 22565: 'Hi, I was written by process 22565',
 22566: 'Hi, I was written by process 22566',
 22567: 'Hi, I was written by process 22567',
 22568: 'Hi, I was written by process 22568',
 22569: 'Hi, I was written by process 22569',
 22570: 'Hi, I was written by process 22570',
 22571: 'Hi, I was written by process 22571'}

यह एक अलग उदाहरण है जहां प्रत्येक प्रक्रिया वैश्विक DictProxyऑब्जेक्ट में बस अपनी प्रक्रिया आईडी लॉग करती है d


3

शायद आप पायथन को आजमा सकते हैं , पाइथन के लिए मेमोरी आधारित हैश टेबल एक्सटेंशन साझा कर रहा है।

नोटिस

  1. यह पूरी तरह से परीक्षण नहीं है, सिर्फ आपके संदर्भ के लिए।

  2. वर्तमान में इसमें मल्टीप्रोसेसिंग के लिए लॉक / सेमी मैकेनिज्म का अभाव है।

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