পাইথন মাল্টিপ্রসেসিং পিকলিংএরর: <টাইপ 'ফাংশন'> তোলা যায় না


243

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

আমি এই সমস্যাটি সম্পর্কে পূর্ববর্তী কয়েকটি নোট সন্ধান করেছি। এগুলি সবই ক্লাস ফাংশনটির মধ্যে সংজ্ঞায়িত পুল কল করতে কল ব্যবহার করার কারণে ঘটেছিল। তবে আমার ক্ষেত্রে এটি হয় না।

Exception in thread Thread-3:
Traceback (most recent call last):
  File "/usr/lib64/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/lib64/python2.7/threading.py", line 505, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/usr/lib64/python2.7/multiprocessing/pool.py", line 313, in _handle_tasks
    put(task)
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed

আমি কোন সাহায্য কৃতজ্ঞ হবে।

আপডেট : আমি যে ফাংশনটি নিয়েছি তা মডিউলটির শীর্ষ স্তরে সংজ্ঞায়িত করা হয়েছে। যদিও এটি কোনও ফাংশনকে কল করে যা একটি নেস্টেড ফাংশন ধারণ করে। যেমন, f()কলগুলি g()কলগুলি h()যার নেস্টেড ফাংশন রয়েছে i()এবং আমি কল করছি pool.apply_async(f)f(), g(), h()সমস্ত শীর্ষস্থানীয় পর্যায়ে সংজ্ঞায়িত করা হয়। আমি এই প্যাটার্নটির সাথে সহজ উদাহরণ চেষ্টা করেছি এবং এটি কার্যকর হয়।


