মাল্টিপ্রসেসিং: একাধিক প্রক্রিয়ার মধ্যে আমি কীভাবে একটি ডিক ভাগ করব?


113

এমন একটি প্রোগ্রাম যা বেশ কয়েকটি প্রক্রিয়া তৈরি করে যা একটি যোগদানের যোগ্য ক্যুতে কাজ করে Qএবং পরিণতিতে Dফলাফল সংরক্ষণের জন্য একটি বিশ্বব্যাপী অভিধানে কারসাজি করতে পারে । (সুতরাং প্রতিটি শিশু প্রক্রিয়া Dতার ফলাফল সংরক্ষণ করতে ব্যবহার করতে পারে এবং অন্যান্য শিশু প্রক্রিয়াগুলি কী ফলাফল উত্পন্ন করছে তাও দেখতে পারে)

যদি আমি একটি শিশু প্রক্রিয়াতে অভিধান ডি প্রিন্ট করি তবে আমি তার উপর (অর্থাত্ D তে) যে পরিবর্তনগুলি করেছি তা দেখতে পাচ্ছি। তবে প্রধান প্রক্রিয়াটি কিউতে যোগদানের পরে, আমি ডি প্রিন্ট করলে এটি একটি খালি ডিক!

আমি বুঝতে পারি এটি একটি সিঙ্ক্রোনাইজেশন / লক ইস্যু। কেউ কি আমাকে বলতে পারে যে এখানে কী ঘটছে এবং আমি কীভাবে ডি এর অ্যাক্সেসকে সিঙ্ক্রোনাইজ করতে পারি?


1
এটি কমপক্ষে পাইথন ৩.7.২ তে প্রত্যাশা অনুযায়ী কাজ করে না ওএসএক্স ১০.১৪.৪ ব্যবহার করে ডিক্ট সিঙ্ক্রোনাইজ হয় না এবং এর বিষয়বস্তুগুলি অন্যান্য প্রক্রিয়া দ্বারা পুনরায় লেখা হয়। তবে <code> মাল্টিপ্রসেসিং M ম্যানেজার ()। তালিকা () </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
ধন্যবাদ প্রেরক আসলে, ডি = মাল্টিপ্রসেসিং। ম্যানেজার ()। ডিক () আমার সমস্যা সমাধান করে sol আমি ডি = ডিক () ব্যবহার করছিলাম।
DOP

3
@ লোরেঞ্জোবেলি, আপনি যদি ম্যানেজারের অ্যাক্সেস সিঙ্ক্রোনাইজড হয় কিনা তা যদি জিজ্ঞাসা করেন তবে আমি বিশ্বাস করি উত্তরটি হ্যাঁ। multiprocessing.Manager()একটি উদাহরণ প্রদান করেSyncManager , যার নাম যতটা পরামর্শ দেয়!
প্রেরক

@ সেন্ডারেল আমি একটি শিশু প্রক্রিয়া সহ একটি পিতামাতার প্রক্রিয়াটির অকার্যকর এলোমেলো অবস্থা ভাগ করতে চাই। আমি চেষ্টা করার চেষ্টা করেছি Managerকিন্তু এখনও ভাগ্য নেই। আপনি কি দয়া করে এখানে আমার প্রশ্নটি একবার দেখে নিতে পারেন এবং সমাধানের প্রস্তাব দিতে পারেন কিনা? আমি np.random.seed(None)প্রতিবার যদি এলোমেলো সংখ্যা উত্পন্ন করি তবে আমি এখনও বিভিন্ন এলোমেলো নম্বর পেতে পারি , তবে এটি আমাকে পিতামাতার প্রক্রিয়াটির এলোমেলো অবস্থা ব্যবহার করতে দেয় না, যা আমি চাই না। কোন সাহায্য ব্যাপকভাবে প্রশংসা করা হয়।
আমির

