পাইথনে সমান্তরাল প্রোগ্রামিং কীভাবে করবেন?


141

সি ++ এর জন্য আমরা সমান্তরাল প্রোগ্রামিং করতে ওপেনএমপি ব্যবহার করতে পারি; তবে ওপেনএমপি পাইথনের পক্ষে কাজ করবে না। আমার অজগর প্রোগ্রামের কিছু অংশের সমান্তরাল করতে চাইলে আমার কী করা উচিত?

কোডটির গঠন হিসাবে বিবেচনা করা যেতে পারে:

solve1(A)
solve2(B)

যেখানে solve1এবং solve2দুটি স্বতন্ত্র ফাংশন। চলমান সময় হ্রাস করার জন্য এই ধরণের কোডটি ক্রমানুসারে পরিবর্তে সমান্তরালে কীভাবে চালানো যায়? আশা করি কেউ আমাকে সাহায্য করতে পারে। আগাম ধন্যবাদ। কোডটি হ'ল:

def solve(Q, G, n):
    i = 0
    tol = 10 ** -4

    while i < 1000:
        inneropt, partition, x = setinner(Q, G, n)
        outeropt = setouter(Q, G, n)

        if (outeropt - inneropt) / (1 + abs(outeropt) + abs(inneropt)) < tol:
            break

        node1 = partition[0]
        node2 = partition[1]

        G = updateGraph(G, node1, node2)

        if i == 999:
            print "Maximum iteration reaches"
    print inneropt

যেখানে সেটিনার এবং সেউটর দুটি পৃথক ফাংশন। আমি যেখানে সমান্তরাল করতে চাই ...


31
মাল্টিপ্রসেসিং এ একবার দেখুন । দ্রষ্টব্য: পাইথনের থ্রেডগুলি কেবলমাত্র I / O- বাউন্ডের জন্য সিপিইউ-বাউন্ড কাজের জন্য উপযুক্ত নয়।
9000

4
@ 9000 +100 বনাম আই / ও নির্ভরশীল কার্যগুলি সিপিইউ উল্লেখ করার জন্য বাধা দেয়।
হাইপারবোরাস

@ 9000 আসলে থ্রেডগুলি সিপিইউ-বাউন্ডড টাস্কের পক্ষে যথাসম্ভব উপযুক্ত নয় যতদূর আমি জানি! প্রকৃত সিপিইউযুক্ত কাজগুলি করার সময় প্রক্রিয়াগুলি যাওয়ার উপায়।
ওমর আল-ইতাওয়াই

6
@ ওমারিথা: কেন, আপনার যদি অনেকগুলি সিপিইউ কোর থাকে (যথারীতি এখনই) তবে থ্রেডগুলি ঠিকঠাক কাজ করে। তারপরে আপনার প্রক্রিয়া এই সমস্ত কোরকে সমান্তরালভাবে লোড করে এবং তাদের মধ্যে স্পষ্টতভাবে ভাগ করে নেওয়ার জন্য সাধারণ ডেটা ভাগ করে নিতে পারে (এটি কোনও স্পষ্টভাবে ভাগ করা মেমরির অঞ্চল বা আন্ত-প্রক্রিয়া বার্তা না করে)।
9000

1
@ ব্যবহারকারী2134774: আচ্ছা, হ্যাঁ, আমার দ্বিতীয় মন্তব্যটি কিছুটা অর্থপূর্ণ নয়। সম্ভবত জিআইএলকে ছেড়ে দেওয়া কেবলমাত্র সি এক্সটেনশানগুলি এতে উপকৃত হতে পারে; উদাহরণস্বরূপ NumPy এবং পান্ডার অংশগুলি এটি করে। অন্যান্য ক্ষেত্রে এটি ভুল (তবে আমি এখন এটি সম্পাদনা করতে পারি না)।
9000

উত্তর:


162

আপনি মাল্টিপ্রসেসিং মডিউলটি ব্যবহার করতে পারেন । এই ক্ষেত্রে আমি একটি প্রসেসিং পুল ব্যবহার করতে পারি:

from multiprocessing import Pool
pool = Pool()
result1 = pool.apply_async(solve1, [A])    # evaluate "solve1(A)" asynchronously
result2 = pool.apply_async(solve2, [B])    # evaluate "solve2(B)" asynchronously
answer1 = result1.get(timeout=10)
answer2 = result2.get(timeout=10)

