天道酬勤,学无止境

多重处理:如何在类中定义的函数上使用Pool.map?(Multiprocessing: How to use Pool.map on a function defined in a class?)

问题

当我运行类似的东西时:

from multiprocessing import Pool

p = Pool(5)
def f(x):
     return x*x

p.map(f, [1,2,3])

它工作正常。 但是,将其作为类的函数:

class calculate(object):
    def run(self):
        def f(x):
            return x*x

        p = Pool()
        return p.map(f, [1,2,3])

cl = calculate()
print cl.run()

给我以下错误:

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

我看过Alex Martelli的一篇帖子,涉及类似的问题,但还不够明确。

回答1

我也对pool.map可以接受哪种功能的限制感到恼火。 为了避免这种情况,我写了以下内容。 即使递归使用parmap,它似乎也可以工作。

from multiprocessing import Process, Pipe
from itertools import izip

def spawn(f):
    def fun(pipe, x):
        pipe.send(f(x))
        pipe.close()
    return fun

def parmap(f, X):
    pipe = [Pipe() for x in X]
    proc = [Process(target=spawn(f), args=(c, x)) for x, (p, c) in izip(X, pipe)]
    [p.start() for p in proc]
    [p.join() for p in proc]
    return [p.recv() for (p, c) in pipe]

if __name__ == '__main__':
    print parmap(lambda x: x**x, range(1, 5))
回答2

我无法使用到目前为止发布的代码,因为使用“ multiprocessing.Pool”的代码不适用于lambda表达式,并且不使用“ multiprocessing.Pool”的代码会产生与工作项一样多的进程。

我修改了代码,它生成了预定义数量的工作程序,并且仅在存在空闲工作程序时才迭代输入列表。 我还为工作程序st ctrl-c按预期方式启用了“守护程序”模式。

import multiprocessing


def fun(f, q_in, q_out):
    while True:
        i, x = q_in.get()
        if i is None:
            break
        q_out.put((i, f(x)))


def parmap(f, X, nprocs=multiprocessing.cpu_count()):
    q_in = multiprocessing.Queue(1)
    q_out = multiprocessing.Queue()

    proc = [multiprocessing.Process(target=fun, args=(f, q_in, q_out))
            for _ in range(nprocs)]
    for p in proc:
        p.daemon = True
        p.start()

    sent = [q_in.put((i, x)) for i, x in enumerate(X)]
    [q_in.put((None, None)) for _ in range(nprocs)]
    res = [q_out.get() for _ in range(len(sent))]

    [p.join() for p in proc]

    return [x for i, x in sorted(res)]


if __name__ == '__main__':
    print(parmap(lambda i: i * 2, [1, 2, 3, 4, 6, 7, 8]))
回答3

除非您跳出标准库,否则多重处理和酸洗将受到破坏和限制。

如果使用称为pathos.multiprocesssingmultiprocessing pathos.multiprocesssing ,则可以直接在多处理的map函数中使用类和类方法。 这是因为使用dill代替了picklecPickle ,并且dill可以在python中序列化几乎所有东西。

pathos.multiprocessing还提供了一个异步映射函数…,它可以map具有多个参数的函数(例如map(math.pow, [1,2,3], [4,5,6])

查看讨论:多重处理和莳萝可以一起做什么?

和:http://matthewrocklin.com/blog/work/2013/12/05/Parallelism-and-Serialization

它甚至可以处理您最初编写的代码,而无需修改,也可以从解释器处理。 为什么还有其他更脆弱且针对单个案例的问题呢?

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> class calculate(object):
...  def run(self):
...   def f(x):
...    return x*x
...   p = Pool()
...   return p.map(f, [1,2,3])
... 
>>> cl = calculate()
>>> print cl.run()
[1, 4, 9]

在此处获取代码:https://github.com/uqfoundation/pathos

而且,只是为了炫耀它可以做什么:

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> 
>>> p = Pool(4)
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> x = [0,1,2,3]
>>> y = [4,5,6,7]
>>> 
>>> p.map(add, x, y)
[4, 6, 8, 10]
>>> 
>>> class Test(object):
...   def plus(self, x, y): 
...     return x+y
... 
>>> t = Test()
>>> 
>>> p.map(Test.plus, [t]*4, x, y)
[4, 6, 8, 10]
>>> 
>>> res = p.amap(t.plus, x, y)
>>> res.get()
[4, 6, 8, 10]
回答4

据我所知,目前还没有解决您的问题的方法:您必须通过导入模块来访问您给map()的函数。 这就是罗伯特的代码起作用的原因:可以通过导入以下代码来获得函数f()

def f(x):
    return x*x

class Calculate(object):
    def run(self):
        p = Pool()
        return p.map(f, [1,2,3])

if __name__ == '__main__':
    cl = Calculate()
    print cl.run()

我实际上添加了一个“主要”部分,因为它遵循Windows平台的建议(“确保可以通过新的Python解释器安全地导入主要模块,而不会引起意外的副作用”)。

我还在Calculate前面添加了一个大写字母,以便遵循PEP 8::)

回答5

mrule的解决方案是正确的,但有一个错误:如果子级发回大量数据,则它可以填充管道的缓冲区,阻塞子级的pipe.send() ,而父级正在等待子级退出pipe.join() 。 解决方案是在对儿童进行join()之前读取其数据。 此外,孩子应关闭父母的管道末端,以防止死锁。 下面的代码解决了该问题。 另请注意,此parmapX中为每个元素创建一个进程。 更高级的解决方案是使用multiprocessing.cpu_count()X划分为多个块,然后合并结果,然后再返回。 我将其作为练习留给读者,以免破坏mrule的简洁答案的简洁性。 ;)

