8

クラスのデータ メンバーである関数を処理する際の multiprocessing モジュールの制限に関するさまざまな 議論を認識しています (Pickling の問題による)。

しかし、次のようなものを具体的に許可する別のモジュール、またはマルチプロセッシングの何らかの回避策がありますか (具体的には、関数の定義を並列に適用してクラスの外に存在させることはありません)。

class MyClass():

    def __init__(self):
        self.my_args = [1,2,3,4]
        self.output  = {}

    def my_single_function(self, arg):
        return arg**2

    def my_parallelized_function(self):
        # Use map or map_async to map my_single_function onto the
        # list of self.my_args, and append the return values into
        # self.output, using each arg in my_args as the key.

        # The result should make self.output become
        # {1:1, 2:4, 3:9, 4:16}


foo = MyClass()
foo.my_parallelized_function()
print foo.output

注: これは、クラスの外に移動して、またはコマンドのmy_single_functionようなものを渡すことで簡単に実行できます。しかし、これは関数の並列化された実行を のインスタンスの外にプッシュします。foo.my_argsmapmap_asyncMyClass

私のアプリケーション (毎月のデータのクロス セクションを取得、結合、およびクリーンアップし、それらをそのようなクロス セクションの長い時系列に追加する大規模なデータ クエリを並列化する) では、この機能を私のプログラムのさまざまなユーザーが、さまざまな時間間隔、さまざまな時間増分、収集するデータのさまざまなサブセットなどでクラスのさまざまなインスタンスをインスタンス化するため、それらはすべてそのインスタンスに関連付ける必要があります。

したがって、並列化されたクエリに関連するすべてのデータをインスタンスが所有しているため、並列化の作業もインスタンスによって実行されるようにしたいと考えています。クラス(特に、そのような関数は一般的ではないため、クラス内からあらゆる種類の詳細が必要になります。)

4

3 に答える 3

8

Steven Bethardは、メソッドを pickle 化/unpickle できるようにする方法を投稿しました。次のように使用できます。

import multiprocessing as mp
import copy_reg
import types

def _pickle_method(method):
    # Author: Steven Bethard
    # http://bytes.com/topic/python/answers/552476-why-cant-you-pickle-instancemethods
    func_name = method.im_func.__name__
    obj = method.im_self
    cls = method.im_class
    cls_name = ''
    if func_name.startswith('__') and not func_name.endswith('__'):
        cls_name = cls.__name__.lstrip('_')
    if cls_name:
        func_name = '_' + cls_name + func_name
    return _unpickle_method, (func_name, obj, cls)

def _unpickle_method(func_name, obj, cls):
    # Author: Steven Bethard
    # http://bytes.com/topic/python/answers/552476-why-cant-you-pickle-instancemethods
    for cls in cls.mro():
        try:
            func = cls.__dict__[func_name]
        except KeyError:
            pass
        else:
            break
    return func.__get__(obj, cls)

# This call to copy_reg.pickle allows you to pass methods as the first arg to
# mp.Pool methods. If you comment out this line, `pool.map(self.foo, ...)` results in
# PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup
# __builtin__.instancemethod failed

copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)

class MyClass(object):

    def __init__(self):
        self.my_args = [1,2,3,4]
        self.output  = {}

    def my_single_function(self, arg):
        return arg**2

    def my_parallelized_function(self):
        # Use map or map_async to map my_single_function onto the
        # list of self.my_args, and append the return values into
        # self.output, using each arg in my_args as the key.

        # The result should make self.output become
        # {1:1, 2:4, 3:9, 4:16}
        self.output = dict(zip(self.my_args,
                               pool.map(self.my_single_function, self.my_args)))

それで

pool = mp.Pool()   
foo = MyClass()
foo.my_parallelized_function()

収量

print foo.output
# {1: 1, 2: 4, 3: 9, 4: 16}
于 2012-07-30T18:07:59.043 に答える
1

私が信じているより良いエレガントなソリューションがあります。クラスでマルチプロセッシングを行うコードに次の行を追加しても、プールを介してメソッドを渡すことができます。コードはクラスの上にある必要があります

import copy_reg
    import types

    def _reduce_method(meth):
        return (getattr,(meth.__self__,meth.__func__.__name__))
    copy_reg.pickle(types.MethodType,_reduce_method)

メソッドをピクルする方法の詳細については、以下を参照してください http://docs.python.org/2/library/copy_reg.html

于 2013-11-08T14:36:12.997 に答える