Python线程锁定/类变量初始化混淆

时间:2015-05-30 15:54:19

标签: python multithreading class locking scikit-learn

我有一个类,如果多个线程访问它会表现得很奇怪。线程在sklearn的GridSearch训练期间启动(作业= 3),所以我不确切地知道它们是如何被调用的。

我的班级本身看起来大致如下:

from sklearn.base import BaseEstimator, TransformerMixin
import threading

class FeatureExtractorBase(BaseEstimator, TransformerMixin):
    expensive_dependency = {}
    lock = threading.lock()
    is_loaded = False

    @staticmethod
    def load_dependencies():
        FeatureExtractorBase.lock.acquire()
        if not FeatureExtractorBase.is_loaded:
            print('first request, start loading..')
            # load dependencies, takes a while
            FeatureExtractorBase.is_loaded = True
            print('done')
        else:
            pass
        FeatureExtractorBase.lock.release()

class ActualExtractor(FeatureExtractorBase):
    def transform(self, data):
        FeatureExtractorBase.load_dependencies()
        # generate features from data using dependencies
        return features

这个类使用了我希望的懒惰初始化。立即初始化会导致问题,我不能再这样做了。并且由于在一次程序调用期间类会重新初始化几次,因此每次初始化构造函数中的数据都会浪费时间。现在,问题是 这不是我想要的方式,这是输出:

Starting training
Fitting 3 folds for each of 1 candidates, totalling 3 fits
first request, start loading..
first request, start loading..
first request, start loading..
done.
done.
done.
Done   1 jobs       | elapsed:   56.2s
Done   3 out of   3 | elapsed:  1.0min finished

Starting evaluation
first request, start loading..
done.

不仅输入三个线程,我认为同时是锁定区域,一分钟后在测试期间,同一区域再次输入 - 尽管is_loaded应该设置为{{1 }} 在那时候。

这是我第一次使用Python处理线程,而且我对类仍然非常笨拙,所以我确信我在这里做错了。但我无法看到什么或在哪里。

1 个答案:

答案 0 :(得分:1)

由于全局解释器锁定(GIL),线程本身并不能加速其瓶颈是CPU而不是IO(读/写)的python进程。 实际上获得加速sklearn使用多处理进行并行化。这与线程不同,因为对象被复制到一个单独的进程中,因此实际上有多个类的副本。 因此,每次启动新进程时,都会复制原始的非初始化类,然后再次加载。

我认为这是sklearn用于网格搜索的主要并行化模块。 https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/externals/joblib/parallel.py