Python多进程似乎没有使用超过一个核心

35
我想使用Python multiprocessing来运行预测模型的网格搜索。当我查看核心使用情况时,似乎总是只使用一个核心。您有什么想法我做错了什么吗?

我希望使用Python的multiprocessing模块对预测模型进行网格搜索。然而,当我查看计算机的核心使用情况时,似乎始终只使用了一个核心。请问您有任何想法我可能出了什么问题吗?

import multiprocessing
from sklearn import svm
import itertools

#first read some data
#X will be my feature Numpy 2D array
#y will be my 1D Numpy array of labels

#define the grid        
C = [0.1, 1]
gamma = [0.0]
params = [C, gamma]
grid = list(itertools.product(*params))
GRID_hx = []

def worker(par, grid_list):
    #define a sklearn model
    clf = svm.SVC(C=g[0], gamma=g[1],probability=True,random_state=SEED)
    #run a cross validation function: returns error
    ll = my_cross_validation_function(X, y, model=clf, n=1, test_size=0.2)
    print(par, ll)
    grid_list.append((par, ll))


if __name__ == '__main__':
   manager = multiprocessing.Manager()
   GRID_hx = manager.list()
   jobs = []
   for g in grid:
      p = multiprocessing.Process(target=worker, args=(g,GRID_hx))
      jobs.append(p)
      p.start()
      p.join()

   print("\n-------------------")
   print("SORTED LIST")
   print("-------------------")
   L = sorted(GRID_hx, key=itemgetter(1))
   for l in L[:5]:
      print l

1
一旦您修复了连接问题,您可能还想了解全局解释器锁(GIL)。Python不能同时在两个线程上执行Python代码。但是,在像numpy这样的用于Python的C库的情况下,那些库可以在执行非常计算密集型任务时选择放弃GIL。如果要有效地使用多个核心,请确保大部分工作都在其中一个放弃GIL的C库中完成。 - Cort Ammon
注意:您可能想使用Pool而不是手动创建和加入每个单独的进程。只需执行pool.map(worker, args=zip(grid, [GRID_hx]*len(grid))]),这将自动启动不同的进程(并行)并加入它们。 - Bakuriu
5
@CortAmmon 你所写的内容完全不相关。他正在使用多进程而不是多线程,因此GIL在该代码中没有任何作用。此外:他使用multiprocessing而不是threading可能意味着他已经知道GIL的存在。 - Bakuriu
@Bakuriu 你说得完全正确。很抱歉我没注意到! - Cort Ammon
3个回答

50

你的问题是你一开始就加入每个工作:

for g in grid:
    p = multiprocessing.Process(target=worker, args=(g,GRID_hx))
    jobs.append(p)
    p.start()
    p.join()

join块代码执行直到所对应的进程结束工作。这意味着你的代码开始只能一次启动一个进程,等待其完成后再启动下一个进程

为了让所有进程并行运行,你需要先启动它们全部,然后再同时加入它们

jobs = []
for g in grid:
    p = multiprocessing.Process(target=worker, args=(g,GRID_hx))
    jobs.append(p)
    p.start()

for j in jobs:
    j.join()

文档:链接


6
根据文档,join()命令会锁定当前线程直到指定的线程返回。因此,在for循环中,您基本上是启动每个线程,然后等待它完成,然后才进行下一次迭代。
我建议将join放在循环外面!

5

我认为:

for g in grid:
    g.p = multiprocessing.Process(target=worker, args=(g,GRID_hx))
    jobs.append(g.p)
    g.p.start()
for g in grid:
    g.p.join()

目前你正在生成一个任务,然后等待它完成,再去下一个。


1
p.start() 这一行会引发 NameError 错误,因为 p 不存在。 - Ethan Furman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接