2014-03-25 25 views
2

我正在工作在多线程环境中,并且看起来像这样一类(含过量噪声去除):classmethods线程安全吗?

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

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

仅使用局部变量是线程安全的。但是当你从不同线程改变同一个非本地变量时,它变得不安全。

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

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

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

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

3

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

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

+0

感谢您的回答。那么就简单地调用'cls.do_thing'危险没有锁?直觉上我不这么认为,但我没有太多的多线程经验。 – aquavitae

+0

依赖于'thing'' do_thing()'做... – shx2

0

两个其他的答案都在的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开始突出显示。