1
@ রেডিও কন্ট্রোলড একটি আপডেট লিখে খুশি, তবে সংক্ষেপে, যদিও আপনি মনে করেন না যে আপনি এটি সরাসরি ঘটতে পারবেন, আপনি একই কী এবং মানগুলির সাহায্যে সহজেই একটি নতুন পরিচালিত ডিক তৈরি করতে পারেন এবং এটি মূলটির পরিবর্তে ব্যবহার করতে পারেন। এটা কি আপনার মামলার পক্ষে পর্যাপ্ত?
প্রেরক

1
@ সেন্ডারেল, এটাই আমি শেষ করেছিলাম। সুতরাং উত্তরটি হ'ল আপনাকে কেবল এটি করতে হবে।
রেডিও নিয়ন্ত্রিত

25

মাল্টিপ্রসেসিং থ্রেডিংয়ের মতো নয়। প্রতিটি শিশু প্রক্রিয়া মূল প্রক্রিয়াটির মেমরির একটি অনুলিপি পাবে। সাধারণত যোগাযোগ (পাইপ / সকেট), সিগন্যাল বা ভাগ করা মেমরির মাধ্যমে রাষ্ট্র ভাগ করা হয়।

মাল্টিপ্রসেসিং কিছু বিমূর্ত আপনার ব্যবহারের ক্ষেত্রে জন্য উপলব্ধ - ভাগ বলে যে প্রক্সি ব্যবহার দ্বারা স্থানীয় হিসাবে গণ্য বা ভাগ করা মেমোরি আছে: http://docs.python.org/library/multiprocessing.html#sharing-state-between-processes

প্রাসঙ্গিক বিভাগ:


1
অনেক ধন্যবাদ. আপনি আমাকে / সমাধানের দিকে নিয়ে গেছেন: মাল্টিপ্রসেসিং.ম্যানেজার ()। ডিক ()।
DOP

"প্রতিটি শিশু প্রক্রিয়া মূল প্রক্রিয়াটির মেমরির একটি অনুলিপি পাবেন" এই বিবৃতিটির অর্থ কী তা নিয়ে কেউ ব্যাখ্যা করতে পারেন?
Itme2003

@ Itme2003 ডিফল্টরূপে একটি স্বাচ্ছন্দিত প্রক্রিয়াটির পিতামাতার প্রক্রিয়াটির স্মৃতিতে কোনও অ্যাক্সেস নেই (এটি থ্রেডের ক্ষেত্রে কীকি পার্থক্যগুলির মধ্যে একটি)। সুতরাং যখন কোনও প্রক্রিয়া পিতামাতার প্রক্রিয়াটির কোনও বস্তুর প্রয়োজন হয়, তখন এটির একটি অনুলিপি তৈরি করতে হবে (প্রকৃত অবজেক্টের রেফারেন্স না দিয়ে)। উপরের উত্তরটি প্রক্রিয়াগুলির মধ্যে কীভাবে অবজেক্টগুলি ভাগ করে নেওয়া যায় তা বিশদভাবে জানায়।
নিক্লাস মার্টশ

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

16

আমি আমার নিজের কাজটি ভাগ করে নিতে চাই যা ম্যানেজারের ডিকের চেয়ে দ্রুত এবং পাইশ্মহ্যাট লাইব্রেরির চেয়ে সহজ এবং স্থিতিশীল যা প্রচুর পরিমাণে মেমরি ব্যবহার করে এবং ম্যাক ওএসের জন্য কাজ করে না। যদিও আমার ডিক কেবল প্লেয়ার স্ট্রিংয়ের জন্য কাজ করে এবং বর্তমানে তা পরিবর্তনযোগ্য। আমি লিনিয়ার প্রোবিং বাস্তবায়ন ব্যবহার করি এবং টেবিলের পরে পৃথক মেমরি ব্লকে কী এবং মানগুলির জোড় সঞ্চয় করি।

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রয়েছে যা শীর্ষ স্তরের সমস্ত পরিচিত API নকল করে 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. বর্তমানে এটি মাল্টিপ্রসেসিংয়ের জন্য লক / সেম প্রক্রিয়াগুলির অভাব রয়েছে।

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