from multiprocessing import Process, Pipe
from itertools import izip

def spawn(f):
    def fun(ppipe, cpipe,x):
        ppipe.close()
        cpipe.send(f(x))
        cpipe.close()
    return fun

def parmap(f,X):
    pipe=[Pipe() for x in X]
    proc=[Process(target=spawn(f),args=(p,c,x)) for x,(p,c) in izip(X,pipe)]
    [p.start() for p in proc]
    ret = [p.recv() for (p,c) in pipe]
    [p.join() for p in proc]
    return ret

if __name__ == '__main__':
    print parmap(lambda x:x**x,range(1,5))
回答6

我也为此感到挣扎。 作为一个简化的示例,我具有作为类的数据成员的功能:

from multiprocessing import Pool
import itertools
pool = Pool()
class Example(object):
    def __init__(self, my_add): 
        self.f = my_add  
    def add_lists(self, list1, list2):
        # Needed to do something like this (the following line won't work)
        return pool.map(self.f,list1,list2)  

我需要在同一类的Pool.map()调用中使用self.f函数,而self.f没有将元组作为参数。 由于此函数是嵌入在类中的,因此我不清楚如何编写包装器的类型以及其他建议的答案。

我通过使用另一个接受元组/列表的包装器解决了这个问题,其中第一个元素是函数,其余元素是该函数的参数,称为eval_func_tuple(f_args)。 使用此方法,有问题的行可以用return pool.map(eval_func_tuple,itertools.izip(itertools.repeat(self.f),list1,list2))代替。 这是完整的代码:

档案:util.py

def add(a, b): return a+b

def eval_func_tuple(f_args):
    """Takes a tuple of a function and args, evaluates and returns result"""
    return f_args[0](*f_args[1:])  

档案:main.py

from multiprocessing import Pool
import itertools
import util  

pool = Pool()
class Example(object):
    def __init__(self, my_add): 
        self.f = my_add  
    def add_lists(self, list1, list2):
        # The following line will now work
        return pool.map(util.eval_func_tuple, 
            itertools.izip(itertools.repeat(self.f), list1, list2)) 

if __name__ == '__main__':
    myExample = Example(util.add)
    list1 = [1, 2, 3]
    list2 = [10, 20, 30]
    print myExample.add_lists(list1, list2)  

运行main.py将得到[11,22,33]。 随时进行改进,例如,也可以将eval_func_tuple修改为采用关键字参数。

另一方面,在另一个答案中,对于进程数多于可用CPU数的情况,可以使函数“ parmap”更有效。 我在下面复制一个编辑后的版本。 这是我的第一篇文章,我不确定是否应该直接编辑原始答案。 我还重命名了一些变量。

from multiprocessing import Process, Pipe  
from itertools import izip  

def spawn(f):  
    def fun(pipe,x):  
        pipe.send(f(x))  
        pipe.close()  
    return fun  

def parmap(f,X):  
    pipe=[Pipe() for x in X]  
    processes=[Process(target=spawn(f),args=(c,x)) for x,(p,c) in izip(X,pipe)]  
    numProcesses = len(processes)  
    processNum = 0  
    outputList = []  
    while processNum < numProcesses:  
        endProcessNum = min(processNum+multiprocessing.cpu_count(), numProcesses)  
        for proc in processes[processNum:endProcessNum]:  
            proc.start()  
        for proc in processes[processNum:endProcessNum]:  
            proc.join()  
        for proc,c in pipe[processNum:endProcessNum]:  
            outputList.append(proc.recv())  
        processNum = endProcessNum  
    return outputList    

if __name__ == '__main__':  
    print parmap(lambda x:x**x,range(1,5))         
回答7

我知道这个问题是在8年零10个月前提出的,但我想向您介绍我的解决方案:

from multiprocessing import Pool

class Test:

    def __init__(self):
        self.main()

    @staticmethod
    def methodForMultiprocessing(x):
        print(x*x)

    def main(self):
        if __name__ == "__main__":
            p = Pool()
            p.map(Test.methodForMultiprocessing, list(range(1, 11)))
            p.close()

TestObject = Test()

您只需要使您的类函数成为静态方法即可。 但是也可以使用类方法:

from multiprocessing import Pool

class Test:

    def __init__(self):
        self.main()

    @classmethod
    def methodForMultiprocessing(cls, x):
        print(x*x)

    def main(self):
        if __name__ == "__main__":
            p = Pool()
            p.map(Test.methodForMultiprocessing, list(range(1, 11)))
            p.close()

TestObject = Test()

在Python 3.7.3中测试

回答8

我回答了klaus se和aganders3的回答,并制作了一个文档化的模块,该模块更具可读性,并保存在一个文件中。 您可以将其添加到您的项目中。 它甚至有一个可选的进度条!

"""
The ``processes`` module provides some convenience functions
for using parallel processes in python.

Adapted from http://stackoverflow.com/a/16071616/287297

Example usage:

    print prll_map(lambda i: i * 2, [1, 2, 3, 4, 6, 7, 8], 32, verbose=True)

Comments:

"It spawns a predefined amount of workers and only iterates through the input list
 if there exists an idle worker. I also enabled the "daemon" mode for the workers so
 that KeyboardInterupt works as expected."

Pitfalls: all the stdouts are sent back to the parent stdout, intertwined.

Alternatively, use this fork of multiprocessing: 
https://github.com/uqfoundation/multiprocess
"""

