classmethods线程是否安全?

时间:2014-03-25 06:01:11

标签: python multithreading python-3.x class-method

我正在开发一个在多线程环境中运行的类,看起来像这样(去除了过多的噪声):

class B:

    @classmethod
    def apply(cls, item):
        cls.do_thing(item)

    @classmethod
    def do_thing(cls, item)
        'do something to item'

    def run(self):
        pool = multiprocessing.Pool()
        for list_of_items in self.data_groups:
            pool.map(list_of_items, self.apply)

我担心的是两个线程可能同时调用applydo_thing,或者一个子类可能会尝试在其中一个函数中使用cls做一些愚蠢的事情。我可以使用staticmethod代替classmethod,但调用do_thing会变得复杂得多,特别是如果子类重新实现其中一个而不是另一个。所以我的问题是:上面的类是线程安全的,还是使用像这样的类方法有潜在的问题?

3 个答案:

答案 0 :(得分:3)

在这方面,类方法和常规函数(以及实例方法)之间没有区别。两者都不是自动线程安全的。

如果一个或多个类方法/方法/函数可以同时处理来自不同线程的数据结构,则需要添加同步保护,通常使用threading.Lock s。

答案 1 :(得分:3)

方法是否是线程安全取决于方法的作用。

仅使用局部变量是线程安全的。但是,当您从不同的线程更改相同的非局部变量时,它变得不安全。

‘do something to item’似乎只修改给定的对象,该对象独立于列表中的任何其他对象,因此它应该是线程安全的。

如果同一个对象在列表中多次,您可能需要考虑使对象线程安全。这可以通过在修改对象的每个方法中使用with self.object_scope_lock:来完成。

无论如何,你在这里做的是使用进程而不是线程。在这种情况下,对象被pickle并通过管道发送到另一个进程,在那里它们被修改并发回。与线程进程相比,不共享内存。所以我认为在类方法中使用锁会产生影响。

http://docs.python.org/3/library/threading.html?highlight=threading#module-threading

答案 2 :(得分:1)

其他两个答案在技术上都是正确的,因为do_thing()的安全性取决于函数内部发生的事情。

但更准确的答案是呼叫本身是安全的。换句话说,如果apply()do_thing()pure functions,那么您的代码是安全的。任何不安全因素都是由于它们不是纯函数(例如在执行期间依赖或影响共享变量)

正如shx2所提到的,类方法只是"在"视觉上的一个类,用于分组。它们对类的任何实例都没有固有的附件。因此,此代码在功能上大致相同:

def apply(item):
    do_thing(item)

def do_thing(item)
    'do something to item'

class B:
    def run(self):
        pool = multiprocessing.Pool()
        for list_of_items in self.data_groups:
            pool.map(list_of_items, apply)

关于并发性的另一个注释,给出了其他答案:

  1. threading.Lock很容易理解,但应该是您的最后手段。在天真的实现中,它通常比完全线性处理慢。如果您可以使用threading.Eventqueue.Queuemultiprocessing.Pipe等内容来转移信息,那么您的代码通常会更快。
  2. asyncio是python3中的新热点。要做到这一点有点困难,但通常是最快的方法。
  3. 如果你想在python中使用现代并发技术,请查看核心开发人员Raymond Hettinger's Keynote on Concurrency。整个事情很棒,但lock的缺点从t = 57:59开始突出显示。