3
শীর্ষ স্তরের / স্বীকৃত উত্তরটি ভাল তবে এর অর্থ হতে পারে আপনার কোডটি পুনর্গঠন করা দরকার যা বেদনাদায়ক হতে পারে। আমি এই সমস্যা আছে এমন কারও জন্য সুপারিশ করব অতিরিক্ত ব্যবহার dillএবং ব্যবহারের উত্তরগুলি পড়ার জন্য pathos। তবে, ভ্যাটকোবজেক্টসের সাথে কাজ করার সময় আমি কোনও সমাধানের ভাগ্যেই ভাগ্যবান নই :( যে কেউ সমান্তরাল প্রক্রিয়াকরণে ভিটিপিপলিডাটাতে পাইথন কোড চালাতে পেরেছেন?
ক্রিস

উত্তর:


305

এখানে কী কী আচার তৈরি করা যায় তার একটি তালিকা এখানে । বিশেষত, ফাংশনগুলি কেবল পিকলেবল হয় যদি সেগুলি মডিউলের শীর্ষ স্তরে সংজ্ঞায়িত করা হয়।

এই কোডের টুকরো:

import multiprocessing as mp

class Foo():
    @staticmethod
    def work(self):
        pass

if __name__ == '__main__':   
    pool = mp.Pool()
    foo = Foo()
    pool.apply_async(foo.work)
    pool.close()
    pool.join()

আপনি যে পোস্ট করেছেন তার প্রায় অনুরূপ একটি ত্রুটি এনে দেয়:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 505, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 315, in _handle_tasks
    put(task)
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed

সমস্যাটি হ'ল poolপদ্ধতিগুলি mp.SimpleQueueসমস্তরূপে কর্মী প্রক্রিয়াগুলিতে কাজগুলি পাস করার জন্য একটি ব্যবহার করে। মডিউলের শীর্ষ স্তরে এটি সংজ্ঞায়িত না হওয়ায় mp.SimpleQueueঅবশ্যই প্রয়োজনীয় সমস্ত কিছু অবশ্যই foo.workবাছাইযোগ্য এবং চয়নযোগ্য নয়।

এটি শীর্ষ স্তরের কোনও ফাংশন সংজ্ঞায়িত করে স্থির করা যেতে পারে, যা কল করে foo.work():

def work(foo):
    foo.work()

pool.apply_async(work,args=(foo,))

লক্ষ্য করুন যে fooবাছাইযোগ্য, যেহেতু Fooশীর্ষ স্তরে সংজ্ঞায়িত এবং foo.__dict__পিকলেবল।


2
আপনার উত্তর দেওয়ার জন্য ধন্যবাদ. আমি আমার প্রশ্ন আপডেট। আমি কারণটি হিন্টিং করি না, যদিও
ভেন্ডেটা

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

3
এছাড়াও: আপনি যদি কোনও মডিউলের শীর্ষ স্তরের কোনও ফাংশনটি সংজ্ঞায়িত করেন তবে এটি সজ্জিত হয় তবে রেফারেন্সটি সাজসজ্জারের আউটপুটটি হবে এবং আপনি যেভাবেই এই ত্রুটিটি পেয়ে যাবেন।
ববপোকের্ট

5
মাত্র 5 বছর দেরীতে, তবে আমি কেবল এটির মধ্যে দিয়েছি। এটা পরিনত হয় যে "শীর্ষ স্তরের" স্বাভাবিকের তুলনায় আরো আক্ষরিক গ্রহণ করা হবে আছে: এটা আমার মনে হচ্ছে ফাংশন সংজ্ঞা পূর্ববর্তী আছে পুল আরম্ভের (অর্থাত pool = Pool()লাইন এখানে )। আমি এটি আশা করিনি, এবং এটিই কারণ হ'ল ওপির সমস্যাটি বহাল।
আন্দ্রেস ডেক

4
বিশেষত, ফাংশনগুলি কেবল পিকলেবল হয় যদি সেগুলি মডিউলের শীর্ষ স্তরে সংজ্ঞায়িত করা হয়। এটি প্রদর্শিত হয় যে functool.partialকোনও শীর্ষ-স্তরের ফাংশনে আবেদনের ফলাফলটিও আচার-সক্ষম, এমনকি যদি এটি অন্য ফাংশনের অভ্যন্তরে সংজ্ঞায়িত হয়।
ব্যবহারকারী 1071847

96

আমি pathos.multiprocesssingপরিবর্তে ব্যবহার করব multiprocessing। যে ব্যবহারের pathos.multiprocessingএকটি কাঁটাচামচ । পাইথনের প্রায় কোনও কিছু সিরিয়ালাইজ করতে পারে, তাই আপনি সমান্তরালে আরও অনেক কিছু প্রেরণ করতে সক্ষম হন। কাঁটাচামচ এছাড়াও হিসাবে আপনি বর্গ পদ্ধতি জন্য প্রয়োজন, একাধিক যুক্তি ফাংশন সাথে সরাসরি কাজ করার ক্ষমতা আছে।multiprocessingdilldillpathos

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> p = Pool(4)
>>> class Test(object):
...   def plus(self, x, y): 
...     return x+y
... 
>>> t = Test()
>>> p.map(t.plus, x, y)
[4, 6, 8, 10]
>>> 
>>> class Foo(object):
...   @staticmethod
...   def work(self, x):
...     return x+1
... 
>>> f = Foo()
>>> p.apipe(f.work, f, 100)
<processing.pool.ApplyResult object at 0x10504f8d0>
>>> res = _
>>> res.get()
101

এখানে pathos(এবং যদি আপনি চান dill) পান : https://github.com/uqfoundation


5
একটি ট্রিট কাজ। অন্য কারও জন্য, আমি উভয় লাইব্রেরি ইনস্টল করেছি: sudo pip install git+https://github.com/uqfoundation/dill.git@masterএবংsudo pip install git+https://github.com/uqfoundation/pathos.git@master
আলেকজান্ডার ম্যাকফার্লান

5
@ আলেকজান্ডারম্যাকফার্লেন আমি পাইথন প্যাকেজগুলি ইনস্টল করব না sudo(বিশেষত গিথুব হিসাবে বাহ্যিক উত্স থেকে)। পরিবর্তে, আমি চালানোর জন্য সুপারিশ করব:pip install --user git+...
ক্রিস

শুধু ব্যবহার করা pip install pathosদুঃখজনকভাবে কাজ করে না এবং এই বার্তাটি দেয়:Could not find a version that satisfies the requirement pp==1.5.7-pathos (from pathos)
x অ্যাপল

11
pip install pathosএখন কাজ করে, এবং pathosপাইথন 3 সামঞ্জস্যপূর্ণ।
মাইক ম্যাকার্নস

3
@DanielGoldfarb: multiprocessএকটি কাঁটাচামচ হয় multiprocessingযেখানে dillপ্রতিস্থাপিত হয়েছে pickleকোডে বিভিন্ন জায়গায়, এটা যে ... কিন্তু মূলত। pathosকিছু অতিরিক্ত API স্তর সরবরাহ করে multiprocessএবং এতে অতিরিক্ত ব্যাকেন্ড রয়েছে। তবে, এটির মূল বক্তব্য।
মাইক ম্যাকার্নস

29

যেমনটি অন্যরা বলেছেন multiprocessingযে পাইথন অবজেক্টগুলি কেবল কর্মী প্রক্রিয়াগুলিতে স্থানান্তর করতে পারে যা মিশ্রিত করা যায়। যদি আপনি আনটবু দ্বারা বর্ণিত হিসাবে আপনার কোডটি পুনর্গঠিত করতে না পারেন, তবে dillআমি নীচে দেখানো হিসাবে আপনি ডেটা স্থানান্তর করার জন্য (বিশেষত কোড ডেটা) বাড়ানো বাছাই / আনপিকলিং ক্ষমতা ব্যবহার করতে পারেন ।

এই সমাধানটির জন্য কেবল dillঅন্য কোনও গ্রন্থাগার স্থাপন করা প্রয়োজন pathos:

import os
from multiprocessing import Pool

import dill


def run_dill_encoded(payload):
    fun, args = dill.loads(payload)
    return fun(*args)


def apply_async(pool, fun, args):
    payload = dill.dumps((fun, args))
    return pool.apply_async(run_dill_encoded, (payload,))


if __name__ == "__main__":

    pool = Pool(processes=5)

    # asyn execution of lambda
    jobs = []
    for i in range(10):
        job = apply_async(pool, lambda a, b: (a, b, a * b), (i, i + 1))
        jobs.append(job)

    for job in jobs:
        print job.get()
    print

    # async execution of static method

    class O(object):

        @staticmethod
        def calc():
            return os.getpid()

    jobs = []
    for i in range(10):
        job = apply_async(pool, O.calc, ())
        jobs.append(job)

    for job in jobs:
        print job.get()

6
আমি dillএবং pathosলেখক… এবং আপনি যখন ঠিক বলেছেন, pathosআমার উত্তর হিসাবে ব্যবহার করা কি এতটা সুন্দর এবং ক্লিনার এবং আরও নমনীয় নয় ? অথবা সম্ভবত আমি কিছুটা পক্ষপাতদুষ্ট…
মাইক ম্যাকার্নস

4
pathosলেখার সময় আমি স্ট্যাটাস সম্পর্কে সচেতন ছিলাম না এবং এমন একটি সমাধান উপস্থাপন করতে চেয়েছিলাম যা উত্তরের খুব কাছাকাছি। এখন যেহেতু আমি আপনার সমাধানটি দেখেছি আমি সম্মত হয়েছি যে এটিই যাওয়ার উপায়।
রকসপ্রোকার

আমি আপনার সমাধানটি পড়েছি এবং মত ছিলাম, Doh… I didn't even think of doing it like that. তাই দুর্দান্ত ছিল।
মাইক ম্যাকার্নস

4
: পোস্ট করার জন্য ধন্যবাদ, আমি dilling / undilling আর্গুমেন্ট জন্য এই পদ্ধতির যে জরা করা যায়নি ব্যবহৃত stackoverflow.com/questions/27883574/...
jazzblue

@rocksportrocker। আমি এই উদাহরণটি পড়ছি এবং কেন স্পষ্ট forলুপ রয়েছে তা বুঝতে পারি না । আমি সাধারণত দেখতে চাই সমান্তরাল রুটিন একটি তালিকা নেবে এবং লুপ ছাড়াই একটি তালিকা ফিরে আসবে।
ব্যবহারকারী 1700890

20

আমি খুঁজে পেয়েছি যে আমি এতে প্রোফাইলার ব্যবহার করার চেষ্টা করে ঠিকঠাকভাবে কোডের টুকরো টুকরোটিতে ত্রুটি আউটপুট উত্পন্ন করতে পারি।

নোট করুন যে এটি উইন্ডোতে ছিল (যেখানে কাঁটাচামচটি কিছুটা কম মার্জিত)

আমি দৌড়ছিলাম:

python -m profile -o output.pstats <script> 

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

সংরক্ষণাগারগুলির জন্য এখানে অন্য কেউ প্রবেশ করার ক্ষেত্রে পোস্টিং।


3
বাহ, উল্লেখ করার জন্য ধন্যবাদ! এটি আমাকে শেষ ঘন্টা বা তার জন্য বাদাম চালিয়েছে; আমি খুব সাধারণ উদাহরণ পর্যন্ত সবকিছু চেষ্টা করেছিলাম - কিছুই মনে হয় কাজ করে না। তবে আমার প্রোফাইলটিও আমার ব্যাচফাইলে চলছিল :(
টিম

1
ওহ, আপনাকে যথেষ্ট ধন্যবাদ দিতে পারে না এটি যদিও এতটাই অপ্রত্যাশিত তাই নির্বাক শোনায়। আমি মনে করি এটি ডক্সে উল্লেখ করা উচিত। আমার যা কিছু ছিল তা ছিল আমদানি পিডিবি বিবৃতি, এবং কেবলমাত্র একটি সাধারণ শীর্ষ স্তরের ফাংশনটি pass'আচারযোগ্য' ছিল না।
0xc0de

10

যখন এই সমস্যাটি আসে তখন multiprocessingএকটি সহজ সমাধান থেকে স্যুইচ করা Poolহয় ThreadPool। এটি আমদানি ব্যতীত কোডের কোনও পরিবর্তন ছাড়াই করা যেতে পারে-

from multiprocessing.pool import ThreadPool as Pool

এটি কাজ করে কারণ থ্রেডপুল একটি নতুন প্রক্রিয়া তৈরি করার পরিবর্তে মূল থ্রেডের সাথে মেমরি ভাগ করে। এর অর্থ এই যে পিকিংয়ের দরকার নেই।

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

সুতরাং আপনি যদি পাইথন ব্যবহারকারী স্থানে এক টন স্টাফ প্রক্রিয়াজাত করেন তবে এটি সেরা পদ্ধতি নাও হতে পারে।


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

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

সত্য, ধন্যবাদ। তবুও আপনি উত্তরে একটি সতর্কবাণী অন্তর্ভুক্ত করতে চাইতে পারেন। এই দিনগুলিতে যখন প্রক্রিয়াকরণ শক্তি বৃদ্ধি প্রায়শই আরও শক্তিশালী সিপিইউ কোরের পরিবর্তে আরও আকারে আসে, মাল্টিকোর থেকে একক-কোর কার্যকরকরণে স্যুইচ করা একটি বরং উল্লেখযোগ্য পার্শ্ব প্রতিক্রিয়া।
এন্ড্রে উভয়ই

ভাল পয়েন্ট- আমি উত্তরটি আরও বিশদ সহ আপডেট করেছি। যদিও আমি উল্লেখ করতে চাই যে থ্রেডযুক্ত মাল্টিপ্রসেসিংয়ে স্যুইচিংয়ের ফলে পাইথনটি কেবল একটি কোরে কাজ করে না।
টিডিভম

4

এই দ্রবণটির জন্য কেবল ডিল স্থাপন করা প্রয়োজন এবং প্যাথো হিসাবে কোনও লাইব্রেরি নেই

def apply_packed_function_for_map((dumped_function, item, args, kwargs),):
    """
    Unpack dumped function as target function and call it with arguments.

    :param (dumped_function, item, args, kwargs):
        a tuple of dumped function and its arguments
    :return:
        result of target function
    """
    target_function = dill.loads(dumped_function)
    res = target_function(item, *args, **kwargs)
    return res


def pack_function_for_map(target_function, items, *args, **kwargs):
    """
    Pack function and arguments to object that can be sent from one
    multiprocessing.Process to another. The main problem is:
        «multiprocessing.Pool.map*» or «apply*»
        cannot use class methods or closures.
    It solves this problem with «dill».
    It works with target function as argument, dumps it («with dill»)
    and returns dumped function with arguments of target function.
    For more performance we dump only target function itself
    and don't dump its arguments.
    How to use (pseudo-code):

        ~>>> import multiprocessing
        ~>>> images = [...]
        ~>>> pool = multiprocessing.Pool(100500)
        ~>>> features = pool.map(
        ~...     *pack_function_for_map(
        ~...         super(Extractor, self).extract_features,
        ~...         images,
        ~...         type='png'
        ~...         **options,
        ~...     )
        ~... )
        ~>>>

    :param target_function:
        function, that you want to execute like  target_function(item, *args, **kwargs).
    :param items:
        list of items for map
    :param args:
        positional arguments for target_function(item, *args, **kwargs)
    :param kwargs:
        named arguments for target_function(item, *args, **kwargs)
    :return: tuple(function_wrapper, dumped_items)
        It returs a tuple with
            * function wrapper, that unpack and call target function;
            * list of packed target function and its' arguments.
    """
    dumped_function = dill.dumps(target_function)
    dumped_items = [(dumped_function, item, args, kwargs) for item in items]
    return apply_packed_function_for_map, dumped_items

এটি ন্যালি অ্যারেগুলির জন্যও কাজ করে।


2
Can't pickle <type 'function'>: attribute lookup __builtin__.function failed

অ্যাসিঙ্ক জবটিতে পাস হওয়া মডেল অবজেক্টের অভ্যন্তরে যদি কোনও ইনবিল্ট ফাংশন থাকে তবে এই ত্রুটিটিও আসবে।

সুতরাং পাস করা মডেল অবজেক্টগুলির ইনবিল্ট ফাংশন নেই তা পরীক্ষা করে দেখুন । (আমাদের ক্ষেত্রে আমরা নির্দিষ্ট ক্ষেত্রটি ট্র্যাক করতে মডেলটির অভ্যন্তরে জ্যাঙ্গো-মডেল-ইউজগুলিরFieldTracker() ফাংশন ব্যবহার করছিলাম )। এখানে প্রাসঙ্গিক গিটহাব ইস্যুটির লিঙ্ক


0

@ রকসপোর্ট্রোকার সলিউশনে বিল্ডিং করা, ফলাফলগুলি প্রেরণ এবং পুনর্নবীকরণের সময় ডিল করার অর্থ হবে।

import dill
import itertools
def run_dill_encoded(payload):
    fun, args = dill.loads(payload)
    res = fun(*args)
    res = dill.dumps(res)
    return res

def dill_map_async(pool, fun, args_list,
                   as_tuple=True,
                   **kw):
    if as_tuple:
        args_list = ((x,) for x in args_list)

    it = itertools.izip(
        itertools.cycle([fun]),
        args_list)
    it = itertools.imap(dill.dumps, it)
    return pool.map_async(run_dill_encoded, it, **kw)

if __name__ == '__main__':
    import multiprocessing as mp
    import sys,os
    p = mp.Pool(4)
    res = dill_map_async(p, lambda x:[sys.stdout.write('%s\n'%os.getpid()),x][-1],
                  [lambda x:x+1]*10,)
    res = res.get(timeout=100)
    res = map(dill.loads,res)
    print(res)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.