# Modules #
import multiprocessing
from tqdm import tqdm

################################################################################
def apply_function(func_to_apply, queue_in, queue_out):
    while not queue_in.empty():
        num, obj = queue_in.get()
        queue_out.put((num, func_to_apply(obj)))

################################################################################
def prll_map(func_to_apply, items, cpus=None, verbose=False):
    # Number of processes to use #
    if cpus is None: cpus = min(multiprocessing.cpu_count(), 32)
    # Create queues #
    q_in  = multiprocessing.Queue()
    q_out = multiprocessing.Queue()
    # Process list #
    new_proc  = lambda t,a: multiprocessing.Process(target=t, args=a)
    processes = [new_proc(apply_function, (func_to_apply, q_in, q_out)) for x in range(cpus)]
    # Put all the items (objects) in the queue #
    sent = [q_in.put((i, x)) for i, x in enumerate(items)]
    # Start them all #
    for proc in processes:
        proc.daemon = True
        proc.start()
    # Display progress bar or not #
    if verbose:
        results = [q_out.get() for x in tqdm(range(len(sent)))]
    else:
        results = [q_out.get() for x in range(len(sent))]
    # Wait for them to finish #
    for proc in processes: proc.join()
    # Return results #
    return [x for i, x in sorted(results)]

################################################################################
def test():
    def slow_square(x):
        import time
        time.sleep(2)
        return x**2
    objs    = range(20)
    squares = prll_map(slow_square, objs, 4, verbose=True)
    print "Result: %s" % squares

编辑:添加了@ alexander-mcfarlane建议和一个测试功能

回答9

我知道这个问题是在6年前提出的,但是只是想添加我的解决方案,因为上面的一些建议看起来非常复杂,但是我的解决方案实际上非常简单。

我要做的就是将pool.map()调用包装到一个辅助函数中。 将方法的类对象和args作为元组传递,看起来有点像这样。

def run_in_parallel(args):
    return args[0].method(args[1])

myclass = MyClass()
method_args = [1,2,3,4,5,6]
args_map = [ (myclass, arg) for arg in method_args ]
pool = Pool()
pool.map(run_in_parallel, args_map)
回答10

在类中定义的函数(即使在类中的函数内部)也不会真正使用户感到烦恼。 但是,这可行:

def f(x):
    return x*x

class calculate(object):
    def run(self):
        p = Pool()
    return p.map(f, [1,2,3])

cl = calculate()
print cl.run()
回答11

我修改了klaus se的方法,因为当它以较小的列表为我工作时,当项目数大于或等于1000时,它将挂起。 我None一次以None停止条件一次推送作业,而是一次全部加载了输入队列,只是让进程在其上进行修改,直到其为空。

from multiprocessing import cpu_count, Queue, Process

def apply_func(f, q_in, q_out):
    while not q_in.empty():
        i, x = q_in.get()
        q_out.put((i, f(x)))

# map a function using a pool of processes
def parmap(f, X, nprocs = cpu_count()):
    q_in, q_out   = Queue(), Queue()
    proc = [Process(target=apply_func, args=(f, q_in, q_out)) for _ in range(nprocs)]
    sent = [q_in.put((i, x)) for i, x in enumerate(X)]
    [p.start() for p in proc]
    res = [q_out.get() for _ in sent]
    [p.join() for p in proc]

    return [x for i,x in sorted(res)]

编辑:不幸的是,现在我在系统上遇到此错误:Multiprocessing Queue maxsize限制为32767,希望那里的解决方法会有所帮助。

回答12

如果您以某种方式手动忽略了类中的对象列表中的Pool对象,则可以运行您的代码而不会出现任何问题,因为它不能像错误所指出的那样进行pickle 。 您可以使用__getstate__函数(也请__getstate__此处)执行以下操作。 Pool对象将尝试查找__getstate____setstate__函数,并在运行mapmap_async等时找到它们时执行它们:

class calculate(object):
    def __init__(self):
        self.p = Pool()
    def __getstate__(self):
        self_dict = self.__dict__.copy()
        del self_dict['p']
        return self_dict
    def __setstate__(self, state):
        self.__dict__.update(state)

    def f(self, x):
        return x*x
    def run(self):
        return self.p.map(self.f, [1,2,3])

然后做:

cl = calculate()
cl.run()

将为您提供输出:

[1, 4, 9]

我已经在Python 3.x中测试了上面的代码,并且可以正常工作。

回答13

这可能不是一个很好的解决方案,但就我而言,我是这样解决的。

from multiprocessing import Pool

def foo1(data):
    self = data.get('slf')
    lst = data.get('lst')
    return sum(lst) + self.foo2()