এটি আপনার জন্য জেনেরিক কাজ করতে পারে এমন প্রক্রিয়াগুলিকে ছড়িয়ে দেবে। যেহেতু আমরা পাস করিনি processes, এটি আপনার মেশিনের প্রতিটি সিপিইউ কোরের জন্য একটি প্রক্রিয়া তৈরি করবে। প্রতিটি সিপিইউ কোর একই সাথে একটি প্রক্রিয়া চালাতে পারে।

আপনি যদি কোনও একক কার্যক্রমে একটি তালিকা মানচিত্র করতে চান তবে আপনি এটি করতে পারেন:

args = [A, B]
results = pool.map(solve1, args)

থ্রেড ব্যবহার করবেন না কারণ জিআইএল পাইথন বস্তুগুলিতে কোনও ক্রিয়াকলাপটিকে লক করে।


1
pool.mapএছাড়াও অভিধানগুলি আরগ হিসাবে গ্রহণ করে ? নাকি কেবল সাধারণ তালিকা?
বান্ডার

আমি মনে করি কেবল তালিকা। তবে আপনি কেবল ডিক্টেমাইটস () এ পাস করতে পারবেন যা মূল মান টিপলগুলির একটি তালিকা হবে
ম্যাট উইলিয়ামসন

দুর্ভাগ্যক্রমে এটি একটি 'অপসারণযোগ্য প্রকার:' তালিকা 'ত্রুটিতে শেষ হয়
বান্ডার

