Skip to main content
 首页 » 编程设计

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

2025年05月04日44me-sa

我有一个类,如果被多个线程访问,它的行为会很奇怪。线程在 sklearn 的 GridSearch 期间启动。 training (with jobs=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 中处理线程,我对类仍然很笨拙,所以我确定我在这里做错了什么。但我看不到什么或在哪里。

请您参考如下方法:

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

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