class Foo(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def foo2(self):
        return self.a**self.b   

    def foo(self):
        p = Pool(5)
        lst = [1, 2, 3]
        result = p.map(foo1, (dict(slf=self, lst=lst),))
        return result

if __name__ == '__main__':
    print(Foo(2, 4).foo())

我必须将self传递给函数,因为我必须通过该函数访问类的属性和函数。 这对我有用。 始终欢迎提出更正和建议。

回答14

这是我为在python3中使用多处理池而编写的样板,特别是使用python3.7.7来运行测试。 我使用imap_unordered获得了最快的运行imap_unordered 。 只需插入您的方案并尝试一下即可。 您可以使用timeit或仅使用time.time()来确定最适合您的方法。

import multiprocessing
import time

NUMBER_OF_PROCESSES = multiprocessing.cpu_count()
MP_FUNCTION = 'starmap'  # 'imap_unordered' or 'starmap' or 'apply_async'

def process_chunk(a_chunk):
    print(f"processig mp chunk {a_chunk}")
    return a_chunk


map_jobs = [1, 2, 3, 4]

result_sum = 0

s = time.time()
if MP_FUNCTION == 'imap_unordered':
    pool = multiprocessing.Pool(processes=NUMBER_OF_PROCESSES)
    for i in pool.imap_unordered(process_chunk, map_jobs):
        result_sum += i
elif MP_FUNCTION == 'starmap':
    pool = multiprocessing.Pool(processes=NUMBER_OF_PROCESSES)
    try:
        map_jobs = [(i, ) for i in map_jobs]
        result_sum = pool.starmap(process_chunk, map_jobs)
        result_sum = sum(result_sum)
    finally:
        pool.close()
        pool.join()
elif MP_FUNCTION == 'apply_async':
    with multiprocessing.Pool(processes=NUMBER_OF_PROCESSES) as pool:
        result_sum = [pool.apply_async(process_chunk, [i, ]).get() for i in map_jobs]
    result_sum = sum(result_sum)
print(f"result_sum is {result_sum}, took {time.time() - s}s")

在上述情况下, imap_unordered实际上对我而言表现最差。 试用您的案例,并在打算运行它的机器上对其进行基准测试。 另请阅读过程池。 干杯!

回答15

我不确定是否已采用这种方法,但是我正在使用的解决方法是:

from multiprocessing import Pool

t = None

def run(n):
    return t.f(n)

class Test(object):
    def __init__(self, number):
        self.number = number

    def f(self, x):
        print x * self.number

    def pool(self):
        pool = Pool(2)
        pool.map(run, range(10))

if __name__ == '__main__':
    t = Test(9)
    t.pool()
    pool = Pool(2)
    pool.map(run, range(10))

输出应为:

0
9
18
27
36
45
54
63
72
81
0
9
18
27
36
45
54
63
72
81
回答16
class Calculate(object):
  # Your instance method to be executed
  def f(self, x, y):
    return x*y

if __name__ == '__main__':
  inp_list = [1,2,3]
  y = 2
  cal_obj = Calculate()
  pool = Pool(2)
  results = pool.map(lambda x: cal_obj.f(x, y), inp_list)

您可能希望将此函数应用于类的每个不同实例。 那么这也是解决方案

class Calculate(object):
  # Your instance method to be executed
  def __init__(self, x):
    self.x = x

  def f(self, y):
    return self.x*y

if __name__ == '__main__':
  inp_list = [Calculate(i) for i in range(3)]
  y = 2
  pool = Pool(2)
  results = pool.map(lambda x: x.f(y), inp_list)
回答17

这是我的解决方案,我认为它比这里的大多数其他解决方案都没有那么强大。 这类似于nightowl的答案。

someclasses = [MyClass(), MyClass(), MyClass()]

def method_caller(some_object, some_method='the method'):
    return getattr(some_object, some_method)()

othermethod = partial(method_caller, some_method='othermethod')

with Pool(6) as pool:
    result = pool.map(othermethod, someclasses)
回答18

来自http://www.rueckstiess.net/research/snippets/show/ca1d7d90和http://qingkaikong.blogspot.com/2016/12/python-parallel-method-in-class.html

我们可以创建一个外部函数,并使用类self对象将其作为种子:

from joblib import Parallel, delayed
def unwrap_self(arg, **kwarg):
    return square_class.square_int(*arg, **kwarg)

class square_class:
    def square_int(self, i):
        return i * i

    def run(self, num):
        results = []
        results = Parallel(n_jobs= -1, backend="threading")\
            (delayed(unwrap_self)(i) for i in zip([self]*len(num), num))
        print(results)

或不带joblib:

from multiprocessing import Pool
import time

def unwrap_self_f(arg, **kwarg):
    return C.f(*arg, **kwarg)

class C:
    def f(self, name):
        print 'hello %s,'%name
        time.sleep(5)
        print 'nice to meet you.'

    def run(self):
        pool = Pool(processes=2)
        names = ('frank', 'justin', 'osi', 'thomas')
        pool.map(unwrap_self_f, zip([self]*len(names), names))

if __name__ == '__main__':
    c = C()
    c.run()

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 不能泡菜使用多重处理Pool.map()时(Can't pickle <type 'instancemethod'> when using multiprocessing Pool.map())
    问题 我正在尝试使用multiprocessing的Pool.map()函数来同时划分工作。 当我使用以下代码时,它可以正常工作: import multiprocessing def f(x): return x*x def go(): pool = multiprocessing.Pool(processes=4) print pool.map(f, range(10)) if __name__== '__main__' : go() 但是,当我以更加面向对象的方式使用它时,它将无法正常工作。 它给出的错误信息是: PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed 当以下是我的主程序时,会发生这种情况: import someClass if __name__== '__main__' : sc = someClass.someClass() sc.go() 以下是我的someClass类: import multiprocessing class someClass(object): def __init__(self): pass def f(self, x): return x*x def go(self)
  • 接口和类之间的区别是什么?为什么可以在类中直接实现方法,为什么要使用接口?(What is the difference between an interface and a class, and why I should use an interface when I can implement the methods directly in the class?)
    问题 我知道这是一个非常基本的问题,但是一位面试官以非常棘手的方式问我,我很无助:( 我只知道接口的材料或理论定义,并且在我从事的许多项目中也都实现了它。 但是我真的不明白为什么这样做有用。 我也不了解界面中的一件事。 即例如,我们使用 conn.Dispose(); 在最后块。 但是我看不到该类正在实现或继承IDisposable接口( SqlConnection )类。 我想知道如何仅可以调用方法名称。 同样,我也不了解Dispose方法的工作原理,因为我们需要为所有接口方法使用自己的实现来实现函数体。 那么接口如何被接受或命名为合同呢? 直到现在,这些问题一直在我的脑海中浮现,坦率地说,我从未见过任何好的线索可以用我能理解的方式解释我的问题。 像往常一样,MSDN看起来非常可怕,并且没有清晰的界线(伙计们,请高水平开发的人为借口,我强烈认为任何代码或文章都应该引起任何看到它的人的注意,因此,就像许多其他人所说的那样,MSDN没用)。 面试官说: 他有5种方法,并且很乐意直接在类中实现它,但是如果您必须使用Abstract类或接口,则选择哪种方法,为什么? 我确实回答了我在各个博客中读到的所有东西,并说了抽象类和接口的优点和缺点,但是他不相信,他通常试图理解“为什么要使用接口”。 即使我只能一次实现相同的方法,也不能改变它,但是一般来说,“为什么抽象类”还是可以的。
  • 在Python多处理中将Pool.map与共享内存数组结合(Combine Pool.map with shared memory Array in Python multiprocessing)
    问题 我有一个很大的(只读)数据数组,我想由多个进程并行处理。 我喜欢Pool.map函数,并希望使用它来并行计算该数据上的函数。 我看到可以使用Value或Array类在进程之间使用共享内存数据。 但是当我尝试使用它时,我得到一个RuntimeError: 'SynchronizedString objects should only be shared between processes through inheritance使用Pool.map函数时, RuntimeError: 'SynchronizedString objects should only be shared between processes through inheritance : 这是我正在尝试做的一个简化示例: from sys import stdin from multiprocessing import Pool, Array def count_it( arr, key ): count = 0 for c in arr: if c == key: count += 1 return count if __name__ == '__main__': testData = "abcabcs bsdfsdf gdfg dffdgdfg sdfsdfsd sdfdsfsdf" # want to
  • 接口默认方法是什么鬼
    接口之所以成为接口,就在于它没有实现,只是声明。但后来一切都变了,Java 里出现了默认方法,C# 也出现了默认方法。接口已经不像传统意义上的接口,其概念开始向抽象类靠近,一个纯抽象的东西,突然出现了实体,于是开始傻傻分不清了。 世界已经变了,可他是怎么开始改变的呢? 1. 缘起 虽然本文有提到 Java,但是笔者近年主要还是在写 C# 程序,所以未明确语言的命名规范会更倾向 C# 的规范一些,敬请谅解。 曾经,我们定义了 IStringList 接口,它声明了一个列表: 这只是个例子,为了避免引入更多的技术概念,这里没有使用泛型举例。 interface IStringList { void Add(string o); // 添加元素 void Remove(int i); // 删除元素 string Get(int i); // 获取元素 int Length { get; } // 获取列表长度 } 不管怎么说,这个列表已经拥有了基本的增删除改查功能,比如遍历,可以这样写 IStringList list = createList(); for (var i = 0; i < list.Length; i++) { string o = list.Get(i); // Do something with o } 这个 IStringList
  • Java接口如何模拟多重继承?(How do Java Interfaces simulate multiple inheritance?)
    问题 我正在阅读“ Java教程”(第2次)。 我刚读完有关接口的部分,但仍然不了解Java接口如何模拟多重继承。 有比书中更清楚的解释吗? 回答1 假设您的域中有两种东西:卡车和厨房 卡车具有driveTo()方法,而Kitchens具有cook()方法。 现在,假设Pauli决定从送货卡车的后部出售比萨饼。 他想要一种可以与drive()和cook()一起使用的东西。 在C ++中,他将使用多重继承来做到这一点。 在Java中,这被认为太危险了,因此您可以从主类继承,但是可以从接口“继承”行为,这些行为对于所有意图和目的都是抽象类,没有字段或方法实现。 因此,在Java中,我们倾向于使用委托来实现多重继承: Pauli对卡车进行了子类化,并在名为“厨房”的成员变量中为卡车添加了厨房。 他通过调用kitchen.cook()来实现Kitchen接口。 class PizzaTruck extends Truck implements Kitchen { Kitchen kitchen; public void cook(Food foodItem) { kitchen.cook(foodItem); } } 他是一个快乐的人,因为他现在可以做类似的事情; pizzaTruck.driveTo(beach); pizzaTruck.cook
  • 何时使用:Java 8+接口默认方法与抽象方法(When to use: Java 8+ interface default method, vs. abstract method)
    问题 Java 8允许在称为“默认方法”的接口中默认实现方法。 我在何时使用那种interface default method而不是abstract class (带有abstract method(s)之间感到困惑。 那么,什么时候应该使用默认方法接口,什么时候应该使用抽象类(带有抽象方法)? 在这种情况下,抽象类仍然有用吗? 回答1 除了默认方法实现(例如私有状态)外,抽象类还有很多,但是从Java 8开始,无论选择哪种方法,都应该在接口中使用Defender(又名default )方法。 对默认方法的限制是,只能在对其他接口方法的调用方面实现默认方法,而无需参考特定实现的状态。 因此,主要用例是更高级别的便捷方法。 这项新功能的好处在于,在您不得不为便利方法使用抽象类,从而将实现者限制为单一继承之前,现在您可以拥有仅接口和最少实现量的真正干净的设计程序员的努力。 向Java 8引入default方法的最初动机是希望用面向lambda的方法扩展Collections Framework接口,而不破坏任何现有实现。 尽管这与公共图书馆的作者更为相关,但是您可能会发现相同的功能在您的项目中也很有用。 您可以在一个集中的地方添加新的便利,而不必依赖其他类型层次结构的外观。 回答2 有一些技术差异。 与Java 8接口相比,抽象类仍然可以做更多的事情: 抽象类可以有一个构造函数。
  • 什么是mixin,为什么它们有用?(What is a mixin, and why are they useful?)
    问题 在“ Python编程”中,Mark Lutz提到了“ mixins”。 我来自C / C ++ / C#背景,以前没有听说过这个词。 什么是mixin? 在本示例的两行之间进行阅读(我已经链接到它,因为它很长),我认为这是使用多重继承来扩展类而不是“适当的”子类的一种情况。 这是正确的吗? 为什么我要这样做而不是将新功能放入子类中? 因此,为什么混合/多重继承方法比使用组合更好? 什么将mixin与多重继承区分开? 这仅仅是语义问题吗? 回答1 mixin是一种特殊的多重继承。 使用mixin的主要情况有两种: 您想为一个类提供很多可选功能。 您想在许多不同的类中使用一种特定功能。 例如,考虑werkzeug的请求和响应系统。 我可以说一个普通的旧请求对象: from werkzeug import BaseRequest class Request(BaseRequest): pass 如果我想添加接受标头支持,我会做到这一点 from werkzeug import BaseRequest, AcceptMixin class Request(AcceptMixin, BaseRequest): pass 如果我想创建一个支持接受标头,etag,身份验证和用户代理支持的请求对象,则可以执行以下操作: from werkzeug import BaseRequest
  • 继承和多态
    继承(inheritance) 机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础.上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认识过程。 多态性(polymorphism) 多态性是考虑在不同层次的类中,以及在同一类中,同名的成员函数之间的关系问题。函数的重载,运算符的重载,属于编译时的多态性。以虚基类为基础的运行时的多态性是面向对象程序设计的标志题。函数的重载,运算符的重载,属于编译时的多态性。以虚基类为基础的运行时的多态性是面向对象程序设计的标志 继承 C++通过类派生的机制来支持继承,被继承的类叫做基类或超类,新产生的来叫做派生类或子类。基类和派生类的集合叫做类继承层次结构。 使用方法: class 派生类名 :访问限定符 基类名,…,访问限定符 基类名 编制派生类分为四步: 1、吸收基类成员:无论数据成员还是函数成员,除构造函数和析构函数外全盘接收。 2、改造基类成员:声明一个和某基类同名的新成员,派生类的新成员就屏蔽了基类同名成员叫做同名覆盖。 3、发展新成员:派生类新成员与基类的所有成员步同名,它的加入保证派生类在功能上有所发展,独有的新成员是继承和派生的核心特征 。 4、重写构造函数和析构函数。 访问控制,也叫继承方式,对基类成员的进一步限制。 公有继承(public)
  • PHP接口的意义是什么?(What is the point of interfaces in PHP?)
    问题 接口允许您创建定义实现它的类的方法的代码。 但是,您不能向这些方法添加任何代码。 抽象类使您可以做同样的事情,并向该方法中添加代码。 现在,如果您可以使用抽象类实现相同的目标,为什么我们甚至需要接口的概念? 有人告诉我,它与从C ++到Java的OO理论有关,这是PHP的OO东西所基于的。 这个概念在Java中有用但在PHP中没有用吗? 这只是一种避免在抽象类中乱扔占位符的方法吗? 我想念什么吗? 回答1 接口的全部目的是使您能够灵活地使您的类被强制实现多个接口,但仍不允许多重继承。 从多个类继承的问题很多,而且也各不相同,其上的Wikipedia页面对此进行了很好的总结。 接口是一种折衷。 多重继承的大多数问题都不适用于抽象基类,因此,当今大多数现代语言都禁用了多重继承,但调用了抽象基类接口,并允许一个类根据需要“实现”许多此类。 回答2 该概念在面向对象的编程中非常有用。 对我来说,我认为接口是一种合同。 只要我的班级和您的班级就此方法签名协议达成共识,我们就可以“接口”。 至于抽象类,我认为它们更多是一些某些方法的基类,因此我需要填写详细信息。 回答3 如果已经有抽象类,为什么还需要一个接口? 防止多重继承(可能导致多个已知问题)。 这些问题之一: “钻石问题”(有时称为“致命的死亡钻石”)是当两个B类和C类从A继承而D类从B和C继承时产生的歧义。 B和C已被覆盖
  • 第十三节: 面向对象(二)
    面向对象(二) 面向对象(二)封装property装饰器继承**继承简介****方法重写****super()****多重继承** 作业 面向对象(二) 封装 出现封装的原因:我们需要一种方式来增强数据的安全性 • 1. 属性不能随意修改 • 2. 属性不能改为任意的值封装是面向对象的三大特性之一 • 封装是指隐藏对象中一些不希望被外部所访问到的属性或方法可以为对象的属性使用 双下划线 开头 __xxx(单下划线:弱私有,双下划线:强私有)。双下划线开头的属性,是对象的隐藏属性(私有属性),隐藏属性只能在类的内部访问,无法通过对象访问但,如果一个属性以"_xxx_“的形式定义,那么它可以被外部访问。以”_xxx_“定义的属性在 Python 的类中是特殊属性,有很多预定义的特殊属性都是以“_xxx_”定义,所以我们不要把普通属性用”_xxx_" 定义。其实隐藏属性只不过是Python自动为属性改了一个名字 --> _类名__属性名 例如 __name -> _Person__name这种方式实际上依然可以在外部访问,可以通过“ _类名__xx ”访问到属性的值。遵照编码规范我们也不该在外部访问 _xx 或 __xx 属性,一般我们会将一些私有属性以_开头一般情况下,使用_开头的属性都是私有属性,没有特殊情况下不要修改私有属性 # 如下圆类Circle的示例
  • Java:如果A扩展了B并且B扩展了Object,那是多重继承(Java : If A extends B and B extends Object, is that multiple inheritance)
    问题 我刚刚接受采访,有人问我一个问题。 采访者-Java是否支持多重继承? 我-不 采访者-Java中的每个类都扩展了类Object(类Object除外),如果我们从外部扩展了一个类,例如 Class A extends B{ // some code here } 那么您可以说A类扩展了B类和Object类,这意味着它是多重继承。 那么,怎么说Java不支持多重继承呢? 我-实际上,类B扩展了类Object,因此,当您在类A中扩展类B时,类A间接扩展了类Object。 这是多级继承,而不是多继承。 但是我的回答使他不满意。 我的答案正确吗? 还是我在哪里错? 内部实际发生了什么? 回答1 我的答案是正确的吗? 是的,主要是肯定的,并且一定是在您所描述的上下文中。 这不是多重继承: 就是您所说的,具有多个级别的单一继承。 这是多重继承:从两个或多个彼此没有任何“ is”关系的碱基继承; 将从不相关的行继承,或者从先前分歧的行继承(在Java中,由于Object始终是基础,因此它将是后者): (图片来源:“://”模式下的http://yuml.me) 内部实际上会发生什么? 就像您说的那样:有多个级别。 当编译器解析实例上的成员时: obj.member ...它看起来是因为obj的类型(在这种情况下是一个类,例如ClassB )是否具有member ,这是因为它直接提供了它
  • Python多重处理安全地写入文件(Python multiprocessing safely writing to a file)
    问题 我正在尝试解决一个涉及许多子问题的大数值问题,并且我正在使用Python的多处理模块(特别是Pool.map)将不同的独立子问题分解为不同的核心。 每个子问题都涉及计算大量子问题,并且我试图通过将结果存储到文件中(如果尚未通过任何过程对其进行计算)来有效地记住这些结果,否则跳过计算并仅从文件中读取结果。 我的文件存在并发问题:不同的流程有时会检查以查看是否已经计算了子子问题(通过查找将结果存储在文件中),没有找到子子问题,运行计算,然后尝试同时将结果写入同一文件。 如何避免这样写冲突? 回答1 @ GP89提到了一个很好的解决方案。 使用队列将写入任务发送到对文件具有唯一写访问权​​的专用进程。 所有其他工作人员均具有只读访问权限。 这将消除冲突。 这是一个使用apply_async的示例,但它也适用于map: import multiprocessing as mp import time fn = 'c:/temp/temp.txt' def worker(arg, q): '''stupidly simulates long running process''' start = time.clock() s = 'this is a test' txt = s for i in range(200000): txt += s done = time.clock() -
  • 如何在Python中进行并行编程?(How to do parallel programming in Python?)
    问题 对于C ++,我们可以使用OpenMP进行并行编程。 但是,OpenMP不适用于Python。 如果要并行执行python程序的某些部分,该怎么办? 该代码的结构可以认为是: 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 其中setinner和setouter是两个独立的功能。 那是我要平行的地方... 回答1 您可以使用多处理模块。 对于这种情况,我可以使用一个处理池: from
  • 面向对象和面向过程的区别
    C是面向过程C++、 JAVA是面向对象面向对象和面向过程的区别一个博大,一个精深.总体而言,面向对象简单,面向过程对人员要求素质过高面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。艾兰.库伯的《软件创新之路》中提到:面向过程和面向对象的区别并不像人们想象得那么大面向对象的大部分思想在面向过程中也能体现但面向过程最大的问题(也许是唯一先天的缺陷)在于随着系统的膨胀,面向过程将无法应付,最终导致系统的崩溃面向对象的提出正是试图解决这一软件危机目前看来,似乎有一定成效但仍任重道远---------------------------------------------------------------做一些对比来说吧:分析 基本构件 方法 工具---------------------------------面向过程 基于算法 函数/过程 数据流图、伪代码... ...面向对象 基于对象 类 UML建模... Rose,viso等---------------------------------------------------------------其实我始终认为,不管是面向对象,还是面向过程
  • Python是否在类中具有“私有”变量?(Does Python have “private” variables in classes?)
    问题 我来自Java世界,正在阅读Bruce Eckels的Python 3 Patterns,Recipes和Idioms 。 在阅读类时,它继续说在Python中不需要声明实例变量。 您只需在构造函数中使用它们,然后它们就在那里。 因此,例如: class Simple: def __init__(self, s): print("inside the simple constructor") self.s = s def show(self): print(self.s) def showMsg(self, msg): print(msg + ':', self.show()) 如果是这样,那么Simple类的任何对象都可以在类外部更改变量s的值。 例如: if __name__ == "__main__": x = Simple("constructor argument") x.s = "test15" # this changes the value x.show() x.showMsg("A message") 在Java中,我们已经学会了有关公共/私有/保护变量的知识。 这些关键字之所以有意义,是因为有时您需要一个类中的变量,而该类之外的任何人都无法访问该变量。 为什么在Python中不需要这样做? 回答1 这是文化的。 在Python中
  • 在C ++中使用“ super”(Using “super” in C++)
    问题 我的编码风格包括以下成语: class Derived : public Base { public : typedef Base super; // note that it could be hidden in // protected/private section, instead // Etc. } ; 这使我可以将“ super”用作Base的别名,例如,在构造函数中: Derived(int i, int j) : super(i), J(j) { } 甚至当从基类的重写版本中调用该方法时: void Derived::foo() { super::foo() ; // ... And then, do something else } 它甚至可以被链接(尽管我仍然需要找到它的用途): class DerivedDerived : public Derived { public : typedef Derived super; // note that it could be hidden in // protected/private section, instead // Etc. } ; void DerivedDerived::bar() { super::bar() ; // will call Derived::bar super::super
  • 我怎么知道什么时候创建一个界面?(How will I know when to create an interface?)
    问题 在开发学习中,我觉得必须学习更多有关接口的知识。 我经常阅读有关它们的信息,但似乎我无法掌握它们。 我已经阅读了以下示例:Animal基类,带有IAnimal接口,用于处理“ Walk”,“ Run”,“ GetLegs”等内容-但我从未从事过某些工作,并且感觉像“嘿,我应该使用接口这里!” 我想念什么? 为什么我很难理解这个概念! 我可能从未意识到具体需要的事实,这让我感到很震惊-主要是由于缺少理解它们的某些方面! 这让我觉得自己在成为一名开发人员方面缺少了一些重要的东西! 如果有人有这样的经历并取得了突破,我将不胜感激如何理解这一概念的一些技巧。 谢谢你。 回答1 它解决了这个具体问题: 您有4种不同类型的a,b,c,d。 在您的代码中,您都有类似以下内容的代码: a.Process(); b.Process(); c.Process(); d.Process(); 为什么不让他们实现IProcessable,然后执行 List<IProcessable> list; foreach(IProcessable p in list) p.Process(); 例如,当您添加50种类型的类都做相同的事情时,这将更好地扩展。 另一个具体问题: 您是否看过System.Linq.Enumerable? 它定义了许多扩展方法,这些扩展方法可用于实现IEnumerable的任何类型。
  • Ruby中的include和require有什么区别?(What is the difference between include and require in Ruby?)
    问题 我的问题类似于“在Ruby中包含和扩展之间有什么区别?”。 Ruby中的require和include什么区别? 如果我只想使用我班上某个模块中的方法,我是否require它或include其include ? 回答1 Ruby中的“ include”和“ require”有什么区别? 回答: include和require方法的作用截然不同。 require方法可以完成大多数其他编程语言所包含的功能:运行另一个文件。 它还会跟踪您过去所需的内容,并且不需要两次相同的文件。 要运行没有此附加功能的另一个文件,可以使用load方法。 include方法从另一个模块中获取所有方法,并将它们包括到当前模块中。 与require相比,这是语言级别的事情,而不是文件级别的事情。 include方法是与其他模块(通常称为混合)“扩展”类的主要方法。 例如,如果您的类定义了方法“ each”,则可以包括mixin模块Enumerable,并且它可以充当集合。 由于include动词在其他语言中的用法非常不同,因此可能会造成混淆。 资源 因此,如果您只想使用模块,而不是扩展它或进行混入,那么您将需要使用require 。 奇怪的是,Ruby的require类似于C的include ,而Ruby的include几乎没有C的include 。 回答2 如果使用模块,则意味着要将所有方法都带入类中
  • iOS求职之OC面试题
    1、Objective-C的类可以多重继承么?可以采用多个协议么?答:不可以多重继承,可以采用多个协议。2、#import和#include的区别是什么?#import<> 跟 #import""有什么区别?import能避免头文件被重复包含的问题:1) 一般来说,导入objective c的头文件时用#import,包含c/c++头文件时用#include。使用include要注意重复引用的问题:class A,class B都引用了class C,class D若引用class A与class B,就会报重复引用的错误。2)#import 确定一个文件只能被导入一次,这使你在递归包含中不会出现问题。所以,#import比起#include的好处就是它避免了重复引用的问题。所以在OC中我们基本用的都是import。#import<> 包含iOS框架类库里的类,#import""包含项目里自定义的类。3、Category是什么?扩展一个类的方式用继承好还是类目好?为什么?答 :Category是类目。用类目好,因为继承要满足a is a b的关系,而类目只需要满足a has a b的关系,局限性更小,你不用定义子类就能扩展一个类的功能,还能将类的定义分开放在不同的源文件里, 用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。4、延展是什么
  • C#中的多重继承(Multiple Inheritance in C#)
    问题 由于多重继承很糟糕(这会使源代码更加复杂),因此C#不会直接提供这种模式。 但是有时具有此功能会有所帮助。 例如,我能够使用接口和三个类似的类来实现缺少的多重继承模式: public interface IFirst { void FirstMethod(); } public interface ISecond { void SecondMethod(); } public class First:IFirst { public void FirstMethod() { Console.WriteLine("First"); } } public class Second:ISecond { public void SecondMethod() { Console.WriteLine("Second"); } } public class FirstAndSecond: IFirst, ISecond { First first = new First(); Second second = new Second(); public void FirstMethod() { first.FirstMethod(); } public void SecondMethod() { second.SecondMethod(); } } 每次我向其中一个接口添加一个方法时