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



我有一个类的行为奇怪,如果由多个线程访问。这些线程是在sklearn的GridSearch训练期间启动的(job =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在那时应该被设置为True

这是我第一次在Python中处理线程,我对类仍然很笨拙,所以我确定我在这里做错了什么。

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

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

相关内容

  • 没有找到相关文章

最新更新