আমার শেষ মন্তব্য ছাড়াও:। ڈک.items () `কাজ। ত্রুটিটি উত্থাপিত হয়, কারণ প্রক্রিয়া-ফানকিশনের পরিবর্তনশীল অন্তর্দৃষ্টিটির হ্যান্ডলিংটি আমাকে পরিবর্তন করতে হয়েছিল। দুর্ভাগ্যক্রমে ত্রুটি-বার্তা খুব সহায়ক ছিল না ... সুতরাং: আপনার ইঙ্গিতটির জন্য আপনাকে ধন্যবাদ। :-)
বেন্ডার

2
এখানে সময়সীমা কী?
গামা 18

26

এটি রায়ের সাথে খুব মার্জিতভাবে করা যেতে পারে ।

আপনার উদাহরণটির সমান্তরাল করতে আপনার @ray.remoteসাজসজ্জারের সাথে আপনার ফাংশনগুলি সংজ্ঞায়িত করতে হবে এবং তারপরে তাদের সাথে অনুরোধ করতে হবে .remote

import ray

ray.init()

# Define the functions.

@ray.remote
def solve1(a):
    return 1

@ray.remote
def solve2(b):
    return 2

# Start two tasks in the background.
x_id = solve1.remote(0)
y_id = solve2.remote(1)

# Block until the tasks are done and get the results.
x, y = ray.get([x_id, y_id])

মাল্টিপ্রসেসিং মডিউলটির মাধ্যমে এর অনেকগুলি সুবিধা রয়েছে ।

  1. একই কোডটি একটি মাল্টিকোর মেশিনের পাশাপাশি মেশিনগুলির একটি ক্লাস্টারে চালিত হবে।
  2. প্রক্রিয়াগুলি ভাগ করে নেওয়া মেমরি এবং শূন্য-অনুলিপি সিরিয়ালের মাধ্যমে দক্ষতার সাথে ডেটা ভাগ করে ।
  3. ত্রুটি বার্তা সুন্দরভাবে প্রচার করা হয়।
  4. এই ফাংশন কলগুলি একসাথে রচনা করা যেতে পারে, যেমন,

    @ray.remote
    def f(x):
        return x + 1
    
    x_id = f.remote(1)
    y_id = f.remote(x_id)
    z_id = f.remote(y_id)
    ray.get(z_id)  # returns 4
    
  5. দূরবর্তী অবস্থান থেকে ক্রিয়াকলাপ চাওয়া ছাড়াও ক্লাসগুলি অভিনেতা হিসাবে দূরবর্তী সময়ে ইনস্ট্যান্ট করা যেতে পারে ।

দ্রষ্টব্য যে রায় এমন একটি কাঠামো যা আমি বিকাশে সহায়তা করেছি।


আমি একটি ত্রুটি পেয়ে যাচ্ছি যা বলে যে "প্রয়োজনীয় রশ্মি পূরণ করে এমন সংস্করণ খুঁজে
পেল

2
সাধারণত এই ধরণের ত্রুটির অর্থ আপনার আপগ্রেড করা দরকার pip। আমি চেষ্টা করার পরামর্শ দেব pip install --upgrade pip। আপনার যদি sudoএকেবারে ব্যবহারের প্রয়োজন হয় তবে সম্ভবত এটি pipইনস্টল rayকরতে যা ব্যবহার করছেন তার সংস্করণটি আপগ্রেড হচ্ছে এমনটি নয়। আপনি চেক করতে পারেন pip --version। এছাড়াও, উইন্ডোজ বর্তমানে সমর্থিত নয় তাই যদি আপনি উইন্ডোজটিতে থাকেন তবে সম্ভবত এটি সমস্যা।
রবার্ট নিশিহার

1
কেবলমাত্র একটি নোট এটি মূলত একাধিক মেশিনে সমবর্তী কাজ বিতরণের জন্য।
ম্যাট উইলিয়ামসন

2
এটি আসলে একক-মেশিন কেস এবং ক্লাস্টার সেটিং উভয়ের জন্যই অনুকূলিত ized নকশার অনেকগুলি সিদ্ধান্ত (যেমন, ভাগ করা মেমরি, জিরো-কপি সিরিয়ালাইজেশন) একক মেশিনকে ভালভাবে সমর্থন করার জন্য লক্ষ্যযুক্ত।
রবার্ট নিশিহার

2
যদি দস্তাবেজগুলি আরও উল্লেখ করে তবে এটি দুর্দান্ত হবে। ডক্সটি পড়ে আমি বুঝতে পেরেছিলাম যে এটি সত্যই সিঙ্গল মেশিনের ক্ষেত্রে নয়।
স্লেজ

4

সিপিথন গ্লোবাল ইন্টারপ্রেটার লক ব্যবহার করে যা সমান্তরাল প্রোগ্রামিংকে সি ++ এর চেয়ে কিছুটা আকর্ষণীয় করে তোলে

এই বিষয়ের চ্যালেঞ্জের বেশ কয়েকটি দরকারী উদাহরণ এবং বর্ণনা রয়েছে:

পাইথন গ্লোবাল ইন্টারপ্রেটার লক (জিআইএল) লিনাক্সে টাস্কসেট ব্যবহার করে মাল্টি-কোর সিস্টেমে ওয়ার্কআরাউন্ড?


13
আপনি অক্ষমতাটিকে সত্যই একযোগে কোড চালানোর জন্য "আকর্ষণীয়" বলছেন ? : - /
ম্যানুয়েলস্কিনিড 3

4

সমাধান যেমন, অন্যেরা বলেছে, একাধিক প্রক্রিয়া ব্যবহার করা। কোন কাঠামোটি আরও উপযুক্ত, তবে এটি অনেকগুলি কারণের উপর নির্ভর করে। ইতিমধ্যে উল্লিখিতগুলি ছাড়াও, এখানে রয়েছে চারম 4 পিপি এবং এমপিআইপিপি (আমি চার্ম 4py এর বিকাশকারী)।

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

উদাহরণস্বরূপ, charm4py এ এটি করা যেতে পারে:

class Worker(Chare):

    def __init__(self, Q, G, n):
        self.G = G
        ...

    def setinner(self, node1, node2):
        self.updateGraph(node1, node2)
        ...


def solve(Q, G, n):
    # create 2 workers, each on a different process, passing the initial state
    worker_a = Chare(Worker, onPE=0, args=[Q, G, n])
    worker_b = Chare(Worker, onPE=1, args=[Q, G, n])
    while i < 1000:
        result_a = worker_a.setinner(node1, node2, ret=True)  # execute setinner on worker A
        result_b = worker_b.setouter(node1, node2, ret=True)  # execute setouter on worker B

        inneropt, partition, x = result_a.get()  # wait for result from worker A
        outeropt = result_b.get()  # wait for result from worker B
        ...

মনে রাখবেন যে এই উদাহরণের জন্য আমাদের কেবলমাত্র একজন কর্মী প্রয়োজন। মূল লুপটি কোনও একটি ফাংশন সম্পাদন করতে পারে এবং কর্মীকে অন্যটিকে সম্পাদন করতে পারে। তবে আমার কোডটি কয়েকটি বিষয় চিত্রিত করতে সহায়তা করে:

  1. কর্মী এ 0 প্রক্রিয়াতে চালিত হয় (মূল লুপের সমান)। ফলাফলটির result_a.get()অপেক্ষায় অবরুদ্ধ থাকা অবস্থায়, শ্রমিক এ একই প্রক্রিয়াতে গণনা করে।
  2. আর্গুমেন্টগুলি স্বয়ংক্রিয়ভাবে কর্মী এ সম্পর্কিত রেফারেন্স দ্বারা পাস করা হয়, যেহেতু এটি একই প্রক্রিয়াতে রয়েছে (কোনও অনুলিপি জড়িত নেই)।

2

কিছু ক্ষেত্রে, নুম্বা ব্যবহার করে স্বয়ংক্রিয়ভাবে লুপগুলি সমান্তরাল করা সম্ভব , যদিও এটি কেবল পাইথনের একটি ছোট উপসেটের সাথে কাজ করে:

from numba import njit, prange

@njit(parallel=True)
def prange_test(A):
    s = 0
    # Without "parallel=True" in the jit-decorator
    # the prange statement is equivalent to range
    for i in prange(A.shape[0]):
        s += A[i]
    return s

দুর্ভাগ্যক্রমে, মনে হচ্ছে যে নুম্বা কেবল নম্পি অ্যারেগুলিতে কাজ করে, তবে অন্যান্য পাইথন অবজেক্টের সাথে নয়। তত্ত্ব অনুসারে, পাইথনকে সি ++ তে সংকলন করা এবং তারপরে এটি স্বয়ংক্রিয়ভাবে ইন্টেল সি ++ সংকলকটি ব্যবহার করে সমান্তরাল হওয়া সম্ভব হতে পারে , যদিও আমি এখনও এটি চেষ্টা করে নি।


2

joblibসমান্তরাল গণনা এবং মাল্টিপ্রসেসিং করতে আপনি গ্রন্থাগারটি ব্যবহার করতে পারেন ।

from joblib import Parallel, delayed

আপনি কেবল এমন একটি ফাংশন তৈরি fooকরতে পারেন যা আপনি সমান্তরালভাবে চালিত করতে চান এবং নীচের কোডের উপরের ভিত্তিতে সমান্তরাল প্রক্রিয়াকরণ প্রয়োগ করে:

output = Parallel(n_jobs=num_cores)(delayed(foo)(i) for i in input)

কোথায় num_coresথেকে প্রাপ্ত করা যাবে multiprocessingলাইব্রেরি রূপে অনুসৃত:

import multiprocessing

num_cores = multiprocessing.cpu_count()

যদি আপনার একাধিক ইনপুট আর্গুমেন্ট সহ কোনও ফাংশন থাকে এবং আপনি কেবল একটি তালিকার মাধ্যমে একটি যুক্তির মাধ্যমে পুনরাবৃত্তি করতে চান, তবে আপনি partialফাংশনটি functoolsলাইব্রেরি থেকে নিম্নলিখিতটি হিসাবে ব্যবহার করতে পারেন :

from joblib import Parallel, delayed
import multiprocessing
from functools import partial
def foo(arg1, arg2, arg3, arg4):
    '''
    body of the function
    '''
    return output
input = [11,32,44,55,23,0,100,...] # arbitrary list
num_cores = multiprocessing.cpu_count()
foo_ = partial(foo, arg2=arg2, arg3=arg3, arg4=arg4)
# arg1 is being fetched from input list
output = Parallel(n_jobs=num_cores)(delayed(foo_)(i) for i in input)

আপনি এখানে বেশ কয়েকটি উদাহরণ সহ পাইথন এবং আর মাল্টিপ্রসেসিংয়ের সম্পূর্ণ ব্যাখ্যা পেতে পারেন ।

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