我一直在尝试使用python中的多处理模块来实现计算成本高昂的任务的并行性。
我能够执行我的代码,但它并不是并行运行的。我一直在阅读多处理的手册页和foruns,找出它为什么不起作用,我还没想出来。
我认为问题可能与执行我创建和导入的其他模块的某种锁定有关。
这是我的代码:
main.py:
##import my modules
import prepare_data
import filter_part
import wrapper_part
import utils
from myClasses import ML_set
from myClasses import data_instance
n_proc = 5
def main():
if __name__ == '__main__':
##only main process should run this
data = prepare_data.import_data() ##read data from file
data = prepare_data.remove_and_correct_outliers(data)
data = prepare_data.normalize_data_range(data)
features = filter_part.filter_features(data)
start_t = time.time()
##parallelism will be used on this part
best_subset = wrapper_part.wrapper(n_proc, data, features)
print time.time() - start_t
main()
wrapper_part.py:
##my modules
from myClasses import ML_set
from myClasses import data_instance
import utils
def wrapper(n_proc, data, features):
p_work_list = utils.divide_features(n_proc-1, features)
n_train, n_test = utils.divide_data(data)
workers = []
for i in range(0,n_proc-1):
print "sending process:", i
p = mp.Process(target=worker_classification, args=(i, p_work_list[i], data, features, n_train, n_test))
workers.append(p)
p.start()
for worker in workers:
print "waiting for join from worker"
worker.join()
return
def worker_classification(id, work_list, data, features, n_train, n_test):
print "Worker ", id, " starting..."
best_acc = 0
best_subset = []
while (work_list != []):
test_subset = work_list[0]
del(work_list[0])
train_set, test_set = utils.cut_dataset(n_train, n_test, data, test_subset)
_, acc = classification_decision_tree(train_set, test_set)
if acc > best_acc:
best_acc = acc
best_subset = test_subset
print id, " found best subset -> ", best_subset, " with accuracy: ", best_acc
所有其他模块都不使用多处理模块并且工作正常。 在这个阶段,我只是测试并行测试,甚至没有尝试获得结果,因此在进程和共享内存变量之间没有任何通信。 每个进程都使用一些变量,但是在生成进程之前定义它们,所以据我所知,我相信每个进程都有自己的变量副本。
作为5个流程的输出,我得到了这个:
importing data from file...
sending process: 0
sending process: 1
Worker 0 starting...
0 found best subset -> [2313] with accuracy: 60.41
sending process: 2
Worker 1 starting...
1 found best subset -> [3055] with accuracy: 60.75
sending process: 3
Worker 2 starting...
2 found best subset -> [3977] with accuracy: 62.8
waiting for join from worker
waiting for join from worker
waiting for join from worker
waiting for join from worker
Worker 3 starting...
3 found best subset -> [5770] with accuracy: 60.07
55.4430000782
4个进程执行并行部分大约需要55秒。仅使用1个进程对此进行测试,执行时间为16秒:
importing data from file...
sending process: 0
waiting for join from worker
Worker 0 starting...
0 found best subset -> [5870] with accuracy: 63.32
16.4409999847
我在python 2.7和Windows 8上运行它
修改
我在ubuntu上测试了我的代码并且它工作正常,我猜它与Windows 8和python有关。 这是ubuntu上的输出:
importing data from file...
size trainset: 792 size testset: 302
sending process: 0
sending process: 1
Worker 0 starting...
sending process: 2
Worker 1 starting...
sending process: 3
Worker 2 starting...
waiting for join from worker
Worker 3 starting...
2 found best subset -> [5199] with accuracy: 60.93
1 found best subset -> [3198] with accuracy: 60.93
0 found best subset -> [1657] with accuracy: 61.26
waiting for join from worker
waiting for join from worker
waiting for join from worker
3 found best subset -> [5985] with accuracy: 62.25
6.1428809166
我将从现在开始使用ubuntu进行测试,但是我想知道为什么代码在Windows上不起作用。
答案 0 :(得分:2)
请务必阅读multiprocessing
手册中的Windows指南:https://docs.python.org/2/library/multiprocessing.html#windows
特别是“安全导入主模块”:
相反,应该通过使用来保护程序的“入口点”
if __name__ == '__main__':
如下:
您在上面显示的第一个代码段中违反了此规则,所以我看起来没有这个。希望您观察到的问题的解决方案就像包含这种保护一样简单。
这一点很重要:在类Unix系统上,子进程是通过分叉创建的。在这种情况下,操作系统会创建创建fork的进程的精确副本。也就是说,所有状态都由子进程从父进程继承。例如,这意味着定义了所有函数和类。
在Windows上,没有此类系统调用。 Python需要执行在子项中创建新的Python解释器会话的相当繁重的任务,并重新创建(逐步)父项的状态。例如,需要再次定义所有函数和类。这就是为什么重型import
机器在Windows上的Python多处理子代的引擎下进行的原因。这个机器在孩子进口主模块时启动。在您的情况下,这意味着打电话给孩子main()
!当然,你不希望这样。
你可能会发现这很乏味。我发现令人印象深刻的是multiprocessing
模块设法为两个非常不同的平台提供相同功能的接口。实际上,就流程处理而言,POSIX兼容的操作系统和Windows是如此不同,以至于很难想出一个适用于这两者的抽象。