scikit-learn中n_jobs设为-1或大值时出现队列线程异常问题
Fix for ValueError: need at most 63 handles when using n_jobs=-1 in scikit-learn (Windows)
这个问题我之前在Windows环境下处理过,根源是Windows系统底层API的限制:sklearn依赖的loky多进程库,在Windows上会调用WaitForMultipleObjects函数,而这个函数最多只能同时等待63个句柄。当你设置n_jobs=-1(会使用所有CPU核心)或者设置的数值过大时,创建的进程数加上其他系统句柄会超过63,就会触发这个错误。
下面是几个可行的解决办法:
1. 限制n_jobs的最大值
直接把n_jobs设置为不超过60的数值(留几个句柄给系统进程),或者动态取CPU核心数和60的最小值,避免超过限制。比如修改你的代码:
import os from sklearn import datasets from sklearn.model_selection import cross_validate, StratifiedKFold from sklearn.linear_model import RidgeClassifier iris = datasets.load_iris() iris_X = iris.data iris_y = iris.target skf = StratifiedKFold(n_splits=5, random_state=0, shuffle=True) scoring = {'accuracy': 'accuracy'} model_ridge = RidgeClassifier(random_state=0) # 动态设置n_jobs为CPU核心数和60的最小值 max_workers = min(os.cpu_count(), 60) scores = cross_validate(estimator=model_ridge, X=iris_X, y=iris_y, scoring=scoring, cv=skf.split(iris_X, iris_y), n_jobs=max_workers)
2. 改用线程作为并行后端
如果你的模型是非CPU密集型(或者不受Python GIL限制,比如sklearn多数基于C扩展的模型已经释放了GIL),可以改用线程后端替代进程,这样不会触发Windows的句柄限制。只需要在cross_validate里加上backend="threading"参数:
scores = cross_validate(estimator=model_ridge, X=iris_X, y=iris_y, scoring=scoring, cv=skf.split(iris_X, iris_y), n_jobs=-1, backend="threading")
注意:如果你的模型是纯Python编写的CPU密集型任务,线程可能不会带来性能提升,但至少能解决这个错误。
3. 检查并更新相关依赖库
虽然你已经重装过scikit-learn和joblib,但可以尝试更新到最新稳定版,新版本的loky可能对Windows的句柄限制做了优化:
pip install --upgrade scikit-learn joblib loky
补充说明
之前n_jobs=-1能正常工作,可能是因为之前你的系统进程占用的句柄数更少,或者当时的CPU核心数更少,总句柄数没超过63。近期可能因为系统更新、后台进程增加或者CPU核心数识别变化(比如启用了超线程),导致总句柄数突破了限制。
内容的提问来源于stack exchange,提问作者Kirill Dolmatov
相关产品推荐
相关产品推荐

